From 81c3009c077ddab40df052bffaa646526e2b8dfc Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 31 Oct 2008 16:45:58 -0400 Subject: [boilerplate/Makefile.win32] Only build source files, not headers --- boilerplate/Makefile.win32 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/boilerplate/Makefile.win32 b/boilerplate/Makefile.win32 index a98b9fe3..84075dab 100644 --- a/boilerplate/Makefile.win32 +++ b/boilerplate/Makefile.win32 @@ -4,9 +4,12 @@ include Makefile.win32.features CFLAGS += -I../src -SOURCES = \ +HEADERS = \ $(enabled_cairo_boilerplate_headers) \ $(enabled_cairo_boilerplate_private) \ + $(NULL) + +SOURCES = \ $(enabled_cairo_boilerplate_sources) \ $(NULL) @@ -15,5 +18,6 @@ OBJECTS = $(patsubst %.c, $(CFG)/%.obj, $(SOURCES)) all: $(CFG)/boiler.lib + $(CFG)/boiler.lib: $(OBJECTS) lib -NOLOGO -OUT:$@ $(OBJECTS) $(WIN_LIBS) -- cgit v1.2.3 From ed2081d97401741db10b0244eaba7ff31ae63346 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 2 Nov 2008 15:05:07 +1030 Subject: Specify a background color for XFAIL text To improve readability on terminals with a white background. --- test/cairo-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cairo-test.c b/test/cairo-test.c index 11ca650d..90ca0af5 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -192,7 +192,7 @@ _cairo_test_init (cairo_test_context_t *ctx, #ifdef HAVE_UNISTD_H if (*fail_face == '\0' && isatty (2)) { fail_face = "\033[41;37;1m"; - xfail_face = "\033[33;1m"; + xfail_face = "\033[43;37;1m"; normal_face = "\033[m"; if (isatty (1)) print_fail_on_stdout = FALSE; -- cgit v1.2.3 From d682d275b90f7326df76d2764c513c8b6d5b551b Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 20:50:53 +0930 Subject: Add an extents argument to the high level surface backend functions Add a "cairo_rectangle_int_t *extents" argument to to the following backend functions: paint mask, stroke fill show_glyphs show_text_glyphs This will be used to pass the extents of each operation computed by the analysis surface to the backend. This is required for implementing EXTEND_PAD. --- src/cairo-analysis-surface.c | 49 +++++++++++++++++++++++--------------- src/cairo-directfb-surface.c | 3 ++- src/cairo-gstate.c | 12 +++++----- src/cairo-meta-surface.c | 27 ++++++++++++--------- src/cairo-paginated-surface.c | 27 ++++++++++++--------- src/cairo-pdf-surface.c | 18 +++++++++----- src/cairo-ps-surface.c | 12 ++++++---- src/cairo-quartz-surface.c | 15 ++++++++---- src/cairo-surface.c | 45 +++++++++++++++++++--------------- src/cairo-svg-surface.c | 24 ++++++++++++------- src/cairo-type3-glyph-surface.c | 17 ++++++++----- src/cairo-win32-printing-surface.c | 12 ++++++---- src/cairo-win32-surface.c | 3 ++- src/cairo-xlib-surface.c | 8 ++++--- src/cairoint.h | 39 ++++++++++++++++++++---------- src/test-meta-surface.c | 25 +++++++++++-------- src/test-paginated-surface.c | 25 +++++++++++-------- 17 files changed, 223 insertions(+), 138 deletions(-) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 4337e92c..be3f734b 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -322,7 +322,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 +334,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); @@ -363,7 +364,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 +376,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; @@ -445,7 +447,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 +462,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); @@ -515,7 +518,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 +532,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); @@ -583,7 +587,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 +601,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 +609,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; @@ -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) @@ -898,13 +904,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 +923,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 +933,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 +943,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, diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index 351e00d8..5a970b94 100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -1687,7 +1687,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; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 7e56a778..5b8c87d7 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -899,7 +899,7 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) status = _cairo_surface_paint (gstate->target, gstate->op, - pattern); + pattern, NULL); if (pattern == &pattern_stack.base) _cairo_pattern_fini (pattern); @@ -938,7 +938,7 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, 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); @@ -980,7 +980,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); @@ -1056,7 +1056,7 @@ _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); @@ -1679,7 +1679,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; @@ -1696,7 +1696,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); } diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c index faf48558..5f9fed25 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -219,7 +219,8 @@ _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; @@ -260,7 +261,8 @@ 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; @@ -306,7 +308,8 @@ _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; @@ -361,7 +364,8 @@ _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; @@ -419,7 +423,8 @@ _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; @@ -806,13 +811,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, NULL); 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, NULL); break; case CAIRO_COMMAND_STROKE: { @@ -834,7 +839,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, &dev_ctm, &dev_ctm_inverse, command->stroke.tolerance, - command->stroke.antialias); + command->stroke.antialias, NULL); break; } case CAIRO_COMMAND_FILL: @@ -881,7 +886,7 @@ _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, NULL); i++; } else status = _cairo_surface_fill (target, @@ -890,7 +895,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, NULL); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: @@ -927,7 +932,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, NULL); free (dev_glyphs); break; diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index ec9419bb..94a599e0 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -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: @@ -529,7 +529,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 +540,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 +564,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 +578,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 +588,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 +601,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 +623,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 +650,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; } diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index b2a5619e..6db4cd32 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -4420,7 +4420,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; @@ -4500,7 +4501,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; @@ -4584,7 +4586,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; @@ -4675,7 +4678,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; @@ -4774,7 +4778,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; @@ -4865,7 +4870,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; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index fbfdc3e5..62421438 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -3043,7 +3043,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; @@ -3108,7 +3109,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; @@ -3141,7 +3143,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; @@ -3203,7 +3206,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; diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index fc9439e3..2addd8bc 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -1667,7 +1667,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) + 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; @@ -1722,7 +1723,8 @@ _cairo_quartz_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_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1829,7 +1831,8 @@ _cairo_quartz_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_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1973,7 +1976,8 @@ _cairo_quartz_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) { CGAffineTransform textTransform, ctm; #define STATIC_BUF_SIZE 64 @@ -2286,7 +2290,8 @@ static cairo_int_status_t _cairo_quartz_surface_mask (void *abstract_surface, cairo_operator_t op, cairo_pattern_t *source, - cairo_pattern_t *mask) + cairo_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; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index ff75cc2f..40b10e72 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -327,7 +327,7 @@ _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); @@ -373,7 +373,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 @@ -1473,7 +1473,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; @@ -1490,7 +1491,7 @@ _cairo_surface_paint (cairo_surface_t *surface, 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 +1509,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; @@ -1532,7 +1534,7 @@ _cairo_surface_mask (cairo_surface_t *surface, 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 +1566,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; @@ -1600,7 +1603,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,13 +1617,13 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, } status = _cairo_surface_fill (surface, fill_op, fill_source, path, - fill_rule, fill_tolerance, fill_antialias); + fill_rule, fill_tolerance, fill_antialias, NULL); if (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); + stroke_tolerance, stroke_antialias, NULL); if (status) return _cairo_surface_set_error (surface, status); @@ -1635,7 +1639,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; @@ -1659,7 +1664,7 @@ _cairo_surface_stroke (cairo_surface_t *surface, 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 +1692,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; @@ -1706,7 +1712,7 @@ _cairo_surface_fill (cairo_surface_t *surface, 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; @@ -2258,7 +2264,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; @@ -2314,7 +2321,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 +2329,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 +2343,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 +2362,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); } } diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index a50f13b8..039cc39c 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -1890,7 +1890,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; @@ -1925,7 +1926,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; @@ -2013,7 +2015,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; @@ -2065,9 +2068,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; @@ -2154,7 +2158,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; @@ -2189,7 +2194,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; @@ -2261,7 +2267,7 @@ FALLBACK: } 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); diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c index 58048aca..6f9eb43e 100644 --- a/src/cairo-type3-glyph-surface.c +++ b/src/cairo-type3-glyph-surface.c @@ -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; @@ -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; diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 553ef406..77febf0b 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -1037,7 +1037,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 +1115,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 +1237,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 +1297,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; diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 05f5188c..70af72bb 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -1566,7 +1566,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; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 7efe8287..c59694d5 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, @@ -1283,7 +1284,7 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac status = _cairo_surface_paint (&image->base, CAIRO_OPERATOR_SOURCE, - &solid_pattern->base); + &solid_pattern->base, NULL); if (status) goto BAIL; @@ -3966,7 +3967,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; diff --git a/src/cairoint.h b/src/cairoint.h index f94e6821..4e9eea4e 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -726,13 +726,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 +745,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 +755,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 +765,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 +793,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 +815,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" @@ -1734,13 +1741,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, @@ -1756,7 +1765,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, @@ -1767,7 +1777,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, @@ -1776,7 +1787,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, @@ -1789,7 +1801,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, diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c index f19cbd69..71700bdd 100644 --- a/src/test-meta-surface.c +++ b/src/test-meta-surface.c @@ -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); } diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c index ba80a107..cfb87f33 100644 --- a/src/test-paginated-surface.c +++ b/src/test-paginated-surface.c @@ -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); } -- cgit v1.2.3 From fb7cfdd94d4e436e066d884f6dc294efd896b344 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 20:52:08 +0930 Subject: Make meta-surface store and replay extents of each operation To be able to provide the extents of each operation to the backend during the render phase the meta-surface needs to store the extents computed by the analysis surface during the analysis phase. The extents argument is either a pointer to the extents of the operation stored in the meta-surface or NULL. During analysis the analysis surface writes the extents to the meta-surface. During the render phase the extents is made available to paginated surface backends. --- src/cairo-analysis-surface.c | 12 ++++++++++++ src/cairo-meta-surface-private.h | 1 + src/cairo-meta-surface.c | 33 +++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index be3f734b..d5b63e8e 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -354,6 +354,8 @@ _cairo_analysis_surface_paint (void *abstract_surface, } is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + if (paint_extents) + *paint_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -432,6 +434,8 @@ _cairo_analysis_surface_mask (void *abstract_surface, } is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + if (mask_extents) + *mask_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -505,6 +509,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); @@ -574,6 +580,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); @@ -642,6 +650,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents); } + if (show_glyphs_extents) + *show_glyphs_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -726,6 +736,8 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, 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); 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 5f9fed25..cfaaf304 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -232,6 +232,10 @@ _cairo_meta_surface_paint (void *abstract_surface, 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); @@ -274,6 +278,10 @@ _cairo_meta_surface_mask (void *abstract_surface, 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); @@ -321,6 +329,10 @@ _cairo_meta_surface_stroke (void *abstract_surface, 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); @@ -377,6 +389,10 @@ _cairo_meta_surface_fill (void *abstract_surface, 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); @@ -436,6 +452,10 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, 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); @@ -811,13 +831,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, NULL); + &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, NULL); + &command->mask.mask.base, &command->header.extents); break; case CAIRO_COMMAND_STROKE: { @@ -839,7 +859,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, &dev_ctm, &dev_ctm_inverse, command->stroke.tolerance, - command->stroke.antialias, NULL); + command->stroke.antialias, &command->header.extents); break; } case CAIRO_COMMAND_FILL: @@ -886,7 +906,8 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, &dev_ctm, &dev_ctm_inverse, stroke_command->stroke.tolerance, - stroke_command->stroke.antialias, NULL); + stroke_command->stroke.antialias, + &stroke_command->header.extents); i++; } else status = _cairo_surface_fill (target, @@ -895,7 +916,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, dev_path, command->fill.fill_rule, command->fill.tolerance, - command->fill.antialias, NULL); + command->fill.antialias, &command->header.extents); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: @@ -932,7 +953,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, NULL); + command->show_text_glyphs.scaled_font, &command->header.extents); free (dev_glyphs); break; -- cgit v1.2.3 From d146cb4056ab54cf85454a6fe9d36282ca7a3f2e Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 20:56:01 +0930 Subject: PDF: Store the operation extents in each pattern The extents will be used by EXTEND_PAD patterns as well as any other pattern that can benefit from knowing the extents of the operation it will be used with. --- src/cairo-pdf-surface-private.h | 1 + src/cairo-pdf-surface.c | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index ab222ded..7f2764ff 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; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 6db4cd32..3920bd02 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -775,6 +775,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) { @@ -833,6 +834,15 @@ _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; @@ -3879,7 +3889,8 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, &pattern_res, &gstate_res); + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, NULL, + &pattern_res, &gstate_res); if (status) return status; @@ -3934,7 +3945,8 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, &pattern_res, &gstate_res); + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, NULL, + &pattern_res, &gstate_res); if (status) return status; @@ -4440,7 +4452,8 @@ _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) @@ -4601,7 +4614,8 @@ _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) @@ -4698,7 +4712,8 @@ _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) @@ -4807,6 +4822,7 @@ _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) @@ -4818,6 +4834,7 @@ _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) @@ -4885,7 +4902,8 @@ _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) -- cgit v1.2.3 From 6c92edd9a3b0c79857cfa8dee482efa56f40c714 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 20:56:49 +0930 Subject: PDF: Implement EXTEND_PAD for image patterns Images with EXTEND_PAD are painted into a new image the size of the operation extents. The new image is then embedded in the PDF file with the pattern matrix adjusted to ensure the image origin is in the correct location. --- src/cairo-pdf-surface.c | 70 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 3920bd02..218cd4fd 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1552,25 +1552,75 @@ CLEANUP: 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_surface_acquire_source_image (pattern->surface, &image, &image_extra); if (status) goto BAIL; - status = _cairo_pdf_surface_emit_image (surface, image, resource, pattern->base.filter); + 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 (status) + goto BAIL; + } + + status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image, + resource, pattern->base.filter); if (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); @@ -1657,6 +1707,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]; @@ -1678,10 +1730,12 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, pattern_height = pattern_extents.height; } else { status = _cairo_pdf_surface_emit_image_surface (surface, - pattern, + pdf_pattern, &pattern_resource, &pattern_width, - &pattern_height); + &pattern_height, + &origin_x, + &origin_y); if (status) return status; } @@ -1693,7 +1747,6 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, 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: { @@ -1777,6 +1830,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); -- cgit v1.2.3 From e639b536711c07bc09355205f476ab3f73012268 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 21:00:30 +0930 Subject: PDF: meta-surface patterns with EXTEND_PAD are unsupported We have to use fallback images for this. --- src/cairo-pdf-surface.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 218cd4fd..27fcbe08 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -4412,8 +4412,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 (cairo_pattern_get_extend (pattern) == CAIRO_EXTEND_PAD) + return CAIRO_INT_STATUS_UNSUPPORTED; + else + return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; + } } } -- cgit v1.2.3 From 19ee13ca2b5b1e08a7fc965516be514d2fe40232 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 21:01:17 +0930 Subject: PS: Implement EXTEND_PAD for image patterns Images with EXTEND_PAD are painted into a new image the size of the operation extents. The new image is then embedded in the PS file with the pattern matrix adjusted to ensure the image origin is in the correct location. --- src/cairo-ps-surface-private.h | 1 + src/cairo-ps-surface.c | 99 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 17 deletions(-) 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 62421438..ea8a2b77 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -79,6 +79,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, @@ -2224,11 +2228,16 @@ _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; @@ -2242,16 +2251,62 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, *height = pattern_extents.height; } else { status = _cairo_surface_acquire_source_image (pattern->surface, - &surface->image, + &surface->acquired_image, &surface->image_extra); if (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 (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 @@ -2279,24 +2334,28 @@ _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); + extents, + &width, &height, + &origin_x, &origin_y); if (status) return status; @@ -2329,6 +2388,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); @@ -2349,6 +2409,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 +2419,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 +2429,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); + extents, + &pattern_width, &pattern_height, + &origin_x, &origin_y); if (status) return status; switch (pattern->base.extend) { - /* We implement EXTEND_PAD like EXTEND_NONE for now */ case CAIRO_EXTEND_PAD: case CAIRO_EXTEND_NONE: { @@ -2914,7 +2977,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; @@ -2951,6 +3015,7 @@ _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) return status; @@ -3079,13 +3144,13 @@ _cairo_ps_surface_paint (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - op); + paint_extents, op); if (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; @@ -3125,7 +3190,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; @@ -3177,14 +3242,14 @@ _cairo_ps_surface_fill (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - op); + extents, op); if (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; @@ -3225,7 +3290,7 @@ _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; -- cgit v1.2.3 From a39a4f52ac4a057f579e881a9a929029bcc514d1 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 21:02:26 +0930 Subject: PS: meta-surface patterns with EXTEND_PAD are unsupported We have to use fallback images for this. --- src/cairo-ps-surface.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index ea8a2b77..e050ddbb 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -1571,8 +1571,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 (cairo_pattern_get_extend (pattern) == CAIRO_EXTEND_PAD) + return CAIRO_INT_STATUS_UNSUPPORTED; + else + return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; + } } if (op == CAIRO_OPERATOR_SOURCE) -- cgit v1.2.3 From 3c684347f49a581bfba35202ec61a5f6334acd4a Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 7 Sep 2008 20:46:20 +0930 Subject: Add cairo_surface_set_mime_data() Currently only handles jpeg data. --- src/cairo-surface-fallback.c | 15 ++++++++++ src/cairo-surface-private.h | 4 +++ src/cairo-surface.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ src/cairo.h | 15 ++++++++++ 4 files changed, 101 insertions(+) diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index a5dcd57a..62661174 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -1075,6 +1075,21 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) snapshot->device_transform = surface->device_transform; snapshot->device_transform_inverse = surface->device_transform_inverse; + if (surface->jpeg_destroy && + surface->jpeg_data != NULL && + surface->jpeg_data_length != 0) + { + snapshot->jpeg_data = malloc (surface->jpeg_data_length); + if (snapshot->jpeg_data == NULL) { + cairo_surface_destroy (snapshot); + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + } + + memcpy (snapshot->jpeg_data, surface->jpeg_data, surface->jpeg_data_length); + snapshot->jpeg_data_length = surface->jpeg_data_length; + snapshot->jpeg_destroy = free; + } + snapshot->is_snapshot = TRUE; return snapshot; diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h index efd4365e..1b5bb049 100644 --- a/src/cairo-surface-private.h +++ b/src/cairo-surface-private.h @@ -100,6 +100,10 @@ struct _cairo_surface { */ cairo_bool_t has_font_options; cairo_font_options_t font_options; + + unsigned char *jpeg_data; + unsigned int jpeg_data_length; + cairo_destroy_func_t jpeg_destroy; }; #endif /* CAIRO_SURFACE_PRIVATE_H */ diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 40b10e72..79366f24 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -220,6 +220,10 @@ _cairo_surface_init (cairo_surface_t *surface, surface->is_snapshot = FALSE; surface->has_font_options = FALSE; + + surface->jpeg_data = NULL; + surface->jpeg_data_length = 0; + surface->jpeg_destroy = NULL; } cairo_surface_t * @@ -440,6 +444,9 @@ cairo_surface_destroy (cairo_surface_t *surface) _cairo_user_data_array_fini (&surface->user_data); + if (surface->jpeg_data) + surface->jpeg_destroy (surface->jpeg_data); + free (surface); } slim_hidden_def(cairo_surface_destroy); @@ -589,6 +596,66 @@ cairo_surface_set_user_data (cairo_surface_t *surface, key, user_data, destroy); } +/** + * 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) +{ + if (strcmp (mime_type, CAIRO_MIME_TYPE_JPEG) == 0) { + *data = surface->jpeg_data; + *length = surface->jpeg_data_length; + } else { + *data = NULL; + } +} + +/** + * 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. + * + * 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 + **/ +void +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) +{ + if (strcmp (mime_type, CAIRO_MIME_TYPE_JPEG) == 0) { + if (surface->jpeg_data) + surface->jpeg_destroy (surface->jpeg_data); + + surface->jpeg_data = data; + surface->jpeg_data_length = length; + surface->jpeg_destroy = destroy; + } +} + /** * _cairo_surface_set_font_options: * @surface: a #cairo_surface_t diff --git a/src/cairo.h b/src/cairo.h index 97d9455a..32005bbe 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1947,6 +1947,21 @@ cairo_surface_set_user_data (cairo_surface_t *surface, void *user_data, cairo_destroy_func_t destroy); +#define CAIRO_MIME_TYPE_JPEG "image/jpeg" + +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 void +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); + cairo_public void cairo_surface_get_font_options (cairo_surface_t *surface, cairo_font_options_t *options); -- cgit v1.2.3 From 3707178fa48e23b85c5640f3cee72e19f49c700b Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 8 Sep 2008 10:26:58 +0930 Subject: PDF: Implement JPEG image embedding --- src/Makefile.sources | 2 + src/cairo-jpeg-info-private.h | 54 ++++++++++++++++ src/cairo-jpeg-info.c | 142 ++++++++++++++++++++++++++++++++++++++++++ src/cairo-pdf-surface.c | 55 ++++++++++++++++ 4 files changed, 253 insertions(+) create mode 100644 src/cairo-jpeg-info-private.h create mode 100644 src/cairo-jpeg-info.c diff --git a/src/Makefile.sources b/src/Makefile.sources index 082b6af8..6a0e93b9 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-jpeg-info-private.h \ cairo-malloc-private.h \ cairo-meta-surface-private.h \ cairo-mutex-impl-private.h \ @@ -109,6 +110,7 @@ cairo_sources = \ cairo-hash.c \ cairo-hull.c \ cairo-image-surface.c \ + cairo-jpeg-info.c \ cairo-lzw.c \ cairo-matrix.c \ cairo-meta-surface.c \ diff --git a/src/cairo-jpeg-info-private.h b/src/cairo-jpeg-info-private.h new file mode 100644 index 00000000..1a376c93 --- /dev/null +++ b/src/cairo-jpeg-info-private.h @@ -0,0 +1,54 @@ +/* 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 + */ + +#ifndef CAIRO_JPEG_INFO_PRIVATE_H +#define CAIRO_JPEG_INFO_PRIVATE_H + +#include "cairoint.h" + +typedef struct _cairo_jpeg_info { + int width; + int height; + int num_components; + int bits_per_component; +} cairo_jpeg_info_t; + +cairo_private cairo_int_status_t +_cairo_jpeg_get_info (unsigned char *data, + long length, + cairo_jpeg_info_t *info); + + +#endif /* CAIRO_JPEG_INFO_PRIVATE_H */ diff --git a/src/cairo-jpeg-info.c b/src/cairo-jpeg-info.c new file mode 100644 index 00000000..75dc0bf2 --- /dev/null +++ b/src/cairo-jpeg-info.c @@ -0,0 +1,142 @@ +/* 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 + */ + +#include "cairoint.h" +#include "cairo-jpeg-info-private.h" + +/* 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 unsigned char * +_skip_segment (unsigned char *p) +{ + int len; + + p++; + len = p[0] << 8; + len |= p[1]; + + return p + len; +} + +static void +_extract_info (cairo_jpeg_info_t *info, 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_jpeg_get_info (unsigned char *data, + long length, + cairo_jpeg_info_t *info) +{ + 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; + + _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 = _skip_segment (p); + break; + } + } + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 27fcbe08..827c9eac 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -50,6 +50,7 @@ #include "cairo-paginated-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-type3-glyph-surface-private.h" +#include "cairo-jpeg-info-private.h" #include #include @@ -1550,6 +1551,55 @@ CLEANUP: 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 = CAIRO_STATUS_SUCCESS; + cairo_jpeg_info_t info; + + if (source->jpeg_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_jpeg_get_info (source->jpeg_data, + source->jpeg_data_length, + &info); + if (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); + + *res = surface->pdf_stream.self; + _cairo_output_stream_write (surface->output, + source->jpeg_data, + source->jpeg_data_length); + 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_pdf_pattern_t *pdf_pattern, @@ -1567,6 +1617,11 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, int x = 0; int y = 0; + 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) goto BAIL; -- cgit v1.2.3 From 540ac11113015f0fd6856d016cb38fec5282b6ce Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 2 Nov 2008 11:42:33 +1030 Subject: type1-subset: return unsupported on FT errors and let type1-fallback handle it. This fixes the bug reported by Peter Weilbacher in http://lists.cairographics.org/archives/cairo/2008-October/015569.html --- src/cairo-type1-subset.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index ddc4ce76..bbff33d9 100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -553,18 +553,14 @@ 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 != 0) + 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 != 0) + return CAIRO_INT_STATUS_UNSUPPORTED; font->glyphs[i].name = strdup (buffer); if (font->glyphs[i].name == NULL) -- cgit v1.2.3 From 1685bbee1bf1ebc015ada94f77756d8d10c7818d Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 2 Nov 2008 19:50:59 +1030 Subject: test/README: fix typo --- test/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/README b/test/README index cb8a80e4..c039ebb2 100644 --- a/test/README +++ b/test/README @@ -125,7 +125,7 @@ Here are some of the relevant details: X server that uses only software for all rendering. One such X server is Xvfb which can be started like this: - Xfvb -screen 0 1280x1024x24 -ac -nolisten tcp :2 + Xvfb -screen 0 1280x1024x24 -ac -nolisten tcp :2 after which the test suite can be run against it like so: -- cgit v1.2.3 From 6434cddb899d750b815d71f8f51ae3e4568dd3c0 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 2 Nov 2008 11:42:33 +1030 Subject: type1-subset: return unsupported on FT errors and let type1-fallback handle it. This fixes the bug reported by Peter Weilbacher in http://lists.cairographics.org/archives/cairo/2008-October/015569.html --- src/cairo-type1-subset.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index ddc4ce76..bbff33d9 100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -553,18 +553,14 @@ 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 != 0) + 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 != 0) + return CAIRO_INT_STATUS_UNSUPPORTED; font->glyphs[i].name = strdup (buffer); if (font->glyphs[i].name == NULL) -- cgit v1.2.3 From f3cbc5cf4580da83b7edacfd381afee3d571c659 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 31 Oct 2008 23:47:16 +0000 Subject: [trace] Use utf8 len in show_text_glyphs(). Honour the parameter specifying the length of the utf8 string when emitting show_text_glyphs. --- util/cairo-trace/trace.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 548eb694..708557be 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -1087,18 +1087,23 @@ _emit_image (cairo_surface_t *image) } static void -_emit_string_literal (const char *utf8) +_emit_string_literal (const char *utf8, int len) { char c; + const char *end; if (utf8 == NULL) { fprintf (logfile, "()"); return; } + if (len < 0) + len = strlen (utf8); + end = utf8 + len; + fprintf (logfile, "("); - while ((c = *utf8++)) { - switch (c) { + while (utf8 < end) { + switch ((c = *utf8++)) { case '\n': case '\r': case '\\': @@ -1847,7 +1852,7 @@ cairo_select_font_face (cairo_t *cr, const char *family, cairo_font_slant_t slan { if (cr != NULL && _write_lock ()) { _emit_context (cr); - _emit_string_literal (family); + _emit_string_literal (family, -1); fprintf (logfile, " //%s //%s select_font_face\n", _slant_to_string (slant), _weight_to_string (weight)); @@ -2097,7 +2102,7 @@ cairo_show_text (cairo_t *cr, const char *utf8) { if (cr != NULL && _write_lock ()) { _emit_context (cr); - _emit_string_literal (utf8); + _emit_string_literal (utf8, -1); fprintf (logfile, " show_text\n"); _write_unlock (); } @@ -2226,8 +2231,7 @@ cairo_show_text_glyphs (cairo_t *cr, _emit_context (cr); - _emit_string_literal (utf8); - fprintf (logfile, " %d ", utf8_len); + _emit_string_literal (utf8, utf8_len); _emit_glyphs (font, glyphs, num_glyphs); fprintf (logfile, " ["); @@ -2254,7 +2258,7 @@ cairo_text_path (cairo_t *cr, const char *utf8) { if (cr != NULL && _write_lock ()) { _emit_context (cr); - _emit_string_literal (utf8); + _emit_string_literal (utf8, -1); fprintf (logfile, " text_path\n"); _write_unlock (); } @@ -2507,7 +2511,7 @@ cairo_surface_write_to_png (cairo_surface_t *surface, const char *filename) { if (surface != NULL && _write_lock ()) { fprintf (logfile, "%% s%ld ", _get_surface_id (surface)); - _emit_string_literal (filename); + _emit_string_literal (filename, -1); fprintf (logfile, " write_to_png\n"); _write_unlock (); } @@ -2524,7 +2528,7 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface, fprintf (logfile, "%% s%ld ", _get_surface_id (surface)); lookup_symbol (symbol, sizeof (symbol), write_func); - _emit_string_literal (symbol); + _emit_string_literal (symbol, -1); fprintf (logfile, " write_to_png_stream\n"); _write_unlock (); } @@ -2743,7 +2747,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) "dict\n" " /type 42 set\n" " /pattern "); - _emit_string_literal ((char *) parsed); + _emit_string_literal ((char *) parsed, -1); fprintf (logfile, " set\n" " font\n"); @@ -2926,7 +2930,7 @@ cairo_ps_surface_create (const char *filename, double width_in_points, double he "dict\n" " /type (PS) set\n" " /filename "); - _emit_string_literal (filename); + _emit_string_literal (filename, -1); fprintf (logfile, " set\n" " /width %g set\n" @@ -2993,7 +2997,7 @@ cairo_pdf_surface_create (const char *filename, double width_in_points, double h "dict\n" " /type (PDF) set\n" " /filename "); - _emit_string_literal (filename); + _emit_string_literal (filename, -1); fprintf (logfile, " set\n" " /width %g set\n" @@ -3058,7 +3062,7 @@ cairo_svg_surface_create (const char *filename, double width, double height) "dict\n" " /type (SVG) set\n" " /filename "); - _emit_string_literal (filename); + _emit_string_literal (filename, -1); fprintf (logfile, " set\n" " /width %g set\n" @@ -3129,7 +3133,7 @@ cairo_image_surface_create_from_png (const char *filename) " /format //%s set\n" " /filename ", width, height, format_str); - _emit_string_literal (filename); + _emit_string_literal (filename, -1); fprintf (logfile, " set\n" " /source "); @@ -3297,7 +3301,7 @@ cairo_script_surface_create (const char *filename, "dict\n" " /type (script) set\n" " /filename "); - _emit_string_literal (filename); + _emit_string_literal (filename, -1); fprintf (logfile, " set\n" " /width %g set\n" -- cgit v1.2.3 From 350fa7b98e5045a4fa05f64a1ad7d8167036be34 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 1 Nov 2008 13:12:43 +0000 Subject: [trace] Fix boundary terminations Don't increment the terminator! --- util/cairo-trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 708557be..a9e4ce30 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -2235,7 +2235,7 @@ cairo_show_text_glyphs (cairo_t *cr, _emit_glyphs (font, glyphs, num_glyphs); fprintf (logfile, " ["); - for (n = 0; n < num_clusters++; n++) { + for (n = 0; n < num_clusters; n++) { fprintf (logfile, " %d %d", clusters[n].num_bytes, clusters[n].num_glyphs); -- cgit v1.2.3 From 04e3bb932eeac4f403b512087b96a164d082d52c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 2 Nov 2008 21:51:37 +0000 Subject: [trace] Emit set_mime_data(). Wrap the new cairo_surface_set_mime_data() function. --- util/cairo-trace/trace.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index a9e4ce30..601bf945 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -912,7 +912,9 @@ _write_zlib_data (struct _data_stream *stream, bool flush) } static void -_write_data (struct _data_stream *stream, void *data, unsigned int length) +_write_data (struct _data_stream *stream, + const void *data, + unsigned int length) { unsigned int count; const unsigned char *p = data; @@ -963,7 +965,7 @@ _write_data_end (struct _data_stream *stream) } static void -_emit_data (void *data, unsigned int length) +_emit_data (const void *data, unsigned int length) { struct _data_stream stream; @@ -2506,6 +2508,30 @@ cairo_surface_show_page (cairo_surface_t *surface) return DLCALL (cairo_surface_show_page, surface); } +void +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) +{ + if (surface != NULL && _write_lock ()) { + _emit_surface (surface); + _emit_string_literal (mime_type, -1); + fprintf (logfile, " "); + _emit_data (data, length); + fprintf (logfile, " /deflate filter set_mime_data\n"); + + _write_unlock (); + } + + return DLCALL (cairo_surface_set_mime_data, + surface, + mime_type, + data, length, + destroy); +} + cairo_status_t cairo_surface_write_to_png (cairo_surface_t *surface, const char *filename) { -- cgit v1.2.3 From f77723fc88c12ebf6f5bff5a1797649d134ecc5d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 2 Nov 2008 19:59:53 +0000 Subject: [pdf] Missing status check. Check that stream was successfully opened before attempting to write to it. --- src/cairo-pdf-surface.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 827c9eac..d2547520 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1553,7 +1553,7 @@ CLEANUP: static cairo_int_status_t _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, - cairo_surface_t *source, + cairo_surface_t *source, cairo_pdf_resource_t *res, int *width, int *height) @@ -1587,6 +1587,8 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, info.height, info.num_components == 1 ? "/DeviceGray" : "/DeviceRGB", info.bits_per_component); + if (status) + return status; *res = surface->pdf_stream.self; _cairo_output_stream_write (surface->output, -- cgit v1.2.3 From afef83a1fae028b45cefd6b4698e7b32ad4d6fc7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 09:40:35 +0000 Subject: Compile tidy. Fix a few minor compiler warnings. --- src/cairo-pdf-surface.c | 2 +- src/cairo-ps-surface.c | 2 +- src/cairo-surface.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index d2547520..51eb07ef 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -4470,7 +4470,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; if ( _cairo_surface_is_meta (surface_pattern->surface)) { - if (cairo_pattern_get_extend (pattern) == CAIRO_EXTEND_PAD) + if (pattern->extend == CAIRO_EXTEND_PAD) return CAIRO_INT_STATUS_UNSUPPORTED; else return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index e050ddbb..29e9872e 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -1572,7 +1572,7 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; if ( _cairo_surface_is_meta (surface_pattern->surface)) { - if (cairo_pattern_get_extend (pattern) == CAIRO_EXTEND_PAD) + if (pattern->extend == CAIRO_EXTEND_PAD) return CAIRO_INT_STATUS_UNSUPPORTED; else return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 79366f24..808fc852 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -605,13 +605,13 @@ cairo_surface_set_user_data (cairo_surface_t *surface, * * 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. + * mime type, @data is set %NULL. * * Since: 1.10 **/ void cairo_surface_get_mime_data (cairo_surface_t *surface, - const char *mime_type, + const char *mime_type, const unsigned char **data, unsigned int *length) { @@ -650,7 +650,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, if (surface->jpeg_data) surface->jpeg_destroy (surface->jpeg_data); - surface->jpeg_data = data; + surface->jpeg_data = (unsigned char *) data; surface->jpeg_data_length = length; surface->jpeg_destroy = destroy; } -- cgit v1.2.3 From 8fc3d0ffebea5622332327cdef9222486cc85581 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 11:01:22 +0000 Subject: [mime-data] Allow embedding of arbitrary mime-types. Use the surface user-data array allow to store an arbitrary set of alternate image representations keyed by an interned string (which ensures that it has a unique key in the user-visible namespace). Update the API to mirror that of cairo_surface_set_user_data() [i.e. return a status indicator] and switch internal users of the mime-data to the public functions. --- src/cairo-debug.c | 2 + src/cairo-jpeg-info-private.h | 6 +-- src/cairo-jpeg-info.c | 19 ++++--- src/cairo-misc.c | 98 ++++++++++++++++++++++++++++++++++++ src/cairo-mutex-list-private.h | 1 + src/cairo-pdf-surface.c | 16 +++--- src/cairo-surface-fallback.c | 37 ++++++++++---- src/cairo-surface-private.h | 4 -- src/cairo-surface.c | 91 ++++++++++++++++++++++++++------- src/cairo-types-private.h | 7 +++ src/cairo.h | 4 +- src/cairoint.h | 8 +++ test/Makefile.am | 3 ++ test/mime-data.c | 111 +++++++++++++++++++++++++++++++++++++++++ test/mime-data.ref.png | Bin 0 -> 263 bytes test/romedalen.jpg | Bin 0 -> 11400 bytes util/cairo-trace/trace.c | 2 +- 17 files changed, 351 insertions(+), 58 deletions(-) create mode 100644 test/mime-data.c create mode 100644 test/mime-data.ref.png create mode 100644 test/romedalen.jpg 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-jpeg-info-private.h b/src/cairo-jpeg-info-private.h index 1a376c93..365825ca 100644 --- a/src/cairo-jpeg-info-private.h +++ b/src/cairo-jpeg-info-private.h @@ -46,9 +46,9 @@ typedef struct _cairo_jpeg_info { } cairo_jpeg_info_t; cairo_private cairo_int_status_t -_cairo_jpeg_get_info (unsigned char *data, - long length, - cairo_jpeg_info_t *info); +_cairo_jpeg_get_info (const unsigned char *data, + long length, + cairo_jpeg_info_t *info); #endif /* CAIRO_JPEG_INFO_PRIVATE_H */ diff --git a/src/cairo-jpeg-info.c b/src/cairo-jpeg-info.c index 75dc0bf2..ca85ceff 100644 --- a/src/cairo-jpeg-info.c +++ b/src/cairo-jpeg-info.c @@ -59,33 +59,32 @@ #define SOF14 0xce #define SOF15 0xcf -static unsigned char * -_skip_segment (unsigned char *p) +static const unsigned char * +_skip_segment (const unsigned char *p) { int len; p++; - len = p[0] << 8; - len |= p[1]; + len = (p[0] << 8) | p[1]; return p + len; } static void -_extract_info (cairo_jpeg_info_t *info, unsigned char *p) +_extract_info (cairo_jpeg_info_t *info, const unsigned char *p) { info->width = (p[6] << 8) + p[7]; - info->height = (p[4] << 8) + p[5];; + info->height = (p[4] << 8) + p[5]; info->num_components = p[8]; info->bits_per_component = p[3]; } cairo_int_status_t -_cairo_jpeg_get_info (unsigned char *data, - long length, - cairo_jpeg_info_t *info) +_cairo_jpeg_get_info (const unsigned char *data, + long length, + cairo_jpeg_info_t *info) { - unsigned char *p = data; + const unsigned char *p = data; while (p + 1 < data + length) { if (*p != 0xff) diff --git a/src/cairo-misc.c b/src/cairo-misc.c index 27050a24..667fa528 100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -667,3 +667,101 @@ _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 (! _cairo_hash_table_lookup (_cairo_intern_string_ht, + &tmpl.hash_entry, + (cairo_hash_entry_t **) &istring)) + { + istring = malloc (sizeof (cairo_intern_string_t) + len + 1); + if (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 (status) + free (istring); + } else + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); + + if (status == CAIRO_STATUS_SUCCESS) + *str_inout = istring->string; + + 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-pdf-surface.c b/src/cairo-pdf-surface.c index 51eb07ef..7bcb0577 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1558,15 +1558,17 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, int *width, int *height) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; + const unsigned char *mime_data; + unsigned int mime_data_length; cairo_jpeg_info_t info; - if (source->jpeg_data == NULL) + cairo_surface_get_mime_data (&surface->base, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; - status = _cairo_jpeg_get_info (source->jpeg_data, - source->jpeg_data_length, - &info); + status = _cairo_jpeg_get_info (mime_data, mime_data_length, &info); if (status) return status; @@ -1591,9 +1593,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, return status; *res = surface->pdf_stream.self; - _cairo_output_stream_write (surface->output, - source->jpeg_data, - source->jpeg_data_length); + _cairo_output_stream_write (surface->output, mime_data, mime_data_length); status = _cairo_pdf_surface_close_stream (surface); *width = info.width; diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index 62661174..7cfbd65f 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -1035,6 +1035,8 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) cairo_status_t status; cairo_surface_pattern_t pattern; cairo_image_surface_t *image; + const unsigned char *mime_data; + unsigned int mime_data_length; void *image_extra; status = _cairo_surface_acquire_source_image (surface, @@ -1075,19 +1077,32 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) snapshot->device_transform = surface->device_transform; snapshot->device_transform_inverse = surface->device_transform_inverse; - if (surface->jpeg_destroy && - surface->jpeg_data != NULL && - surface->jpeg_data_length != 0) - { - snapshot->jpeg_data = malloc (surface->jpeg_data_length); - if (snapshot->jpeg_data == NULL) { + /* XXX Need to copy all known image representations... + * For now, just copy "image/jpeg", but in future we should construct + * an array of known types and iterate. + */ + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data != NULL) { + unsigned char *mime_data_copy; + + mime_data_copy = malloc (mime_data_length); + if (mime_data == NULL) { cairo_surface_destroy (snapshot); - return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + memcpy (mime_data_copy, mime_data, mime_data_length); + + status = cairo_surface_set_mime_data (snapshot, + CAIRO_MIME_TYPE_JPEG, + mime_data_copy, + mime_data_length, + free); + if (status) { + free (mime_data_copy); + cairo_surface_destroy (snapshot); + return _cairo_surface_create_in_error (status); } - - memcpy (snapshot->jpeg_data, surface->jpeg_data, surface->jpeg_data_length); - snapshot->jpeg_data_length = surface->jpeg_data_length; - snapshot->jpeg_destroy = free; } snapshot->is_snapshot = TRUE; diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h index 1b5bb049..efd4365e 100644 --- a/src/cairo-surface-private.h +++ b/src/cairo-surface-private.h @@ -100,10 +100,6 @@ struct _cairo_surface { */ cairo_bool_t has_font_options; cairo_font_options_t font_options; - - unsigned char *jpeg_data; - unsigned int jpeg_data_length; - cairo_destroy_func_t jpeg_destroy; }; #endif /* CAIRO_SURFACE_PRIVATE_H */ diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 808fc852..109cbb91 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -220,10 +220,6 @@ _cairo_surface_init (cairo_surface_t *surface, surface->is_snapshot = FALSE; surface->has_font_options = FALSE; - - surface->jpeg_data = NULL; - surface->jpeg_data_length = 0; - surface->jpeg_destroy = NULL; } cairo_surface_t * @@ -444,9 +440,6 @@ cairo_surface_destroy (cairo_surface_t *surface) _cairo_user_data_array_fini (&surface->user_data); - if (surface->jpeg_data) - surface->jpeg_destroy (surface->jpeg_data); - free (surface); } slim_hidden_def(cairo_surface_destroy); @@ -615,12 +608,39 @@ cairo_surface_get_mime_data (cairo_surface_t *surface, const unsigned char **data, unsigned int *length) { - if (strcmp (mime_type, CAIRO_MIME_TYPE_JPEG) == 0) { - *data = surface->jpeg_data; - *length = surface->jpeg_data_length; - } else { - *data = NULL; + 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 (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 (mime_data->destroy && mime_data->data) + mime_data->destroy (mime_data->data); + + free (mime_data); } /** @@ -638,23 +658,56 @@ cairo_surface_get_mime_data (cairo_surface_t *surface, * 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. **/ -void +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) { - if (strcmp (mime_type, CAIRO_MIME_TYPE_JPEG) == 0) { - if (surface->jpeg_data) - surface->jpeg_destroy (surface->jpeg_data); + cairo_status_t status; + cairo_mime_data_t *mime_data; + + if (surface->status) + return surface->status; - surface->jpeg_data = (unsigned char *) data; - surface->jpeg_data_length = length; - surface->jpeg_destroy = destroy; + status = _cairo_intern_string (&mime_type, -1); + if (status) + return _cairo_surface_set_error (surface, status); + + mime_data = _cairo_user_data_array_get_data (&surface->user_data, + (cairo_user_data_key_t *) mime_type); + if (mime_data != NULL) { + if (mime_data->destroy && mime_data->data) + mime_data->destroy (mime_data->data); + + mime_data->data = (unsigned char *) data; + mime_data->length = length; + mime_data->destroy = destroy; + } else { + mime_data = malloc (sizeof (cairo_mime_data_t)); + if (mime_data == NULL) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + mime_data->data = (unsigned char *) data; + mime_data->length = length; + mime_data->destroy = destroy; + + status = _cairo_user_data_array_set_data (&surface->user_data, + (cairo_user_data_key_t *) mime_type, + mime_data, + _cairo_mime_data_destroy); + if (status) + return _cairo_surface_set_error (surface, status); } + + return CAIRO_STATUS_SUCCESS; } +slim_hidden_def (cairo_surface_set_mime_data); /** * _cairo_surface_set_font_options: diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 12e1a20e..8bcbf9aa 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -52,6 +52,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; @@ -342,4 +343,10 @@ typedef enum _cairo_image_transparency { CAIRO_IMAGE_UNKNOWN } cairo_image_transparency_t; +struct _cairo_mime_data { + unsigned char *data; + unsigned int length; + cairo_destroy_func_t destroy; +}; + #endif /* CAIRO_TYPES_PRIVATE_H */ diff --git a/src/cairo.h b/src/cairo.h index 32005bbe..a1cd0c55 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1951,11 +1951,11 @@ cairo_surface_set_user_data (cairo_surface_t *surface, cairo_public void cairo_surface_get_mime_data (cairo_surface_t *surface, - const char *mime_type, + const char *mime_type, const unsigned char **data, unsigned int *length); -cairo_public void +cairo_public cairo_status_t cairo_surface_set_mime_data (cairo_surface_t *surface, const char *mime_type, const unsigned char *data, diff --git a/src/cairoint.h b/src/cairoint.h index 4e9eea4e..7fe853cf 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1391,6 +1391,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); @@ -2515,6 +2521,8 @@ 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_set_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); diff --git a/test/Makefile.am b/test/Makefile.am index 21976de6..02debdf4 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -106,6 +106,7 @@ test_sources = \ mask-transformed-image.c \ mask-transformed-similar.c \ meta-surface-pattern.c \ + mime-data.c \ miter-precision.c \ move-to-show-surface.c \ new-sub-path.c \ @@ -687,6 +688,7 @@ REFERENCE_IMAGES = \ meta-surface-pattern.svg11.rgb24.ref.png \ meta-surface-pattern.svg12.argb32.ref.png \ meta-surface-pattern.svg12.rgb24.ref.png \ + mime-data.ref.png \ miter-precision.ref.png \ miter-precision.ps2.ref.png \ miter-precision.ps3.ref.png \ @@ -994,6 +996,7 @@ EXTRA_DIST += \ 6x13.pcf \ make-html.pl \ romedalen.png \ +romedalen.jpg \ surface-source.c \ $(REFERENCE_IMAGES) diff --git a/test/mime-data.c b/test/mime-data.c new file mode 100644 index 00000000..b3649153 --- /dev/null +++ b/test/mime-data.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#include +#include + +/* Basic test to exercise the new mime-data embedding. */ + +static cairo_status_t +read_jpg_file (const cairo_test_context_t *ctx, + unsigned char **data_out, + unsigned int *length_out) +{ + const char jpg_filename[] = "romedalen.jpg"; + FILE *file; + unsigned char *buf; + unsigned int len; + + file = fopen (jpg_filename, "rb"); + if (file == NULL) { + char filename[4096]; + + /* try again with srcdir */ + snprintf (filename, sizeof (filename), + "%s/%s", ctx->srcdir, jpg_filename); + file = fopen (filename, "rb"); + } + if (file == NULL) { + switch (errno) { + case ENOMEM: + return CAIRO_STATUS_NO_MEMORY; + default: + return CAIRO_STATUS_FILE_NOT_FOUND; + } + } + + fseek (file, 0, SEEK_END); + len = ftell (file); + fseek (file, 0, SEEK_SET); + + buf = xmalloc (len); + *length_out = fread (buf, 1, len, file); + fclose (file); + if (*length_out != len) { + free (buf); + return CAIRO_STATUS_READ_ERROR; + } + + *data_out = buf; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + unsigned char *jpg_data; + unsigned int jpg_len; + cairo_status_t status; + + status = read_jpg_file (ctx, &jpg_data, &jpg_len); + if (status) { + return cairo_test_status_from_status (ctx, status); + } + + image = cairo_test_create_surface_from_png (ctx, "romedalen.png"); + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG, + jpg_data, jpg_len, free); + if (status) { + cairo_surface_destroy (image); + return cairo_test_status_from_status (ctx, status); + } + + cairo_set_source_surface (cr, image, 0, 0); + cairo_surface_destroy (image); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mime_data, + "Check that the mime-data embedding works", + "jpeg, api", /* keywords */ + NULL, /* requirements */ + 10, 10, + NULL, draw) diff --git a/test/mime-data.ref.png b/test/mime-data.ref.png new file mode 100644 index 00000000..cc13baf0 Binary files /dev/null and b/test/mime-data.ref.png differ diff --git a/test/romedalen.jpg b/test/romedalen.jpg new file mode 100644 index 00000000..d655e3d8 Binary files /dev/null and b/test/romedalen.jpg differ diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 601bf945..7c595f1a 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -2508,7 +2508,7 @@ cairo_surface_show_page (cairo_surface_t *surface) return DLCALL (cairo_surface_show_page, surface); } -void +cairo_status_t cairo_surface_set_mime_data (cairo_surface_t *surface, const char *mime_type, const unsigned char *data, -- cgit v1.2.3 From 2c08f3f83b1acd168cd74b300272970658179a0f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 11:30:38 +0000 Subject: [trace] Autodetect -lbfd during configure Stop being lazy and detect libbfd during configure. --- configure.ac | 10 ++++++++++ util/cairo-trace/Makefile.am | 2 +- util/cairo-trace/lookup-symbol.c | 6 +++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index da2f8613..97a09b6a 100644 --- a/configure.ac +++ b/configure.ac @@ -495,6 +495,16 @@ esac AM_CONDITIONAL(BUILD_TRACE, test "x$have_ld_preload" = "xyes") +AC_CHECK_LIB(bfd, bfd_openr, + [AC_CHECK_HEADER(bfd.h, [have_bfd=yes], + [have_bfd="no (requires binutils-dev)"])], + [have_bfd="no (requires binutils-dev)"]) +if test "x$have_bfd" = "xyes"; then + AC_DEFINE([HAVE_BFD], [1], [Define to 1 if you have binutils-dev installed]) + BFD_LIBS=-lbfd + AC_SUBST(BFD_LIBS) +fi + dnl =========================================================================== AC_ARG_ENABLE(some-floating-point, diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am index 13161c6d..6d7d7489 100644 --- a/util/cairo-trace/Makefile.am +++ b/util/cairo-trace/Makefile.am @@ -10,7 +10,7 @@ cairo_trace_la_SOURCES = \ trace.c cairo_trace_la_CFLAGS = @FREETYPE_CFLAGS@ @CAIRO_CFLAGS@ cairo_trace_la_LDFLAGS = -module -no-undefined -cairo_trace_la_LIBADD = -ldl -lz -lbfd +cairo_trace_la_LIBADD = -ldl -lz @BFD_LIBS@ system-install: grep -sq @libdir@/cairo-trace.so /etc/ld.so.preload || echo @libdir@/cairo-trace.so >> /etc/ld.so.preload diff --git a/util/cairo-trace/lookup-symbol.c b/util/cairo-trace/lookup-symbol.c index b5f0fdfd..df7e6b00 100644 --- a/util/cairo-trace/lookup-symbol.c +++ b/util/cairo-trace/lookup-symbol.c @@ -62,7 +62,7 @@ #include #include -#ifdef HAVE_LIBBFD +#if HAVE_BFD #include #include @@ -255,7 +255,7 @@ char * lookup_symbol (char *buf, int buflen, const void *ptr) { struct file_match match; -#ifdef HAVE_LIBBFD +#if HAVE_BFD struct symtab symtab; struct symbol symbol; #endif @@ -271,7 +271,7 @@ lookup_symbol (char *buf, int buflen, const void *ptr) if (match.file == NULL || *match.file == '\0') match.file = "/proc/self/exe"; -#ifdef HAVE_LIBBFD +#if HAVE_BFD if (! _symtab_init (&symtab, match.file)) return buf; -- cgit v1.2.3 From ca83df55a63eab1821dbc009f65b3b09d61f5b62 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 11:46:31 +0000 Subject: [trace] Wrap test surfaces. Wrap the test surfaces to avoid crashes whilst tracing the test suite. --- util/cairo-trace/trace.c | 116 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 108 insertions(+), 8 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 7c595f1a..b8676c34 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -37,7 +37,7 @@ #include #include -#ifdef CAIRO_HAS_FT_FONT +#if CAIRO_HAS_FT_FONT # include #endif @@ -2755,7 +2755,7 @@ cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) return DLCALL (cairo_pattern_set_extend, pattern, extend); } -#ifdef CAIRO_HAS_FT_FONT +#if CAIRO_HAS_FT_FONT cairo_font_face_t * cairo_ft_font_face_create_for_pattern (FcPattern *pattern) { @@ -2939,7 +2939,7 @@ FT_Done_Face (FT_Face face) } #endif -#ifdef CAIRO_HAS_PS_SURFACE +#if CAIRO_HAS_PS_SURFACE #include cairo_surface_t * @@ -3006,7 +3006,7 @@ cairo_ps_surface_set_size (cairo_surface_t *surface, double width_in_points, dou #endif -#ifdef CAIRO_HAS_PDF_SURFACE +#if CAIRO_HAS_PDF_SURFACE #include cairo_surface_t * @@ -3071,7 +3071,7 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface, double width_in_points, do } #endif -#ifdef CAIRO_HAS_SVG_SURFACE +#if CAIRO_HAS_SVG_SURFACE #include cairo_surface_t * @@ -3215,7 +3215,7 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *c return ret; } -#ifdef CAIRO_HAS_XLIB_SURFACE +#if CAIRO_HAS_XLIB_SURFACE #include cairo_surface_t * @@ -3275,7 +3275,7 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *scree return ret; } -#ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE +#if CAIRO_HAS_XLIB_XRENDER_SURFACE #include cairo_surface_t * cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, Screen *screen, XRenderPictFormat *format, int width, int height) @@ -3309,7 +3309,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, #endif #endif -#ifdef CAIRO_HAS_SCRIPT_SURFACE +#if CAIRO_HAS_SCRIPT_SURFACE #include cairo_surface_t * cairo_script_surface_create (const char *filename, @@ -3373,3 +3373,103 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func, return ret; } #endif + +#if CAIRO_HAS_TEST_SURFACES +#include +cairo_surface_t * +_cairo_test_fallback_surface_create (cairo_content_t content, + int width, + int height) +{ + cairo_surface_t *ret; + long surface_id; + + ret = DLCALL (_cairo_test_fallback_surface_create, content, width, height); + surface_id = _create_surface_id (ret); + + if (_write_lock ()) { + fprintf (logfile, + "dict\n" + " /type (test-fallback) set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, + surface_id); + _get_object (SURFACE, ret)->defined = true; + _push_operand (SURFACE, ret); + _write_unlock (); + } + + return ret; +} + +#include +cairo_surface_t * +_cairo_test_paginated_surface_create_for_data (unsigned char *data, + cairo_content_t content, + int width, + int height, + int stride) +{ + cairo_surface_t *ret; + long surface_id; + + ret = DLCALL (_cairo_test_paginated_surface_create_for_data, + data, content, width, height, stride); + surface_id = _create_surface_id (ret); + + if (_write_lock ()) { + /* XXX store initial data? */ + fprintf (logfile, + "dict\n" + " /type (test-paginated) set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " /stride %d set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, stride, + surface_id); + _get_object (SURFACE, ret)->defined = true; + _push_operand (SURFACE, ret); + _write_unlock (); + } + + return ret; +} + +#include +cairo_surface_t * +_cairo_test_meta_surface_create (cairo_content_t content, + int width, + int height) +{ + cairo_surface_t *ret; + long surface_id; + + ret = DLCALL (_cairo_test_meta_surface_create, content, width, height); + surface_id = _create_surface_id (ret); + + if (_write_lock ()) { + fprintf (logfile, + "dict\n" + " /type (test-meta) set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, + surface_id); + _get_object (SURFACE, ret)->defined = true; + _push_operand (SURFACE, ret); + _write_unlock (); + } + + return ret; +} +#endif -- cgit v1.2.3 From 34586860ef08e6aab988ba227997dfe376f9d319 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 12:11:14 +0000 Subject: [trace] Big-endian compile fixes. A few typos. --- util/cairo-trace/trace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index b8676c34..864038d4 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -1002,7 +1002,7 @@ _emit_image (cairo_surface_t *image) break; case CAIRO_FORMAT_A8: for (row = height; row--; ) { - _write_data (&ouput, data, width); + _write_data (&stream, data, width); data += stride; } break; @@ -1011,7 +1011,7 @@ _emit_image (cairo_surface_t *image) int col; rowdata = data; for (col = width; col--; ) { - _write_data (&ouput, rowdata, 3); + _write_data (&stream, rowdata, 3); rowdata+=4; } data += stride; @@ -1024,8 +1024,8 @@ _emit_image (cairo_surface_t *image) } break; default: - ASSERT_NOT_REACHED; - break; + _write_data_end (&stream); + return; } #else if (stride > ARRAY_LENGTH (row_stack)) { -- cgit v1.2.3 From b3462c5616ae24fd391ad0872d2fbb98c6cd0c92 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 13:10:42 +0000 Subject: [test] Convert a few residual '-out.*' Catch a few -out.* hiding in boilerplate. --- boilerplate/cairo-boilerplate-pdf.c | 2 +- boilerplate/cairo-boilerplate-ps.c | 2 +- boilerplate/cairo-boilerplate-svg.c | 2 +- boilerplate/cairo-boilerplate-win32-printing.c | 2 +- test/Makefile.am | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c index 70002385..7e5e1624 100644 --- a/boilerplate/cairo-boilerplate-pdf.c +++ b/boilerplate/cairo-boilerplate-pdf.c @@ -72,7 +72,7 @@ _cairo_boilerplate_pdf_create_surface (const char *name, ptc->width = width; ptc->height = height; - xasprintf (&ptc->filename, "%s-out.pdf", name); + xasprintf (&ptc->filename, "%s.out.pdf", name); xunlink (ptc->filename); surface = cairo_pdf_surface_create (ptc->filename, width, height); diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c index b2e1e122..c3efceab 100644 --- a/boilerplate/cairo-boilerplate-ps.c +++ b/boilerplate/cairo-boilerplate-ps.c @@ -86,7 +86,7 @@ _cairo_boilerplate_ps_create_surface (const char *name, *closure = ptc = xmalloc (sizeof (ps_target_closure_t)); - xasprintf (&ptc->filename, "%s-out.ps", name); + xasprintf (&ptc->filename, "%s.out.ps", name); xunlink (ptc->filename); ptc->level = level; diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c index 195dc786..e6c1355f 100644 --- a/boilerplate/cairo-boilerplate-svg.c +++ b/boilerplate/cairo-boilerplate-svg.c @@ -65,7 +65,7 @@ _cairo_boilerplate_svg_create_surface (const char *name, ptc->width = width; ptc->height = height; - xasprintf (&ptc->filename, "%s-out.svg", name); + xasprintf (&ptc->filename, "%s.out.svg", name); xunlink (ptc->filename); surface = cairo_svg_surface_create (ptc->filename, width, height); diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c index a5f21fff..13a65515 100644 --- a/boilerplate/cairo-boilerplate-win32-printing.c +++ b/boilerplate/cairo-boilerplate-win32-printing.c @@ -181,7 +181,7 @@ _cairo_boilerplate_win32_printing_create_surface (const char *name, *closure = ptc = xmalloc (sizeof (win32_target_closure_t)); - xasprintf (&ptc->filename, "%s-out.ps", name); + xasprintf (&ptc->filename, "%s.out.ps", name); xunlink (ptc->filename); memset (&di, 0, sizeof (DOCINFO)); diff --git a/test/Makefile.am b/test/Makefile.am index 02debdf4..948716a0 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1225,12 +1225,12 @@ CLEANFILES += \ # reality of portability was raised and it became.... clean-local: clean-caches rm -rf output - -${FIND} . -name '*-out.*' -print | ${XARGS} ${RM} + -${FIND} . -name '*.out.*' -print | ${XARGS} ${RM} -${FIND} . -name '*.log' -print | ${XARGS} ${RM} -${FIND} . -name '*.[is]' -print | ${XARGS} ${RM} clean-caches: - -${FIND} . -name '*-pass.*' -print | ${XARGS} ${RM} - -${FIND} . -name '*-fail.*' -print | ${XARGS} ${RM} + -${FIND} . -name '*.pass.*' -print | ${XARGS} ${RM} + -${FIND} . -name '*.fail.*' -print | ${XARGS} ${RM} # The following definitions both should work. #FAILED_TESTS = `grep -l '\' $(test_sources:.c=.log) 2>/dev/null | sed -e 's/[.]log$$//' | xargs echo` -- cgit v1.2.3 From 43e2370b024f66d995c514fd53414d3d8588a481 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 14:20:35 +0000 Subject: [test] Update extend-pad. extend-pad was not a clear demonstration of the EXTEND_PAD mode, so revamp it to show the filter extending a 4 pixel surface to cover the entire output. However, this hides a discrepancy with the vector surfaces that we cannot prevent the external renders from applying an interpolation to the border pixels, so we copy the original test to extend-pad-border to check the desired behaviour on boundary pixels. --- test/Makefile.am | 4 ++ test/extend-pad-border.c | 95 ++++++++++++++++++++++++++++++++++++++++ test/extend-pad-border.ref.png | Bin 0 -> 616 bytes test/extend-pad-similar.c | 82 ++++++++++++++++++++++++++++++++++ test/extend-pad-similar.ref.png | Bin 0 -> 315 bytes test/extend-pad.c | 50 ++++++++------------- test/extend-pad.ref.png | Bin 616 -> 315 bytes 7 files changed, 200 insertions(+), 31 deletions(-) create mode 100644 test/extend-pad-border.c create mode 100644 test/extend-pad-border.ref.png create mode 100644 test/extend-pad-similar.c create mode 100644 test/extend-pad-similar.ref.png diff --git a/test/Makefile.am b/test/Makefile.am index 948716a0..c2a87ee8 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -51,6 +51,8 @@ test_sources = \ device-offset-positive.c \ device-offset-scale.c \ extend-pad.c \ + extend-pad-border.c \ + extend-pad-similar.c \ extend-reflect.c \ extend-reflect-similar.c \ extend-repeat.c \ @@ -439,6 +441,8 @@ REFERENCE_IMAGES = \ device-offset.rgb24.ref.png \ device-offset-scale.ref.png \ extend-pad.ref.png \ + extend-pad-border.ref.png \ + extend-pad-similar.ref.png \ extend-reflect.ref.png \ extend-reflect-similar.ref.png \ extend-reflect-similar.ps2.ref.png \ diff --git a/test/extend-pad-border.c b/test/extend-pad-border.c new file mode 100644 index 00000000..79a81fcf --- /dev/null +++ b/test/extend-pad-border.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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. + * + * Author: Behdad Esfahbod + */ + +#include +#include "cairo-test.h" +#include + +#define SIZE 90 + +/* Check the border-pixels of an EXTEND_PAD image pattern */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t * cr_surface; + int surface_size = (SIZE - 30) / 10; + + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill (cr); + + /* Create an image surface with my favorite four colors in each + * quadrant. */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + surface_size, surface_size); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, + 0, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, + surface_size / 2, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, + 0, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, + surface_size / 2, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + + cairo_scale (cr, 10, 10); + cairo_set_source_surface (cr, cairo_get_target (cr_surface), 1.5, 1.5); + cairo_destroy (cr_surface); + + /* Using EXTEND_REFLECT makes this test pass for image and xlib backends */ + /*cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);*/ + + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_rectangle (cr, 1.5, 1.5, 6, 6); + cairo_clip (cr); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_pad_border, + "Test CAIRO_EXTEND_PAD for surface patterns", + "XFAIL=!image,pdf,ps,svg extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/test/extend-pad-border.ref.png b/test/extend-pad-border.ref.png new file mode 100644 index 00000000..9292f8bb Binary files /dev/null and b/test/extend-pad-border.ref.png differ diff --git a/test/extend-pad-similar.c b/test/extend-pad-similar.c new file mode 100644 index 00000000..357252ac --- /dev/null +++ b/test/extend-pad-similar.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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. + * + * Author: Behdad Esfahbod + */ + +#include +#include "cairo-test.h" +#include + +#define SIZE 90 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr_surface; + + /* Create a 4-pixel similar surface with my favorite four colors in each + * quadrant. */ + surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR, 2, 2); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + /* upper-left = white */ + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, 0, 0, 1, 1); + cairo_fill (cr_surface); + + /* upper-right = red */ + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, 1, 0, 1, 1); + cairo_fill (cr_surface); + + /* lower-left = green */ + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, 0, 1, 1, 1); + cairo_fill (cr_surface); + + /* lower-right = blue */ + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, 1, 1, 1, 1); + cairo_fill (cr_surface); + + /* Now use extend pad to cover the entire surface with those 4 colors */ + cairo_set_source_surface (cr, cairo_get_target (cr_surface), + width/2 - 1, + height/2 - 1); + cairo_destroy (cr_surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_pad_similar, + "Test CAIRO_EXTEND_PAD for similar surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/test/extend-pad-similar.ref.png b/test/extend-pad-similar.ref.png new file mode 100644 index 00000000..82da7b65 Binary files /dev/null and b/test/extend-pad-similar.ref.png differ diff --git a/test/extend-pad.c b/test/extend-pad.c index ed4ffd02..15a2079b 100644 --- a/test/extend-pad.c +++ b/test/extend-pad.c @@ -34,52 +34,40 @@ static cairo_test_status_t draw (cairo_t *cr, int width, int height) { cairo_surface_t *surface; - cairo_t * cr_surface; - int surface_size = (SIZE - 30) / 10; + cairo_t *cr_surface; - cairo_set_source_rgba (cr, 0, 0, 0, 1); - cairo_rectangle (cr, 0, 0, SIZE, SIZE); - cairo_fill (cr); - - /* Create an image surface with my favorite four colors in each + /* Create a 4-pixel image surface with my favorite four colors in each * quadrant. */ - surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, - surface_size, surface_size); + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 2, 2); cr_surface = cairo_create (surface); cairo_surface_destroy (surface); + /* upper-left = white */ cairo_set_source_rgb (cr_surface, 1, 1, 1); - cairo_rectangle (cr_surface, - 0, 0, - surface_size / 2, surface_size / 2); + cairo_rectangle (cr_surface, 0, 0, 1, 1); cairo_fill (cr_surface); + + /* upper-right = red */ cairo_set_source_rgb (cr_surface, 1, 0, 0); - cairo_rectangle (cr_surface, - surface_size / 2, 0, - surface_size / 2, surface_size / 2); + cairo_rectangle (cr_surface, 1, 0, 1, 1); cairo_fill (cr_surface); + + /* lower-left = green */ cairo_set_source_rgb (cr_surface, 0, 1, 0); - cairo_rectangle (cr_surface, - 0, surface_size / 2, - surface_size / 2, surface_size / 2); + cairo_rectangle (cr_surface, 0, 1, 1, 1); cairo_fill (cr_surface); + + /* lower-right = blue */ cairo_set_source_rgb (cr_surface, 0, 0, 1); - cairo_rectangle (cr_surface, - surface_size / 2, surface_size / 2, - surface_size / 2, surface_size / 2); + cairo_rectangle (cr_surface, 1, 1, 1, 1); cairo_fill (cr_surface); - cairo_scale (cr, 10, 10); - cairo_set_source_surface (cr, cairo_get_target (cr_surface), 1.5, 1.5); + /* Now use extend pad to cover the entire surface with those 4 colors */ + cairo_set_source_surface (cr, cairo_get_target (cr_surface), + width/2 - 1, + height/2 - 1); cairo_destroy (cr_surface); - - /* Using EXTEND_REFLECT makes this test pass for image and xlib backends */ - /*cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);*/ - cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); - cairo_rectangle (cr, 1.5, 1.5, 6, 6); - cairo_clip (cr); - cairo_paint (cr); return CAIRO_TEST_SUCCESS; @@ -87,7 +75,7 @@ draw (cairo_t *cr, int width, int height) CAIRO_TEST (extend_pad, "Test CAIRO_EXTEND_PAD for surface patterns", - "XFAIL=!image,pdf,ps,svg extend", /* keywords */ + "extend", /* keywords */ NULL, /* requirements */ SIZE, SIZE, NULL, draw) diff --git a/test/extend-pad.ref.png b/test/extend-pad.ref.png index 9292f8bb..82da7b65 100644 Binary files a/test/extend-pad.ref.png and b/test/extend-pad.ref.png differ -- cgit v1.2.3 From c80a1c68c19f876c9f55b7c6d62b18ae110b11d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 23:16:09 +0000 Subject: [configure] Make trace consistent. Remove the debianism from the comments for HAVE_BFD and comply with Behdad's guidelines on using $(...) within Makefile.am. --- configure.ac | 5 ++--- util/cairo-trace/Makefile.am | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 97a09b6a..1ed086ec 100644 --- a/configure.ac +++ b/configure.ac @@ -497,10 +497,9 @@ AM_CONDITIONAL(BUILD_TRACE, test "x$have_ld_preload" = "xyes") AC_CHECK_LIB(bfd, bfd_openr, [AC_CHECK_HEADER(bfd.h, [have_bfd=yes], - [have_bfd="no (requires binutils-dev)"])], - [have_bfd="no (requires binutils-dev)"]) + [have_bfd=no])], [have_bfd=no]) if test "x$have_bfd" = "xyes"; then - AC_DEFINE([HAVE_BFD], [1], [Define to 1 if you have binutils-dev installed]) + AC_DEFINE([HAVE_BFD], [1], [Define to 1 if you have the binutils development files installed]) BFD_LIBS=-lbfd AC_SUBST(BFD_LIBS) fi diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am index 6d7d7489..b927768d 100644 --- a/util/cairo-trace/Makefile.am +++ b/util/cairo-trace/Makefile.am @@ -8,15 +8,15 @@ cairo_trace_la_SOURCES = \ lookup-symbol.c \ lookup-symbol.h \ trace.c -cairo_trace_la_CFLAGS = @FREETYPE_CFLAGS@ @CAIRO_CFLAGS@ +cairo_trace_la_CFLAGS = $(FREETYPE_CFLAGS) $(CAIRO_CFLAGS) cairo_trace_la_LDFLAGS = -module -no-undefined -cairo_trace_la_LIBADD = -ldl -lz @BFD_LIBS@ +cairo_trace_la_LIBADD = -ldl -lz $(BFD_LIBS) system-install: grep -sq @libdir@/cairo-trace.so /etc/ld.so.preload || echo @libdir@/cairo-trace.so >> /etc/ld.so.preload system-uninstall: - sed -e '/\/usr\/local\/lib\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; + sed -e '@libdir@\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; EXTRA_DIST = \ COPYING \ -- cgit v1.2.3 From 4f032ca35a7086b76775e4b53c6b99ba4e1eb3cb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 23:23:09 +0000 Subject: [trace] Install cairo-trace.so into $(libdir)/cairo Install the auxiliary library into the cairo subdirectory within the lib path, so that it doesn't clutter $(libdir) and sets a precedent for future auxiliary libraries. --- util/cairo-trace/Makefile.am | 7 ++++--- util/cairo-trace/cairo-trace.in | 13 ++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am index b927768d..c6caf0c6 100644 --- a/util/cairo-trace/Makefile.am +++ b/util/cairo-trace/Makefile.am @@ -1,5 +1,6 @@ bin_SCRIPTS = cairo-trace -lib_LTLIBRARIES = cairo-trace.la +cairolibdir = @libdir@/cairo +cairolib_LTLIBRARIES = cairo-trace.la AM_CPPFLAGS = -I$(top_srcdir)/src \ -I$(top_builddir)/src @@ -13,10 +14,10 @@ cairo_trace_la_LDFLAGS = -module -no-undefined cairo_trace_la_LIBADD = -ldl -lz $(BFD_LIBS) system-install: - grep -sq @libdir@/cairo-trace.so /etc/ld.so.preload || echo @libdir@/cairo-trace.so >> /etc/ld.so.preload + grep -sq @cairolibdir@/cairo-trace.so /etc/ld.so.preload || echo @libdir@/cairo-trace.so >> /etc/ld.so.preload system-uninstall: - sed -e '@libdir@\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; + sed -e '@cairolibdir@\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; EXTRA_DIST = \ COPYING \ diff --git a/util/cairo-trace/cairo-trace.in b/util/cairo-trace/cairo-trace.in index ee381614..93bb954c 100644 --- a/util/cairo-trace/cairo-trace.in +++ b/util/cairo-trace/cairo-trace.in @@ -49,10 +49,17 @@ if test -z "$nofile"; then filename=`basename $1`.$$.trace fi +LD_PRELOAD=@libdir@/cairo/cairo-trace.so +export LD_PRELOAD + +# Force the decimal output to the 'C' locale +LC_ALL=C +export LC_ALL + if test -z "$filename"; then - LD_PRELOAD=@libdir@/cairo-trace.so CAIRO_TRACE_FD=3 LC_ALL=C $* 3>&1 >/dev/null + CAIRO_TRACE_FD=3 $* 3>&1 >/dev/null elif test -n "$silent"; then - LD_PRELOAD=@libdir@/cairo-trace.so LC_ALL=C CAIRO_TRACE_OUTFILE_EXACT=$filename $* + CAIRO_TRACE_OUTFILE_EXACT=$filename $* else - LD_PRELOAD=@libdir@/cairo-trace.so CAIRO_TRACE_FD=3 LC_ALL=C $* 3>&1 >/dev/null | tee $filename + CAIRO_TRACE_FD=3 $* 3>&1 >/dev/null | tee $filename fi -- cgit v1.2.3 From 90217550120f129004bc555b59ced28b4b25a4d4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Nov 2008 23:45:12 +0000 Subject: [mime-data] Copy a reference to the mime-data on snapshotting. Instead of doing a full-copy of the mime data (which can be 10K-100K, or even larger) just copy a reference to the original mime to the snapshot surface (as suggested by Behdad). --- src/cairo-surface-fallback.c | 29 +++-------------- src/cairo-surface.c | 77 +++++++++++++++++++++++++++++++------------- src/cairo-types-private.h | 2 ++ src/cairoint.h | 5 +++ 4 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index 7cfbd65f..f8f89025 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -1035,8 +1035,6 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) cairo_status_t status; cairo_surface_pattern_t pattern; cairo_image_surface_t *image; - const unsigned char *mime_data; - unsigned int mime_data_length; void *image_extra; status = _cairo_surface_acquire_source_image (surface, @@ -1081,28 +1079,11 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) * For now, just copy "image/jpeg", but in future we should construct * an array of known types and iterate. */ - cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_JPEG, - &mime_data, &mime_data_length); - if (mime_data != NULL) { - unsigned char *mime_data_copy; - - mime_data_copy = malloc (mime_data_length); - if (mime_data == NULL) { - cairo_surface_destroy (snapshot); - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } - memcpy (mime_data_copy, mime_data, mime_data_length); - - status = cairo_surface_set_mime_data (snapshot, - CAIRO_MIME_TYPE_JPEG, - mime_data_copy, - mime_data_length, - free); - if (status) { - free (mime_data_copy); - cairo_surface_destroy (snapshot); - return _cairo_surface_create_in_error (status); - } + status = _cairo_surface_copy_mime_data (snapshot, surface, + CAIRO_MIME_TYPE_JPEG); + if (status) { + cairo_surface_destroy (snapshot); + return _cairo_surface_create_in_error (status); } snapshot->is_snapshot = TRUE; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 109cbb91..72997b08 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -637,6 +637,9 @@ _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->data) mime_data->destroy (mime_data->data); @@ -679,35 +682,63 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, if (status) return _cairo_surface_set_error (surface, status); - mime_data = _cairo_user_data_array_get_data (&surface->user_data, + mime_data = malloc (sizeof (cairo_mime_data_t)); + if (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; + + status = _cairo_user_data_array_set_data (&surface->user_data, + (cairo_user_data_key_t *) mime_type, + mime_data, + _cairo_mime_data_destroy); + if (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 (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) { - if (mime_data->destroy && mime_data->data) - mime_data->destroy (mime_data->data); + if (mime_data == NULL) + return CAIRO_STATUS_SUCCESS; - mime_data->data = (unsigned char *) data; - mime_data->length = length; - mime_data->destroy = destroy; - } else { - mime_data = malloc (sizeof (cairo_mime_data_t)); - if (mime_data == NULL) - return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY)); - - mime_data->data = (unsigned char *) data; - mime_data->length = length; - mime_data->destroy = destroy; - - status = _cairo_user_data_array_set_data (&surface->user_data, - (cairo_user_data_key_t *) mime_type, - mime_data, - _cairo_mime_data_destroy); - if (status) - return _cairo_surface_set_error (surface, status); + _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 (status) { + _cairo_mime_data_destroy (mime_data); + return _cairo_surface_set_error (dst, status); } return CAIRO_STATUS_SUCCESS; } -slim_hidden_def (cairo_surface_set_mime_data); /** * _cairo_surface_set_font_options: diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 8bcbf9aa..30180b0c 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -41,6 +41,7 @@ #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_cache cairo_cache_t; @@ -344,6 +345,7 @@ typedef enum _cairo_image_transparency { } 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; diff --git a/src/cairoint.h b/src/cairoint.h index 7fe853cf..c7acbf74 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1665,6 +1665,11 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style, 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); -- cgit v1.2.3 From 310026ab42c2078e2749c886c74c5b38cab41671 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 4 Nov 2008 01:51:06 -0500 Subject: [aclocal.dolt.m4] Fix build with bash versions <= 3.0 (bug #18363) --- build/aclocal.dolt.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/aclocal.dolt.m4 b/build/aclocal.dolt.m4 index 8c75480a..8f94582f 100644 --- a/build/aclocal.dolt.m4 +++ b/build/aclocal.dolt.m4 @@ -157,7 +157,7 @@ for arg in "$[]@"; do case "$arg" in --mode=compile) modeok=true ;; --tag=CC|--tag=CXX) tagok=true ;; - *) args+=("$arg") + *) args@<:@${#args[@]}@:>@="$arg" ;; esac done if $modeok && $tagok ; then -- cgit v1.2.3 From 1d8ad69abb88f6e0283b6ce2aadc5d801b8e3722 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 4 Nov 2008 01:51:06 -0500 Subject: [aclocal.dolt.m4] Fix build with bash versions <= 3.0 (bug #18363) --- build/aclocal.dolt.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/aclocal.dolt.m4 b/build/aclocal.dolt.m4 index 8c75480a..8f94582f 100644 --- a/build/aclocal.dolt.m4 +++ b/build/aclocal.dolt.m4 @@ -157,7 +157,7 @@ for arg in "$[]@"; do case "$arg" in --mode=compile) modeok=true ;; --tag=CC|--tag=CXX) tagok=true ;; - *) args+=("$arg") + *) args@<:@${#args[@]}@:>@="$arg" ;; esac done if $modeok && $tagok ; then -- cgit v1.2.3 From 3664b32195b101ebab9a5f9087095306f8969c80 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 10:38:41 +0000 Subject: [trace] Remove more @..@ from Makefile.am Use $(..) for make variable substitution as opposed to incorrectly using @..@ for substitution by configure. --- util/cairo-trace/Makefile.am | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am index c6caf0c6..f9c68b18 100644 --- a/util/cairo-trace/Makefile.am +++ b/util/cairo-trace/Makefile.am @@ -1,5 +1,5 @@ bin_SCRIPTS = cairo-trace -cairolibdir = @libdir@/cairo +cairolibdir = $(libdir)/cairo cairolib_LTLIBRARIES = cairo-trace.la AM_CPPFLAGS = -I$(top_srcdir)/src \ @@ -9,15 +9,15 @@ cairo_trace_la_SOURCES = \ lookup-symbol.c \ lookup-symbol.h \ trace.c -cairo_trace_la_CFLAGS = $(FREETYPE_CFLAGS) $(CAIRO_CFLAGS) +cairo_trace_la_CFLAGS = $(CAIRO_CFLAGS) cairo_trace_la_LDFLAGS = -module -no-undefined cairo_trace_la_LIBADD = -ldl -lz $(BFD_LIBS) -system-install: - grep -sq @cairolibdir@/cairo-trace.so /etc/ld.so.preload || echo @libdir@/cairo-trace.so >> /etc/ld.so.preload +system-install: install + grep -sq $(cairolibdir)/cairo-trace.so /etc/ld.so.preload || echo $(cairolibdir)/cairo-trace.so >> /etc/ld.so.preload -system-uninstall: - sed -e '@cairolibdir@\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; +system-uninstall: uninstall + sed -e '$(cairolibdir)\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; EXTRA_DIST = \ COPYING \ -- cgit v1.2.3 From 5ba95b7e1287ade0b8a1acf2f5cb73fa1f44c451 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 09:22:28 +0000 Subject: [trace] Convert [1 0 0 1 0 0] to identity Simplify the trace/replay by replacing the identity array with the identity operator. --- util/cairo-trace/trace.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 864038d4..eeca07a1 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -800,6 +800,14 @@ _get_surface_id (cairo_surface_t *surface) return _get_id (SURFACE, surface); } +static bool +_matrix_is_identity (const cairo_matrix_t *m) +{ + return m->xx == 1. && m->yx == 0. && + m->xy == 0. && m->yy == 1. && + m->x0 == 0. && m->y0 == 0.; +} + #define BUFFER_SIZE 16384 struct _data_stream { z_stream zlib_stream; @@ -1558,10 +1566,14 @@ cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) void cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { - _emit_cairo_op (cr, "[%g %g %g %g %g %g] set_matrix\n", - matrix->xx, matrix->yx, - matrix->xy, matrix->yy, - matrix->x0, matrix->y0); + if (_matrix_is_identity (matrix)) { + _emit_cairo_op (cr, "identity set_matrix\n"); + } else { + _emit_cairo_op (cr, "[%g %g %g %g %g %g] set_matrix\n", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + } return DLCALL (cairo_set_matrix, cr, matrix); } @@ -2707,11 +2719,15 @@ cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, doub void cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix) { - _emit_pattern_op (pattern, - "[%g %g %g %g %g %g] set_matrix\n", - matrix->xx, matrix->yx, - matrix->xy, matrix->yy, - matrix->x0, matrix->y0); + if (_matrix_is_identity (matrix)) { + _emit_pattern_op (pattern, "identity set_matrix\n"); + } else { + _emit_pattern_op (pattern, + "[%g %g %g %g %g %g] set_matrix\n", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + } return DLCALL (cairo_pattern_set_matrix, pattern, matrix); } -- cgit v1.2.3 From 3f18d38fbdc661d34e0fd951e0fd3aa1aa2cbcc9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 10:31:48 +0000 Subject: [win32] Compile fix for extend-pad extents. Update the show_glyphs() prototype to include the extents argument. --- src/cairo-win32-printing-surface.c | 3 ++- src/cairo-win32-private.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 77febf0b..94bbc28a 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -1418,7 +1418,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); diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h index 09f63286..6f15408a 100644 --- a/src/cairo-win32-private.h +++ b/src/cairo-win32-private.h @@ -145,7 +145,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, -- cgit v1.2.3 From 73bc278c7a4630cd9299c974771ffd6e9245d0ac Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Nov 2008 22:25:26 +1030 Subject: Add pdf mime data test To test that images in PDF files correctly embedded the mime data. --- test/Makefile.am | 2 + test/pdf-mime-data.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 test/pdf-mime-data.c diff --git a/test/Makefile.am b/test/Makefile.am index c2a87ee8..ce17cce2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -217,6 +217,7 @@ endif if CAIRO_HAS_PDF_SURFACE test_sources += pdf-features.c +test_sources += pdf-mime-data.c test_sources += pdf-surface-source.c endif @@ -999,6 +1000,7 @@ REFERENCE_IMAGES = \ EXTRA_DIST += \ 6x13.pcf \ make-html.pl \ +romedalen.jpg \ romedalen.png \ romedalen.jpg \ surface-source.c \ diff --git a/test/pdf-mime-data.c b/test/pdf-mime-data.c new file mode 100644 index 00000000..11076ea5 --- /dev/null +++ b/test/pdf-mime-data.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2008 Adrian Johnson + * + * 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. + * + * Author: Adrian Johnson + */ + +#include +#include +#include + +#include "cairo-test.h" + +/* This test checks that the mime data is correctly used by the PDF + * surface when embedding images.. + */ + +/* Both a *.png and *.jpg file with this name is required since we + * are not using a jpeg library */ +#define IMAGE_FILE "romedalen" + + +static cairo_test_status_t +read_file (const char *file, unsigned char **data, unsigned int *len) +{ + FILE *fp; + + fp = fopen (file, "rb"); + if (fp == NULL) + return CAIRO_TEST_FAILURE; + + fseek (fp, 0, SEEK_END); + *len = ftell(fp); + fseek (fp, 0, SEEK_SET); + *data = malloc (*len); + if (*data == NULL) + return CAIRO_TEST_NO_MEMORY; + + if (fread(*data, *len, 1, fp) != 1) + return CAIRO_TEST_FAILURE; + + fclose(fp); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + const char *filename = "pdf-mime-data-out.pdf"; + cairo_surface_t *image; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status, status2; + cairo_test_status_t test_status; + int width, height; + unsigned char *data; + unsigned char *out_data; + unsigned int len, out_len; + char command[4096]; + int exit_status; + + if (! cairo_test_is_target_enabled (ctx, "pdf")) + return CAIRO_TEST_UNTESTED; + + image = cairo_image_surface_create_from_png (IMAGE_FILE ".png"); + test_status = read_file (IMAGE_FILE ".jpg", &data, &len); + if (test_status) { + cairo_test_log (ctx, "Could not read input jpeg file %s\n", IMAGE_FILE ".jpg"); + return test_status; + } + + cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG, data, len, free); + width = cairo_image_surface_get_width (image); + height = cairo_image_surface_get_height (image); + + surface = cairo_pdf_surface_create (filename, width + 20, height + 20); + cr = cairo_create (surface); + cairo_translate (cr, 10, 10); + cairo_set_source_surface (cr, image, 0, 0); + cairo_paint (cr); + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_finish (surface); + status2 = cairo_surface_status (surface); + if (status != CAIRO_STATUS_SUCCESS) + status = status2; + cairo_surface_destroy (surface); + cairo_surface_destroy (image); + + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; + } + + printf ("pdf-mime-data: Please check %s to ensure it looks/prints correctly.\n", filename); + + sprintf (command, "pdfimages -j %s pdf-mime-data-out", filename); + exit_status = system (command); + if (exit_status) { + cairo_test_log (ctx, "pdfimages failed with exit status %d\n", exit_status); + return CAIRO_TEST_FAILURE; + } + + test_status = read_file (IMAGE_FILE ".jpg", &data, &len); + if (test_status) { + cairo_test_log (ctx, "Could not read input jpeg file %s\n", IMAGE_FILE ".jpg"); + return test_status; + } + + test_status = read_file ("pdf-mime-data-out-000.jpg", &out_data, &out_len); + if (test_status) { + cairo_test_log (ctx, "Could not read input jpeg file %s\n", "pdf-mime-data-out-000.jpg"); + return test_status; + } + + if (len != out_len || memcmp(data, out_data, len) != 0) { + cairo_test_log (ctx, "output mime data does not match source mime data\n"); + return CAIRO_TEST_FAILURE; + } + free (data); + free (out_data); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pdf_mime_data, + "Check mime data correctly used by PDF surface", + "pdf", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) -- cgit v1.2.3 From 30976635d7072c06d00e39b106e41be7b08c6c49 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Nov 2008 22:52:45 +1030 Subject: PS: Implement JPEG embedding --- src/cairo-ps-surface.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 29e9872e..e0db5757 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-jpeg-info-private.h" #include #include @@ -2118,6 +2119,93 @@ bail1: return status; } +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_jpeg_info_t info; + + cairo_surface_get_mime_data (&surface->base, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_jpeg_get_info (mime_data, mime_data_length, &info); + if (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 (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) @@ -2316,7 +2404,9 @@ BAIL: 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; @@ -2326,6 +2416,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); } @@ -2404,7 +2501,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; @@ -2502,7 +2599,8 @@ _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); + status = _cairo_ps_surface_emit_surface (surface, pattern, op, + pattern_width, pattern_height); if (status) return status; -- cgit v1.2.3 From aa616abc9ab02e333cf0cad4f524b15c710bf449 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 11:18:22 +0000 Subject: [png] Use RGB for opaque images. If the ARGB32 is opaque, discard the alpha channel - so we should generate byte identical output to the reference images. --- src/cairo-png.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cairo-png.c b/src/cairo-png.c index 06e7cb55..4721825e 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -190,7 +190,10 @@ write_png (cairo_surface_t *surface, 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 +240,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); -- cgit v1.2.3 From 282d7744275f623ce550638df953ef279d2209f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 12:53:15 +0000 Subject: [mime-type] Request the mime-data for the source surface, not ourselves! Fixup a typo I introduced that caused us to request the jpeg data for the destination surface and not the source. --- src/cairo-pdf-surface.c | 2 +- src/cairo-ps-surface.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 7bcb0577..6edea4a5 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1563,7 +1563,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, unsigned int mime_data_length; cairo_jpeg_info_t info; - cairo_surface_get_mime_data (&surface->base, CAIRO_MIME_TYPE_JPEG, + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, &mime_data, &mime_data_length); if (mime_data == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index e0db5757..5dcdce52 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -2130,11 +2130,10 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface, unsigned int mime_data_length; cairo_jpeg_info_t info; - cairo_surface_get_mime_data (&surface->base, CAIRO_MIME_TYPE_JPEG, + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, &mime_data, &mime_data_length); - if (mime_data == NULL) { + if (mime_data == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; - } status = _cairo_jpeg_get_info (mime_data, mime_data_length, &info); if (status) -- cgit v1.2.3 From 8007618837c0292b6ebc6a4f954c5049d4e99d8a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 12:31:10 +0000 Subject: [test] Fix compilation of imagediff. imagediff broke once again. --- test/Makefile.am | 3 ++- test/imagediff.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/test/Makefile.am b/test/Makefile.am index ce17cce2..8319c30b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1149,7 +1149,8 @@ imagediff_SOURCES = \ buffer-diff.c \ buffer-diff.h imagediff_LDADD = \ - $(top_builddir)/test/pdiff/libpdiff.la + $(top_builddir)/test/pdiff/libpdiff.la \ + $(top_builddir)/src/libcairo.la png_flatten_SOURCES = png-flatten.c png_flatten_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) diff --git a/test/imagediff.c b/test/imagediff.c index 424ca6dc..6ebbcfca 100644 --- a/test/imagediff.c +++ b/test/imagediff.c @@ -46,6 +46,23 @@ _xunlink (const char *pathname) } } +void +cairo_test_logv (const cairo_test_context_t *ctx, + const char *fmt, va_list va) +{ + vfprintf (stderr, fmt, va); +} + +void +cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...) +{ + va_list va; + + va_start (va, fmt); + vfprintf (stderr, fmt, va); + va_end (va); +} + /* Flatten an ARGB surface by blending it over white. The resulting * surface, (still in ARGB32 format, but with only alpha==1.0 * everywhere) is returned in the same surface pointer. -- cgit v1.2.3 From 8407470409ad9cb93263a1c2da7dd7446d3f897e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 12:45:47 +0000 Subject: [test] Adapt pdf-mime-data for non-srcdir build. Need to look for reference/input images from srcdir as well. --- test/Makefile.am | 2 +- test/pdf-mime-data.c | 44 ++++++++++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index 8319c30b..bbf3970f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1002,7 +1002,6 @@ EXTRA_DIST += \ make-html.pl \ romedalen.jpg \ romedalen.png \ -romedalen.jpg \ surface-source.c \ $(REFERENCE_IMAGES) @@ -1219,6 +1218,7 @@ CLEANFILES += \ pdf-surface-source.pdf \ ps-surface-source.ps \ pdf-features.pdf \ + pdf-mime-data.out* \ ps-features.ps \ svg-clip.svg \ svg-surface.svg \ diff --git a/test/pdf-mime-data.c b/test/pdf-mime-data.c index 11076ea5..c949335e 100644 --- a/test/pdf-mime-data.c +++ b/test/pdf-mime-data.c @@ -24,12 +24,13 @@ * Author: Adrian Johnson */ +#include "cairo-test.h" + #include +#include #include #include -#include "cairo-test.h" - /* This test checks that the mime data is correctly used by the PDF * surface when embedding images.. */ @@ -40,13 +41,30 @@ static cairo_test_status_t -read_file (const char *file, unsigned char **data, unsigned int *len) +read_file (const cairo_test_context_t *ctx, + const char *file, + unsigned char **data, + unsigned int *len) { FILE *fp; fp = fopen (file, "rb"); - if (fp == NULL) - return CAIRO_TEST_FAILURE; + if (file == NULL) { + char filename[4096]; + + /* try again with srcdir */ + snprintf (filename, sizeof (filename), + "%s/%s", ctx->srcdir, file); + fp = fopen (filename, "rb"); + } + if (fp == NULL) { + switch (errno) { + case ENOMEM: + return CAIRO_TEST_NO_MEMORY; + default: + return CAIRO_TEST_FAILURE; + } + } fseek (fp, 0, SEEK_END); *len = ftell(fp); @@ -65,7 +83,7 @@ read_file (const char *file, unsigned char **data, unsigned int *len) static cairo_test_status_t preamble (cairo_test_context_t *ctx) { - const char *filename = "pdf-mime-data-out.pdf"; + const char *filename = "pdf-mime-data.out.pdf"; cairo_surface_t *image; cairo_surface_t *surface; cairo_t *cr; @@ -82,7 +100,7 @@ preamble (cairo_test_context_t *ctx) return CAIRO_TEST_UNTESTED; image = cairo_image_surface_create_from_png (IMAGE_FILE ".png"); - test_status = read_file (IMAGE_FILE ".jpg", &data, &len); + test_status = read_file (ctx, IMAGE_FILE ".jpg", &data, &len); if (test_status) { cairo_test_log (ctx, "Could not read input jpeg file %s\n", IMAGE_FILE ".jpg"); return test_status; @@ -114,22 +132,24 @@ preamble (cairo_test_context_t *ctx) printf ("pdf-mime-data: Please check %s to ensure it looks/prints correctly.\n", filename); - sprintf (command, "pdfimages -j %s pdf-mime-data-out", filename); + sprintf (command, "pdfimages -j %s pdf-mime-data.out", filename); exit_status = system (command); if (exit_status) { cairo_test_log (ctx, "pdfimages failed with exit status %d\n", exit_status); return CAIRO_TEST_FAILURE; } - test_status = read_file (IMAGE_FILE ".jpg", &data, &len); + test_status = read_file (ctx, IMAGE_FILE ".jpg", &data, &len); if (test_status) { cairo_test_log (ctx, "Could not read input jpeg file %s\n", IMAGE_FILE ".jpg"); return test_status; } - test_status = read_file ("pdf-mime-data-out-000.jpg", &out_data, &out_len); + test_status = read_file (ctx, "pdf-mime-data.out-000.jpg", &out_data, &out_len); if (test_status) { - cairo_test_log (ctx, "Could not read input jpeg file %s\n", "pdf-mime-data-out-000.jpg"); + cairo_test_log (ctx, + "Could not read input jpeg file %s\n", + "pdf-mime-data.out-000.jpg"); return test_status; } @@ -145,7 +165,7 @@ preamble (cairo_test_context_t *ctx) CAIRO_TEST (pdf_mime_data, "Check mime data correctly used by PDF surface", - "pdf", /* keywords */ + "pdf, mime-data", /* keywords */ NULL, /* requirements */ 0, 0, preamble, NULL) -- cgit v1.2.3 From c13a09ddb411287224c15728b14f23fef472f7d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 13:00:36 +0000 Subject: [test] Use a different jpeg image for mime-data Detect when we successfully encode the JPEG data from the mime-type by using a completely image. --- test/Makefile.am | 3 +++ test/mime-data.c | 6 +++++- test/mime-data.pdf.ref.png | Bin 0 -> 96 bytes test/mime-data.ps.ref.png | Bin 0 -> 368 bytes test/scarab.jpg | Bin 0 -> 9650 bytes 5 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test/mime-data.pdf.ref.png create mode 100644 test/mime-data.ps.ref.png create mode 100644 test/scarab.jpg diff --git a/test/Makefile.am b/test/Makefile.am index bbf3970f..1bc5c47b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -694,6 +694,8 @@ REFERENCE_IMAGES = \ meta-surface-pattern.svg12.argb32.ref.png \ meta-surface-pattern.svg12.rgb24.ref.png \ mime-data.ref.png \ + mime-data.ps.ref.png \ + mime-data.pdf.ref.png \ miter-precision.ref.png \ miter-precision.ps2.ref.png \ miter-precision.ps3.ref.png \ @@ -1002,6 +1004,7 @@ EXTRA_DIST += \ make-html.pl \ romedalen.jpg \ romedalen.png \ +scarab.jpg \ surface-source.c \ $(REFERENCE_IMAGES) diff --git a/test/mime-data.c b/test/mime-data.c index b3649153..dd1e0955 100644 --- a/test/mime-data.c +++ b/test/mime-data.c @@ -35,7 +35,11 @@ read_jpg_file (const cairo_test_context_t *ctx, unsigned char **data_out, unsigned int *length_out) { - const char jpg_filename[] = "romedalen.jpg"; + /* Deliberately use a non-matching jpeg image, so that we can identify + * when the JPEG representation is used in preference to the image + * surface. + */ + const char jpg_filename[] = "scarab.jpg"; FILE *file; unsigned char *buf; unsigned int len; diff --git a/test/mime-data.pdf.ref.png b/test/mime-data.pdf.ref.png new file mode 100644 index 00000000..f04fe6ce Binary files /dev/null and b/test/mime-data.pdf.ref.png differ diff --git a/test/mime-data.ps.ref.png b/test/mime-data.ps.ref.png new file mode 100644 index 00000000..43d10320 Binary files /dev/null and b/test/mime-data.ps.ref.png differ diff --git a/test/scarab.jpg b/test/scarab.jpg new file mode 100644 index 00000000..6a66ff78 Binary files /dev/null and b/test/scarab.jpg differ -- cgit v1.2.3 From 9900a2adf3e43e752bd421f00e81873b41db4c30 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 13:41:02 +0000 Subject: [test] Update mime-data jpeg reference data. ickle_: If we are going to use a different image for jpeg in mime-data maybe we could create a jpg that contains the text "jpeg". That way when support for the other image formats is added the mime-data test could have one image for each type with each image and it is easy to see that each image is the correct one. --- test/jpeg.jpg | Bin 0 -> 2316 bytes test/mime-data.c | 6 +++--- test/mime-data.pdf.ref.png | Bin 96 -> 4345 bytes test/mime-data.ps.ref.png | Bin 368 -> 4345 bytes test/mime-data.ref.png | Bin 263 -> 127 bytes 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 test/jpeg.jpg diff --git a/test/jpeg.jpg b/test/jpeg.jpg new file mode 100644 index 00000000..a1bac1c8 Binary files /dev/null and b/test/jpeg.jpg differ diff --git a/test/mime-data.c b/test/mime-data.c index dd1e0955..a387d672 100644 --- a/test/mime-data.c +++ b/test/mime-data.c @@ -39,7 +39,7 @@ read_jpg_file (const cairo_test_context_t *ctx, * when the JPEG representation is used in preference to the image * surface. */ - const char jpg_filename[] = "scarab.jpg"; + const char jpg_filename[] = "jpeg.jpg"; FILE *file; unsigned char *buf; unsigned int len; @@ -92,7 +92,7 @@ draw (cairo_t *cr, int width, int height) return cairo_test_status_from_status (ctx, status); } - image = cairo_test_create_surface_from_png (ctx, "romedalen.png"); + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50); status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG, jpg_data, jpg_len, free); if (status) { @@ -111,5 +111,5 @@ CAIRO_TEST (mime_data, "Check that the mime-data embedding works", "jpeg, api", /* keywords */ NULL, /* requirements */ - 10, 10, + 200, 50, NULL, draw) diff --git a/test/mime-data.pdf.ref.png b/test/mime-data.pdf.ref.png index f04fe6ce..cf53a610 100644 Binary files a/test/mime-data.pdf.ref.png and b/test/mime-data.pdf.ref.png differ diff --git a/test/mime-data.ps.ref.png b/test/mime-data.ps.ref.png index 43d10320..cf53a610 100644 Binary files a/test/mime-data.ps.ref.png and b/test/mime-data.ps.ref.png differ diff --git a/test/mime-data.ref.png b/test/mime-data.ref.png index cc13baf0..782a2eef 100644 Binary files a/test/mime-data.ref.png and b/test/mime-data.ref.png differ -- cgit v1.2.3 From 3f7a21c5c93d8648ded097757852df44fc9fcaeb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 13:46:10 +0000 Subject: [test] Add jpeg.jpg to EXTRA_DIST Forgot to add the new file to the distribution with the previous commit. --- test/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Makefile.am b/test/Makefile.am index 1bc5c47b..2ffbfb63 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1002,6 +1002,7 @@ REFERENCE_IMAGES = \ EXTRA_DIST += \ 6x13.pcf \ make-html.pl \ +jpeg.jpg \ romedalen.jpg \ romedalen.png \ scarab.jpg \ -- cgit v1.2.3 From a3d56c60e85176526d6cce139441b6921acc9218 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 14:06:02 +0000 Subject: [trace] Use a common directory by default. If called directly (e.g. via /etc/ld.so.preload) put the output trace into a central directory, and not the pwd. --- util/cairo-trace/Makefile.am | 10 ++++++++-- util/cairo-trace/trace.c | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am index f9c68b18..50bd255e 100644 --- a/util/cairo-trace/Makefile.am +++ b/util/cairo-trace/Makefile.am @@ -1,5 +1,7 @@ -bin_SCRIPTS = cairo-trace cairolibdir = $(libdir)/cairo +cairooutdir = $(localstatedir)/lib/cairo-trace + +bin_SCRIPTS = cairo-trace cairolib_LTLIBRARIES = cairo-trace.la AM_CPPFLAGS = -I$(top_srcdir)/src \ @@ -9,15 +11,19 @@ cairo_trace_la_SOURCES = \ lookup-symbol.c \ lookup-symbol.h \ trace.c +cairo_trace_la_CPPFLAGS = -DCAIRO_TRACE_OUTDIR="\"$(cairooutdir)\"" \ + $(AM_CPPFLAGS) cairo_trace_la_CFLAGS = $(CAIRO_CFLAGS) cairo_trace_la_LDFLAGS = -module -no-undefined cairo_trace_la_LIBADD = -ldl -lz $(BFD_LIBS) + system-install: install + mkdir -p $(cairooutdir) grep -sq $(cairolibdir)/cairo-trace.so /etc/ld.so.preload || echo $(cairolibdir)/cairo-trace.so >> /etc/ld.so.preload system-uninstall: uninstall - sed -e '$(cairolibdir)\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; + sed -e '/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload; EXTRA_DIST = \ COPYING \ diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index eeca07a1..680a6b9e 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -41,6 +41,10 @@ # include #endif +#ifndef CAIRO_TRACE_OUTDIR +#define CAIRO_TRACE_OUTDIR "." +#endif + #include "lookup-symbol.h" /* Reverse the bits in a byte with 7 operations (no 64-bit): @@ -448,13 +452,13 @@ _init_logfile (void) filename = getenv ("CAIRO_TRACE_OUTDIR"); if (filename == NULL) - filename = "."; + filename = CAIRO_TRACE_OUTDIR; get_prog_name (name, sizeof (name)); if (*name == '\0') strcpy (name, "cairo-trace.dat"); - snprintf (buf, sizeof (buf), "%s/%s.%d.cs", + snprintf (buf, sizeof (buf), "%s/%s.%d.trace", filename, name, getpid()); filename = buf; -- cgit v1.2.3 From 068d465bb3541cc0ffc3cb9daa0848365c0a6a24 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 14:57:21 +0000 Subject: [trace] Fix emission of cairo_scaled_font_create() In the case where the font face was no longer on the operand stack, the font face would not have been passed to cairo_scaled_font_create(). --- util/cairo-trace/trace.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 680a6b9e..b958e759 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -2089,26 +2089,25 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, options != NULL && _write_lock ()) { - font_face_id = _get_font_face_id (font_face); - - if (_pop_operands_to (FONT_FACE, font_face)) { + if (_pop_operands_to (FONT_FACE, font_face)) _consume_operand (); - _emit_matrix (font_matrix); - fprintf (logfile, " "); - _emit_matrix (ctm); - fprintf (logfile, " "); - } else { - _emit_matrix (font_matrix); - fprintf (logfile, " "); - _emit_matrix (ctm); - fprintf (logfile, " "); - _emit_font_options (options); - } + else + fprintf (logfile, "f%ld ", _get_font_face_id (font_face)); + + _emit_matrix (font_matrix); + fprintf (logfile, " "); + + _emit_matrix (ctm); + fprintf (logfile, " "); + _emit_font_options (options); + fprintf (logfile, " scaled_font dup /sf%ld exch def\n", scaled_font_id); + _get_object (SCALED_FONT, ret)->defined = true; _push_operand (SCALED_FONT, ret); + _write_unlock (); } -- cgit v1.2.3 From 59bdeba9abd7bef15c6855d707c4cf92b623cb00 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 18:42:05 +0000 Subject: [matrix] Minimise pixman conversion error. Minimise the error of the pixman matrix about the centre of the displayed area rather than the origin. --- src/cairo-image-surface.c | 25 +++++++++++++++++-------- src/cairo-matrix.c | 24 ++++++++++++++---------- src/cairo-pattern.c | 3 ++- src/cairo-xlib-surface.c | 33 +++++++++++++++++++++++---------- src/cairoint.h | 4 +++- test/Makefile.am | 3 +-- test/surface-pattern.pdf.ref.png | Bin 15996 -> 14776 bytes test/surface-pattern.ref.png | Bin 11439 -> 11044 bytes test/surface-pattern.svg.ref.png | Bin 0 -> 16151 bytes test/surface-pattern.svg11.ref.png | Bin 17663 -> 0 bytes test/surface-pattern.svg12.ref.png | Bin 17663 -> 0 bytes 11 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 test/surface-pattern.svg.ref.png delete mode 100644 test/surface-pattern.svg11.ref.png delete mode 100644 test/surface-pattern.svg12.ref.png diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 12614c1a..f84cf7fb 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -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,11 +863,13 @@ _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); + status = _cairo_image_surface_set_matrix (surface, &attributes->matrix, + xc, yc); if (status) return status; @@ -968,13 +971,17 @@ _cairo_image_surface_composite (cairo_operator_t op, if (status) return status; - status = _cairo_image_surface_set_attributes (src, &src_attr); + status = _cairo_image_surface_set_attributes (src, &src_attr, + dst_x + width / 2., + dst_y + height / 2.); if (status) - goto CLEANUP_SURFACES; + goto CLEANUP_SURFACES; if (mask) { - status = _cairo_image_surface_set_attributes (mask, &mask_attr); + status = _cairo_image_surface_set_attributes (mask, &mask_attr, + dst_x + width / 2., + dst_y + height / 2.); if (status) goto CLEANUP_SURFACES; @@ -1151,7 +1158,9 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, if (status) goto finish; - status = _cairo_image_surface_set_attributes (src, &attributes); + status = _cairo_image_surface_set_attributes (src, &attributes, + src_x + width / 2., + src_y + height / 2.); if (status) goto CLEANUP_SOURCE; diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index b644dec8..555c4fee 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,8 +877,7 @@ _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; @@ -899,9 +900,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,8 +913,8 @@ _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; + /* find the device space coordinate that maps to (xc, yc) */ + x = xc, y = yc; cairo_matrix_transform_point (&inv, &x, &y); /* transform the resulting device space coordinate back @@ -924,9 +926,11 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, if (! pixman_transform_point_3d (pixman_transform, &vector)) return; - /* Ideally, the vector should now be (0, 0). We can now compensate + /* Ideally, the vector should now be (xc, yc). We can now compensate * for the resulting error */ - pixman_transform->matrix[0][2] -= vector.vector[0]; - pixman_transform->matrix[1][2] -= vector.vector[1]; + pixman_transform->matrix[0][2] += + _cairo_fixed_16_16_from_double (xc) - vector.vector[0]; + pixman_transform->matrix[1][2] += + _cairo_fixed_16_16_from_double (yc) - vector.vector[1]; } } diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 02b0674f..5a6bf6c9 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -1403,7 +1403,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); diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index c59694d5..12c2cccb 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -1312,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; @@ -1411,13 +1415,16 @@ _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); + status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix, + xc, yc); if (status) return status; @@ -1746,13 +1753,17 @@ _cairo_xlib_surface_composite (cairo_operator_t op, switch (operation) { case DO_RENDER: - status = _cairo_xlib_surface_set_attributes (src, &src_attr); + status = _cairo_xlib_surface_set_attributes (src, &src_attr, + dst_x + width / 2., + dst_y + height / 2.); if (status) goto BAIL; _cairo_xlib_surface_ensure_dst_picture (dst); if (mask) { - status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); + status = _cairo_xlib_surface_set_attributes (mask, &mask_attr, + dst_x + width / 2., + dst_y + height/ 2.); if (status) goto BAIL; @@ -2161,7 +2172,9 @@ _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); + status = _cairo_xlib_surface_set_attributes (src, &attributes, + dst_x + width / 2., + dst_y + height / 2.); if (status) goto BAIL; @@ -4064,7 +4077,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, goto BAIL1; } - status = _cairo_xlib_surface_set_attributes (src, &attributes); + status = _cairo_xlib_surface_set_attributes (src, &attributes, 0, 0); if (status) goto BAIL1; diff --git a/src/cairoint.h b/src/cairoint.h index c7acbf74..63fefd7a 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -2208,7 +2208,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 diff --git a/test/Makefile.am b/test/Makefile.am index 2ffbfb63..e3d42d8e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -912,8 +912,7 @@ REFERENCE_IMAGES = \ surface-pattern-scale-up.ps2.ref.png \ surface-pattern-scale-up.ps3.ref.png \ surface-pattern-scale-up.ref.png \ - surface-pattern.svg12.ref.png \ - surface-pattern.svg11.ref.png \ + surface-pattern.svg.ref.png \ svg-surface-source.ref.png \ text-antialias-gray.ref.png \ text-antialias-gray.quartz.ref.png \ diff --git a/test/surface-pattern.pdf.ref.png b/test/surface-pattern.pdf.ref.png index bfb34788..c37e2a4f 100644 Binary files a/test/surface-pattern.pdf.ref.png and b/test/surface-pattern.pdf.ref.png differ diff --git a/test/surface-pattern.ref.png b/test/surface-pattern.ref.png index d1c2b335..9cdf6a54 100644 Binary files a/test/surface-pattern.ref.png and b/test/surface-pattern.ref.png differ diff --git a/test/surface-pattern.svg.ref.png b/test/surface-pattern.svg.ref.png new file mode 100644 index 00000000..2078fc0e Binary files /dev/null and b/test/surface-pattern.svg.ref.png differ diff --git a/test/surface-pattern.svg11.ref.png b/test/surface-pattern.svg11.ref.png deleted file mode 100644 index 5569a557..00000000 Binary files a/test/surface-pattern.svg11.ref.png and /dev/null differ diff --git a/test/surface-pattern.svg12.ref.png b/test/surface-pattern.svg12.ref.png deleted file mode 100644 index 5569a557..00000000 Binary files a/test/surface-pattern.svg12.ref.png and /dev/null differ -- cgit v1.2.3 From aad980900314bd032468f41a3216769c66e62097 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 19:11:55 +0000 Subject: [test] Only depend on any2ppm if we build it. Do not add a dependency to any2ppm if it has been deconfigured. --- test/Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/Makefile.am b/test/Makefile.am index e3d42d8e..29389695 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -283,8 +283,11 @@ cairo_test_suite_LDADD = \ cairo_test_suite_DEPENDENCIES = \ $(top_builddir)/test/pdiff/libpdiff.la \ $(top_builddir)/boilerplate/libcairoboilerplate.la \ - $(top_builddir)/src/libcairo.la \ + $(top_builddir)/src/libcairo.la +if BUILD_ANY2PPM +cairo_test_suite_DEPENDENCIES += \ any2ppm +endif if HAVE_PTHREAD cairo_test_suite_LDADD += -lpthread endif -- cgit v1.2.3 From 8855f9583e84ae2e6d981e21133f590bff2065ab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 20:04:02 +0000 Subject: [test] Add scale-offset-(similar|image) Add a test case for the scaling bug reported by Michel Iwaniec: http://lists.cairographics.org/archives/cairo/2008-November/015660.html --- test/Makefile.am | 6 ++ test/scale-offset-image.c | 142 ++++++++++++++++++++++++++++++++++ test/scale-offset-image.ps.ref.png | Bin 0 -> 7445 bytes test/scale-offset-image.ref.png | Bin 0 -> 10005 bytes test/scale-offset-similar.c | 143 +++++++++++++++++++++++++++++++++++ test/scale-offset-similar.ps.ref.png | Bin 0 -> 7819 bytes test/scale-offset-similar.ref.png | Bin 0 -> 10005 bytes 7 files changed, 291 insertions(+) create mode 100644 test/scale-offset-image.c create mode 100644 test/scale-offset-image.ps.ref.png create mode 100644 test/scale-offset-image.ref.png create mode 100644 test/scale-offset-similar.c create mode 100644 test/scale-offset-similar.ps.ref.png create mode 100644 test/scale-offset-similar.ref.png diff --git a/test/Makefile.am b/test/Makefile.am index 29389695..db1acf19 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -141,6 +141,8 @@ test_sources = \ rgb24-ignore-alpha.c \ rotate-image-surface-paint.c \ scale-down-source-surface-paint.c \ + scale-offset-image.c \ + scale-offset-similar.c \ scale-source-surface-paint.c \ stroke-ctm-caps.c \ stroke-image.c \ @@ -812,6 +814,10 @@ REFERENCE_IMAGES = \ rotate-image-surface-paint.svg12.ref.png \ rotate-image-surface-paint.svg11.ref.png \ scale-down-source-surface-paint.ref.png \ + scale-offset-image.ref.png \ + scale-offset-image.ps.ref.png \ + scale-offset-similar.ref.png \ + scale-offset-similar.ps.ref.png \ scale-source-surface-paint.pdf.argb32.ref.png \ scale-source-surface-paint.ref.png \ scale-source-surface-paint.rgb24.ref.png \ diff --git a/test/scale-offset-image.c b/test/scale-offset-image.c new file mode 100644 index 00000000..ab553422 --- /dev/null +++ b/test/scale-offset-image.c @@ -0,0 +1,142 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* + * Test case derived from the bug report by Michel Iwaniec: + * http://lists.cairographics.org/archives/cairo/2008-November/015660.html + */ + +#include "cairo-test.h" + +static cairo_surface_t * +create_source (cairo_surface_t *target, int width, int height) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + width, height); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, + width - 4, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, + width - 2, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, + width - 4, height - 2, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, + width - 2, height - 2, + 2, 2); + cairo_fill (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static void +draw_grid (cairo_t *cr, cairo_pattern_t *pattern, int dst_x, int dst_y) +{ + cairo_matrix_t m; + + cairo_save (cr); + cairo_translate (cr, dst_x, dst_y); + cairo_scale (cr, 16, 16); + cairo_rotate (cr, 1); + + cairo_matrix_init_translate (&m, 2560-4, 1280-4); + cairo_pattern_set_matrix (pattern, &m); + cairo_set_source (cr, pattern); + cairo_rectangle (cr, 0, 0, 4, 4); + cairo_fill (cr); + + cairo_set_source_rgb (cr, .7, .7, .7); + cairo_set_line_width (cr, 1./16); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 4, 0); + cairo_move_to (cr, 0, 2); + cairo_line_to (cr, 4, 2); + cairo_move_to (cr, 0, 4); + cairo_line_to (cr, 4, 4); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, 4); + cairo_move_to (cr, 2, 0); + cairo_line_to (cr, 2, 4); + cairo_move_to (cr, 4, 0); + cairo_line_to (cr, 4, 4); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + cairo_pattern_t *pattern; + + cairo_paint (cr); + + source = create_source (cairo_get_target (cr), 2560, 1280); + pattern = cairo_pattern_create_for_surface (source); + cairo_surface_destroy (source); + + cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + + draw_grid (cr, pattern, 50, 0); + draw_grid (cr, pattern, 130, 0); + draw_grid (cr, pattern, 210, 0); + draw_grid (cr, pattern, 290, 0); + + draw_grid (cr, pattern, 50, 230); + draw_grid (cr, pattern, 130, 230); + draw_grid (cr, pattern, 210, 230); + draw_grid (cr, pattern, 290, 230); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (scale_offset_image, + "Tests drawing surfaces under various scales and transforms", + "XFAIL=!ps surface scale-offset", /* keywords */ + NULL, /* requirements */ + 320, 320, + NULL, draw) + diff --git a/test/scale-offset-image.ps.ref.png b/test/scale-offset-image.ps.ref.png new file mode 100644 index 00000000..b87612aa Binary files /dev/null and b/test/scale-offset-image.ps.ref.png differ diff --git a/test/scale-offset-image.ref.png b/test/scale-offset-image.ref.png new file mode 100644 index 00000000..325bdf43 Binary files /dev/null and b/test/scale-offset-image.ref.png differ diff --git a/test/scale-offset-similar.c b/test/scale-offset-similar.c new file mode 100644 index 00000000..074ce05e --- /dev/null +++ b/test/scale-offset-similar.c @@ -0,0 +1,143 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* + * Test case derived from the bug report by Michel Iwaniec: + * http://lists.cairographics.org/archives/cairo/2008-November/015660.html + */ + +#include "cairo-test.h" + +static cairo_surface_t * +create_source (cairo_surface_t *target, int width, int height) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_surface_create_similar (target, + CAIRO_CONTENT_COLOR, + width, height); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, + width - 4, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, + width - 2, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, + width - 4, height - 2, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, + width - 2, height - 2, + 2, 2); + cairo_fill (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static void +draw_grid (cairo_t *cr, cairo_pattern_t *pattern, int dst_x, int dst_y) +{ + cairo_matrix_t m; + + cairo_save (cr); + cairo_translate (cr, dst_x, dst_y); + cairo_scale (cr, 16, 16); + cairo_rotate (cr, 1); + + cairo_matrix_init_translate (&m, 2560-4, 1280-4); + cairo_pattern_set_matrix (pattern, &m); + cairo_set_source (cr, pattern); + cairo_rectangle (cr, 0, 0, 4, 4); + cairo_fill (cr); + + cairo_set_source_rgb (cr, .7, .7, .7); + cairo_set_line_width (cr, 1./16); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 4, 0); + cairo_move_to (cr, 0, 2); + cairo_line_to (cr, 4, 2); + cairo_move_to (cr, 0, 4); + cairo_line_to (cr, 4, 4); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, 4); + cairo_move_to (cr, 2, 0); + cairo_line_to (cr, 2, 4); + cairo_move_to (cr, 4, 0); + cairo_line_to (cr, 4, 4); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + cairo_pattern_t *pattern; + + cairo_paint (cr); + + source = create_source (cairo_get_target (cr), 2560, 1280); + pattern = cairo_pattern_create_for_surface (source); + cairo_surface_destroy (source); + + cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + + draw_grid (cr, pattern, 50, 0); + draw_grid (cr, pattern, 130, 0); + draw_grid (cr, pattern, 210, 0); + draw_grid (cr, pattern, 290, 0); + + draw_grid (cr, pattern, 50, 230); + draw_grid (cr, pattern, 130, 230); + draw_grid (cr, pattern, 210, 230); + draw_grid (cr, pattern, 290, 230); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (scale_offset_similar, + "Tests drawing surfaces under various scales and transforms", + "XFAIL=!ps surface scale-offset", /* keywords */ + NULL, /* requirements */ + 320, 320, + NULL, draw) + diff --git a/test/scale-offset-similar.ps.ref.png b/test/scale-offset-similar.ps.ref.png new file mode 100644 index 00000000..a60e9ad4 Binary files /dev/null and b/test/scale-offset-similar.ps.ref.png differ diff --git a/test/scale-offset-similar.ref.png b/test/scale-offset-similar.ref.png new file mode 100644 index 00000000..325bdf43 Binary files /dev/null and b/test/scale-offset-similar.ref.png differ -- cgit v1.2.3 From 68309481aa9295026e3e7e6407c793f899b5e600 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 08:03:01 +0000 Subject: [test] Mark targets with is_meta? Allow tests to skip targets based on whether they are a meta surface or not. --- boilerplate/cairo-boilerplate.c | 40 ++++++++++++++++++++++++---------------- boilerplate/cairo-boilerplate.h | 1 + test/cairo-test.c | 13 ++++++++++++- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c index 632624f5..50f9f399 100644 --- a/boilerplate/cairo-boilerplate.c +++ b/boilerplate/cairo-boilerplate.c @@ -313,7 +313,9 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_test_meta_create_surface, NULL, NULL, _cairo_boilerplate_get_image_surface, - cairo_surface_write_to_png + cairo_surface_write_to_png, + NULL, NULL, + FALSE, TRUE }, { "test-meta", "image", NULL, @@ -322,7 +324,9 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_test_meta_create_surface, NULL, NULL, _cairo_boilerplate_get_image_surface, - cairo_surface_write_to_png + cairo_surface_write_to_png, + NULL, NULL, + FALSE, TRUE }, { "test-paginated", "image", NULL, @@ -332,7 +336,9 @@ static cairo_boilerplate_target_t targets[] = NULL, _cairo_boilerplate_test_paginated_get_image_surface, _cairo_boilerplate_test_paginated_surface_write_to_png, - _cairo_boilerplate_test_paginated_cleanup + _cairo_boilerplate_test_paginated_cleanup, + NULL, + FALSE, TRUE, }, { "test-paginated", "image", NULL, @@ -342,7 +348,9 @@ static cairo_boilerplate_target_t targets[] = NULL, _cairo_boilerplate_test_paginated_get_image_surface, _cairo_boilerplate_test_paginated_surface_write_to_png, - _cairo_boilerplate_test_paginated_cleanup + _cairo_boilerplate_test_paginated_cleanup, + NULL, + FALSE, TRUE }, #endif #ifdef CAIRO_HAS_GLITZ_SURFACE @@ -457,7 +465,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_win32_printing_get_image_surface, _cairo_boilerplate_win32_printing_surface_write_to_png, _cairo_boilerplate_win32_printing_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "win32-printing", "win32"".ps", @@ -467,7 +475,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_win32_printing_get_image_surface, _cairo_boilerplate_win32_printing_surface_write_to_png, _cairo_boilerplate_win32_printing_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, #endif #endif @@ -533,7 +541,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_ps_get_image_surface, _cairo_boilerplate_ps_surface_write_to_png, _cairo_boilerplate_ps_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "ps2", "ps", ".ps", @@ -544,7 +552,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_ps_get_image_surface, _cairo_boilerplate_ps_surface_write_to_png, _cairo_boilerplate_ps_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "ps3", "ps", ".ps", @@ -556,7 +564,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_ps_get_image_surface, _cairo_boilerplate_ps_surface_write_to_png, _cairo_boilerplate_ps_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "ps3", "ps", ".ps", @@ -567,7 +575,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_ps_get_image_surface, _cairo_boilerplate_ps_surface_write_to_png, _cairo_boilerplate_ps_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, #endif #if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE @@ -581,7 +589,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_pdf_get_image_surface, _cairo_boilerplate_pdf_surface_write_to_png, _cairo_boilerplate_pdf_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "pdf", "pdf", ".pdf", @@ -592,7 +600,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_pdf_get_image_surface, _cairo_boilerplate_pdf_surface_write_to_png, _cairo_boilerplate_pdf_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, #endif #if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE @@ -610,7 +618,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_svg_get_image_surface, _cairo_boilerplate_svg_surface_write_to_png, _cairo_boilerplate_svg_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "svg11", "svg", NULL, @@ -621,7 +629,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_svg_get_image_surface, _cairo_boilerplate_svg_surface_write_to_png, _cairo_boilerplate_svg_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "svg12", "svg", NULL, @@ -632,7 +640,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_svg_get_image_surface, _cairo_boilerplate_svg_surface_write_to_png, _cairo_boilerplate_svg_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, { "svg12", "svg", NULL, @@ -643,7 +651,7 @@ static cairo_boilerplate_target_t targets[] = _cairo_boilerplate_svg_get_image_surface, _cairo_boilerplate_svg_surface_write_to_png, _cairo_boilerplate_svg_cleanup, - NULL, TRUE + NULL, TRUE, TRUE }, #endif #if CAIRO_HAS_BEOS_SURFACE diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h index 9d12b8dd..19b29572 100644 --- a/boilerplate/cairo-boilerplate.h +++ b/boilerplate/cairo-boilerplate.h @@ -162,6 +162,7 @@ typedef struct _cairo_boilerplate_target cairo_boilerplate_cleanup_t cleanup; cairo_boilerplate_wait_t synchronize; cairo_bool_t is_vector; + cairo_bool_t is_meta; } cairo_boilerplate_target_t; cairo_boilerplate_target_t ** diff --git a/test/cairo-test.c b/test/cairo-test.c index 90ca0af5..24d693dc 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -704,7 +704,9 @@ cairo_test_for_target (cairo_test_context_t *ctx, xasprintf (&diff_path, "%s" CAIRO_TEST_DIFF_SUFFIX, base_path); if (ctx->test->requirements != NULL) { - const char *required = target->is_vector ? "target=raster" : "target=vector"; + const char *required; + + required = target->is_vector ? "target=raster" : "target=vector"; if (strstr (ctx->test->requirements, required) != NULL) { cairo_test_log (ctx, "Error: Skipping for %s target %s\n", target->is_vector ? "vector" : "raster", @@ -712,6 +714,15 @@ cairo_test_for_target (cairo_test_context_t *ctx, ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } + + required = target->is_meta ? "target=!meta" : "target=meta"; + if (strstr (ctx->test->requirements, required) != NULL) { + cairo_test_log (ctx, "Error: Skipping for %s target %s\n", + target->is_meta ? "meta" : "non-meta", + target->name); + ret = CAIRO_TEST_UNTESTED; + goto UNWIND_STRINGS; + } } width = ctx->test->width; -- cgit v1.2.3 From 432fe1ec2792153ec2559ef52aece3fcdc9c5df4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 15:30:23 +0000 Subject: [trace] Mark filter mode as immediate. Be consistent and use "//" for the filter mode to indicate a constant. --- util/cairo-trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index b958e759..b79f7dfc 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -2751,7 +2751,7 @@ _filter_to_string (cairo_filter_t filter) void cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) { - _emit_pattern_op (pattern, "%s set_filter\n", _filter_to_string (filter)); + _emit_pattern_op (pattern, "//%s set_filter\n", _filter_to_string (filter)); return DLCALL (cairo_pattern_set_filter, pattern, filter); } -- cgit v1.2.3 From 4a4b10271a614ee9bf982994b8f9ec6b6102ee10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 00:02:09 +0000 Subject: [trace] Capture foreign drawables. If we attempt to use a surface as a source before we write to it, record the surface contents. --- util/cairo-trace/trace.c | 102 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 9 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index b79f7dfc..c16efc69 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -107,6 +107,8 @@ struct _object { const void *addr; Type *type; unsigned long int token; + int width, height; + bool foreign; bool defined; int operand; void *data; @@ -333,6 +335,7 @@ _object_create (Type *type, const void *ptr) obj = malloc (sizeof (Object)); obj->defined = false; + obj->foreign = false; obj->operand = -1; obj->type = type; obj->addr = ptr; @@ -1214,6 +1217,7 @@ cairo_create (cairo_surface_t *target) if (target != NULL && _write_lock ()) { surface_id = _get_surface_id (target); + _get_object (SURFACE, target)->foreign = false; /* we presume that we will continue to use the context */ if (_pop_operands_to (SURFACE, target)){ @@ -1335,6 +1339,40 @@ cairo_set_source_rgba (cairo_t *cr, double red, double green, double blue, doubl return DLCALL (cairo_set_source_rgba, cr, red, green, blue, alpha); } +static void +_emit_source_image (cairo_surface_t *surface) +{ + Object *obj; + cairo_surface_t *image; + cairo_t *cr; + + obj = _get_object (SURFACE, surface); + + image = DLCALL (cairo_image_surface_create, + CAIRO_FORMAT_ARGB32, + obj->width, + obj->height); + cr = DLCALL (cairo_create, image); + DLCALL (cairo_set_source_surface, cr, surface, 0, 0); + DLCALL (cairo_paint, cr); + DLCALL (cairo_destroy, cr); + + fprintf (logfile, + "dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //ARGB32 set\n" + " /source ", + obj->width, obj->height); + _emit_image (image); + fprintf (logfile, + " /deflate filter set\n" + " image set_source_image "); + DLCALL (cairo_surface_destroy, image); + + _get_object (SURFACE, surface)->foreign = false; +} + void cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y) { @@ -1355,6 +1393,9 @@ cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, doubl fprintf (logfile, "s%ld ", _get_surface_id (surface)); } + if (_get_object (SURFACE, surface)->foreign) + _emit_source_image (surface); + fprintf (logfile, "pattern"); if (x != 0. || y != 0.) fprintf (logfile, " %g %g translate", -x, -y); @@ -2078,7 +2119,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, { cairo_scaled_font_t *ret; long scaled_font_id; - long font_face_id; ret = DLCALL (cairo_scaled_font_create, font_face, font_matrix, ctm, options); scaled_font_id = _create_scaled_font_id (ret); @@ -2395,12 +2435,27 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, "dict\n" " /width %d set\n" " /height %d set\n" - " /format //%s set\n" - " /source ", - width, height, format_str); - _emit_image (ret); + " /format //%s set\n", + width, height, + format_str); + + /* cairo_image_surface_create_for_data() is both used to supply + * foreign pixel data to cairo and in order to read pixels back. + * Defer grabbing the pixel contents until we have to, but only for + * "large" images, for small images the overhead of embedding pixels + * is negligible. + */ + if (width * height < 128) { + fprintf (logfile, " /source "); + _emit_image (ret); + fprintf (logfile, " /deflate filter set\n"); + } else { + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; + _get_object (SURFACE, ret)->foreign = true; + } + fprintf (logfile, - " /deflate filter set\n" " image dup /s%ld exch def\n", surface_id); _get_object (SURFACE, ret)->defined = true; @@ -2650,6 +2705,10 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) } else { fprintf (logfile, "s%ld ", surface_id); } + + if (_get_object (SURFACE, surface)->foreign) + _emit_source_image (surface); + fprintf (logfile, "pattern %% p%ld\n", pattern_id); _push_operand (PATTERN, ret); _write_unlock (); @@ -3238,7 +3297,10 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *c #include cairo_surface_t * -cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int width, int height) +cairo_xlib_surface_create (Display *dpy, + Drawable drawable, + Visual *visual, + int width, int height) { cairo_surface_t *ret; long surface_id; @@ -3251,13 +3313,18 @@ cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int fprintf (logfile, "dict\n" " /type (xlib) set\n" + " /drawable /%lx set\n" " /width %d set\n" " /height %d set\n" " surface dup /s%ld exch def\n", + drawable, width, height, surface_id); _get_object (SURFACE, ret)->defined = true; + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; + _get_object (SURFACE, ret)->foreign = true; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3266,7 +3333,10 @@ cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int } cairo_surface_t * -cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *screen, int width, int height) +cairo_xlib_surface_create_for_bitmap (Display *dpy, + Pixmap bitmap, + Screen *screen, + int width, int height) { cairo_surface_t *ret; long surface_id; @@ -3279,14 +3349,19 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *scree fprintf (logfile, "dict\n" " /type (xlib) set\n" + " /drawable /%lx set\n" " /width %d set\n" " /height %d set\n" " /depth 1 set\n" " surface dup /s%ld exch def\n", + bitmap, width, height, surface_id); _get_object (SURFACE, ret)->defined = true; + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; + _get_object (SURFACE, ret)->foreign = true; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3297,7 +3372,11 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *scree #if CAIRO_HAS_XLIB_XRENDER_SURFACE #include cairo_surface_t * -cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, Screen *screen, XRenderPictFormat *format, int width, int height) +cairo_xlib_surface_create_with_xrender_format (Display *dpy, + Drawable drawable, + Screen *screen, + XRenderPictFormat *format, + int width, int height) { cairo_surface_t *ret; long surface_id; @@ -3310,15 +3389,20 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, fprintf (logfile, "dict\n" " /type (xrender) set\n" + " /drawable /%lx set\n" " /width %d set\n" " /height %d set\n" " /depth %d set\n" " surface dup /s%ld exch def\n", + drawable, width, height, format->depth, surface_id); _get_object (SURFACE, ret)->defined = true; + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; + _get_object (SURFACE, ret)->foreign = true; _push_operand (SURFACE, ret); _write_unlock (); } -- cgit v1.2.3 From d1b8186fd75922e73e62ef8f2ebb011e334ebe36 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 01:16:25 +0000 Subject: [trace] Correct emission of set_font_face and set_source set_font_face was not consuming it's operand but blithely placing an undefined font_face onto the operand stack, whereas set_source was performing invalid exchanges on the stack. --- util/cairo-trace/trace.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index c16efc69..c12820e9 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -1423,13 +1423,6 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source) _exch_operands (); _consume_operand (); } - else if (_is_current (PATTERN, source, 0)) - { - _emit_context (cr); - fprintf (logfile, "exch "); - _exch_operands (); - _consume_operand (); - } else { _emit_context (cr); @@ -1938,8 +1931,33 @@ cairo_get_font_face (cairo_t *cr) void cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face) { - _emit_cairo_op (cr, "f%ld set_font_face\n", - _get_font_face_id (font_face)); + if (cr != NULL && font_face != NULL) { + if (_pop_operands_to (FONT_FACE, font_face)) { + if (_is_current (CONTEXT, cr, 1)) { + if (_write_lock ()) { + _consume_operand (); + fprintf (logfile, "set_font_face\n"); + _write_unlock (); + } + } else { + if (_get_object (CONTEXT, cr)->defined) { + if (_write_lock ()) { + _consume_operand (); + fprintf (logfile, + "c%ld exch set_font_face pop\n", + _get_context_id (cr)); + _write_unlock (); + } + } else { + _emit_cairo_op (cr, "f%ld set_font_face\n", + _get_font_face_id (font_face)); + } + } + } else { + _emit_cairo_op (cr, "f%ld set_font_face\n", + _get_font_face_id (font_face)); + } + } return DLCALL (cairo_set_font_face, cr, font_face); } -- cgit v1.2.3 From c95eebc92316ad50840fab1cec6c14b6c3e50fa5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 09:56:02 +0000 Subject: [pattern] Split the translation between the matrix and [xy]_offset pixman limits the src] co-ordinates (and thus [xy]_offset] to 16bits, so we need to be careful how much of the translation vector to push into [xy]_offset. Since the range is the same for both, split the integer component between the matrix and the offset. test/scale-offset* now at least shows the source image, even if it is misplaced. --- src/cairo-pattern.c | 7 +++++-- test/scale-offset-image.ps.ref.png | Bin 7445 -> 7289 bytes test/scale-offset-image.ref.png | Bin 10005 -> 9953 bytes test/scale-offset-similar.ps.ref.png | Bin 7819 -> 7860 bytes test/scale-offset-similar.ref.png | Bin 10005 -> 9953 bytes 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 5a6bf6c9..9d476cde 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -2000,8 +2000,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); diff --git a/test/scale-offset-image.ps.ref.png b/test/scale-offset-image.ps.ref.png index b87612aa..1aed28d3 100644 Binary files a/test/scale-offset-image.ps.ref.png and b/test/scale-offset-image.ps.ref.png differ diff --git a/test/scale-offset-image.ref.png b/test/scale-offset-image.ref.png index 325bdf43..8c6b0fe2 100644 Binary files a/test/scale-offset-image.ref.png and b/test/scale-offset-image.ref.png differ diff --git a/test/scale-offset-similar.ps.ref.png b/test/scale-offset-similar.ps.ref.png index a60e9ad4..7002b2ef 100644 Binary files a/test/scale-offset-similar.ps.ref.png and b/test/scale-offset-similar.ps.ref.png differ diff --git a/test/scale-offset-similar.ref.png b/test/scale-offset-similar.ref.png index 325bdf43..8c6b0fe2 100644 Binary files a/test/scale-offset-similar.ref.png and b/test/scale-offset-similar.ref.png differ -- cgit v1.2.3 From e811173311ebe76d47eebcf5c6c5c798f9d3ea72 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 10:59:15 +0000 Subject: [matrix] Compensate pixman_matrix in device space. We wish to reduce the visible error when converting to a pixman matrix, so perform the compensation in device space instead of pattern space. --- src/cairo-image-surface.c | 4 ++-- src/cairo-matrix.c | 53 ++++++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index f84cf7fb..0efdb7a9 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -1159,8 +1159,8 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, goto finish; status = _cairo_image_surface_set_attributes (src, &attributes, - src_x + width / 2., - src_y + height / 2.); + dst_x + width / 2., + dst_y + height / 2.); if (status) goto CLEANUP_SOURCE; diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index 555c4fee..0c7f305a 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -879,8 +879,6 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, *pixman_transform = pixman_identity_transform; } else { cairo_matrix_t inv; - double x,y; - pixman_vector_t vector; 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); @@ -913,24 +911,37 @@ _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 (xc, yc) */ - x = xc, y = yc; - 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 (xc, yc). We can now compensate - * for the resulting error */ - pixman_transform->matrix[0][2] += - _cairo_fixed_16_16_from_double (xc) - vector.vector[0]; - pixman_transform->matrix[1][2] += - _cairo_fixed_16_16_from_double (yc) - vector.vector[1]; + /* find the pattern space coordinate that maps to (xc, yc) */ + xc += .5; yc += .5; /* offset for the pixel centre */ + 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) [offset for pixel + * centre]. We can now compensate for the resulting error. + */ + x -= xc; x += .5; + y -= yc; y += .5; + 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 (TRUE); } } -- cgit v1.2.3 From 29621bd3995c5269fd6f73ab501383433bd29768 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 12:16:47 +0000 Subject: [matrix] Remove stray offset from previous commit. I moved the pixel centre to xc,yc but forgot to remove it during compensation - as caught by the test suite. Refresh a couple of reference images that depend upon exact pixel-centre rounding conditions. --- src/cairo-matrix.c | 8 ++++---- test/rotate-image-surface-paint.ref.png | Bin 232 -> 190 bytes test/surface-pattern.pdf.ref.png | Bin 14776 -> 14791 bytes test/surface-pattern.ref.png | Bin 11044 -> 11100 bytes test/surface-pattern.svg.ref.png | Bin 16151 -> 16069 bytes 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index 0c7f305a..05589833 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -929,11 +929,11 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, y = pixman_fixed_to_double (vector.vector[1]); cairo_matrix_transform_point (&inv, &x, &y); - /* Ideally, the vector should now be (xc, yc) [offset for pixel - * centre]. We can now compensate for the resulting error. + /* Ideally, the vector should now be (xc, yc). + * We can now compensate for the resulting error. */ - x -= xc; x += .5; - y -= yc; y += .5; + 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); diff --git a/test/rotate-image-surface-paint.ref.png b/test/rotate-image-surface-paint.ref.png index bd20481f..5c98d7d8 100644 Binary files a/test/rotate-image-surface-paint.ref.png and b/test/rotate-image-surface-paint.ref.png differ diff --git a/test/surface-pattern.pdf.ref.png b/test/surface-pattern.pdf.ref.png index c37e2a4f..ff9131c2 100644 Binary files a/test/surface-pattern.pdf.ref.png and b/test/surface-pattern.pdf.ref.png differ diff --git a/test/surface-pattern.ref.png b/test/surface-pattern.ref.png index 9cdf6a54..db60da6f 100644 Binary files a/test/surface-pattern.ref.png and b/test/surface-pattern.ref.png differ diff --git a/test/surface-pattern.svg.ref.png b/test/surface-pattern.svg.ref.png index 2078fc0e..cdbcf476 100644 Binary files a/test/surface-pattern.svg.ref.png and b/test/surface-pattern.svg.ref.png differ -- cgit v1.2.3 From 248dd97075b50cd91619022098ed5dd35a66b5df Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 6 Nov 2008 00:17:53 +1030 Subject: win32-printing: Implement JPEG support --- src/cairo-win32-printing-surface.c | 91 ++++++++++++++++++++++++++++++++++---- src/cairo-win32-private.h | 3 ++ 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 94bbc28a..34b31c7d 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-jpeg-info-private.h" #include @@ -75,6 +76,10 @@ # define GRADIENT_FILL_RECT_H 0x00 #endif +#if !defined(CHECKJPEGFORMAT) +# define CHECKJPEGFORMAT 0x1017 +#endif + #define PELS_72DPI ((LONG)(72. / 0.0254)) static const cairo_surface_backend_t cairo_win32_printing_surface_backend; @@ -99,6 +104,16 @@ _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; +} + static cairo_int_status_t analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern) { @@ -486,6 +501,48 @@ _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 **jpeg_data, + unsigned int *jpeg_length, + int *jpeg_width, + int *jpeg_height) +{ + const unsigned char *mime_data; + unsigned int mime_data_length; + cairo_jpeg_info_t info; + 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_jpeg_get_info (mime_data, mime_data_length, &info); + 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; + + *jpeg_data = mime_data; + *jpeg_length = mime_data_length; + *jpeg_width = info.width; + *jpeg_height = info.height; + + 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 +560,10 @@ _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 *jpeg_data; + unsigned int jpeg_size; + int jpeg_width, jpeg_height; + cairo_bool_t use_jpeg; /* If we can't use StretchDIBits with this surface, we can't do anything * here. @@ -532,7 +593,18 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf goto CLEANUP_IMAGE; } - if (image->format != CAIRO_FORMAT_RGB24) { + status = _cairo_win32_printing_surface_check_jpeg (surface, + pattern->surface, + &jpeg_data, + &jpeg_size, + &jpeg_width, + &jpeg_height); + if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + use_jpeg = (status == CAIRO_STATUS_SUCCESS); + + if (!use_jpeg && image->format != CAIRO_FORMAT_RGB24) { cairo_surface_pattern_t opaque_pattern; opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, @@ -577,14 +649,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_jpeg ? jpeg_width : opaque_image->width; + bi.bmiHeader.biHeight = use_jpeg ? - jpeg_height : -opaque_image->height; + bi.bmiHeader.biSizeImage = use_jpeg ? jpeg_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_jpeg ? BI_JPEG : BI_RGB; bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrImportant = 0; @@ -626,9 +698,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_jpeg ? jpeg_width : opaque_image->width, + use_jpeg ? jpeg_height : opaque_image->height, + use_jpeg ? jpeg_data : opaque_image->data, &bi, DIB_RGB_COLORS, SRCCOPY)) @@ -1594,6 +1666,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); diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h index 6f15408a..7b07a864 100644 --- a/src/cairo-win32-private.h +++ b/src/cairo-win32-private.h @@ -117,6 +117,9 @@ 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), }; cairo_status_t -- cgit v1.2.3 From 2261590875b4be7aa258c51e766f68974750e9e7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 15:11:32 +0000 Subject: [trace] Trim a few bytes from glyph arrays Remove some redundant whitespace from the glyph arrays to improve readability and shrink the output file size. --- util/cairo-trace/trace.c | 65 ++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index c12820e9..2ca184f0 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -2206,7 +2206,10 @@ _emit_glyphs (cairo_scaled_font_t *font, x = glyphs->x; y = glyphs->y; if (n < num_glyphs) { /* need full glyph range */ - fprintf (logfile, "[ %g %g [", x, y); + bool first; + + fprintf (logfile, "[%g %g [", x, y); + first = true; while (num_glyphs--) { cairo_text_extents_t extents; @@ -2215,10 +2218,14 @@ _emit_glyphs (cairo_scaled_font_t *font, { x = glyphs->x; y = glyphs->y; - fprintf (logfile, " ] %g %g [", x, y); + fprintf (logfile, "] %g %g [", x, y); + first = true; } - fprintf (logfile, " %lu", glyphs->index); + if (! first) + fprintf (logfile, " "); + fprintf (logfile, "%lu", glyphs->index); + first = false; cairo_scaled_font_glyph_extents (font, glyphs, 1, &extents); x += extents.x_advance; @@ -2226,37 +2233,41 @@ _emit_glyphs (cairo_scaled_font_t *font, glyphs++; } - fprintf (logfile, " ] ]"); + fprintf (logfile, "]]"); } else { struct _data_stream stream; - fprintf (logfile, "[ %g %g <~", x, y); - _write_base85_data_start (&stream); - while (num_glyphs--) { - cairo_text_extents_t extents; - unsigned char c; - - if (fabs (glyphs->x - x) > TOLERANCE || - fabs (glyphs->y - y) > TOLERANCE) - { - x = glyphs->x; - y = glyphs->y; - _write_base85_data_end (&stream); - fprintf (logfile, "~> %g %g <~", x, y); - _write_base85_data_start (&stream); - } + if (num_glyphs == 1) { + fprintf (logfile, "[%g %g <%x>]", x, y, glyphs->index); + } else { + fprintf (logfile, "[%g %g <~", x, y); + _write_base85_data_start (&stream); + while (num_glyphs--) { + cairo_text_extents_t extents; + unsigned char c; + + if (fabs (glyphs->x - x) > TOLERANCE || + fabs (glyphs->y - y) > TOLERANCE) + { + x = glyphs->x; + y = glyphs->y; + _write_base85_data_end (&stream); + fprintf (logfile, "~> %g %g <~", x, y); + _write_base85_data_start (&stream); + } - c = glyphs->index; - _write_base85_data (&stream, &c, 1); + c = glyphs->index; + _write_base85_data (&stream, &c, 1); - cairo_scaled_font_glyph_extents (font, glyphs, 1, &extents); - x += extents.x_advance; - y += extents.y_advance; + cairo_scaled_font_glyph_extents (font, glyphs, 1, &extents); + x += extents.x_advance; + y += extents.y_advance; - glyphs++; + glyphs++; + } + _write_base85_data_end (&stream); + fprintf (logfile, "~>]"); } - _write_base85_data_end (&stream); - fprintf (logfile, "~> ]"); } } -- cgit v1.2.3 From 199c0e71139fe9baf83e74ea69c01629ace5f9a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 15:12:19 +0000 Subject: [svg] Embed jpeg data. Support jpeg embedding for svg output. --- src/cairo-svg-surface.c | 50 +++++++++++++++++++++++++++++++++++++++++++++---- test/Makefile.am | 1 + 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 039cc39c..8c232423 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-jpeg-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; @@ -975,13 +976,55 @@ base64_write_func (void *closure, return _cairo_output_stream_get_status (info->output); } +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_jpeg_info_t jpeg_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_jpeg_get_info (mime_data, mime_data_length, &jpeg_info); + if (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 (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; info.output = output; info.in_mem = 0; @@ -996,8 +1039,7 @@ _cairo_surface_base64_encode (cairo_surface_t *surface, 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); diff --git a/test/Makefile.am b/test/Makefile.am index db1acf19..d9d4d398 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -701,6 +701,7 @@ REFERENCE_IMAGES = \ mime-data.ref.png \ mime-data.ps.ref.png \ mime-data.pdf.ref.png \ + mime-data.svg.ref.png \ miter-precision.ref.png \ miter-precision.ps2.ref.png \ miter-precision.ps3.ref.png \ -- cgit v1.2.3 From 43cfaec39cc742ddfbf566b36391d620400e10be Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 5 Nov 2008 11:50:20 -0500 Subject: Define RepeatNone, etc if the available Render version doesn't (#18385) --- src/cairo-xlib-xrender-private.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 #include +/* 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 -- cgit v1.2.3 From a1ab11df01962bea5752f5a5b53926a26a6f34ae Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 5 Nov 2008 11:50:20 -0500 Subject: Define RepeatNone, etc if the available Render version doesn't (#18385) --- src/cairo-xlib-xrender-private.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 #include +/* 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 -- cgit v1.2.3 From 89616dee8f11c6a7de3fa476b13661420648786f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 16:41:13 +0000 Subject: [surface] Don't allocate a structure for mime_data == NULL. If the user attempts to clear the attached mime data representation, just clear the user data slot and do not allocate an empty structure. --- src/cairo-surface.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 72997b08..9df75ca4 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -682,15 +682,18 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, if (status) return _cairo_surface_set_error (surface, status); - mime_data = malloc (sizeof (cairo_mime_data_t)); - if (mime_data == NULL) - return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + if (data != NULL) { + mime_data = malloc (sizeof (cairo_mime_data_t)); + if (mime_data == NULL) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY)); - CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1); + 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->data = (unsigned char *) data; + mime_data->length = length; + mime_data->destroy = destroy; + } else + mime_data = NULL; status = _cairo_user_data_array_set_data (&surface->user_data, (cairo_user_data_key_t *) mime_type, -- cgit v1.2.3 From e40d62a0fe96b8b937017a3bc2f18766c411ec41 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 16:38:34 +0000 Subject: [png] Attach the png representation to cairo_surface_create_from_png(). Attach the original png data as an alternate representation for image surfaces created by cairo_surface_create_from_png(). --- src/cairo-output-stream-private.h | 5 ++ src/cairo-output-stream.c | 28 ++++++++- src/cairo-png.c | 127 +++++++++++++++++++++++--------------- src/cairo-surface-fallback.c | 20 +++--- src/cairo.h | 1 + 5 files changed, 122 insertions(+), 59 deletions(-) diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h index 787d0616..6f10483f 100644 --- a/src/cairo-output-stream-private.h +++ b/src/cairo-output-stream-private.h @@ -161,6 +161,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..c31c2da5 100644 --- a/src/cairo-output-stream.c +++ b/src/cairo-output-stream.c @@ -656,6 +656,32 @@ _cairo_memory_stream_create (void) 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 (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 (*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 +696,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)); } diff --git a/src/cairo-png.c b/src/cairo-png.c index 4721825e..b4aeb081 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 #include #include +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) @@ -436,9 +445,43 @@ 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) +{ + while (size) { + size_t ret; + + ret = fread (data, 1, size, closure); + size -= ret; + data += ret; + + if (size && (feof (closure) || ferror (closure))) + 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 (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; @@ -450,6 +493,8 @@ 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; /* XXX: Perhaps we'll want some other error handlers? */ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, @@ -467,7 +512,8 @@ read_png (png_rw_ptr read_func, goto BAIL; } - png_set_read_fn (png, closure, read_func); + png_closure->png_data = _cairo_memory_stream_create (); + png_set_read_fn (png, png_closure, stream_read_func); status = CAIRO_STATUS_SUCCESS; #ifdef PNG_SETJMP_SUPPORTED @@ -589,6 +635,27 @@ 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 (status) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + + status = cairo_surface_set_mime_data (surface, + CAIRO_MIME_TYPE_PNG, + mime_data, + mime_data_length, + free); + if (status) { + free (mime_data); + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + BAIL: if (row_pointers) free (row_pointers); @@ -600,25 +667,6 @@ read_png (png_rw_ptr read_func, 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); - } - } -} - /** * cairo_image_surface_create_from_png: * @filename: name of PNG file to load @@ -638,11 +686,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: @@ -658,32 +706,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; -}; + fclose (png_closure.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; - - 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; } /** @@ -707,5 +736,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-surface-fallback.c b/src/cairo-surface-fallback.c index f8f89025..bb29a9f0 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -1036,6 +1036,11 @@ _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, + NULL + }, **mime_type; status = _cairo_surface_acquire_source_image (surface, &image, &image_extra); @@ -1075,15 +1080,12 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) snapshot->device_transform = surface->device_transform; snapshot->device_transform_inverse = surface->device_transform_inverse; - /* XXX Need to copy all known image representations... - * For now, just copy "image/jpeg", but in future we should construct - * an array of known types and iterate. - */ - status = _cairo_surface_copy_mime_data (snapshot, surface, - CAIRO_MIME_TYPE_JPEG); - if (status) { - cairo_surface_destroy (snapshot); - return _cairo_surface_create_in_error (status); + for (mime_type = mime_types; *mime_type; mime_type++) { + status = _cairo_surface_copy_mime_data (snapshot, surface, *mime_type); + if (status) { + cairo_surface_destroy (snapshot); + return _cairo_surface_create_in_error (status); + } } snapshot->is_snapshot = TRUE; diff --git a/src/cairo.h b/src/cairo.h index a1cd0c55..cbc109f3 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1948,6 +1948,7 @@ cairo_surface_set_user_data (cairo_surface_t *surface, cairo_destroy_func_t destroy); #define CAIRO_MIME_TYPE_JPEG "image/jpeg" +#define CAIRO_MIME_TYPE_PNG "image/png" cairo_public void cairo_surface_get_mime_data (cairo_surface_t *surface, -- cgit v1.2.3 From e4ec5c762f6d01cc5af28dc0a256e268a04101aa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 16:44:49 +0000 Subject: [svg] Embed original PNG data. Embed the attached PNG representation of a surface in preference to re-encoding the surface. --- src/cairo-svg-surface.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 8c232423..cfc56c43 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -1015,6 +1015,40 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, 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 (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) @@ -1026,6 +1060,10 @@ _cairo_surface_base64_encode (cairo_surface_t *surface, 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; info.trailing = 0; -- cgit v1.2.3 From d63267e4e7e148836dcfc4c8e2a8396ddaab70d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 17:18:51 +0000 Subject: [test] Update mime-data to check image/png Add a "image/png" mime-type test. --- test/Makefile.am | 1 + test/mime-data.c | 67 +++++++++++++++++++++++++++++---------------- test/mime-data.pdf.ref.png | Bin 4345 -> 4466 bytes test/mime-data.ps.ref.png | Bin 4345 -> 4466 bytes test/mime-data.ref.png | Bin 127 -> 155 bytes test/mime-data.svg.ref.png | Bin 0 -> 6153 bytes test/png.png | Bin 0 -> 2096 bytes 7 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 test/mime-data.svg.ref.png create mode 100644 test/png.png diff --git a/test/Makefile.am b/test/Makefile.am index d9d4d398..131ed603 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1012,6 +1012,7 @@ EXTRA_DIST += \ 6x13.pcf \ make-html.pl \ jpeg.jpg \ +png.png \ romedalen.jpg \ romedalen.png \ scarab.jpg \ diff --git a/test/mime-data.c b/test/mime-data.c index a387d672..87fe74c8 100644 --- a/test/mime-data.c +++ b/test/mime-data.c @@ -31,27 +31,23 @@ /* Basic test to exercise the new mime-data embedding. */ static cairo_status_t -read_jpg_file (const cairo_test_context_t *ctx, - unsigned char **data_out, - unsigned int *length_out) +read_file (const cairo_test_context_t *ctx, + const char *filename, + unsigned char **data_out, + unsigned int *length_out) { - /* Deliberately use a non-matching jpeg image, so that we can identify - * when the JPEG representation is used in preference to the image - * surface. - */ - const char jpg_filename[] = "jpeg.jpg"; FILE *file; unsigned char *buf; unsigned int len; - file = fopen (jpg_filename, "rb"); + file = fopen (filename, "rb"); if (file == NULL) { - char filename[4096]; + char path[4096]; /* try again with srcdir */ - snprintf (filename, sizeof (filename), - "%s/%s", ctx->srcdir, jpg_filename); - file = fopen (filename, "rb"); + snprintf (path, sizeof (path), + "%s/%s", ctx->srcdir, filename); + file = fopen (path, "rb"); } if (file == NULL) { switch (errno) { @@ -79,37 +75,62 @@ read_jpg_file (const cairo_test_context_t *ctx, } static cairo_test_status_t -draw (cairo_t *cr, int width, int height) +paint_file (cairo_t *cr, + const char *filename, const char *mime_type, + int x, int y) { const cairo_test_context_t *ctx = cairo_test_get_context (cr); cairo_surface_t *image; - unsigned char *jpg_data; - unsigned int jpg_len; + unsigned char *mime_data; + unsigned int mime_length; cairo_status_t status; - status = read_jpg_file (ctx, &jpg_data, &jpg_len); - if (status) { + /* Deliberately use a non-matching MIME images, so that we can identify + * when the MIME representation is used in preference to the plain image + * surface. + */ + status = read_file (ctx, filename, &mime_data, &mime_length); + if (status) return cairo_test_status_from_status (ctx, status); - } image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50); - status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG, - jpg_data, jpg_len, free); + + status = cairo_surface_set_mime_data (image, mime_type, + mime_data, mime_length, free); if (status) { cairo_surface_destroy (image); return cairo_test_status_from_status (ctx, status); } - cairo_set_source_surface (cr, image, 0, 0); + cairo_set_source_surface (cr, image, x, y); cairo_surface_destroy (image); + cairo_paint (cr); return CAIRO_TEST_SUCCESS; } +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const char jpg_filename[] = "jpeg.jpg"; + const char png_filename[] = "png.png"; + cairo_test_status_t status; + + status = paint_file (cr, jpg_filename, CAIRO_MIME_TYPE_JPEG, 0, 0); + if (status) + return status; + + status = paint_file (cr, png_filename, CAIRO_MIME_TYPE_PNG, 0, 50); + if (status) + return status; + + return CAIRO_TEST_SUCCESS; +} + CAIRO_TEST (mime_data, "Check that the mime-data embedding works", "jpeg, api", /* keywords */ NULL, /* requirements */ - 200, 50, + 200, 100, NULL, draw) diff --git a/test/mime-data.pdf.ref.png b/test/mime-data.pdf.ref.png index cf53a610..ebfcb790 100644 Binary files a/test/mime-data.pdf.ref.png and b/test/mime-data.pdf.ref.png differ diff --git a/test/mime-data.ps.ref.png b/test/mime-data.ps.ref.png index cf53a610..ebfcb790 100644 Binary files a/test/mime-data.ps.ref.png and b/test/mime-data.ps.ref.png differ diff --git a/test/mime-data.ref.png b/test/mime-data.ref.png index 782a2eef..ccbf1b63 100644 Binary files a/test/mime-data.ref.png and b/test/mime-data.ref.png differ diff --git a/test/mime-data.svg.ref.png b/test/mime-data.svg.ref.png new file mode 100644 index 00000000..96a7bec4 Binary files /dev/null and b/test/mime-data.svg.ref.png differ diff --git a/test/png.png b/test/png.png new file mode 100644 index 00000000..56c428e1 Binary files /dev/null and b/test/png.png differ -- cgit v1.2.3 From ec559822cfe6df0006ca2db2aa3a11699326865c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 18:11:36 +0000 Subject: [trace] Use the mime-type image representation When emitting image data, first check to see if we have a pre-compressed alternate representation. --- util/cairo-trace/trace.c | 303 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 214 insertions(+), 89 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 2ca184f0..df2ec5c9 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -989,8 +989,62 @@ _emit_data (const void *data, unsigned int length) _write_data_end (&stream); } -static void -_emit_image (cairo_surface_t *image) +static const char * +_format_to_string (cairo_format_t format) +{ + const char *names[] = { + "ARGB32", /* CAIRO_FORMAT_ARGB32 */ + "RGB24", /* CAIRO_FORMAT_RGB24 */ + "A8", /* CAIRO_FORMAT_A8 */ + "A1" /* CAIRO_FORMAT_A1 */ + }; + return names[format]; +} + +static const char * +_status_to_string (cairo_status_t status) +{ + const char *names[] = { + "STATUS_SUCCESS", + "STATUS_NO_MEMORY", + "STATUS_INVALID_RESTORE", + "STATUS_INVALID_POP_GROUP", + "STATUS_NO_CURRENT_POINT", + "STATUS_INVALID_MATRIX", + "STATUS_INVALID_STATUS", + "STATUS_NULL_POINTER", + "STATUS_INVALID_STRING", + "STATUS_INVALID_PATH_DATA", + "STATUS_READ_ERROR", + "STATUS_WRITE_ERROR", + "STATUS_SURFACE_FINISHED", + "STATUS_SURFACE_TYPE_MISMATCH", + "STATUS_PATTERN_TYPE_MISMATCH", + "STATUS_INVALID_CONTENT", + "STATUS_INVALID_FORMAT", + "STATUS_INVALID_VISUAL", + "STATUS_FILE_NOT_FOUND", + "STATUS_INVALID_DASH", + "STATUS_INVALID_DSC_COMMENT", + "STATUS_INVALID_INDEX", + "STATUS_CLIP_NOT_REPRESENTABLE", + "STATUS_TEMP_FILE_ERROR", + "STATUS_INVALID_STRIDE", + "STATUS_FONT_TYPE_MISMATCH", + "STATUS_USER_FONT_IMMUTABLE", + "STATUS_USER_FONT_ERROR", + "STATUS_NEGATIVE_COUNT", + "STATUS_INVALID_CLUSTERS", + "STATUS_INVALID_SLANT", + "STATUS_INVALID_WEIGHT" + }; + return names[status]; +} + +static void CAIRO_PRINTF_FORMAT(2, 3) +_emit_image (cairo_surface_t *image, + const char *info, + ...) { int stride, row, width, height; cairo_format_t format; @@ -998,6 +1052,20 @@ _emit_image (cairo_surface_t *image) uint8_t *rowdata; uint8_t *data; struct _data_stream stream; + const char *mime_types[] = { + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_PNG, + NULL + }, **mime_type; + + if (cairo_surface_status (image)) { + fprintf (logfile, + "dict\n" + " /status //%s set\n" + " image", + _status_to_string (cairo_surface_status (image))); + return; + } width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); @@ -1005,6 +1073,43 @@ _emit_image (cairo_surface_t *image) format = cairo_image_surface_get_format (image); data = cairo_image_surface_get_data (image); + fprintf (logfile, + "dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //%s set\n", + width, height, + _format_to_string (format)); + if (info != NULL) { + va_list ap; + + va_start (ap, info); + vfprintf (logfile, info, ap); + va_end (ap); + } + + for (mime_type = mime_types; *mime_type; mime_type++) { + const unsigned char *mime_data; + unsigned int mime_length; + + cairo_surface_get_mime_data (image, *mime_type, + &mime_data, &mime_length); + if (mime_data != NULL) { + fprintf (logfile, + " /mime-type (%s) set\n" + " /source <~", + *mime_type); + _write_base85_data_start (&stream); + _write_base85_data (&stream, mime_data, mime_length); + _write_base85_data_end (&stream); + fprintf (logfile, + "~> set\n" + " image"); + return; + } + } + + fprintf (logfile, " /source "); _write_data_start (&stream); #ifdef WORDS_BIGENDIAN @@ -1039,16 +1144,13 @@ _emit_image (cairo_surface_t *image) } break; default: - _write_data_end (&stream); - return; + break; } #else if (stride > ARRAY_LENGTH (row_stack)) { rowdata = malloc (stride); - if (rowdata == NULL) { - _write_data_end (&stream); - return; - } + if (rowdata == NULL) + goto BAIL; } else rowdata = row_stack; @@ -1099,8 +1201,87 @@ _emit_image (cairo_surface_t *image) if (rowdata != row_stack) free (rowdata); +BAIL: _write_data_end (&stream); #endif + fprintf (logfile, + " /deflate filter set\n" + " image"); +} + +static void +_encode_string_literal (char *out, int max, + const char *utf8, int len) +{ + char c; + const char *end; + + *out++ = '('; + max--; + + if (utf8 == NULL) + goto DONE; + + if (len < 0) + len = strlen (utf8); + end = utf8 + len; + + while (utf8 < end) { + if (max < 5) + break; + + switch ((c = *utf8++)) { + case '\n': + *out++ = '\\'; + *out++ = 'n'; + max -= 2; + break; + case '\r': + *out++ = '\\'; + *out++ = 'n'; + max -= 2; + case '\t': + *out++ = '\\'; + *out++ = 't'; + max -= 2; + break; + case '\b': + *out++ = '\\'; + *out++ = 'b'; + max -= 2; + break; + case '\f': + *out++ = '\\'; + *out++ = 'r'; + max -= 2; + break; + case '\\': + case '(': + case ')': + *out++ = '\\'; + *out++ = c; + max -= 2; + break; + default: + if (isprint (c) || isspace (c)) { + *out++ = c; + } else { + int octal = 0; + while (c) { + octal *= 10; + octal += c&7; + c /= 8; + } + octal = snprintf (out, max, "\\%03d", octal); + out += octal; + max -= octal; + } + break; + } + } +DONE: + *out++ = ')'; + *out = '\0'; } static void @@ -1357,17 +1538,9 @@ _emit_source_image (cairo_surface_t *surface) DLCALL (cairo_paint, cr); DLCALL (cairo_destroy, cr); + _emit_image (image, NULL); fprintf (logfile, - "dict\n" - " /width %d set\n" - " /height %d set\n" - " /format //ARGB32 set\n" - " /source ", - obj->width, obj->height); - _emit_image (image); - fprintf (logfile, - " /deflate filter set\n" - " image set_source_image "); + " set_source_image "); DLCALL (cairo_surface_destroy, image); _get_object (SURFACE, surface)->foreign = false; @@ -2238,7 +2411,7 @@ _emit_glyphs (cairo_scaled_font_t *font, struct _data_stream stream; if (num_glyphs == 1) { - fprintf (logfile, "[%g %g <%x>]", x, y, glyphs->index); + fprintf (logfile, "[%g %g <%lx>]", x, y, glyphs->index); } else { fprintf (logfile, "[%g %g <~", x, y); _write_base85_data_start (&stream); @@ -2407,18 +2580,6 @@ cairo_append_path (cairo_t *cr, const cairo_path_t *path) } } -static const char * -_format_to_string (cairo_format_t format) -{ - const char *names[] = { - "ARGB32", /* CAIRO_FORMAT_ARGB32 */ - "RGB24", /* CAIRO_FORMAT_RGB24 */ - "A8", /* CAIRO_FORMAT_A8 */ - "A1" /* CAIRO_FORMAT_A1 */ - }; - return names[format]; -} - cairo_surface_t * cairo_image_surface_create (cairo_format_t format, int width, int height) { @@ -2452,22 +2613,11 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, { cairo_surface_t *ret; long surface_id; - const char *format_str; ret = DLCALL (cairo_image_surface_create_for_data, data, format, width, height, stride); surface_id = _create_surface_id (ret); if (data != NULL && _write_lock ()) { - format_str = _format_to_string (format); - - fprintf (logfile, - "dict\n" - " /width %d set\n" - " /height %d set\n" - " /format //%s set\n", - width, height, - format_str); - /* cairo_image_surface_create_for_data() is both used to supply * foreign pixel data to cairo and in order to read pixels back. * Defer grabbing the pixel contents until we have to, but only for @@ -2476,17 +2626,26 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, */ if (width * height < 128) { fprintf (logfile, " /source "); - _emit_image (ret); - fprintf (logfile, " /deflate filter set\n"); + _emit_image (ret, NULL); + fprintf (logfile, + " dup /s%ld exch def\n", + surface_id); } else { + fprintf (logfile, + "dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //%s set\n" + " image dup /s%ld exch def\n", + width, height, + _format_to_string (format), + surface_id); + _get_object (SURFACE, ret)->width = width; _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->foreign = true; } - fprintf (logfile, - " image dup /s%ld exch def\n", - surface_id); _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -3243,37 +3402,20 @@ cairo_surface_t * cairo_image_surface_create_from_png (const char *filename) { cairo_surface_t *ret; - cairo_format_t format; - int width; - int height; long surface_id; - const char *format_str; ret = DLCALL (cairo_image_surface_create_from_png, filename); - width = cairo_image_surface_get_width (ret); - height = cairo_image_surface_get_height (ret); - format = cairo_image_surface_get_format (ret); - surface_id = _create_surface_id (ret); - format_str = _format_to_string (format); if (_write_lock ()) { + char filename_string[4096]; + + _encode_string_literal (filename_string, sizeof (filename_string), + filename, -1); + _emit_image (ret, " /filename %s set\n", filename_string); fprintf (logfile, - "dict\n" - " /width %d set\n" - " /height %d set\n" - " /format //%s set\n" - " /filename ", - width, height, format_str); - _emit_string_literal (filename, -1); - fprintf (logfile, - " set\n" - " /source "); - _emit_image (ret); - fprintf (logfile, - " /deflate filter set\n" - " image dup /s%ld exch def\n", + " dup /s%ld exch def\n", surface_id); _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); @@ -3287,32 +3429,15 @@ cairo_surface_t * cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *closure) { cairo_surface_t *ret; - cairo_format_t format; - int width; - int height; - const char *format_str; long surface_id; ret = DLCALL (cairo_image_surface_create_from_png_stream, read_func, closure); - width = cairo_image_surface_get_width (ret); - height = cairo_image_surface_get_height (ret); - format = cairo_image_surface_get_format (ret); - surface_id = _create_surface_id (ret); - format_str = _format_to_string (format); if (_write_lock ()) { + _emit_image (ret, NULL); fprintf (logfile, - "dict\n" - " /width %d set\n" - " /height %d set\n" - " /format //%s set\n" - " /source ", - width, height, format_str); - _emit_image (ret); - fprintf (logfile, - " /deflate filter set\n" - " image dup /s%ld exch def\n", + " dup /s%ld exch def\n", surface_id); _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); -- cgit v1.2.3 From 564d64a1323c5cbcde2dd9365ac790fe8aa1c5a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 18:47:34 +0000 Subject: [png] Complete the idempotent read_png() -> write_png() Write out the original PNG mime-data if attached to the surface during cairo_surface_write_to_png(). Similar to how the compressed alternate representations are handled by the other backends. Note: by automatically attaching and using the mime-data in preference to the image data, we break the read_from_png(); draw(); write_to_png() cycle. --- src/cairo-png.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/cairo-png.c b/src/cairo-png.c index b4aeb081..a130ba25 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -148,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; @@ -196,6 +198,18 @@ 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; -- cgit v1.2.3 From 34564aa84a4642dceba75efdeef438be6c6896c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 19:27:49 +0000 Subject: [test/pdf2png] Remove dependency on GdkPixbuf It's appears to be dropped from the current poppler trunk, so just use our own venerable cairo_surface_write_ton_png(). --- configure.ac | 2 +- test/pdf2png.c | 32 +++++++++++++++++++------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index 1ed086ec..40fb1d31 100644 --- a/configure.ac +++ b/configure.ac @@ -391,7 +391,7 @@ test_pdf=no any2ppm_pdf=no if test "x$use_pdf" = "xyes"; then poppler_DEPENDENCY="poppler-glib >= $POPPLER_VERSION_REQUIRED" - PKG_CHECK_MODULES(POPPLER, $poppler_DEPENDENCY pango gtk+-2.0, + PKG_CHECK_MODULES(POPPLER, $poppler_DEPENDENCY, [CAIRO_CHECK_FUNCS_WITH_FLAGS(poppler_page_render, [$POPPLER_CFLAGS], [$POPPLER_LIBS], [test_pdf=yes; any2ppm_pdf=yes], [AC_MSG_RESULT(no); test_pdf="no (requires $poppler_DEPENDENCY)"])], diff --git a/test/pdf2png.c b/test/pdf2png.c index 543a996e..8471a186 100644 --- a/test/pdf2png.c +++ b/test/pdf2png.c @@ -36,21 +36,21 @@ int main (int argc, char *argv[]) { PopplerDocument *document; PopplerPage *page; - GdkPixbuf *pixbuf; double width, height; - GError *error; const char *filename = argv[1]; const char *output_filename = argv[2]; const char *page_label = argv[3]; gchar *absolute, *uri; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + GError *error = NULL; if (argc != 4) FAIL ("usage: pdf2png input_file.pdf output_file.png page"); g_type_init (); - error = NULL; - if (g_path_is_absolute(filename)) { absolute = g_strdup (filename); } else { @@ -74,16 +74,22 @@ int main (int argc, char *argv[]) poppler_page_get_size (page, &width, &height); - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, - width * PIXELS_PER_POINT, - height * PIXELS_PER_POINT); - gdk_pixbuf_fill (pixbuf, 0xffffffff); - poppler_page_render_to_pixbuf (page, 0, 0, width , height, - PIXELS_PER_POINT, 0, pixbuf); + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + cr = cairo_create (surface); + cairo_surface_destroy (surface); - gdk_pixbuf_save (pixbuf, output_filename, "png", &error, NULL); - if (error != NULL) - FAIL (error->message); + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + poppler_page_render (page, cr); + g_object_unref (page); + + status = cairo_surface_write_to_png (cairo_get_target (cr), + output_filename); + cairo_destroy (cr); + + if (status) + FAIL (cairo_status_to_string (status)); return 0; } -- cgit v1.2.3 From 476d5daa9bfc5e9014d1b6572853d1d78ce6a6d9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 19:29:04 +0000 Subject: [trace] Only build if we have zlib. Use the configure check for libz and do not attempt to build the trace unless we have zlib. --- configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 40fb1d31..b13f34ff 100644 --- a/configure.ac +++ b/configure.ac @@ -493,7 +493,9 @@ case $host in ;; esac -AM_CONDITIONAL(BUILD_TRACE, test "x$have_ld_preload" = "xyes") +AM_CONDITIONAL(BUILD_TRACE, + test "x$have_ld_preload" = "xyes" \ + -a "x$have_libz" = "xyes") AC_CHECK_LIB(bfd, bfd_openr, [AC_CHECK_HEADER(bfd.h, [have_bfd=yes], -- cgit v1.2.3 From 0ac98461597420d3dfe52e405c6b3322d32f4854 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 6 Nov 2008 00:04:11 +0000 Subject: [test] Add WINDING variants to in-fill test Check cairo_in_fill() with some WINDING tests as well as the current EVEN_ODD. --- test/in-fill-trapezoid.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/in-fill-trapezoid.c b/test/in-fill-trapezoid.c index 6ff2fefb..f38f97da 100644 --- a/test/in-fill-trapezoid.c +++ b/test/in-fill-trapezoid.c @@ -68,6 +68,62 @@ draw (cairo_t *cr, int width, int height) ret = CAIRO_TEST_FAILURE; } + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + + /* simple rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* simple circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside circle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* overlapping circle/rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + cairo_new_sub_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside circle+rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* holey rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + cairo_rectangle (cr, 5, -5, -10, 10); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside rectangular hole\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* holey circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + cairo_arc_negative (cr, 0, 0, 5, 0, -2 * M_PI); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside circular hole\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* not a holey circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + cairo_arc (cr, 0, 0, 5, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside two circles\n"); + ret = CAIRO_TEST_FAILURE; + } + return ret; } -- cgit v1.2.3 From f5965cb7d6559e051c2581fe446d0b9f40427eb2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Nov 2008 23:48:52 +0000 Subject: [in-fill] Avoid tessellation by counting number of edge crossing to -∞ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Benjamin Otte reports that in one particular benchmark cairo_in_fill() is a hotspot in the profile. Currently we tessellate the entire path and then search for a containing trapezoid. This is very expensive compared to the simple method of counting the number of edge crossing between the point of interest and x=-∞. For example, this speeds tessellate-256 up by almost 3 orders of magnitude. --- src/Makefile.sources | 1 + src/cairo-gstate.c | 30 +----- src/cairo-path-in-fill.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++ src/cairoint.h | 9 ++ 4 files changed, 279 insertions(+), 25 deletions(-) create mode 100644 src/cairo-path-in-fill.c diff --git a/src/Makefile.sources b/src/Makefile.sources index 6a0e93b9..0b44bbf2 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -122,6 +122,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 \ diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 5b8c87d7..1d532c71 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1071,33 +1071,13 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, 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; + return _cairo_path_fixed_in_fill (path, + gstate->fill_rule, + gstate->tolerance, + x, y, + inside_ret); } cairo_status_t diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c new file mode 100644 index 00000000..8bfc9d8a --- /dev/null +++ b/src/cairo-path-in-fill.c @@ -0,0 +1,264 @@ +/* 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 + */ + +#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->x, in_fill->y) <= 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; + + if (! in_fill->has_current_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); + + return _cairo_in_fill_move_to (in_fill, point); +} + +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; + cairo_status_t status; + int i; + + /* 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? */ + status = _cairo_spline_init (&spline, &in_fill->current_point, b, c, d); + if (status == CAIRO_INT_STATUS_DEGENERATE) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_spline_decompose (&spline, in_fill->tolerance); + if (status) + goto CLEANUP_SPLINE; + + for (i = 1; i < spline.num_points; i++) + _cairo_in_fill_line_to (in_fill, &spline.points[i]); + + CLEANUP_SPLINE: + _cairo_spline_fini (&spline); + + return status; +} + +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; +} + +cairo_status_t +_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); + if (status) + goto BAIL; + + 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; + } + + status = CAIRO_STATUS_SUCCESS; + +BAIL: + _cairo_in_fill_fini (&in_fill); + return status; +} diff --git a/src/cairoint.h b/src/cairoint.h index 63fefd7a..fb8bf180 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1522,6 +1522,15 @@ cairo_private cairo_bool_t _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, cairo_box_t *box); +/* cairo-path-in-fill.c */ +cairo_private cairo_status_t +_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, -- cgit v1.2.3 From 9dee7af41f4f5a4c1285e9d7951148e78659c064 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 6 Nov 2008 01:02:23 +0000 Subject: [test] Add off-centre tests to in-fill-trapezoid. Reading through the previous commit spotted that the arguments to edge_compare_for_y_against_x were transposed, but the test-suite had failed to catch detect it. This is due that in order to actually solve the equation we need to have a diagonal edge passing near an off-centre point of interest, which was not among the test cases. So add some off-centre tests to fully exercise the code. --- test/in-fill-trapezoid.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/test/in-fill-trapezoid.c b/test/in-fill-trapezoid.c index f38f97da..717a87a0 100644 --- a/test/in-fill-trapezoid.c +++ b/test/in-fill-trapezoid.c @@ -124,6 +124,72 @@ draw (cairo_t *cr, int width, int height) ret = CAIRO_TEST_FAILURE; } + /* check off-centre */ + cairo_new_path (cr); + cairo_arc (cr, 7.5, 0, 10, 0, 2 * M_PI); + cairo_arc_negative (cr, 7.5, 0, 5, 0, -2 * M_PI); + if (cairo_in_fill (cr, 7.5, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside circular hole\n"); + ret = CAIRO_TEST_FAILURE; + } + cairo_new_path (cr); + cairo_arc (cr, 0, 7.5, 10, 0, 2 * M_PI); + cairo_arc_negative (cr, 0, 7.5, 5, 0, -2 * M_PI); + if (cairo_in_fill (cr, 0, 7.5)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside circular hole\n"); + ret = CAIRO_TEST_FAILURE; + } + cairo_new_path (cr); + cairo_arc (cr, 15, 0, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 15, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside circle\n"); + ret = CAIRO_TEST_FAILURE; + } + cairo_new_path (cr); + cairo_arc (cr, 0, 15, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 15)) { + cairo_test_log (ctx, "Error: Failed to find point inside circle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* simple rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, 10, 0, 5, 5); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point outside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (cairo_in_fill (cr, 20, 20)) { + cairo_test_log (ctx, "Error: Found an unexpected point outside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 12.5, 2.5)) { + cairo_test_log (ctx, "Error: Failed to find point inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* off-centre triangle */ + cairo_new_path (cr); + cairo_move_to (cr, 10, 0); + cairo_line_to (cr, 15, 5); + cairo_line_to (cr, 5, 5); + cairo_close_path (cr); + if (cairo_in_fill (cr, 0, 0) || + cairo_in_fill (cr, 10, 10) || + cairo_in_fill (cr, 20, 0) || + cairo_in_fill (cr, 7, 2.5) || + cairo_in_fill (cr, 13, 2.5)) + { + cairo_test_log (ctx, "Error: Found an unexpected point outside triangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 8, 2.5) || + ! cairo_in_fill (cr, 12, 2.5)) + { + cairo_test_log (ctx, "Error: Failed to find point inside triangle\n"); + ret = CAIRO_TEST_FAILURE; + } + return ret; } -- cgit v1.2.3 From 13627b46209f9239d10a155f2de7e53c0585e4c2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 6 Nov 2008 01:04:52 +0000 Subject: [in-fill] Fix transposed arguments. Silly typo that escaped the test suite. --- src/cairo-path-in-fill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c index 8bfc9d8a..f9920eaf 100644 --- a/src/cairo-path-in-fill.c +++ b/src/cairo-path-in-fill.c @@ -125,7 +125,7 @@ _cairo_in_fill_add_edge (cairo_in_fill_t *in_fill, return; if ((p1->x <= in_fill->x && p2->x <= in_fill->x) || - edge_compare_for_y_against_x (p1, p2, in_fill->x, in_fill->y) <= 0) + edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) <= 0) { in_fill->winding += dir; } -- cgit v1.2.3 From ff0bd64e9436026f11e85eafcd74e9a0131c8b9f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 6 Nov 2008 01:22:39 +0000 Subject: [NEWS] Add a few notes. Help Carl with a speedy snapshot by writing a few notes about what has been added so far to 1.9. --- NEWS | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/NEWS b/NEWS index ec2041ff..a2965a06 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,45 @@ +Release 1.9.2 (2008-11-08?) +=========================== + +API additions: + + cairo_surface_set_mime_data() + cairo_surface_get_mime_data() + + Associate an alternate, compressed, representation for a surface. + Currently: + "image/jpeg" is understood by PDF,PS,SVG,win32-printing. + "image/png" is understood by SVG. + +New backend: + + Simple DirectMedia Layer + +New utility: + + cairo-trace + + Generates a human-readable, replayable, compact representation of + the sequences of drawing commands made by an application. + Though currently the replay tools are out-of-tree - + people.freedesktop.org:~ickle/cairo-script, + people.freedesktop.org:~ickle/sphinx + +Test suite overhaul: + The test suite is undergoing an overhaul, primarily to improve its speed + and utility. + +Optimisations: +Tweaks to tessellator, allocations of patterns, delayed initialisation of +the xlib backend (reduce the cairo overhead of render_bench by ~80%). + +Bug fixes: +EXTEND_PAD. +Better handling of large scale-factors on image patterns. +Emit /Interpolate for PS,PDF images. + + + Release 1.8.2 (2008-10-29 Carl Worth ) ========================================================= The cairo community is pleased to announce the 1.8.2 release of the -- cgit v1.2.3 From 2554d1759835a174b89107808d81d044c3e2e098 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Nov 2008 13:26:46 +0000 Subject: [surface] Pass a separate closure for the mime-type destroy notifier. A limitation of the current API was that the destroy notifier was called on the mime-data block. This prevents the user from passing in a pointer to a managed block, for example a mime-data block belonging to a ref-counted object. We can overcome this by allowing the user to specify the closure to be used with the destroy notifier. --- src/cairo-png.c | 3 ++- src/cairo-surface.c | 9 ++++++--- src/cairo-types-private.h | 1 + src/cairo.h | 11 ++++++----- test/mime-data.c | 3 ++- test/pdf-mime-data.c | 4 +++- util/cairo-trace/trace.c | 6 ++++-- 7 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/cairo-png.c b/src/cairo-png.c index a130ba25..e8f61b5d 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -662,7 +662,8 @@ read_png (struct png_read_closure_t *png_closure) CAIRO_MIME_TYPE_PNG, mime_data, mime_data_length, - free); + free, + mime_data); if (status) { free (mime_data); cairo_surface_destroy (surface); diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 9df75ca4..c419bd5f 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -640,8 +640,8 @@ _cairo_mime_data_destroy (void *ptr) if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count)) return; - if (mime_data->destroy && mime_data->data) - mime_data->destroy (mime_data->data); + if (mime_data->destroy && mime_data->closure) + mime_data->destroy (mime_data->closure); free (mime_data); } @@ -655,6 +655,7 @@ _cairo_mime_data_destroy (void *ptr) * @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 @@ -670,7 +671,8 @@ 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) + cairo_destroy_func_t destroy, + void *closure) { cairo_status_t status; cairo_mime_data_t *mime_data; @@ -692,6 +694,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, mime_data->data = (unsigned char *) data; mime_data->length = length; mime_data->destroy = destroy; + mime_data->closure = closure; } else mime_data = NULL; diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 30180b0c..77f8184b 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -349,6 +349,7 @@ struct _cairo_mime_data { unsigned char *data; unsigned int length; cairo_destroy_func_t destroy; + void *closure; }; #endif /* CAIRO_TYPES_PRIVATE_H */ diff --git a/src/cairo.h b/src/cairo.h index cbc109f3..27d56f5a 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1957,11 +1957,12 @@ cairo_surface_get_mime_data (cairo_surface_t *surface, 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); +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, diff --git a/test/mime-data.c b/test/mime-data.c index 87fe74c8..ec855f85 100644 --- a/test/mime-data.c +++ b/test/mime-data.c @@ -96,7 +96,8 @@ paint_file (cairo_t *cr, image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50); status = cairo_surface_set_mime_data (image, mime_type, - mime_data, mime_length, free); + mime_data, mime_length, + free, mime_data); if (status) { cairo_surface_destroy (image); return cairo_test_status_from_status (ctx, status); diff --git a/test/pdf-mime-data.c b/test/pdf-mime-data.c index c949335e..233374dd 100644 --- a/test/pdf-mime-data.c +++ b/test/pdf-mime-data.c @@ -106,7 +106,9 @@ preamble (cairo_test_context_t *ctx) return test_status; } - cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG, data, len, free); + cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG, + data, len, + free, data); width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index df2ec5c9..03f7c5e5 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -2771,7 +2771,8 @@ 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) + cairo_destroy_func_t destroy, + void *closure) { if (surface != NULL && _write_lock ()) { _emit_surface (surface); @@ -2787,7 +2788,8 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, surface, mime_type, data, length, - destroy); + destroy, + closure); } cairo_status_t -- cgit v1.2.3 From cd2e18ddc65959a736fc7b7f6bbd3e76af0495a9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Nov 2008 18:35:39 +0000 Subject: [test] Fix-up rgb byte packing Another embarrassing, but thankfully, trivial bug. --- boilerplate/cairo-boilerplate.c | 2 ++ test/any2ppm.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c index 50f9f399..b12b6d6a 100644 --- a/boilerplate/cairo-boilerplate.c +++ b/boilerplate/cairo-boilerplate.c @@ -990,6 +990,8 @@ cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file) for (x = 0; x < width; x++) { if (! freadn (buf, 3, file)) goto FAIL; + *(uint32_t *) buf = + (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0); buf += 4; } break; diff --git a/test/any2ppm.c b/test/any2ppm.c index 94450b2f..85c1bdbb 100644 --- a/test/any2ppm.c +++ b/test/any2ppm.c @@ -184,26 +184,30 @@ write_ppm (cairo_surface_t *surface, int fd) len = sprintf (buf, "%s %d %d 255\n", format_str, width, height); for (j = 0; j < height; j++) { - const unsigned char *row = data + stride * j; + const unsigned int *row = (unsigned int *) (data + stride * j); switch ((int) format) { case CAIRO_FORMAT_ARGB32: len = _write (fd, buf, sizeof (buf), len, - row, 4 * width); + (unsigned char *) row, 4 * width); break; case CAIRO_FORMAT_RGB24: for (i = 0; i < width; i++) { + unsigned char rgb[3]; + unsigned int p = *row++; + rgb[0] = (p & 0xff0000) >> 16; + rgb[1] = (p & 0x00ff00) >> 8; + rgb[2] = (p & 0x0000ff) >> 0; len = _write (fd, buf, sizeof (buf), len, - row, 3); - row += 4; + rgb, 3); } break; case CAIRO_FORMAT_A8: len = _write (fd, buf, sizeof (buf), len, - row, width); + (unsigned char *) row, width); break; } if (len < 0) -- cgit v1.2.3 From d15fb9344bf86dd52cda0b43d3dfc49397fd84ec Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Fri, 7 Nov 2008 20:06:35 +0000 Subject: [hash] Set is_unique when finding an available for inserts As we obey the rule in Cairo that we only insert if we know that there is no existing entry in the hash table, we can therefore perform a much quicker search knowing that the key is unique. --- src/cairo-hash.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/cairo-hash.c b/src/cairo-hash.c index 2317eb17..41abafd6 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -448,8 +448,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 @@ -472,13 +472,11 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table, 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; - } + key_and_value, + TRUE); + /* _cairo_hash_table_lookup_internal with key_unique = TRUE + * aways returns an available entry. */ + assert (! ENTRY_IS_LIVE(*entry)); *entry = key_and_value; hash_table->live_entries++; -- cgit v1.2.3 From 2b32c8b9e572c96ce8ba5c7d43b568f18f6da295 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Nov 2008 20:30:33 +0000 Subject: [hash] Return lookup entry. Use the return value to return the result from _cairo_hash_table_lookup() (as opposed to filling an output parameter on the stack) as this (a) results in cleaner code (no strict-alias breaking pointer casts), (b) produces a smaller binary and (c) is measurably faster. --- src/cairo-cache-private.h | 5 ++--- src/cairo-cache.c | 8 +++---- src/cairo-cff-subset.c | 24 +++++++++------------ src/cairo-font-face.c | 9 ++++---- src/cairo-ft-font.c | 6 +++--- src/cairo-hash-private.h | 7 +++--- src/cairo-hash.c | 24 +++++++-------------- src/cairo-misc.c | 7 +++--- src/cairo-scaled-font-subsets.c | 47 ++++++++++++++++++++--------------------- src/cairo-scaled-font.c | 18 +++++++--------- 10 files changed, 67 insertions(+), 88 deletions(-) diff --git a/src/cairo-cache-private.h b/src/cairo-cache-private.h index 4ae63ade..6a9b8b8d 100644 --- a/src/cairo-cache-private.h +++ b/src/cairo-cache-private.h @@ -109,10 +109,9 @@ _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, diff --git a/src/cairo-cache.c b/src/cairo-cache.c index 1c458dff..01e5713d 100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c @@ -222,14 +222,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); } /** diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index 9a4e3d6a..45be5d1c 100644 --- a/src/cairo-cff-subset.c +++ b/src/cairo-cff-subset.c @@ -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,9 +564,8 @@ 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) @@ -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); diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c index 6cea3958..f9a838ae 100644 --- a/src/cairo-font-face.c +++ b/src/cairo-font-face.c @@ -499,11 +499,10 @@ cairo_toy_font_face_create (const char *family, _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); diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index cd112532..7cae0467 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -422,9 +422,9 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, _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; 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 41abafd6..5b2704f2 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 @@ -355,32 +354,25 @@ _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; /* 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; - } + if (ENTRY_IS_LIVE (*entry)) + return *entry; - *entry_return = NULL; - return FALSE; + return NULL; } /** diff --git a/src/cairo-misc.c b/src/cairo-misc.c index 667fa528..5d258ff3 100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -717,10 +717,9 @@ _cairo_intern_string (const char **str_inout, int len) if (_cairo_intern_string_ht == NULL) _cairo_intern_string_ht = _cairo_hash_table_create (_intern_string_equal); - if (! _cairo_hash_table_lookup (_cairo_intern_string_ht, - &tmpl.hash_entry, - (cairo_hash_entry_t **) &istring)) - { + 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 (istring != NULL) { istring->hash_entry.hash = tmpl.hash_entry.hash; diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index 815c4d8b..7ec2a2dc 100644 --- a/src/cairo-scaled-font-subsets.c +++ b/src/cairo-scaled-font-subsets.c @@ -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) @@ -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); @@ -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) @@ -1018,14 +1018,13 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset } 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); diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index bfeeaf66..af217c6c 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -465,14 +465,13 @@ 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)); @@ -823,8 +822,8 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, } 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; @@ -2348,9 +2347,8 @@ _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 */ -- cgit v1.2.3 From f1cae5c52a5ee71b7933fca702bb525d98936838 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Nov 2008 20:52:08 +0000 Subject: [ps] Trivial compile warning clenaup. Add a missing const to silence the compiler. --- src/cairo-ps-surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 5dcdce52..99166510 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -1836,7 +1836,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) { -- cgit v1.2.3 From 899a159b133e22f71e2a176785c91e78838c3fee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 8 Nov 2008 11:16:03 +0000 Subject: [trace] Remove stray /source An accidental /source was pushing pushed onto the operand stack and never used. --- util/cairo-trace/trace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 03f7c5e5..c92215ea 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -2625,7 +2625,6 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, * is negligible. */ if (width * height < 128) { - fprintf (logfile, " /source "); _emit_image (ret, NULL); fprintf (logfile, " dup /s%ld exch def\n", -- cgit v1.2.3 From 1d0faefbc8700833e9bde8a9c825b02b0f3cf910 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Nov 2008 22:48:21 +0000 Subject: [trace] Record the XID as a number Don't waste string constants (which get interned) for a simple number! --- util/cairo-trace/trace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index c92215ea..491184ca 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -3468,7 +3468,7 @@ cairo_xlib_surface_create (Display *dpy, fprintf (logfile, "dict\n" " /type (xlib) set\n" - " /drawable /%lx set\n" + " /drawable 16!%lx set\n" " /width %d set\n" " /height %d set\n" " surface dup /s%ld exch def\n", @@ -3504,7 +3504,7 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, fprintf (logfile, "dict\n" " /type (xlib) set\n" - " /drawable /%lx set\n" + " /drawable 16!%lx set\n" " /width %d set\n" " /height %d set\n" " /depth 1 set\n" @@ -3544,7 +3544,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, fprintf (logfile, "dict\n" " /type (xrender) set\n" - " /drawable /%lx set\n" + " /drawable 16!%lx set\n" " /width %d set\n" " /height %d set\n" " /depth %d set\n" -- cgit v1.2.3 From 5badcf6e370b9808374a1fa547383b236a9dcd21 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 8 Nov 2008 11:17:34 +0000 Subject: [trace] Use a string literal for the type. In order that the string is interned and so is only allocated the once. --- util/cairo-trace/trace.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 491184ca..19e0d735 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -3221,7 +3221,7 @@ cairo_ps_surface_create (const char *filename, double width_in_points, double he if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (PS) set\n" + " /type /PS set\n" " /filename "); _emit_string_literal (filename, -1); fprintf (logfile, @@ -3251,7 +3251,7 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (PS) set\n" + " /type /PS set\n" " /width %g set\n" " /height %g set\n" " surface %% s%ld\n", @@ -3288,7 +3288,7 @@ cairo_pdf_surface_create (const char *filename, double width_in_points, double h if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (PDF) set\n" + " /type /PDF set\n" " /filename "); _emit_string_literal (filename, -1); fprintf (logfile, @@ -3318,7 +3318,7 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closur if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (PDF) set\n" + " /type /PDF set\n" " /width %g set\n" " /height %g set\n" " surface %% s%ld\n", @@ -3353,7 +3353,7 @@ cairo_svg_surface_create (const char *filename, double width, double height) if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (SVG) set\n" + " /type /SVG set\n" " /filename "); _emit_string_literal (filename, -1); fprintf (logfile, @@ -3383,7 +3383,7 @@ cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, void *closur if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (SVG) set\n" + " /type /SVG set\n" " /width %g set\n" " /height %g set\n" " surface %% s%ld\n", @@ -3467,7 +3467,7 @@ cairo_xlib_surface_create (Display *dpy, if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (xlib) set\n" + " /type /xlib set\n" " /drawable 16!%lx set\n" " /width %d set\n" " /height %d set\n" @@ -3503,7 +3503,7 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (xlib) set\n" + " /type /xlib set\n" " /drawable 16!%lx set\n" " /width %d set\n" " /height %d set\n" @@ -3543,7 +3543,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (xrender) set\n" + " /type /xrender set\n" " /drawable 16!%lx set\n" " /width %d set\n" " /height %d set\n" @@ -3583,7 +3583,7 @@ cairo_script_surface_create (const char *filename, if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (script) set\n" + " /type /script set\n" " /filename "); _emit_string_literal (filename, -1); fprintf (logfile, @@ -3617,7 +3617,7 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func, if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (script) set\n" + " /type /script set\n" " /width %g set\n" " /height %g set\n" " surface dup /s%ld exch def\n", @@ -3648,7 +3648,7 @@ _cairo_test_fallback_surface_create (cairo_content_t content, if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (test-fallback) set\n" + " /type /test-fallback set\n" " /content //%s set\n" " /width %d set\n" " /height %d set\n" @@ -3683,7 +3683,7 @@ _cairo_test_paginated_surface_create_for_data (unsigned char *data, /* XXX store initial data? */ fprintf (logfile, "dict\n" - " /type (test-paginated) set\n" + " /type /test-paginated set\n" " /content //%s set\n" " /width %d set\n" " /height %d set\n" @@ -3715,7 +3715,7 @@ _cairo_test_meta_surface_create (cairo_content_t content, if (_write_lock ()) { fprintf (logfile, "dict\n" - " /type (test-meta) set\n" + " /type /test-meta set\n" " /content //%s set\n" " /width %d set\n" " /height %d set\n" -- cgit v1.2.3 From 164069b339843837e04e2522a615f03a83b362c0 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 8 Nov 2008 15:29:40 +0100 Subject: cairo-xcb: avoid leaking memory --- src/cairo-xcb-surface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index d5146592..63618bb0 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -2416,6 +2416,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; } -- cgit v1.2.3 From 57551a91168a68399add9e5c324fba03961b7747 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 11 Nov 2008 08:31:23 -0500 Subject: [quartz] Fix fallout caused by const cairo_pattern_t * 794460186459981cd43ca38f3eba07e3f6bf8908 broke the quartz backend. Fix it by adding const to the appropriate parameters in the function declarations and copying the pattern when needed. --- src/cairo-quartz-surface.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 2addd8bc..1d8c7094 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 @@ -688,7 +688,7 @@ CreateGradientFunction (cairo_gradient_pattern_t *gpat) 0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy }; - return CGFunctionCreate (_cairo_pattern_create_copy (&gpat->base), + return CGFunctionCreate (cairo_pattern_reference (&gpat->base), 1, input_value_range, 4, @@ -766,7 +766,7 @@ 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), + return CGFunctionCreate (cairo_pattern_reference (&gpat->base), 1, input_value_range, 4, @@ -904,7 +904,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; @@ -1174,7 +1174,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)); @@ -1320,7 +1320,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 +1667,7 @@ _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; @@ -1719,7 +1719,7 @@ _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, @@ -1825,7 +1825,7 @@ _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, @@ -1972,7 +1972,7 @@ _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, @@ -2182,8 +2182,8 @@ 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; CGRect rect; @@ -2247,8 +2247,8 @@ _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) { int width = surface->extents.width - surface->extents.x; int height = surface->extents.height - surface->extents.y; @@ -2257,6 +2257,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 = NULL; cairo_int_status_t status; /* Render the gradient to a surface */ @@ -2264,11 +2265,17 @@ _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_set_operator (gradient_surf_cr, CAIRO_OPERATOR_SOURCE); cairo_paint (gradient_surf_cr); status = cairo_status (gradient_surf_cr); cairo_destroy (gradient_surf_cr); + cairo_pattern_destroy (mask_copy); if (status) goto BAIL; @@ -2289,8 +2296,8 @@ _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; -- cgit v1.2.3 From 9c0042840c70c14e3e608ac3849edf5f1ef99816 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 11 Nov 2008 08:41:31 -0500 Subject: [quartz] Add the proper propagation of extents This fixes the problems introduced by d682d275b90f7326df76d2764c513c8b6d5b551b --- src/cairo-quartz-surface.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 1d8c7094..19160b4b 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -2183,21 +2183,22 @@ static cairo_int_status_t _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_surface_pattern_t *mask) + 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); @@ -2206,7 +2207,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); @@ -2223,7 +2224,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); @@ -2248,7 +2249,8 @@ static cairo_int_status_t _cairo_quartz_surface_mask_with_generic (cairo_quartz_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) { int width = surface->extents.width - surface->extents.x; int height = surface->extents.height - surface->extents.y; @@ -2282,7 +2284,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); @@ -2313,7 +2315,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; @@ -2323,9 +2325,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 -- cgit v1.2.3 From 4fdd856569a67636aaf29bc1a76eed44418db484 Mon Sep 17 00:00:00 2001 From: Peter Weilbacher Date: Tue, 11 Nov 2008 15:37:09 +0100 Subject: README: adapt pixman version requirement to match configure.ac --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index c01e0b23..a4ace94d 100644 --- a/README +++ b/README @@ -89,7 +89,7 @@ Supported, "standard" surface backends ------------------------------------ image backend (required) ------------------------ - pixman >= 0.10.0 http://cairographics.org/releases + pixman >= 0.12.0 http://cairographics.org/releases png support (can be left out if desired, but many ----------- applications expect it to be present) -- cgit v1.2.3 From 0a682034a04fa7fc1407e7bc093ae01f4b385ad7 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 11 Nov 2008 13:26:09 -0500 Subject: Make the clipping implementation comment clearer When reviewing the spans changes, I reread this comment and it wasn't as clear as it could be. --- src/cairo-clip.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 93bc151c..5bbffd71 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -478,9 +478,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, -- cgit v1.2.3 From 279a7cef349cf5aa87cdeacb9424413f51117fe8 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Thu, 13 Nov 2008 10:50:41 +0100 Subject: [os2] Fix includes Patch from Dave Yeo to make cairo-os2.h include os2.h directly so the header is standalone. --- src/cairo-os2-private.h | 11 ----------- src/cairo-os2-surface.c | 5 ----- src/cairo-os2.h | 8 ++++++++ 3 files changed, 8 insertions(+), 16 deletions(-) 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 -#else -# include -#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..e4cef052 100644 --- a/src/cairo-os2-surface.c +++ b/src/cairo-os2-surface.c @@ -43,11 +43,6 @@ #include #ifdef BUILD_CAIRO_DLL -# define INCL_WIN -# define INCL_GPI -# define INCL_DOS -# define INCL_DOSERRORS -# include # include "cairo-os2.h" # ifndef __WATCOMC__ # include diff --git a/src/cairo-os2.h b/src/cairo-os2.h index d0a13e47..17f02634 100644 --- a/src/cairo-os2.h +++ b/src/cairo-os2.h @@ -38,6 +38,14 @@ #ifndef _CAIRO_OS2_H_ #define _CAIRO_OS2_H_ +#define INCL_DOS +#define INCL_DOSSEMAPHORES +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_GPI + +#include + #include "cairo.h" CAIRO_BEGIN_DECLS -- cgit v1.2.3 From efa9e1088cbf1b5331cc0bab3348520f3b91ae4b Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Thu, 13 Nov 2008 12:11:12 +0200 Subject: [clip] Fix uninitialised status return in _cairo_clip_intersect_mask() for empty extents. This fixes the clip-all test case crashing for me. --- src/cairo-clip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 5bbffd71..726896e8 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -423,7 +423,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; -- cgit v1.2.3 From 7ad2635ebe84ba7c050a7f00c5389cdc31ab1172 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Nov 2008 09:46:38 +0000 Subject: [trace] Disable stdout by default. Don't hog the terminal when we save to a trace file anyway. --- util/cairo-trace/cairo-trace.in | 48 +++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/util/cairo-trace/cairo-trace.in b/util/cairo-trace/cairo-trace.in index 93bb954c..c9be5a68 100644 --- a/util/cairo-trace/cairo-trace.in +++ b/util/cairo-trace/cairo-trace.in @@ -4,20 +4,43 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ nofile= -silent= +verbose= + +usage() { +cat << EOF +usage: cairo-trace [--no-file|--verbose] command +cairo-trace will generate a log of all calls made by command to +cairo. This log will be stored in a file in the local directory +called command.pid.trace. +Whatever else happens is driven by its argument: + --verbose - Show the trace on stdout. + --no-file - disables the generation of an output file + +Enviroment variables understood by cairo-trace: + CAIRO_TRACE_FLUSH - flush the output after every function call. +EOF +exit +} skip=1 while test $skip -eq 1; do skip=0 case $1 in - --silent) + --verbose) skip=1 - silent=1 + verbose=1 ;; --no-file) skip=1 nofile=1 ;; + --version) + echo "cairo-trace, version @CAIRO_VERSION_MAJOR@.@CAIRO_VERSION_MINOR@.@CAIRO_VERSION_MICRO@." + exit + ;; + --help) + usage + ;; esac if test $skip -eq 1; then shift @@ -25,21 +48,7 @@ while test $skip -eq 1; do done if test $# -eq 0; then -cat << EOF -usage: cairo-trace [--no-file|--silent] command -cairo-trace will generate a log of all calls made by command to -cairo. This log will be stored in a file in the local directory -called command.pid.trace. -Whatever else happens is driven by its argument: - --silent - disables the overriding of stdout by cairo-trace. - The trace file is still generated, but your application - is free to continue to use stdout. - --no-file - disables the generation of an output file - -Enviroment variables understood by cairo-trace: - CAIRO_TRACE_FLUSH - flush the output after every function call. -EOF -exit + usage fi #echo $* @@ -58,7 +67,8 @@ export LC_ALL if test -z "$filename"; then CAIRO_TRACE_FD=3 $* 3>&1 >/dev/null -elif test -n "$silent"; then +elif test -z "$verbose"; then + echo "Recording trace in $filename." CAIRO_TRACE_OUTFILE_EXACT=$filename $* else CAIRO_TRACE_FD=3 $* 3>&1 >/dev/null | tee $filename -- cgit v1.2.3 From 8f3d0b55f50168f061a01eecfcb4ebecbff0e1c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Nov 2008 09:25:24 +0000 Subject: [trace] Add unstable warning. Add warning that CairoScript is unfinished and I may radically alter the format/syntax/language before release. --- util/cairo-trace/trace.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 19e0d735..aa877518 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -419,6 +419,7 @@ _emit_header (void) get_prog_name (name, sizeof (name)); fprintf (logfile, "%%!CairoScript - %s\n", name); + fprintf (logfile, "%%*** Warning CairoScript is still a new tracing format, and is subject to change.\n"); } static bool -- cgit v1.2.3 From 01e2021b2b7b66e7cdb9c4b0326fd5793759848b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Nov 2008 16:15:28 +0000 Subject: [trace] Trace mark-dirty Capture the image data on mark dirty and record in the trace. --- util/cairo-trace/cairo-trace.in | 2 +- util/cairo-trace/trace.c | 121 ++++++++++++++++++++++++++++++++++------ 2 files changed, 106 insertions(+), 17 deletions(-) diff --git a/util/cairo-trace/cairo-trace.in b/util/cairo-trace/cairo-trace.in index c9be5a68..0ba87c74 100644 --- a/util/cairo-trace/cairo-trace.in +++ b/util/cairo-trace/cairo-trace.in @@ -55,7 +55,7 @@ fi filename="" if test -z "$nofile"; then - filename=`basename $1`.$$.trace + filename=`basename -- $1`.$$.trace fi LD_PRELOAD=@libdir@/cairo/cairo-trace.so diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index aa877518..c96723b4 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -685,7 +685,20 @@ _create_context_id (cairo_t *cr) static long _get_id (enum operand_type op_type, const void *ptr) { - return _get_object (op_type, ptr)->token; + Object *obj; + + obj = _get_object (op_type, ptr); + if (obj == NULL) { + if (logfile != NULL) { + fprintf (logfile, + "%% Unknown object of type %s, trace is incomplete.", + _get_type (op_type)->name); + } + _error = true; + return -1; + } + + return obj->token; } static bool @@ -1334,7 +1347,7 @@ _emit_string_literal (const char *utf8, int len) static void _emit_current (Object *obj) { - if (! _pop_operands_to_object (obj)) { + if (obj != NULL && ! _pop_operands_to_object (obj)) { fprintf (logfile, "%s%ld\n", obj->type->op_code, obj->token); _push_operand (obj->type->op_type, obj->addr); } @@ -1399,16 +1412,18 @@ cairo_create (cairo_surface_t *target) if (target != NULL && _write_lock ()) { surface_id = _get_surface_id (target); - _get_object (SURFACE, target)->foreign = false; + if (surface_id != -1) { + _get_object (SURFACE, target)->foreign = false; - /* we presume that we will continue to use the context */ - if (_pop_operands_to (SURFACE, target)){ - _consume_operand (); - } else { - fprintf (logfile, "s%ld ", surface_id); + /* we presume that we will continue to use the context */ + if (_pop_operands_to (SURFACE, target)){ + _consume_operand (); + } else { + fprintf (logfile, "s%ld ", surface_id); + } + fprintf (logfile, "context %% c%ld\n", context_id); + _push_operand (CONTEXT, ret); } - fprintf (logfile, "context %% c%ld\n", context_id); - _push_operand (CONTEXT, ret); _write_unlock (); } @@ -1529,6 +1544,8 @@ _emit_source_image (cairo_surface_t *surface) cairo_t *cr; obj = _get_object (SURFACE, surface); + if (obj == NULL) + return; image = DLCALL (cairo_image_surface_create, CAIRO_FORMAT_ARGB32, @@ -1544,7 +1561,39 @@ _emit_source_image (cairo_surface_t *surface) " set_source_image "); DLCALL (cairo_surface_destroy, image); - _get_object (SURFACE, surface)->foreign = false; + obj->foreign = false; +} + +static void +_emit_source_image_rectangle (cairo_surface_t *surface, + int x, int y, + int width, int height) +{ + Object *obj; + cairo_surface_t *image; + cairo_t *cr; + + obj = _get_object (SURFACE, surface); + if (obj == NULL) + return; + + if (obj->foreign) + return _emit_source_image (surface); + + image = DLCALL (cairo_image_surface_create, + CAIRO_FORMAT_ARGB32, + width, + height); + cr = DLCALL (cairo_create, image); + DLCALL (cairo_set_source_surface, cr, surface, x, y); + DLCALL (cairo_paint, cr); + DLCALL (cairo_destroy, cr); + + _emit_image (image, NULL); + fprintf (logfile, + " %d %d set_device_offset set_source_image ", + x, y); + DLCALL (cairo_surface_destroy, image); } void @@ -2601,6 +2650,8 @@ cairo_image_surface_create (cairo_format_t format, int width, int height) " /format //%s set\n" " image dup /s%ld exch def\n", width, height, format_str, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -2641,11 +2692,11 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, _format_to_string (format), surface_id); - _get_object (SURFACE, ret)->width = width; - _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->foreign = true; } + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -2723,15 +2774,27 @@ cairo_surface_flush (cairo_surface_t *surface) void cairo_surface_mark_dirty (cairo_surface_t *surface) { - /* XXX send update rect? */ + if (surface != NULL && _write_lock ()) { + _emit_surface (surface); + fprintf (logfile, "%% mark_dirty\n"); + _emit_source_image (surface); + _write_unlock (); + } return DLCALL (cairo_surface_mark_dirty, surface); } void -cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, int x, int y, int width, int height) +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, int y, int width, int height) { - /* XXX send update rect? */ + if (surface != NULL && _write_lock ()) { + _emit_surface (surface); + fprintf (logfile, "%% %d %d %d %d mark_dirty_rectangle\n", + x, y, width, height); + _emit_source_image_rectangle (surface, x,y, width, height); + _write_unlock (); + } return DLCALL (cairo_surface_mark_dirty_rectangle, surface, x, y, width, height); } @@ -3233,6 +3296,8 @@ cairo_ps_surface_create (const char *filename, double width_in_points, double he width_in_points, height_in_points, surface_id); + _get_object (SURFACE, ret)->width = width_in_points; + _get_object (SURFACE, ret)->height = height_in_points; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3259,6 +3324,8 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure width_in_points, height_in_points, surface_id); + _get_object (SURFACE, ret)->width = width_in_points; + _get_object (SURFACE, ret)->height = height_in_points; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3300,6 +3367,8 @@ cairo_pdf_surface_create (const char *filename, double width_in_points, double h width_in_points, height_in_points, surface_id); + _get_object (SURFACE, ret)->width = width_in_points; + _get_object (SURFACE, ret)->height = height_in_points; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3326,6 +3395,8 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closur width_in_points, height_in_points, surface_id); + _get_object (SURFACE, ret)->width = width_in_points; + _get_object (SURFACE, ret)->height = height_in_points; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3365,6 +3436,8 @@ cairo_svg_surface_create (const char *filename, double width, double height) width, height, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3391,6 +3464,8 @@ cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, void *closur width, height, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _push_operand (SURFACE, ret); _write_unlock (); } @@ -3419,6 +3494,8 @@ cairo_image_surface_create_from_png (const char *filename) fprintf (logfile, " dup /s%ld exch def\n", surface_id); + _get_object (SURFACE, ret)->width = cairo_image_surface_get_width (ret); + _get_object (SURFACE, ret)->height = cairo_image_surface_get_height (ret); _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -3441,6 +3518,8 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *c fprintf (logfile, " dup /s%ld exch def\n", surface_id); + _get_object (SURFACE, ret)->width = cairo_image_surface_get_width (ret); + _get_object (SURFACE, ret)->height = cairo_image_surface_get_height (ret); _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -3594,6 +3673,8 @@ cairo_script_surface_create (const char *filename, " surface dup /s%ld exch def\n", width, height, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -3624,6 +3705,8 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func, " surface dup /s%ld exch def\n", width, height, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -3657,6 +3740,8 @@ _cairo_test_fallback_surface_create (cairo_content_t content, _content_to_string (content), width, height, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -3693,6 +3778,8 @@ _cairo_test_paginated_surface_create_for_data (unsigned char *data, _content_to_string (content), width, height, stride, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); @@ -3724,6 +3811,8 @@ _cairo_test_meta_surface_create (cairo_content_t content, _content_to_string (content), width, height, surface_id); + _get_object (SURFACE, ret)->width = width; + _get_object (SURFACE, ret)->height = height; _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); -- cgit v1.2.3 From 76f249a49399744d6d936e36ca4d68ab4a1f3d3b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Nov 2008 09:12:50 +0000 Subject: [trace] Detect and report broken traces. We cannot trace the cairo-script-interpreter as that uses Cairo's private symbols. --- util/cairo-trace/trace.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index c96723b4..18968464 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -147,7 +147,8 @@ static struct _type_table { } Types; static FILE *logfile; -static int _flush; +static bool _flush; +static bool _error; static const cairo_user_data_key_t destroy_key; static void @@ -484,6 +485,9 @@ done: static bool _write_lock (void) { + if (_error) + return false; + if (! _init_logfile ()) return false; @@ -530,6 +534,15 @@ _get_object (enum operand_type op_type, const void *ptr) obj = _type_get_object (type, ptr); pthread_mutex_unlock (&type->mutex); + if (obj == NULL) { + if (logfile != NULL) { + fprintf (logfile, + "%% Unknown object of type %s, trace is incomplete.", + type->name); + } + _error = true; + } + return obj; } -- cgit v1.2.3 From 4cd6b0c0b9862f398877cb23c294399b480ac8d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Nov 2008 00:37:40 +0000 Subject: [trace] Check for an undefined pattern and use index instead. --- util/cairo-trace/trace.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 18968464..d3e7320d 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -780,6 +780,22 @@ _get_pattern_id (cairo_pattern_t *pattern) return _get_id (PATTERN, pattern); } +static void +_emit_pattern_id (cairo_pattern_t *pattern) +{ + Object *obj = _get_object (PATTERN, pattern); + if (obj == NULL) { + fprintf (logfile, "null "); + } else { + if (obj->defined) { + fprintf (logfile, "p%ld ", obj->token); + } else { + fprintf (logfile, "%d index ", + current_stack_depth - obj->operand - 1); + } + } +} + static long _create_scaled_font_id (cairo_scaled_font_t *font) { @@ -1662,7 +1678,7 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source) else { _emit_context (cr); - fprintf (logfile, "p%ld ", _get_pattern_id (source)); + _emit_pattern_id (source); } fprintf (logfile, "set_source\n"); @@ -2010,7 +2026,7 @@ cairo_mask (cairo_t *cr, cairo_pattern_t *pattern) _consume_operand (); } else { _emit_context (cr); - fprintf (logfile, "p%ld ", _get_pattern_id (pattern)); + _emit_pattern_id (pattern); } fprintf (logfile, " mask\n"); -- cgit v1.2.3 From 5f0aa274459fa182d1f82d393224c46ce2b12785 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 10:45:15 +0000 Subject: [trace] Add caller line info. Use lookup_symbol() on the return address to identify the caller and emit useful debug info to the trace. --- util/cairo-trace/cairo-trace.in | 27 +++++++- util/cairo-trace/lookup-symbol.c | 72 ++++++++++----------- util/cairo-trace/trace.c | 134 +++++++++++++++++++++++++++++++++++---- 3 files changed, 178 insertions(+), 55 deletions(-) diff --git a/util/cairo-trace/cairo-trace.in b/util/cairo-trace/cairo-trace.in index 0ba87c74..cab40823 100644 --- a/util/cairo-trace/cairo-trace.in +++ b/util/cairo-trace/cairo-trace.in @@ -5,6 +5,8 @@ exec_prefix=@exec_prefix@ nofile= verbose= +flush= +nocallers= usage() { cat << EOF @@ -13,11 +15,14 @@ cairo-trace will generate a log of all calls made by command to cairo. This log will be stored in a file in the local directory called command.pid.trace. Whatever else happens is driven by its argument: - --verbose - Show the trace on stdout. - --no-file - disables the generation of an output file + --flush - Flush the output trace after every call. + --verbose - Show the trace on stdout. + --no-file - Disable the creation of an output file. + --no-callers - Do not lookup the caller address/symbol/line whilst tracing. Enviroment variables understood by cairo-trace: CAIRO_TRACE_FLUSH - flush the output after every function call. + CAIRO_TRACE_LINE_INFO - emit line information for most function calls. EOF exit } @@ -30,10 +35,18 @@ while test $skip -eq 1; do skip=1 verbose=1 ;; + --flush) + skip=1 + flush=1 + ;; --no-file) skip=1 nofile=1 ;; + --no-callers) + skip=1 + nocallers=1 + ;; --version) echo "cairo-trace, version @CAIRO_VERSION_MAJOR@.@CAIRO_VERSION_MINOR@.@CAIRO_VERSION_MICRO@." exit @@ -65,6 +78,16 @@ export LD_PRELOAD LC_ALL=C export LC_ALL +if test -n "$nocallers"; then + CAIRO_TRACE_LINE_INFO=0 + export CAIRO_TRACE_LINE_INFO +fi + +if test -n "$flush"; then + CAIRO_TRACE_FLUSH=1 + export CAIRO_TRACE_FLUSH +fi + if test -z "$filename"; then CAIRO_TRACE_FD=3 $* 3>&1 >/dev/null elif test -z "$verbose"; then diff --git a/util/cairo-trace/lookup-symbol.c b/util/cairo-trace/lookup-symbol.c index df7e6b00..42c9c955 100644 --- a/util/cairo-trace/lookup-symbol.c +++ b/util/cairo-trace/lookup-symbol.c @@ -177,43 +177,38 @@ _symbol_init (struct symbol *symbol, struct symtab *symtab, bfd_vma addr) symbol->pc = addr; } -static int +static void _symbol_print (struct symbol *symbol, char *buf, int buflen, const char *filename) { - if (! symbol->found) { - buflen = snprintf (buf, buflen, - "[0x%llx] \?\?() \?\?:0", - (long long unsigned int) symbol->pc); - } else { - const char *name, *h; - char path[1024]; - - name = symbol->functionname; - if (name == NULL || *name == '\0') - name = "??"; - - if (symbol->filename != NULL) - filename = symbol->filename; - if (strcmp (filename, "/proc/self/exe") == 0) { - int len = readlink ("/proc/self/exe", path, sizeof (path) - 1); - if (len != -1) { - path[len] = '\0'; - filename = path; - } - } - h = strrchr (filename, '/'); - if (h != NULL) - filename = h + 1; - - if (symbol->line) { - buflen = snprintf (buf, buflen, "%s (%s:%u)", - name, filename, symbol->line); - } else { - buflen = snprintf (buf, buflen, "%s (%s)", name, filename); + const char *name, *h; + char path[1024]; + + if (! symbol->found) + return; + + name = symbol->functionname; + if (name == NULL || *name == '\0') + name = "??"; + + if (symbol->filename != NULL) + filename = symbol->filename; + if (strcmp (filename, "/proc/self/exe") == 0) { + int len = readlink ("/proc/self/exe", path, sizeof (path) - 1); + if (len != -1) { + path[len] = '\0'; + filename = path; } } + h = strrchr (filename, '/'); + if (h != NULL) + filename = h + 1; - return buflen; + if (symbol->line) { + snprintf (buf, buflen, "%s() [%s:%u]", + name, filename, symbol->line); + } else { + snprintf (buf, buflen, "%s() [%s]", name, filename); + } } #endif @@ -259,14 +254,13 @@ lookup_symbol (char *buf, int buflen, const void *ptr) struct symtab symtab; struct symbol symbol; #endif - int i; + match.file = NULL; match.address = (ElfW(Addr)) ptr; dl_iterate_phdr (find_matching_file, &match); - i = snprintf (buf, buflen, - "0x%llx", - (long long unsigned int) match.address); + snprintf (buf, buflen, "0x%llx", + (long long unsigned int) match.address); if (match.file == NULL || *match.file == '\0') match.file = "/proc/self/exe"; @@ -277,10 +271,8 @@ lookup_symbol (char *buf, int buflen, const void *ptr) _symbol_init (&symbol, &symtab, match.address - match.base); bfd_map_over_sections (symtab.bfd, find_address_in_section, &symbol); - if (symbol.found) { - buf[i++] = ' '; - _symbol_print (&symbol, buf + i, buflen - i, match.file); - } + if (symbol.found) + _symbol_print (&symbol, buf, buflen, match.file); _symbol_fini (&symbol); _symtab_fini (&symtab); diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index d3e7320d..fb3a38cc 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -149,8 +149,23 @@ static struct _type_table { static FILE *logfile; static bool _flush; static bool _error; +static bool _line_info; static const cairo_user_data_key_t destroy_key; +#if __GNUC__ >= 3 +#define _emit_line_info() do { \ + if (_line_info && _write_lock ()) { \ + void *addr = __builtin_return_address(0); \ + char caller[1024]; \ + lookup_symbol (caller, sizeof (caller), addr); \ + fprintf (logfile, "%% %s() called by %s\n", __FUNCTION__, caller); \ + _write_unlock (); \ + } \ +} while (0) +#else +#define _emit_line_info() +#endif + static void _type_release_token (Type *t, unsigned long int token) { @@ -439,6 +454,11 @@ _init_logfile (void) if (env != NULL) _flush = atoi (env); + _line_info = true; + env = getenv ("CAIRO_TRACE_LINE_INFO"); + if (env != NULL) + _line_info = atoi (env); + filename = getenv ("CAIRO_TRACE_FD"); if (filename != NULL) { int fd = atoi (filename); @@ -534,15 +554,6 @@ _get_object (enum operand_type op_type, const void *ptr) obj = _type_get_object (type, ptr); pthread_mutex_unlock (&type->mutex); - if (obj == NULL) { - if (logfile != NULL) { - fprintf (logfile, - "%% Unknown object of type %s, trace is incomplete.", - type->name); - } - _error = true; - } - return obj; } @@ -1439,6 +1450,7 @@ cairo_create (cairo_surface_t *target) ret = DLCALL (cairo_create, target); context_id = _create_context_id (ret); + _emit_line_info (); if (target != NULL && _write_lock ()) { surface_id = _get_surface_id (target); if (surface_id != -1) { @@ -1462,6 +1474,7 @@ cairo_create (cairo_surface_t *target) void cairo_save (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "save\n"); return DLCALL (cairo_save, cr); } @@ -1469,6 +1482,7 @@ cairo_save (cairo_t *cr) void cairo_restore (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "restore\n"); return DLCALL (cairo_restore, cr); } @@ -1476,6 +1490,7 @@ cairo_restore (cairo_t *cr) void cairo_push_group (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "//COLOR_ALPHA push_group\n"); return DLCALL (cairo_push_group, cr); } @@ -1494,6 +1509,7 @@ _content_to_string (cairo_content_t content) void cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) { + _emit_line_info (); _emit_cairo_op (cr, "//%s push_group\n", _content_to_string (content)); return DLCALL (cairo_push_group_with_content, cr, content); } @@ -1505,6 +1521,7 @@ cairo_pop_group (cairo_t *cr) ret = DLCALL (cairo_pop_group, cr); + _emit_line_info (); _emit_cairo_op (cr, "pop_group %% p%ld\n", _create_pattern_id (ret)); _push_operand (PATTERN, ret); @@ -1514,6 +1531,7 @@ cairo_pop_group (cairo_t *cr) void cairo_pop_group_to_source (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "pop_group set_source\n"); return DLCALL (cairo_pop_group_to_source, cr); } @@ -1546,6 +1564,7 @@ _operator_to_string (cairo_operator_t op) void cairo_set_operator (cairo_t *cr, cairo_operator_t op) { + _emit_line_info (); _emit_cairo_op (cr, "//%s set_operator\n", _operator_to_string (op)); return DLCALL (cairo_set_operator, cr, op); } @@ -1553,6 +1572,7 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op) void cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) { + _emit_line_info (); _emit_cairo_op (cr, "%g %g %g rgb set_source\n", red, green, blue); return DLCALL (cairo_set_source_rgb, cr, red, green, blue); } @@ -1560,6 +1580,7 @@ cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) void cairo_set_source_rgba (cairo_t *cr, double red, double green, double blue, double alpha) { + _emit_line_info (); _emit_cairo_op (cr, "%g %g %g %g rgba set_source\n", red, green, blue, alpha); return DLCALL (cairo_set_source_rgba, cr, red, green, blue, alpha); @@ -1628,6 +1649,7 @@ _emit_source_image_rectangle (cairo_surface_t *surface, void cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y) { + _emit_line_info (); if (cr != NULL && surface != NULL && _write_lock ()) { if (_is_current (SURFACE, surface, 0) && _is_current (CONTEXT, cr, 1)) @@ -1662,6 +1684,7 @@ cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, doubl void cairo_set_source (cairo_t *cr, cairo_pattern_t *source) { + _emit_line_info (); if (cr != NULL && source != NULL && _write_lock ()) { if (_is_current (PATTERN, source, 0) && _is_current (CONTEXT, cr, 1)) @@ -1707,6 +1730,7 @@ cairo_get_source (cairo_t *cr) void cairo_set_tolerance (cairo_t *cr, double tolerance) { + _emit_line_info (); _emit_cairo_op (cr, "%g set_tolerance\n", tolerance); return DLCALL (cairo_set_tolerance, cr, tolerance); } @@ -1726,6 +1750,7 @@ _antialias_to_string (cairo_antialias_t antialias) void cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) { + _emit_line_info (); _emit_cairo_op (cr, "//%s set_antialias\n", _antialias_to_string (antialias)); return DLCALL (cairo_set_antialias, cr, antialias); @@ -1744,6 +1769,7 @@ _fill_rule_to_string (cairo_fill_rule_t rule) void cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) { + _emit_line_info (); _emit_cairo_op (cr, "//%s set_fill_rule\n", _fill_rule_to_string (fill_rule)); return DLCALL (cairo_set_fill_rule, cr, fill_rule); @@ -1752,6 +1778,7 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) void cairo_set_line_width (cairo_t *cr, double width) { + _emit_line_info (); _emit_cairo_op (cr, "%g set_line_width\n", width); return DLCALL (cairo_set_line_width, cr, width); } @@ -1770,6 +1797,7 @@ _line_cap_to_string (cairo_line_cap_t line_cap) void cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) { + _emit_line_info (); _emit_cairo_op (cr, "//%s set_line_cap\n", _line_cap_to_string (line_cap)); return DLCALL (cairo_set_line_cap, cr, line_cap); } @@ -1788,6 +1816,7 @@ _line_join_to_string (cairo_line_join_t line_join) void cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join) { + _emit_line_info (); _emit_cairo_op (cr, "//%s set_line_join\n", _line_join_to_string (line_join)); return DLCALL (cairo_set_line_join, cr, line_join); @@ -1796,6 +1825,7 @@ cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join) void cairo_set_dash (cairo_t *cr, const double *dashes, int num_dashes, double offset) { + _emit_line_info (); if (cr != NULL && _write_lock ()) { int n; @@ -1818,6 +1848,7 @@ cairo_set_dash (cairo_t *cr, const double *dashes, int num_dashes, double offset void cairo_set_miter_limit (cairo_t *cr, double limit) { + _emit_line_info (); _emit_cairo_op (cr, "%g set_miter_limit\n", limit); return DLCALL (cairo_set_miter_limit, cr, limit); } @@ -1825,6 +1856,7 @@ cairo_set_miter_limit (cairo_t *cr, double limit) void cairo_translate (cairo_t *cr, double tx, double ty) { + _emit_line_info (); _emit_cairo_op (cr, "%g %g translate\n", tx, ty); return DLCALL (cairo_translate, cr, tx, ty); } @@ -1832,6 +1864,7 @@ cairo_translate (cairo_t *cr, double tx, double ty) void cairo_scale (cairo_t *cr, double sx, double sy) { + _emit_line_info (); _emit_cairo_op (cr, "%g %g scale\n", sx, sy); return DLCALL (cairo_scale, cr, sx, sy); } @@ -1839,6 +1872,7 @@ cairo_scale (cairo_t *cr, double sx, double sy) void cairo_rotate (cairo_t *cr, double angle) { + _emit_line_info (); _emit_cairo_op (cr, "%g rotate\n", angle); return DLCALL (cairo_rotate, cr, angle); } @@ -1846,6 +1880,7 @@ cairo_rotate (cairo_t *cr, double angle) void cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) { + _emit_line_info (); _emit_cairo_op (cr, "[%g %g %g %g %g %g] transform\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, @@ -1856,6 +1891,7 @@ cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) void cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { + _emit_line_info (); if (_matrix_is_identity (matrix)) { _emit_cairo_op (cr, "identity set_matrix\n"); } else { @@ -1904,6 +1940,7 @@ cairo_get_group_target (cairo_t *cr) void cairo_identity_matrix (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "identity set_matrix\n"); return DLCALL (cairo_identity_matrix, cr); } @@ -1912,6 +1949,7 @@ cairo_identity_matrix (cairo_t *cr) void cairo_new_path (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "n "); return DLCALL (cairo_new_path, cr); } @@ -1998,6 +2036,7 @@ cairo_close_path (cairo_t *cr) void cairo_paint (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "paint\n"); DLCALL (cairo_paint, cr); } @@ -2005,6 +2044,7 @@ cairo_paint (cairo_t *cr) void cairo_paint_with_alpha (cairo_t *cr, double alpha) { + _emit_line_info (); _emit_cairo_op (cr, "%g paint_with_alpha\n", alpha); DLCALL (cairo_paint_with_alpha, cr, alpha); } @@ -2012,6 +2052,7 @@ cairo_paint_with_alpha (cairo_t *cr, double alpha) void cairo_mask (cairo_t *cr, cairo_pattern_t *pattern) { + _emit_line_info (); if (cr != NULL && pattern != NULL && _write_lock ()) { if (_is_current (PATTERN, pattern, 0) && _is_current (CONTEXT, cr, 1)) @@ -2038,6 +2079,7 @@ cairo_mask (cairo_t *cr, cairo_pattern_t *pattern) void cairo_mask_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y) { + _emit_line_info (); if (cr != NULL && surface != NULL && _write_lock ()) { if (_is_current (SURFACE, surface, 0) && _is_current (CONTEXT, cr, 1)) @@ -2069,6 +2111,7 @@ cairo_mask_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y) void cairo_stroke (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "stroke\n"); DLCALL (cairo_stroke, cr); } @@ -2076,6 +2119,7 @@ cairo_stroke (cairo_t *cr) void cairo_stroke_preserve (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "stroke+\n"); DLCALL (cairo_stroke_preserve, cr); } @@ -2083,6 +2127,7 @@ cairo_stroke_preserve (cairo_t *cr) void cairo_fill (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "fill\n"); DLCALL (cairo_fill, cr); } @@ -2090,6 +2135,7 @@ cairo_fill (cairo_t *cr) void cairo_fill_preserve (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "fill+\n"); DLCALL (cairo_fill_preserve, cr); } @@ -2097,6 +2143,7 @@ cairo_fill_preserve (cairo_t *cr) void cairo_copy_page (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "copy_page\n"); return DLCALL (cairo_copy_page, cr); } @@ -2104,6 +2151,7 @@ cairo_copy_page (cairo_t *cr) void cairo_show_page (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "show_page\n"); return DLCALL (cairo_show_page, cr); } @@ -2111,6 +2159,7 @@ cairo_show_page (cairo_t *cr) void cairo_clip (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "clip\n"); DLCALL (cairo_clip, cr); } @@ -2118,6 +2167,7 @@ cairo_clip (cairo_t *cr) void cairo_clip_preserve (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "clip+\n"); DLCALL (cairo_clip_preserve, cr); } @@ -2125,6 +2175,7 @@ cairo_clip_preserve (cairo_t *cr) void cairo_reset_clip (cairo_t *cr) { + _emit_line_info (); _emit_cairo_op (cr, "reset_clip\n"); return DLCALL (cairo_reset_clip, cr); } @@ -2154,6 +2205,7 @@ _weight_to_string (cairo_font_weight_t font_weight) void cairo_select_font_face (cairo_t *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { + _emit_line_info (); if (cr != NULL && _write_lock ()) { _emit_context (cr); _emit_string_literal (family, -1); @@ -2183,6 +2235,7 @@ cairo_get_font_face (cairo_t *cr) void cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face) { + _emit_line_info (); if (cr != NULL && font_face != NULL) { if (_pop_operands_to (FONT_FACE, font_face)) { if (_is_current (CONTEXT, cr, 1)) { @@ -2217,6 +2270,7 @@ cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face) void cairo_set_font_size (cairo_t *cr, double size) { + _emit_line_info (); _emit_cairo_op (cr, "%g set_font_size\n", size); return DLCALL (cairo_set_font_size, cr, size); } @@ -2224,6 +2278,7 @@ cairo_set_font_size (cairo_t *cr, double size) void cairo_set_font_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { + _emit_line_info (); _emit_cairo_op (cr, "[%g %g %g %g %g %g] set_font_matrix\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, @@ -2303,6 +2358,7 @@ _emit_font_options (const cairo_font_options_t *options) void cairo_set_font_options (cairo_t *cr, const cairo_font_options_t *options) { + _emit_line_info (); if (cr != NULL && options != NULL && _write_lock ()) { _emit_context (cr); _emit_font_options (options); @@ -2332,6 +2388,7 @@ cairo_get_scaled_font (cairo_t *cr) void cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font) { + _emit_line_info (); if (cr != NULL && scaled_font != NULL) { if (_pop_operands_to (SCALED_FONT, scaled_font)) { if (_is_current (CONTEXT, cr, 1)) { @@ -2393,6 +2450,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, ret = DLCALL (cairo_scaled_font_create, font_face, font_matrix, ctm, options); scaled_font_id = _create_scaled_font_id (ret); + _emit_line_info (); if (font_face != NULL && font_matrix != NULL && ctm != NULL && @@ -2427,6 +2485,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, void cairo_show_text (cairo_t *cr, const char *utf8) { + _emit_line_info (); if (cr != NULL && _write_lock ()) { _emit_context (cr); _emit_string_literal (utf8, -1); @@ -2528,8 +2587,9 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) { cairo_scaled_font_t *font; - font = cairo_get_scaled_font (cr); + font = DLCALL (cairo_get_scaled_font, cr); + _emit_line_info (); if (cr != NULL && glyphs != NULL && _write_lock ()) { _emit_context (cr); _emit_glyphs (font, glyphs, num_glyphs); @@ -2562,8 +2622,9 @@ cairo_show_text_glyphs (cairo_t *cr, { cairo_scaled_font_t *font; - font = cairo_get_scaled_font (cr); + font = DLCALL (cairo_get_scaled_font, cr); + _emit_line_info (); if (cr != NULL && glyphs != NULL && clusters != NULL && _write_lock ()) { int n; @@ -2594,6 +2655,7 @@ cairo_show_text_glyphs (cairo_t *cr, void cairo_text_path (cairo_t *cr, const char *utf8) { + _emit_line_info (); if (cr != NULL && _write_lock ()) { _emit_context (cr); _emit_string_literal (utf8, -1); @@ -2608,8 +2670,9 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) { cairo_scaled_font_t *font; - font = cairo_get_scaled_font (cr); + font = DLCALL (cairo_get_scaled_font, cr); + _emit_line_info (); if (cr != NULL && glyphs != NULL && _write_lock ()) { _emit_context (cr); _emit_glyphs (font, glyphs, num_glyphs); @@ -2628,6 +2691,7 @@ cairo_append_path (cairo_t *cr, const cairo_path_t *path) int i; cairo_path_data_t *p; + _emit_line_info (); if (cr == NULL || path == NULL) return DLCALL (cairo_append_path, cr, path); @@ -2671,6 +2735,7 @@ cairo_image_surface_create (cairo_format_t format, int width, int height) surface_id = _create_surface_id (ret); format_str = _format_to_string (format); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -2698,7 +2763,8 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, ret = DLCALL (cairo_image_surface_create_for_data, data, format, width, height, stride); surface_id = _create_surface_id (ret); - if (data != NULL && _write_lock ()) { + _emit_line_info (); + if (_write_lock ()) { /* cairo_image_surface_create_for_data() is both used to supply * foreign pixel data to cairo and in order to read pixels back. * Defer grabbing the pixel contents until we have to, but only for @@ -2746,6 +2812,7 @@ cairo_surface_create_similar (cairo_surface_t *other, ret = DLCALL (cairo_surface_create_similar, other, content, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (other != NULL && _write_lock ()) { other_id = _get_surface_id (other); @@ -2791,18 +2858,21 @@ _emit_surface_op (cairo_surface_t *surface, const char *fmt, ...) void cairo_surface_finish (cairo_surface_t *surface) { + _emit_line_info (); return DLCALL (cairo_surface_finish, surface); } void cairo_surface_flush (cairo_surface_t *surface) { + _emit_line_info (); return DLCALL (cairo_surface_flush, surface); } void cairo_surface_mark_dirty (cairo_surface_t *surface) { + _emit_line_info (); if (surface != NULL && _write_lock ()) { _emit_surface (surface); fprintf (logfile, "%% mark_dirty\n"); @@ -2817,6 +2887,7 @@ void cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, int x, int y, int width, int height) { + _emit_line_info (); if (surface != NULL && _write_lock ()) { _emit_surface (surface); fprintf (logfile, "%% %d %d %d %d mark_dirty_rectangle\n", @@ -2831,6 +2902,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, void cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, double y_offset) { + _emit_line_info (); _emit_surface_op (surface, "%g %g set_device_offset\n", x_offset, y_offset); return DLCALL (cairo_surface_set_device_offset, surface, x_offset, y_offset); @@ -2839,6 +2911,7 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, doub void cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels_per_inch, double y_pixels_per_inch) { + _emit_line_info (); _emit_surface_op (surface, "%g %g set_fallback_resolution\n", x_pixels_per_inch, y_pixels_per_inch); return DLCALL (cairo_surface_set_fallback_resolution, surface, x_pixels_per_inch, y_pixels_per_inch); @@ -2847,6 +2920,7 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels void cairo_surface_copy_page (cairo_surface_t *surface) { + _emit_line_info (); _emit_surface_op (surface, "copy_page\n"); return DLCALL (cairo_surface_copy_page, surface); } @@ -2854,6 +2928,7 @@ cairo_surface_copy_page (cairo_surface_t *surface) void cairo_surface_show_page (cairo_surface_t *surface) { + _emit_line_info (); _emit_surface_op (surface, "show_page\n"); return DLCALL (cairo_surface_show_page, surface); } @@ -2866,6 +2941,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, cairo_destroy_func_t destroy, void *closure) { + _emit_line_info (); if (surface != NULL && _write_lock ()) { _emit_surface (surface); _emit_string_literal (mime_type, -1); @@ -2887,6 +2963,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, cairo_status_t cairo_surface_write_to_png (cairo_surface_t *surface, const char *filename) { + _emit_line_info (); if (surface != NULL && _write_lock ()) { fprintf (logfile, "%% s%ld ", _get_surface_id (surface)); _emit_string_literal (filename, -1); @@ -2901,6 +2978,7 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface, cairo_write_func_t write_func, void *data) { + _emit_line_info (); if (surface != NULL && _write_lock ()) { char symbol[1024]; @@ -2940,6 +3018,7 @@ cairo_pattern_create_rgb (double red, double green, double blue) ret = DLCALL (cairo_pattern_create_rgb, red, green, blue); pattern_id = _create_pattern_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "/p%ld %g %g %g rgb def\n", pattern_id, red, green, blue); @@ -2959,6 +3038,7 @@ cairo_pattern_create_rgba (double red, double green, double blue, double alpha) ret = DLCALL (cairo_pattern_create_rgba, red, green, blue, alpha); pattern_id = _create_pattern_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "/p%ld %g %g %g %g rgba def\n", pattern_id, red, green, blue, alpha); @@ -2979,6 +3059,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) ret = DLCALL (cairo_pattern_create_for_surface, surface); pattern_id = _create_pattern_id (ret); + _emit_line_info (); if (surface != NULL && _write_lock ()) { surface_id = _get_surface_id (surface); @@ -3008,6 +3089,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1) ret = DLCALL (cairo_pattern_create_linear, x0, y0, x1, y1); pattern_id = _create_pattern_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "%g %g %g %g linear %% p%ld\n", @@ -3030,6 +3112,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, cx1, cy1, radius1); pattern_id = _create_pattern_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "%g %g %g %g %g %g radial %% p%ld\n", @@ -3045,6 +3128,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, void cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, double green, double blue) { + _emit_line_info (); _emit_pattern_op (pattern, "%g %g %g %g 1 add_color_stop\n", offset, red, green, blue); @@ -3054,6 +3138,7 @@ cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, doubl void cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha) { + _emit_line_info (); _emit_pattern_op (pattern, "%g %g %g %g %g add_color_stop\n", offset, red, green, blue, alpha); @@ -3063,6 +3148,7 @@ cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, doub void cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix) { + _emit_line_info (); if (_matrix_is_identity (matrix)) { _emit_pattern_op (pattern, "identity set_matrix\n"); } else { @@ -3092,6 +3178,7 @@ _filter_to_string (cairo_filter_t filter) void cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) { + _emit_line_info (); _emit_pattern_op (pattern, "//%s set_filter\n", _filter_to_string (filter)); return DLCALL (cairo_pattern_set_filter, pattern, filter); } @@ -3111,6 +3198,7 @@ _extend_to_string (cairo_extend_t extend) void cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) { + _emit_line_info (); _emit_pattern_op (pattern, "//%s set_extend\n", _extend_to_string (extend)); return DLCALL (cairo_pattern_set_extend, pattern, extend); } @@ -3125,6 +3213,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) ret = DLCALL (cairo_ft_font_face_create_for_pattern, pattern); font_face_id = _create_font_face_id (ret); + _emit_line_info (); if (pattern != NULL && _write_lock ()) { FcChar8 *parsed; @@ -3179,6 +3268,7 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags) if (data == NULL) return ret; + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3311,6 +3401,7 @@ cairo_ps_surface_create (const char *filename, double width_in_points, double he ret = DLCALL (cairo_ps_surface_create, filename, width_in_points, height_in_points); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3343,6 +3434,7 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure ret = DLCALL (cairo_ps_surface_create_for_stream, write_func, closure, width_in_points, height_in_points); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3365,6 +3457,7 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure void cairo_ps_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points) { + _emit_line_info (); return DLCALL (cairo_ps_surface_set_size, surface, width_in_points, height_in_points); } @@ -3382,6 +3475,7 @@ cairo_pdf_surface_create (const char *filename, double width_in_points, double h ret = DLCALL (cairo_pdf_surface_create, filename, width_in_points, height_in_points); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3414,6 +3508,7 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closur ret = DLCALL (cairo_pdf_surface_create_for_stream, write_func, closure, width_in_points, height_in_points); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3435,6 +3530,7 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closur void cairo_pdf_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points) { + _emit_line_info (); return DLCALL (cairo_pdf_surface_set_size, surface, width_in_points, height_in_points); } #endif @@ -3451,6 +3547,7 @@ cairo_svg_surface_create (const char *filename, double width, double height) ret = DLCALL (cairo_svg_surface_create, filename, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3483,6 +3580,7 @@ cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, void *closur ret = DLCALL (cairo_svg_surface_create_for_stream, write_func, closure, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3514,6 +3612,7 @@ cairo_image_surface_create_from_png (const char *filename) surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { char filename_string[4096]; @@ -3542,6 +3641,7 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *c ret = DLCALL (cairo_image_surface_create_from_png_stream, read_func, closure); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { _emit_image (ret, NULL); fprintf (logfile, @@ -3573,6 +3673,7 @@ cairo_xlib_surface_create (Display *dpy, dpy, drawable, visual, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3609,6 +3710,7 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, dpy, bitmap, screen, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3649,6 +3751,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, dpy, drawable, screen, format, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3689,6 +3792,7 @@ cairo_script_surface_create (const char *filename, ret = DLCALL (cairo_script_surface_create, filename, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3725,6 +3829,7 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func, write_func, data, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3758,6 +3863,7 @@ _cairo_test_fallback_surface_create (cairo_content_t content, ret = DLCALL (_cairo_test_fallback_surface_create, content, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" @@ -3794,6 +3900,7 @@ _cairo_test_paginated_surface_create_for_data (unsigned char *data, data, content, width, height, stride); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { /* XXX store initial data? */ fprintf (logfile, @@ -3829,6 +3936,7 @@ _cairo_test_meta_surface_create (cairo_content_t content, ret = DLCALL (_cairo_test_meta_surface_create, content, width, height); surface_id = _create_surface_id (ret); + _emit_line_info (); if (_write_lock ()) { fprintf (logfile, "dict\n" -- cgit v1.2.3 From cebc84f367a81eedebf7ab0b6b082691923c3ef7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 8 Nov 2008 00:06:38 +0000 Subject: [hash] Separate out unique patterns of iterating over the table. Avoid unnecessary conditionals for the hotpaths by separating out the iteration over the elements into their distinct modes. --- src/cairo-font-face.c | 2 +- src/cairo-hash.c | 185 ++++++++++++++++++++++-------------------------- src/cairo-scaled-font.c | 11 +-- 3 files changed, 93 insertions(+), 105 deletions(-) diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c index f9a838ae..eb4921e3 100644 --- a/src/cairo-font-face.c +++ b/src/cairo-font-face.c @@ -511,7 +511,7 @@ 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; } diff --git a/src/cairo-hash.c b/src/cairo-hash.c index 5b2704f2..78ea56bc 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -108,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 } @@ -205,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; } /** @@ -298,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. */ @@ -335,11 +285,8 @@ _cairo_hash_table_resize (cairo_hash_table_t *hash_table) 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]; } } @@ -366,11 +313,34 @@ _cairo_hash_table_lookup (cairo_hash_table_t *hash_table, cairo_hash_entry_t *key) { cairo_hash_entry_t **entry; + unsigned long table_size, i, idx, step; + + table_size = hash_table->arrangement->size; + idx = key->hash % table_size; + entry = &hash_table->entries[idx]; - /* 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)) - return *entry; + if (ENTRY_IS_LIVE (*entry)) { + if (hash_table->keys_equal (key, *entry)) + return *entry; + } else if (ENTRY_IS_FREE (*entry)) + return NULL; + + 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; } @@ -458,40 +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, - TRUE); - /* _cairo_hash_table_lookup_internal with key_unique = TRUE - * aways returns an available entry. */ - assert (! ENTRY_IS_LIVE(*entry)); - - *entry = key_and_value; hash_table->live_entries++; - status = _cairo_hash_table_resize (hash_table); - if (status) { + if (_cairo_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. @@ -500,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-scaled-font.c b/src/cairo-scaled-font.c index af217c6c..aa1a2c8a 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -476,7 +476,7 @@ _cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t 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); @@ -817,7 +817,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; } else @@ -876,7 +877,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; } } @@ -1035,7 +1037,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], -- cgit v1.2.3 From 9afad537301529a5a4b4ddf8b7e4425002ea39c7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Nov 2008 10:22:17 +0000 Subject: [test] Expand in-fill-trapezoid Test vertices and edges of a rectangle to probe 'corner-cases', using the insideness conditions from flash. --- test/in-fill-trapezoid.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/in-fill-trapezoid.c b/test/in-fill-trapezoid.c index 717a87a0..57429687 100644 --- a/test/in-fill-trapezoid.c +++ b/test/in-fill-trapezoid.c @@ -42,6 +42,40 @@ draw (cairo_t *cr, int width, int height) ret = CAIRO_TEST_FAILURE; } + /* rectangular boundary tests */ + if (cairo_in_fill (cr, -10, -10)) { + cairo_test_log (ctx, "Error: Found top-left vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (cairo_in_fill (cr, -10, 10)) { + cairo_test_log (ctx, "Error: Found bottom-left vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 10, -10)) { + cairo_test_log (ctx, "Error: Failed to find top-right vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (cairo_in_fill (cr, 10, 10)) { + cairo_test_log (ctx, "Error: Found bottom-right vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (cairo_in_fill (cr, -10, 0)) { + cairo_test_log (ctx, "Error: Found left edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 0, -10)) { + cairo_test_log (ctx, "Error: Failed to find top edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 10, 0)) { + cairo_test_log (ctx, "Error: Failed to find right edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (cairo_in_fill (cr, 0, 10)) { + cairo_test_log (ctx, "Error: Found bottom edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + /* simple circle */ cairo_new_path (cr); cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); -- cgit v1.2.3 From 20fc2a2f92e27082a8806b9acb4b904dc84da672 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Nov 2008 11:35:14 +0000 Subject: [in-fill] Fixup boundary insideness testing Benjamin Otte noticed that the top-left vertex was now included within the fill extents. Having updated the test case to check the insideness conditions as defined by flash, fix the edge handling to match. --- src/cairo-path-in-fill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c index f9920eaf..fcac9b13 100644 --- a/src/cairo-path-in-fill.c +++ b/src/cairo-path-in-fill.c @@ -121,7 +121,7 @@ _cairo_in_fill_add_edge (cairo_in_fill_t *in_fill, return; /* edge lies wholly to the right */ - if (p1->x > in_fill->x && p2->x > in_fill->x) + if (p1->x >= in_fill->x && p2->x >= in_fill->x) return; if ((p1->x <= in_fill->x && p2->x <= in_fill->x) || -- cgit v1.2.3 From b06c50cc54140a662adacde6336a3e7777f26ac3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 11:21:26 +0000 Subject: [cairoint.h] Remove unused PLT entries. Trim the slim_hidden_proto/def to match the currently used functions. --- src/cairo-pattern.c | 1 - src/cairo.c | 3 --- src/cairoint.h | 16 ++++++---------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 9d476cde..610ba61b 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -686,7 +686,6 @@ cairo_pattern_get_type (cairo_pattern_t *pattern) { return pattern->type; } -slim_hidden_def (cairo_pattern_get_type); /** * cairo_pattern_status: diff --git a/src/cairo.c b/src/cairo.c index 2a9f7465..56f99e49 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -414,7 +414,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: @@ -597,7 +596,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: @@ -1918,7 +1916,6 @@ cairo_path_extents (cairo_t *cr, if (status) _cairo_set_error (cr, status); } -slim_hidden_def (cairo_path_extents); /** * cairo_paint: diff --git a/src/cairoint.h b/src/cairoint.h index fb8bf180..6101ea55 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -2458,6 +2458,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); @@ -2471,7 +2472,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); @@ -2488,19 +2488,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); @@ -2513,23 +2509,23 @@ 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_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); @@ -2538,16 +2534,16 @@ 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_set_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); -- cgit v1.2.3 From 0769d39d0093ec3bff5b72ecbfcef1bae2f03be2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 11:13:22 +0000 Subject: Add predicate likelihood macros. Define the couple of standard macros that we can use to guide gcc optimisations of which code path will be most likely taken. --- src/cairo-compiler-private.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h index b93fd829..76b8e801 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 _cairo_likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1)) +#define _cairo_unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0)) +#else +#define _cairo_likely(expr) (expr) +#define _cairo_unlikely(expr) (expr) +#endif + #ifndef __GNUC__ #undef __attribute__ #define __attribute__(x) -- cgit v1.2.3 From 47a56e08501ec9375f75c15e35a68c77b313ada4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 10 Sep 2008 16:51:52 +0100 Subject: [type1] Bind the RD procedure As the RD procedure may be called several hundred times for a full font, it is worth binding. --- src/cairo-type1-fallback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c index 83ddc448..1f39a3f0 100644 --- a/src/cairo-type1-fallback.c +++ b/src/cairo-type1-fallback.c @@ -590,7 +590,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" -- cgit v1.2.3 From a856371bef496da0e84226f4fd2fc3cb72e955ac Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Nov 2008 10:45:34 +0000 Subject: Add CairoScript backend. A new meta-surface backend for serialising drawing operations to a CairoScript file. The principal use (as currently envisaged) is to provide a round-trip testing mechanism for CairoScript - i.e. we can generate script files for every test in the suite and check that we can replay them with perfect fidelity. (Obviously this does not provide complete coverage of CairoScript's syntax, but should give reasonable coverage over the operators.) --- boilerplate/Makefile.sources | 3 + boilerplate/cairo-boilerplate-script-private.h | 57 + boilerplate/cairo-boilerplate-script.c | 125 ++ boilerplate/cairo-boilerplate.c | 16 + build/configure.ac.features | 2 + configure.ac | 16 + doc/public/tmpl/cairo-surface.sgml | 1 + src/Makefile.sources | 3 + src/cairo-base85-stream.c | 1 + src/cairo-cache-private.h | 2 +- src/cairo-cache.c | 41 +- src/cairo-deflate-stream.c | 1 + src/cairo-ft-font.c | 12 + src/cairo-ft-private.h | 3 + src/cairo-gstate.c | 3 +- src/cairo-output-stream-private.h | 19 +- src/cairo-output-stream.c | 43 +- src/cairo-path-fixed-private.h | 11 + src/cairo-path-fixed.c | 164 ++ src/cairo-pattern.c | 255 +++ src/cairo-pdf-operators.c | 1 + src/cairo-ps-surface.c | 2 + src/cairo-scaled-font-private.h | 9 +- src/cairo-scaled-font.c | 5 + src/cairo-script-surface.c | 2598 ++++++++++++++++++++++++ src/cairo-script.h | 74 + src/cairo-types-private.h | 1 + src/cairo.h | 4 +- src/cairoint.h | 18 + test/Makefile.am | 4 +- test/any2ppm.c | 87 +- test/mime-data.script.ref.png | Bin 0 -> 1982 bytes 32 files changed, 3540 insertions(+), 41 deletions(-) create mode 100644 boilerplate/cairo-boilerplate-script-private.h create mode 100644 boilerplate/cairo-boilerplate-script.c create mode 100644 src/cairo-script-surface.c create mode 100644 src/cairo-script.h create mode 100644 test/mime-data.script.ref.png diff --git a/boilerplate/Makefile.sources b/boilerplate/Makefile.sources index 44eeb39b..7be44672 100644 --- a/boilerplate/Makefile.sources +++ b/boilerplate/Makefile.sources @@ -36,6 +36,9 @@ cairo_boilerplate_ps_sources = cairo-boilerplate-ps.c cairo_boilerplate_quartz_private = cairo-boilerplate-quartz-private.h cairo_boilerplate_quartz_sources = cairo-boilerplate-quartz.c +cairo_boilerplate_script_private = cairo-boilerplate-script-private.h +cairo_boilerplate_script_sources = cairo-boilerplate-script.c + cairo_boilerplate_sdl_private = cairo-boilerplate-sdl-private.h cairo_boilerplate_sdl_sources = cairo-boilerplate-sdl.c diff --git a/boilerplate/cairo-boilerplate-script-private.h b/boilerplate/cairo-boilerplate-script-private.h new file mode 100644 index 00000000..480e4221 --- /dev/null +++ b/boilerplate/cairo-boilerplate-script-private.h @@ -0,0 +1,57 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#ifndef _CAIRO_BOILERPLATE_SCRIPT_PRIVATE_H_ +#define _CAIRO_BOILERPLATE_SCRIPT_PRIVATE_H_ + +cairo_surface_t * +_cairo_boilerplate_script_create_surface (const char *name, + cairo_content_t content, + int width, + int height, + int max_width, + int max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure); + +cairo_status_t +_cairo_boilerplate_script_finish_surface (cairo_surface_t *surface); + +cairo_status_t +_cairo_boilerplate_script_surface_write_to_png (cairo_surface_t *surface, + const char *filename); + +cairo_surface_t * +_cairo_boilerplate_script_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height); + +void +_cairo_boilerplate_script_cleanup (void *closure); + +#endif diff --git a/boilerplate/cairo-boilerplate-script.c b/boilerplate/cairo-boilerplate-script.c new file mode 100644 index 00000000..ae08cbc5 --- /dev/null +++ b/boilerplate/cairo-boilerplate-script.c @@ -0,0 +1,125 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-boilerplate.h" +#include "cairo-boilerplate-script-private.h" + +#include "cairo-script.h" + +cairo_user_data_key_t script_closure_key; + +typedef struct _script_target_closure { + char *filename; + int width; + int height; +} script_target_closure_t; + +cairo_surface_t * +_cairo_boilerplate_script_create_surface (const char *name, + cairo_content_t content, + int width, + int height, + int max_width, + int max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure) +{ + script_target_closure_t *ptc; + cairo_surface_t *surface; + cairo_status_t status; + + *closure = ptc = xmalloc (sizeof (script_target_closure_t)); + + ptc->width = width; + ptc->height = height; + + xasprintf (&ptc->filename, "%s.out.cs", name); + xunlink (ptc->filename); + + surface = cairo_script_surface_create (ptc->filename, width, height); + + status = cairo_surface_set_user_data (surface, + &script_closure_key, ptc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + free (ptc->filename); + free (ptc); + return surface; +} + +cairo_status_t +_cairo_boilerplate_script_finish_surface (cairo_surface_t *surface) +{ + cairo_surface_finish (surface); + return cairo_surface_status (surface); +} + +cairo_status_t +_cairo_boilerplate_script_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + return CAIRO_STATUS_WRITE_ERROR; +} + +static cairo_surface_t * +_cairo_boilerplate_script_convert_to_image (cairo_surface_t *surface, + int page) +{ + script_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &script_closure_key); + return cairo_boilerplate_convert_to_image (ptc->filename, page); +} + +cairo_surface_t * +_cairo_boilerplate_script_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height) +{ + cairo_surface_t *image; + + image = _cairo_boilerplate_script_convert_to_image (surface, page); + cairo_surface_set_device_offset (image, + cairo_image_surface_get_width (image) - width, + cairo_image_surface_get_height (image) - height); + surface = _cairo_boilerplate_get_image_surface (image, 0, width, height); + cairo_surface_destroy (image); + + return surface; +} + +void +_cairo_boilerplate_script_cleanup (void *closure) +{ + script_target_closure_t *ptc = closure; + free (ptc->filename); + free (ptc); +} diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c index b12b6d6a..f6f68f9c 100644 --- a/boilerplate/cairo-boilerplate.c +++ b/boilerplate/cairo-boilerplate.c @@ -47,6 +47,9 @@ #if CAIRO_HAS_QUARTZ_SURFACE #include "cairo-boilerplate-quartz-private.h" #endif +#if CAIRO_HAS_SCRIPT_SURFACE +#include "cairo-boilerplate-script-private.h" +#endif #if CAIRO_HAS_SDL_SURFACE #include "cairo-boilerplate-sdl-private.h" #endif @@ -603,6 +606,19 @@ static cairo_boilerplate_target_t targets[] = NULL, TRUE, TRUE }, #endif +#if CAIRO_HAS_SCRIPT_SURFACE + { + "script", "script", ".cs", + CAIRO_SURFACE_TYPE_SCRIPT, CAIRO_CONTENT_COLOR_ALPHA, 0, + _cairo_boilerplate_script_create_surface, + NULL, + _cairo_boilerplate_script_finish_surface, + _cairo_boilerplate_script_get_image_surface, + _cairo_boilerplate_script_surface_write_to_png, + _cairo_boilerplate_script_cleanup, + NULL, FALSE + }, +#endif #if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE /* It seems we should be able to round-trip SVG content perfectly * through librsvg and cairo, but for some mysterious reason, some diff --git a/build/configure.ac.features b/build/configure.ac.features index 9fa7086a..9970fde0 100644 --- a/build/configure.ac.features +++ b/build/configure.ac.features @@ -367,6 +367,7 @@ AC_DEFUN([CAIRO_REPORT], echo " XCB: $use_xcb" echo " Win32: $use_win32" echo " OS2: $use_os2" + echo " CairoScript: $use_script" echo " PostScript: $use_ps" echo " PDF: $use_pdf" echo " SVG: $use_svg" @@ -389,6 +390,7 @@ AC_DEFUN([CAIRO_REPORT], echo " test surfaces: $use_test_surfaces" echo " ps testing: $test_ps" echo " pdf testing: $test_pdf" + echo " cs testing: $test_script" echo " svg testing: $test_svg" if test x"$use_win32" = "xyes"; then echo " win32 printing testing: $test_win32_printing" diff --git a/configure.ac b/configure.ac index b13f34ff..a307493c 100644 --- a/configure.ac +++ b/configure.ac @@ -236,6 +236,22 @@ CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [ dnl =========================================================================== +CAIRO_ENABLE_SURFACE_BACKEND(script, script, no, [ + test_script="yes" + csi_CFLAGS= + csi_LIBS=-lcairo-script-interpreter + if test "x$test_script" = "xyes"; then + AC_DEFINE([CAIRO_CAN_TEST_SCRIPT_SURFACE], 1, + [Define to 1 if the CairoScript backend can be tested]) + else + AC_MSG_WARN([CairoScript backend will not be tested]) + fi + AC_SUBST(csi_CFLAGS) + AC_SUBST(csi_LIBS) +]) + +dnl =========================================================================== + # We use pkg-config to look for freetype2, but fall back to # freetype-config if it fails. We prefer pkg-config, since we can # then just put freetype2 >= $FREETYPE_MIN_VERSION in diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml index 3a6cd8d9..93bfe083 100644 --- a/doc/public/tmpl/cairo-surface.sgml +++ b/doc/public/tmpl/cairo-surface.sgml @@ -194,6 +194,7 @@ cairo_backend_surface_create(). @CAIRO_SURFACE_TYPE_WIN32_PRINTING: @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: @CAIRO_SURFACE_TYPE_SDL: +@CAIRO_SURFACE_TYPE_SCRIPT: diff --git a/src/Makefile.sources b/src/Makefile.sources index 0b44bbf2..58781dd9 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -249,3 +249,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-base85-stream.c b/src/cairo-base85-stream.c index 88974039..4d5a4652 100644 --- a/src/cairo-base85-stream.c +++ b/src/cairo-base85-stream.c @@ -124,6 +124,7 @@ _cairo_base85_stream_create (cairo_output_stream_t *output) _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-cache-private.h b/src/cairo-cache-private.h index 6a9b8b8d..5ac8cc8b 100644 --- a/src/cairo-cache-private.h +++ b/src/cairo-cache-private.h @@ -118,7 +118,7 @@ _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 01e5713d..f5caba4b 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, @@ -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; } /** @@ -354,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-deflate-stream.c b/src/cairo-deflate-stream.c index bf2784a2..3bb884ca 100644 --- a/src/cairo-deflate-stream.c +++ b/src/cairo-deflate-stream.c @@ -128,6 +128,7 @@ _cairo_deflate_stream_create (cairo_output_stream_t *output) _cairo_output_stream_init (&stream->base, _cairo_deflate_stream_write, + NULL, _cairo_deflate_stream_close); stream->output = output; diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 7cae0467..4245448e 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -2739,6 +2739,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-gstate.c b/src/cairo-gstate.c index 1d532c71..33880d84 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1056,7 +1056,8 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) path, gstate->fill_rule, gstate->tolerance, - gstate->antialias, NULL); + gstate->antialias, + NULL); if (pattern == &pattern_stack.base) _cairo_pattern_fini (&pattern_stack.base); diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h index 6f10483f..2b3d584e 100644 --- a/src/cairo-output-stream-private.h +++ b/src/cairo-output-stream-private.h @@ -43,14 +43,20 @@ #include #include -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. */ diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c index c31c2da5..9a58aac2 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, @@ -148,7 +152,8 @@ _cairo_output_stream_create (cairo_write_func_t write_func, 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; @@ -173,12 +178,36 @@ _cairo_output_stream_create_in_error (cairo_status_t status) 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) { @@ -574,7 +603,8 @@ _cairo_output_stream_create_for_file (FILE *file) 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; @@ -608,7 +638,8 @@ _cairo_output_stream_create_for_filename (const char *filename) 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; @@ -650,7 +681,7 @@ _cairo_memory_stream_create (void) 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; @@ -727,7 +758,7 @@ _cairo_null_stream_create (void) 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-path-fixed-private.h b/src/cairo-path-fixed-private.h index 4a5990d4..43c33c18 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, @@ -77,4 +78,14 @@ 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); + #endif /* CAIRO_PATH_FIXED_PRIVATE_H */ diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 90861198..027ebedf 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -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) { diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 610ba61b..c78317eb 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -2293,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.c b/src/cairo-pdf-operators.c index 819318a1..f335a37e 100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -300,6 +300,7 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column) _cairo_output_stream_init (&stream->base, _word_wrap_stream_write, + NULL, _word_wrap_stream_close); stream->output = output; stream->max_column = max_column; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 99166510..f4431fa0 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -1740,6 +1740,7 @@ _string_array_stream_create (cairo_output_stream_t *output) _cairo_output_stream_init (&stream->base, _string_array_stream_write, + NULL, _string_array_stream_close); stream->output = output; stream->column = 0; @@ -1766,6 +1767,7 @@ _base85_array_stream_create (cairo_output_stream_t *output) _cairo_output_stream_init (&stream->base, _string_array_stream_write, + NULL, _string_array_stream_close); stream->output = output; stream->column = 0; 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.c b/src/cairo-scaled-font.c index aa1a2c8a..8b749940 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 */ @@ -691,6 +692,8 @@ _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); @@ -2210,6 +2213,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; diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c new file mode 100644 index 00000000..9118d66d --- /dev/null +++ b/src/cairo-script-surface.c @@ -0,0 +1,2598 @@ +/* -*- 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 + */ + +/* 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; mmap[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 (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 (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 (status) + return status; + + status = _emit_line_cap (surface, style->line_cap); + if (status) + return status; + + status = _emit_line_join (surface, style->line_join); + if (status) + return status; + + status = _emit_miter_limit (surface, style->miter_limit, force); + if (status) + return status; + + status = _emit_dash (surface, + style->dash, style->num_dashes, style->dash_offset, + force); + if (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 (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 (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 (status) { + cairo_surface_destroy (similar); + return status; + } + + status = _emit_context (surface); + if (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 (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 (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 (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 (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 (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 (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 (status) + return status; + + status = _emit_identity (surface, &matrix_updated); + if (status) + return status; + + status = _emit_pattern (surface, source); + if (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 (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 (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 (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 (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 (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 (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 (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 (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 (status) + return status; + + status = _emit_fill_rule (surface, fill_rule); + if (status) + return status; + + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (status) + return status; + + status = _emit_antialias (surface, antialias); + if (status) + return status; + + status = _emit_path (surface, path); + if (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 (status) + return status; + + status = _emit_operator (surface, op); + if (status) + return status; + + status = _emit_source (surface, op, source); + if (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 (status) + return status; + + status = _emit_operator (surface, op); + if (status) + return status; + + status = _emit_source (surface, op, source); + if (status) + return status; + + status = _emit_pattern (surface, mask); + if (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 (status) + return status; + + status = _emit_identity (surface, &matrix_updated); + if (status) + return status; + + status = _emit_path (surface, path); + if (status) + return status; + + status = _emit_source (surface, op, source); + if (status) + return status; + + status = _emit_matrix (surface, ctm, &matrix_updated); + if (status) + return status; + + status = _emit_operator (surface, op); + if (status) + return status; + + status = _emit_stroke_style (surface, style, matrix_updated); + if (status) + return status; + + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (status) + return status; + + status = _emit_antialias (surface, antialias); + if (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 (status) + return status; + + status = _emit_operator (surface, op); + if (status) + return status; + + status = _emit_identity (surface, &matrix_updated); + if (status) + return status; + + status = _emit_source (surface, op, source); + if (status) + return status; + + status = _emit_fill_rule (surface, fill_rule); + if (status) + return status; + + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (status) + return status; + + status = _emit_antialias (surface, antialias); + if (status) + return status; + + status = _emit_path (surface, path); + if (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 (status) + return status; + + buf = malloc (size); + if (buf == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL); + if (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 (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 (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 (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 (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 (status) + return status; + + cairo_scaled_font_get_font_options (scaled_font, &options); + status = _emit_font_options (surface, &options); + if (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 (status) + return status; + } else { + status = _emit_context (surface); + if (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 (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 (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 (status) + break; + + have_glyph_prologue = TRUE; + } + + status = _emit_scaled_glyph_vector (surface, + scaled_font, + scaled_glyph); + if (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 (status) + break; + + have_glyph_prologue = TRUE; + } + + status = _emit_scaled_glyph_bitmap (surface, + scaled_font, + scaled_glyph); + if (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 (status) + return status; + + status = _emit_operator (surface, op); + if (status) + return status; + + status = _emit_source (surface, op, source); + if (status) + return status; + + status = _emit_scaled_font (surface, scaled_font); + if (status) + return status; + + status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); + if (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 (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 (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 (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 (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 (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 */ + _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 (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 (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 (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 + */ + +#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-types-private.h b/src/cairo-types-private.h index 77f8184b..905bc401 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -44,6 +44,7 @@ #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; diff --git a/src/cairo.h b/src/cairo.h index 27d56f5a..33655232 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1876,6 +1876,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 @@ -1915,7 +1916,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 diff --git a/src/cairoint.h b/src/cairoint.h index 6101ea55..940e33c5 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -322,9 +322,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 +346,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 */ @@ -2386,6 +2394,16 @@ cairo_private cairo_status_t _cairo_pattern_get_extents (const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents); +cairo_private unsigned long +_cairo_pattern_hash (const cairo_pattern_t *pattern); + +cairo_private unsigned long +_cairo_pattern_size (const cairo_pattern_t *pattern); + +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); diff --git a/test/Makefile.am b/test/Makefile.am index 131ed603..498f6161 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1170,10 +1170,10 @@ png_flatten_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) if BUILD_ANY2PPM check_PROGRAMS += any2ppm -any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS) +any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS) $(csi_CFLAGS) # add LDADD, so poppler/librsvg uses "our" cairo any2ppm_LDFLAGS = $(CAIRO_TEST_UNDEFINED_LDFLAGS) -any2ppm_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS) +any2ppm_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS) $(csi_LIBS) endif if CAIRO_CAN_TEST_PDF_SURFACE diff --git a/test/any2ppm.c b/test/any2ppm.c index 85c1bdbb..1bd42858 100644 --- a/test/any2ppm.c +++ b/test/any2ppm.c @@ -63,6 +63,10 @@ #include +#if CAIRO_CAN_TEST_SCRIPT_SURFACE +#include +#endif + #if CAIRO_CAN_TEST_PDF_SURFACE #include #endif @@ -160,7 +164,21 @@ write_ppm (cairo_surface_t *surface, int fd) int width, height, stride; int i, j; + data = cairo_image_surface_get_data (surface); + height = cairo_image_surface_get_height (surface); + width = cairo_image_surface_get_width (surface); + stride = cairo_image_surface_get_stride (surface); format = cairo_image_surface_get_format (surface); + if (format == CAIRO_FORMAT_ARGB32) { + /* see if we can convert to a standard ppm type and trim a few bytes */ + cairo_bool_t uses_alpha = FALSE; + const unsigned char *alpha = data; + for (j = height * stride; j-- && uses_alpha == FALSE; alpha += 4) + uses_alpha = *alpha != 0xff; + if (! uses_alpha) + format = CAIRO_FORMAT_RGB24; + } + switch (format) { case CAIRO_FORMAT_ARGB32: /* XXX need true alpha for svg */ @@ -177,11 +195,6 @@ write_ppm (cairo_surface_t *surface, int fd) return "unhandled image format"; } - data = cairo_image_surface_get_data (surface); - height = cairo_image_surface_get_height (surface); - width = cairo_image_surface_get_width (surface); - stride = cairo_image_surface_get_stride (surface); - len = sprintf (buf, "%s %d %d 255\n", format_str, width, height); for (j = 0; j < height; j++) { const unsigned int *row = (unsigned int *) (data + stride * j); @@ -220,6 +233,69 @@ write_ppm (cairo_surface_t *surface, int fd) return NULL; } +#if CAIRO_CAN_TEST_SCRIPT_SURFACE +static cairo_surface_t * +_create_image (void *closure, + double width, double height, + csi_object_t *dictionary) +{ + cairo_surface_t **out = closure; + cairo_surface_t *surface; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + return *out = cairo_surface_reference (surface); +} + +static const char * +_cairo_script_render_page (const char *filename, + cairo_surface_t **surface_out) +{ + cairo_script_interpreter_t *csi; + cairo_surface_t *surface = NULL; + cairo_status_t status; + + csi = csi_create (); + csi_set_surface_create_function (csi, _create_image, &surface); + csi_run (csi, filename); + status = csi_destroy (csi); + if (status || surface == NULL) { + cairo_surface_destroy (surface); + return "cairo-script interpreter failed"; + } + + status = cairo_surface_status (surface); + if (status) { + cairo_surface_destroy (surface); + return cairo_status_to_string (status); + } + + *surface_out = surface; + return NULL; +} + +static const char * +cs_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _cairo_script_render_page (argv[0], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +cs_convert (char **argv, int fd) +{ + return "compiled without CairoScript support."; +} +#endif + #if CAIRO_CAN_TEST_PDF_SURFACE /* adapted from pdf2png.c */ static const char * @@ -453,6 +529,7 @@ convert (char **argv, int fd) const char *type; const char *(*func) (char **, int); } converters[] = { + { "cs", cs_convert }, { "pdf", pdf_convert }, { "ps", ps_convert }, { "svg", svg_convert }, diff --git a/test/mime-data.script.ref.png b/test/mime-data.script.ref.png new file mode 100644 index 00000000..a236b044 Binary files /dev/null and b/test/mime-data.script.ref.png differ -- cgit v1.2.3 From cdfffc7420e005b2a7d1979feef8bd304183126c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 11:07:45 +0000 Subject: Add CairoScript interpreter Add a CairoScript interpreter library and use it to replay the test output for the CairoScript backend. The library is also used by the currently standalone Sphinx debugger [git://anongit.freedesktop.org/~ickle/sphinx]. The syntax/operator semantics are not yet finalized, but are expected to mature before the next stable release. --- configure.ac | 20 +- test/Makefile.am | 4 +- test/any2ppm.c | 41 +- util/Makefile.am | 2 +- util/cairo-script/COPYING | 17 + util/cairo-script/Makefile.am | 21 + util/cairo-script/cairo-script-file.c | 1018 +++++ util/cairo-script/cairo-script-hash.c | 448 ++ util/cairo-script/cairo-script-interpreter.c | 473 +++ util/cairo-script/cairo-script-interpreter.h | 104 + util/cairo-script/cairo-script-objects.c | 666 +++ util/cairo-script/cairo-script-operators.c | 5791 ++++++++++++++++++++++++++ util/cairo-script/cairo-script-private.h | 853 ++++ util/cairo-script/cairo-script-scanner.c | 1180 ++++++ util/cairo-script/cairo-script-stack.c | 196 + 15 files changed, 10801 insertions(+), 33 deletions(-) create mode 100644 util/cairo-script/COPYING create mode 100644 util/cairo-script/Makefile.am create mode 100644 util/cairo-script/cairo-script-file.c create mode 100644 util/cairo-script/cairo-script-hash.c create mode 100644 util/cairo-script/cairo-script-interpreter.c create mode 100644 util/cairo-script/cairo-script-interpreter.h create mode 100644 util/cairo-script/cairo-script-objects.c create mode 100644 util/cairo-script/cairo-script-operators.c create mode 100644 util/cairo-script/cairo-script-private.h create mode 100644 util/cairo-script/cairo-script-scanner.c create mode 100644 util/cairo-script/cairo-script-stack.c diff --git a/configure.ac b/configure.ac index a307493c..9bc22e1d 100644 --- a/configure.ac +++ b/configure.ac @@ -236,18 +236,12 @@ CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [ dnl =========================================================================== +any2ppm_cs=no CAIRO_ENABLE_SURFACE_BACKEND(script, script, no, [ - test_script="yes" - csi_CFLAGS= - csi_LIBS=-lcairo-script-interpreter - if test "x$test_script" = "xyes"; then - AC_DEFINE([CAIRO_CAN_TEST_SCRIPT_SURFACE], 1, - [Define to 1 if the CairoScript backend can be tested]) - else - AC_MSG_WARN([CairoScript backend will not be tested]) - fi - AC_SUBST(csi_CFLAGS) - AC_SUBST(csi_LIBS) + test_script=yes + any2ppm_cs=yes + AC_DEFINE([CAIRO_CAN_TEST_SCRIPT_SURFACE], 1, + [Define to 1 if the CairoScript backend can be tested]) ]) dnl =========================================================================== @@ -494,7 +488,8 @@ dnl Build the external converter if we have any of the test backends AM_CONDITIONAL(BUILD_ANY2PPM, test "x$any2ppm_svg" = "xyes" \ -o "x$any2ppm_pdf" = "xyes" \ - -o "x$any2ppm_ps" = "xyes") + -o "x$any2ppm_ps" = "xyes" \ + -o "x$any2ppm_cs" = "xyes") dnl =========================================================================== dnl The tracing utility requires LD_PRELOAD, so only build it for systems @@ -558,6 +553,7 @@ test/Makefile test/pdiff/Makefile perf/Makefile util/Makefile +util/cairo-script/Makefile util/cairo-trace/Makefile util/cairo-trace/cairo-trace doc/Makefile diff --git a/test/Makefile.am b/test/Makefile.am index 498f6161..55179778 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1170,10 +1170,10 @@ png_flatten_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) if BUILD_ANY2PPM check_PROGRAMS += any2ppm -any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS) $(csi_CFLAGS) +any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS) # add LDADD, so poppler/librsvg uses "our" cairo any2ppm_LDFLAGS = $(CAIRO_TEST_UNDEFINED_LDFLAGS) -any2ppm_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS) $(csi_LIBS) +any2ppm_LDADD = $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS) endif if CAIRO_CAN_TEST_PDF_SURFACE diff --git a/test/any2ppm.c b/test/any2ppm.c index 1bd42858..c4cf085e 100644 --- a/test/any2ppm.c +++ b/test/any2ppm.c @@ -171,12 +171,15 @@ write_ppm (cairo_surface_t *surface, int fd) format = cairo_image_surface_get_format (surface); if (format == CAIRO_FORMAT_ARGB32) { /* see if we can convert to a standard ppm type and trim a few bytes */ - cairo_bool_t uses_alpha = FALSE; const unsigned char *alpha = data; - for (j = height * stride; j-- && uses_alpha == FALSE; alpha += 4) - uses_alpha = *alpha != 0xff; - if (! uses_alpha) - format = CAIRO_FORMAT_RGB24; + for (j = height; j--; alpha += stride) { + for (i = 0; i < width; i++) { + if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000) + goto done; + } + } + format = CAIRO_FORMAT_RGB24; + done: ; } switch (format) { @@ -236,14 +239,12 @@ write_ppm (cairo_surface_t *surface, int fd) #if CAIRO_CAN_TEST_SCRIPT_SURFACE static cairo_surface_t * _create_image (void *closure, - double width, double height, - csi_object_t *dictionary) + double width, double height) + //csi_object_t *dictionary) { cairo_surface_t **out = closure; - cairo_surface_t *surface; - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - return *out = cairo_surface_reference (surface); + *out = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + return cairo_surface_reference (*out); } static const char * @@ -253,17 +254,21 @@ _cairo_script_render_page (const char *filename, cairo_script_interpreter_t *csi; cairo_surface_t *surface = NULL; cairo_status_t status; + const cairo_script_interpreter_hooks_t hooks = { + .closure = &surface, + .surface_create = _create_image, + }; - csi = csi_create (); - csi_set_surface_create_function (csi, _create_image, &surface); - csi_run (csi, filename); - status = csi_destroy (csi); - if (status || surface == NULL) { - cairo_surface_destroy (surface); + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + cairo_script_interpreter_run (csi, filename); + status = cairo_script_interpreter_destroy (csi); + if (surface == NULL) { return "cairo-script interpreter failed"; } - status = cairo_surface_status (surface); + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface); if (status) { cairo_surface_destroy (surface); return cairo_status_to_string (status); diff --git a/util/Makefile.am b/util/Makefile.am index 42c831c9..f272e4c4 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/build/Makefile.am.common -SUBDIRS = . +SUBDIRS = . cairo-script if BUILD_TRACE SUBDIRS += cairo-trace diff --git a/util/cairo-script/COPYING b/util/cairo-script/COPYING new file mode 100644 index 00000000..66ad7840 --- /dev/null +++ b/util/cairo-script/COPYING @@ -0,0 +1,17 @@ +Cairo is free software. + +Every source file in the implementation of cairo is available to be +redistributed and/or modified under the terms of either the GNU Lesser +General Public License (LGPL) version 2.1 or the Mozilla Public +License (MPL) version 1.1. Some files are available under more +liberal terms, but we believe that in all cases, each file may be used +under either the LGPL or the MPL. + +See the following files in this directory for the precise terms and +conditions of either license: + + COPYING-LGPL-2.1 + COPYING-MPL-1.1 + +Please see each file in the implementation for copyright and licensing +information, (in the opening comment of each file). diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am new file mode 100644 index 00000000..348519f6 --- /dev/null +++ b/util/cairo-script/Makefile.am @@ -0,0 +1,21 @@ +lib_LTLIBRARIES = libcairo-script-interpreter.la + +cairoincludedir=$(includedir)/cairo +cairoinclude_HEADERS = cairo-script-interpreter.h +libcairo_script_interpreter_la_SOURCES = \ + cairo-script-private.h \ + cairo-script-file.c \ + cairo-script-hash.c \ + cairo-script-interpreter.c \ + cairo-script-objects.c \ + cairo-script-operators.c \ + cairo-script-scanner.c \ + cairo-script-stack.c \ + $(NULL) +libcairo_script_interpreter_la_CPPFLAGS = -I$(top_srcdir)/src +libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS) +libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols) +libcairo_script_interpreter_la_LIBADD = -lz $(CAIRO_LIBS) -L$(top_builddir)/src -lcairo + +EXTRA_DIST = \ + COPYING diff --git a/util/cairo-script/cairo-script-file.c b/util/cairo-script/cairo-script-file.c new file mode 100644 index 00000000..c21ef630 --- /dev/null +++ b/util/cairo-script/cairo-script-file.c @@ -0,0 +1,1018 @@ +/* + * 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 + */ + +#include "cairo-script-private.h" + +#include +#include +#include + +#define CHUNK_SIZE 32768 + +csi_status_t +csi_file_new (csi_t *ctx, + csi_object_t *obj, + const char *path, const char *mode) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->data = NULL; + file->type = STDIO; + file->src = fopen (path, mode); + if (file->src == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND); + } + + file->data = _csi_alloc (ctx, CHUNK_SIZE); + if (file->data == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + file->bp = file->data; + file->rem = 0; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_for_bytes (csi_t *ctx, + csi_object_t *obj, + const char *bytes, + unsigned int length) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->type = BYTES; + file->src = (uint8_t *) bytes; + file->data = (uint8_t *) bytes; + file->bp = (uint8_t *) bytes; + file->rem = length; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_from_string (csi_t *ctx, + csi_object_t *obj, + csi_string_t *src) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->type = BYTES; + file->src = src; src->base.ref++; + file->data = src->string; + file->bp = file->data; + file->rem = src->len; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +static csi_status_t +_csi_file_new_filter (csi_t *ctx, + csi_object_t *obj, + csi_object_t *src, + const csi_filter_funcs_t *funcs, + void *data) +{ + csi_file_t *file; + csi_object_t src_file; + csi_status_t status; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->type = FILTER; + file->data = data; + file->filter = funcs; + status = csi_object_as_file (ctx, src, &src_file); + if (status) { + csi_object_free (ctx, obj); + return status; + } + file->src = src_file.datum.file; + + return CAIRO_STATUS_SUCCESS; +} + + +#if 0 +csi_status_t +csi_file_new_from_stream (csi_t *ctx, + FILE *file, + csi_object_t **out) +{ + csi_file_t *obj; + + obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE); + if (obj == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + obj->type = STDIO; + obj->src = file; + obj->data = _csi_alloc (ctx, CHUNK_SIZE); + if (obj->data == NULL) { + csi_object_free (&obj->base); + return _csi_error (CAIRO_STATUS_UNDEFINED_FILENAME_ERROR); + } + obj->bp = obj->data; + obj->rem = 0; + + *out = &obj->base; + return CAIRO_STATUS_SUCCESS; +} + +static csi_object_t * +_csi_file_new_from_procedure (csi_t *ctx, csi_object_t *src) +{ + csi_file_t *obj; + + obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE); + if (obj == NULL) + return NULL; + + obj->type = PROCEDURE; + obj->src = csi_object_reference (src); + obj->data = NULL; + + return &obj->base; +} +#endif + +typedef struct _ascii85_decode_data { + uint8_t buf[CHUNK_SIZE]; + uint8_t *bp; + short bytes_available; + short eod; +} _ascii85_decode_data_t; + +static int +_getc_skip_whitespace (csi_file_t *src) +{ + int c; + + do switch ((c = csi_file_getc (src))) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + return c; + } while (TRUE); + + return c; +} + +static void +_ascii85_decode (csi_file_t *file) +{ + _ascii85_decode_data_t *data = file->data; + unsigned int n; + + if (data->eod) + return; + + data->bp = data->buf; + + n = 0; + do { + unsigned int v = _getc_skip_whitespace (file->src); + if (v == 'z') { + data->buf[n+0] = 0; + data->buf[n+1] = 0; + data->buf[n+2] = 0; + data->buf[n+3] = 0; + } else if (v == '~') { + v = _getc_skip_whitespace (file->src); + /* c == '>' || IO_ERROR */ + data->eod = TRUE; + break; + } else if (v < '!' || v > 'u') { + /* IO_ERROR */ + data->eod = TRUE; + break; + } else { + unsigned int i; + + v -= '!'; + for (i = 1; i < 5; i++) { + int c = _getc_skip_whitespace (file->src); + if (c == '~') { /* short tuple */ + c = _getc_skip_whitespace (file->src); + /* c == '>' || IO_ERROR */ + data->eod = TRUE; + switch (i) { + case 0: + case 1: + /* IO_ERROR */ + break; + case 2: + v = v * (85*85*85) + 85*85*85 -1; + goto odd1; + case 3: + v = v * (85*85) + 85*85 -1; + goto odd2; + case 4: + v = v * 85 + 84; + data->buf[n+2] = v >> 8 & 0xff; +odd2: + data->buf[n+1] = v >> 16 & 0xff; +odd1: + data->buf[n+0] = v >> 24 & 0xff; + data->bytes_available = n + i - 1; + return; + } + break; + } + v = 85*v + c-'!'; + } + + data->buf[n+0] = v >> 24 & 0xff; + data->buf[n+1] = v >> 16 & 0xff; + data->buf[n+2] = v >> 8 & 0xff; + data->buf[n+3] = v >> 0 & 0xff; + } + n += 4; + } while (n < sizeof (data->buf) && data->eod == FALSE); + + data->bytes_available = n; +} + +static int +_ascii85_decode_getc (csi_file_t *file) +{ + _ascii85_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _ascii85_decode (file); + + if (data->bytes_available == 0) + return EOF; + } + + data->bytes_available--; + return *data->bp++; +} + +static void +_ascii85_decode_putc (csi_file_t *file, int c) +{ + _ascii85_decode_data_t *data = file->data; + data->bytes_available++; + data->bp--; +} + +static int +_ascii85_decode_read (csi_file_t *file, uint8_t *buf, int len) +{ + _ascii85_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _ascii85_decode (file); + + if (data->bytes_available == 0) + return 0; + } + + if (len > data->bytes_available) + len = data->bytes_available; + memcpy (buf, data->bp, len); + data->bp += len; + data->bytes_available -= len; + return len; +} + +csi_status_t +csi_file_new_ascii85_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src) +{ + static const csi_filter_funcs_t funcs = { + _ascii85_decode_getc, + _ascii85_decode_putc, + _ascii85_decode_read, + _csi_free, + }; + _ascii85_decode_data_t *data; + + data = _csi_alloc0 (ctx, sizeof (_ascii85_decode_data_t)); + if (data == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + return _csi_file_new_filter (ctx, obj, src, &funcs, data); +} + +typedef struct _deflate_decode_data { + z_stream zlib_stream; + + uint8_t in[CHUNK_SIZE]; + uint8_t out[CHUNK_SIZE]; + + int bytes_available; + uint8_t *bp; +} _deflate_decode_data_t; + +static void +_deflate_decode (csi_file_t *file) +{ + _deflate_decode_data_t *data = file->data; + uint8_t *bp; + int len; + + data->zlib_stream.next_out = data->out; + data->zlib_stream.avail_out = sizeof (data->out); + + bp = data->in; + len = sizeof (data->in); + if (data->zlib_stream.avail_in) { + memmove (data->in, + data->zlib_stream.next_in, + data->zlib_stream.avail_in); + len -= data->zlib_stream.avail_in; + bp += data->zlib_stream.avail_in; + } + + len = csi_file_read (file->src, bp, len); + + data->zlib_stream.next_in = data->in; + data->zlib_stream.avail_in += len; + + inflate (&data->zlib_stream, len == 0 ? Z_FINISH : Z_NO_FLUSH); + + data->bytes_available = data->zlib_stream.next_out - data->out; + data->bp = data->out; +} + +static int +_deflate_decode_getc (csi_file_t *file) +{ + _deflate_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _deflate_decode (file); + + if (data->bytes_available == 0) + return EOF; + } + + data->bytes_available--; + return *data->bp++; +} + +static void +_deflate_decode_putc (csi_file_t *file, int c) +{ + _deflate_decode_data_t *data = file->data; + data->bytes_available++; + data->bp--; +} + +static int +_deflate_decode_read (csi_file_t *file, uint8_t *buf, int len) +{ + _deflate_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _deflate_decode (file); + + if (data->bytes_available == 0) + return 0; + } + + if (len > (int) data->bytes_available) + len = data->bytes_available; + memcpy (buf, data->bp, len); + data->bp += len; + data->bytes_available -= len; + return len; +} + +static void +_deflate_destroy (csi_t *ctx, void *closure) +{ + _deflate_decode_data_t *data; + + data = closure; + + inflateEnd (&data->zlib_stream); + + _csi_free (ctx, data); +} + +csi_status_t +csi_file_new_deflate_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src) +{ + static const csi_filter_funcs_t funcs = { + _deflate_decode_getc, + _deflate_decode_putc, + _deflate_decode_read, + _deflate_destroy, + }; + _deflate_decode_data_t *data; + + data = _csi_alloc (ctx, sizeof (_deflate_decode_data_t)); + if (data == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + data->zlib_stream.zalloc = Z_NULL; + data->zlib_stream.zfree = Z_NULL; + data->zlib_stream.opaque = Z_NULL; + data->zlib_stream.next_in = data->in; + data->zlib_stream.avail_in = 0; + data->zlib_stream.next_out = data->out; + data->zlib_stream.avail_out = sizeof (data->out); + data->bytes_available = 0; + + if (inflateInit (&data->zlib_stream) != Z_OK) { + _csi_free (ctx, data); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + + return _csi_file_new_filter (ctx, obj, src, &funcs, data); +} + +#if 0 +static int +hex_value (int c) +{ + if (c < '0') + return EOF; + if (c <= '9') + return c - '0'; + c |= 32; + if (c < 'a') + return EOF; + if (c <= 'f') + return c - 'a' + 0xa; + return EOF; +} + +/* Adobe Type 1 Font Format book: p63 */ +typedef struct _decrypt_data { + uint8_t putback[32]; + uint8_t nputback; + csi_bool_t is_hexadecimal; + unsigned short R; + int eod; +} _decrypt_data_t; + +static uint8_t +_decrypt (unsigned short *R, uint8_t cypher) +{ +#define c1 52845 +#define c2 22719 + uint8_t plain; + + plain = cypher ^ (*R >> 8); + *R = (cypher + *R) * c1 + c2; + return plain; +#undef c1 +#undef c2 +} + +int +csi_decrypt (uint8_t *in, int length, + unsigned short salt, int binary, + uint8_t *out) +{ + const uint8_t * const end = in + length; + uint8_t *base = out; + + while (in < end) { + int c; + + if (! binary) { + int c_hi = -1, c_lo = 0; + + while (in < end && (c_hi = *in++)) { + switch (c_hi) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + break; + } + } + if (c_hi < 0) + break; + + while (in < end && (c_lo = *in++)) { + switch (c_lo) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + break; + } + } + + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } else + c = *in++; + + *out++ = _decrypt (&salt, c); + } + + return out - base; +} + +static uint8_t +_encrypt (unsigned short *R, uint8_t plain) +{ +#define c1 52845 +#define c2 22719 + uint8_t cypher; + + cypher = plain ^ (*R >> 8); + *R = (cypher + *R) * c1 + c2; + return cypher; +#undef c1 +#undef c2 +} + +int +csi_encrypt (uint8_t *in, int length, + unsigned short salt, int discard, int binary, + uint8_t *out) +{ + const char hex[]="0123456789abcdef"; + const uint8_t * const end = in + length; + uint8_t *base = out; + int col = 0; + + while (discard--) { + if (! binary) { + int c = _encrypt (&salt, ' '); + *out++ = hex[(c >> 4) & 0xf]; + *out++ = hex[(c >> 0) & 0xf]; + } else + *out++ = _encrypt (&salt, 0); + } + + while (in < end) { + int c; + + c = _encrypt (&salt, *in++); + if (! binary) { + if (col == 78) { + *out++ = '\n'; + col = 0; + } + *out++ = hex[(c >> 4) & 0xf]; + *out++ = hex[(c >> 0) & 0xf]; + col += 2; + } else + *out++ = c; + } + + return out - base; +} + +static int +_decrypt_getc (csi_file_t *file) +{ + _decrypt_data_t *data = file->data; + int c; + + if (data->nputback) + return data->putback[--data->nputback]; + + if (data->is_hexadecimal) { + int c_hi, c_lo; + + c_hi = _getc_skip_whitespace (file->src); + c_lo = _getc_skip_whitespace (file->src); + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } else + c = csi_file_getc (file->src); + + if (c == EOF) + return EOF; + + return _decrypt (&data->R, c); +} + +static void +_decrypt_putc (csi_file_t *file, int c) +{ + _decrypt_data_t *data; + + data = file->data; + + data->putback[data->nputback++] = c; +} + +csi_object_t * +csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard) +{ + csi_object_t *obj; + _decrypt_data_t *data; + int n; + + data = _csi_alloc0 (ctx, sizeof (_decrypt_data_t)); + if (data == NULL) + return NULL; + + data->R = salt; + + obj = _csi_file_new_filter (ctx, src, + _decrypt_getc, + _decrypt_putc, + NULL, + _csi_free, + data); + if (obj == NULL) + return NULL; + + /* XXX determine encoding, eexec only? */ + data->is_hexadecimal = salt != 4330; + for (n = 0; n < discard; n++) { + int c; + c = csi_file_getc (obj); + if (c == EOF) { + return obj; + } + } + return obj; +} +#endif + +csi_status_t +_csi_file_execute (csi_t *ctx, csi_file_t *obj) +{ + return _csi_scan_file (ctx, &ctx->scanner, obj); +} + +int +csi_file_getc (csi_file_t *file) +{ + int c; + + if (_csi_unlikely (file->src == NULL)) + return EOF; + + switch (file->type) { + case STDIO: + if (_csi_likely (file->rem)) { + c = *file->bp++; + file->rem--; + } else { + file->rem = fread (file->bp = file->data, 1, CHUNK_SIZE, file->src); + case BYTES: + if (_csi_likely (file->rem)) { + c = *file->bp++; + file->rem--; + } else + c = EOF; + } + break; + + case PROCEDURE: +#if 0 + if (file->data == NULL) { + csi_status_t status; + csi_object_t *string; + +RERUN_PROCEDURE: + status = csi_object_execute (file->src); + if (status) + return EOF; + + string = csi_pop_operand (file->base.ctx); + if (string == NULL) + return EOF; + file->data = csi_object_as_file (file->base.ctx, string); + csi_object_free (string); + if (file->data == NULL) + return EOF; + } + c = csi_file_getc (file->data); + if (c == EOF) { + csi_object_free (file->data); + file->data = NULL; + goto RERUN_PROCEDURE; + } +#else + c = EOF; +#endif + break; + + case FILTER: + c = file->filter->filter_getc (file); + break; + + default: + c = EOF; + break; + } + + return c; +} + +int +csi_file_read (csi_file_t *file, void *buf, int len) +{ + int ret; + + if (file->src == NULL) + return 0; + + switch (file->type) { + case STDIO: + if (file->rem > 0) { + ret = len; + if (file->rem < ret) + ret = file->rem; + memcpy (buf, file->bp, ret); + file->bp += ret; + file->rem -= ret; + } else + ret = fread (buf, 1, len, file->src); + break; + + case BYTES: + if (file->rem > 0) { + ret = len; + if (file->rem < ret) + ret = file->rem; + memcpy (buf, file->bp, ret); + file->bp += ret; + file->rem -= ret; + } else + ret = 0; + break; + + case PROCEDURE: +#if 0 + if (file->data == NULL) { + csi_status_t status; + csi_object_t *string; + +RERUN_PROCEDURE: + status = csi_object_execute (file->src); + if (status) + return 0; + + string = csi_pop_operand (file->base.ctx); + if (string == NULL) + return 0; + file->data = csi_object_as_file (file->base.ctx, string); + csi_object_free (string); + if (file->data == NULL) + return 0; + } + ret = csi_file_read (file->data, buf, len); + if (ret == 0) { + csi_object_free (file->data); + file->data = NULL; + goto RERUN_PROCEDURE; + } +#else + ret = 0; +#endif + break; + + case FILTER: + ret = file->filter->filter_read (file, buf, len); + break; + + default: + ret = 0; + break; + } + + return ret; +} + +void +csi_file_putc (csi_file_t *file, int c) +{ + if (file->src == NULL) + return; + + switch ((int) file->type) { + case STDIO: + case BYTES: + file->bp--; + file->rem++; + break; + case FILTER: + file->filter->filter_putc (file, c); + break; + default: + break; + } +} + +void +csi_file_flush (csi_file_t *file) +{ + int c; + + if (file->src == NULL) + return; + + switch ((int) file->type) { + case FILTER: /* need to eat EOD */ + while ((c = csi_file_getc (file)) != EOF) + ; + break; + default: + break; + } +} + +void +csi_file_close (csi_t *ctx, csi_file_t *file) +{ + if (file->src == NULL) + return; + + switch (file->type) { + case STDIO: + fclose (file->src); + break; + case BYTES: + if (file->src != file->data) { + csi_string_t *src = file->src; + if (src != NULL && --src->base.ref == 0) + csi_string_free (ctx, src); + } + break; + case FILTER: + { + csi_file_t *src = file->src; + if (src != NULL && --src->base.ref == 0) + _csi_file_free (ctx, src); + } + break; + case PROCEDURE: + default: + break; + } + file->src = NULL; +} + +void +_csi_file_free (csi_t *ctx, csi_file_t *file) +{ + csi_file_flush (file); + /* XXX putback */ + csi_file_close (ctx, file); + + switch (file->type) { + case BYTES: + break; + case PROCEDURE: +#if 0 + csi_object_free (ctx, file->data); +#endif + break; + case STDIO: + _csi_free (ctx, file->data); + break; + case FILTER: + file->filter->filter_destroy (ctx, file->data); + break; + default: + break; + } + + _csi_slab_free (ctx, file, sizeof (csi_file_t)); +} + +csi_status_t +_csi_file_as_string (csi_t *ctx, + csi_file_t *file, + csi_object_t *obj) +{ + char *bytes; + unsigned int len; + unsigned int allocated; + csi_status_t status; + + len = 0; + allocated = 16384; + bytes = _csi_alloc (ctx, allocated); + if (bytes == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + len = 0; + do { + int ret; + + ret = csi_file_read (file, bytes + len, allocated - len); + if (ret == 0) + break; + + len += ret; + if (len > allocated / 2) { + char *newbytes; + int newlen; + + if (_csi_unlikely (allocated > INT32_MAX / 2)) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + newlen = allocated * 2; + newbytes = _csi_realloc (ctx, bytes, newlen); + if (_csi_unlikely (newbytes == NULL)) { + _csi_free (ctx, bytes); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + bytes = newbytes; + allocated = newlen; + } + } while (TRUE); + + status = csi_string_new (ctx, obj, bytes, len); + if (status) { + _csi_free (ctx, bytes); + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + diff --git a/util/cairo-script/cairo-script-hash.c b/util/cairo-script/cairo-script-hash.c new file mode 100644 index 00000000..c1e6bc28 --- /dev/null +++ b/util/cairo-script/cairo-script-hash.c @@ -0,0 +1,448 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare + * Carl Worth + */ + +#include "cairo-script-private.h" + +#include + +/* + * An entry can be in one of three states: + * + * FREE: Entry has never been used, terminates all searches. + * Appears in the table as a %NULL pointer. + * + * DEAD: Entry had been live in the past. A dead entry can be reused + * but does not terminate a search for an exact entry. + * Appears in the table as a pointer to DEAD_ENTRY. + * + * LIVE: Entry is currently being used. + * Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer. + */ + +#define DEAD_ENTRY ((csi_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) > 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 + * entries randomly deleted by memory pressure (except during rehashing, of + * course). These assumptions are potentially bad, but they make the + * implementation straightforward. + * + * Revisit later if evidence appears that we're using excessive memory from + * a mostly-dead table. + * + * This table is open-addressed with double hashing. Each table size is a + * prime chosen to be a little more than double the high water mark for a + * given arrangement, so the tables should remain < 50% full. The table + * size makes for the "first" hash modulus; a second prime (2 less than the + * first prime) serves as the "second" hash modulus, which is co-prime and + * thus guarantees a complete permutation of table indices. + * + * This structure, and accompanying table, is borrowed/modified from the + * file xserver/render/glyph.c in the freedesktop.org x server, with + * permission (and suggested modification of doubling sizes) by Keith + * Packard. + */ + +static const csi_hash_table_arrangement_t hash_table_arrangements [] = { + { 16, 43, 41 }, + { 32, 73, 71 }, + { 64, 151, 149 }, + { 128, 283, 281 }, + { 256, 571, 569 }, + { 512, 1153, 1151 }, + { 1024, 2269, 2267 }, + { 2048, 4519, 4517 }, + { 4096, 9013, 9011 }, + { 8192, 18043, 18041 }, + { 16384, 36109, 36107 }, + { 32768, 72091, 72089 }, + { 65536, 144409, 144407 }, + { 131072, 288361, 288359 }, + { 262144, 576883, 576881 }, + { 524288, 1153459, 1153457 }, + { 1048576, 2307163, 2307161 }, + { 2097152, 4613893, 4613891 }, + { 4194304, 9227641, 9227639 }, + { 8388608, 18455029, 18455027 }, + { 16777216, 36911011, 36911009 }, + { 33554432, 73819861, 73819859 }, + { 67108864, 147639589, 147639587 }, + { 134217728, 295279081, 295279079 }, + { 268435456, 590559793, 590559791 } +}; + +#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements) + +/** + * _csi_hash_table_create: + * @keys_equal: a function to return %TRUE if two keys are equal + * + * Creates a new hash table which will use the keys_equal() function + * to compare hash keys. Data is provided to the hash table in the + * form of user-derived versions of #csi_hash_entry_t. A hash entry + * must be able to hold both a key (including a hash code) and a + * value. Sometimes only the key will be necessary, (as in + * _csi_hash_table_remove), and other times both a key and a value + * will be necessary, (as in _csi_hash_table_insert). + * + * See #csi_hash_entry_t for more details. + * + * Return value: the new hash table or %NULL if out of memory. + **/ +csi_status_t +_csi_hash_table_init (csi_hash_table_t *hash_table, + csi_hash_keys_equal_func_t keys_equal) +{ + hash_table->keys_equal = keys_equal; + + hash_table->arrangement = &hash_table_arrangements[0]; + + hash_table->entries = calloc (hash_table->arrangement->size, + sizeof(csi_hash_entry_t *)); + if (hash_table->entries == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + hash_table->live_entries = 0; + hash_table->iterating = 0; + + return CSI_STATUS_SUCCESS; +} + +/** + * _csi_hash_table_destroy: + * @hash_table: an empty hash table to destroy + * + * Immediately destroys the given hash table, freeing all resources + * associated with it. + * + * WARNING: The hash_table must have no live entries in it before + * _csi_hash_table_destroy is called. It is a fatal error otherwise, + * and this function will halt. The rationale for this behavior is to + * avoid memory leaks and to avoid needless complication of the API + * with destroy notifiy callbacks. + * + * WARNING: The hash_table must have no running iterators in it when + * _csi_hash_table_destroy is called. It is a fatal error otherwise, + * and this function will halt. + **/ +void +_csi_hash_table_fini (csi_hash_table_t *hash_table) +{ + free (hash_table->entries); +} + +static csi_hash_entry_t ** +_csi_hash_table_lookup_unique_key (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + unsigned long table_size, i, idx, step; + csi_hash_entry_t **entry; + + table_size = hash_table->arrangement->size; + idx = key->hash % table_size; + + 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; + + entry = &hash_table->entries[idx]; + if (! ENTRY_IS_LIVE (*entry)) + return entry; + } while (++i < table_size); + + return NULL; +} + +/** + * _csi_hash_table_resize: + * @hash_table: a hash table + * + * Resize the hash table if the number of entries has gotten much + * bigger or smaller than the ideal number of entries for the current + * size. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if out of memory. + **/ +static csi_status_t +_csi_hash_table_resize (csi_hash_table_t *hash_table) +{ + csi_hash_table_t tmp; + unsigned long new_size, i; + + /* This keeps the hash table between 25% and 50% full. */ + unsigned long high = hash_table->arrangement->high_water_mark; + unsigned long low = high >> 2; + + if (hash_table->live_entries >= low && hash_table->live_entries <= high) + return CAIRO_STATUS_SUCCESS; + + tmp = *hash_table; + + if (hash_table->live_entries > high) { + tmp.arrangement = hash_table->arrangement + 1; + /* This code is being abused if we can't make a table big enough. */ + } else { /* hash_table->live_entries < low */ + /* Can't shrink if we're at the smallest size */ + if (hash_table->arrangement == &hash_table_arrangements[0]) + return CAIRO_STATUS_SUCCESS; + tmp.arrangement = hash_table->arrangement - 1; + } + + new_size = tmp.arrangement->size; + tmp.entries = calloc (new_size, sizeof (csi_hash_entry_t*)); + if (tmp.entries == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + for (i = 0; i < hash_table->arrangement->size; ++i) { + if (ENTRY_IS_LIVE (hash_table->entries[i])) { + *_csi_hash_table_lookup_unique_key (&tmp, hash_table->entries[i]) + = hash_table->entries[i]; + } + } + + free (hash_table->entries); + hash_table->entries = tmp.entries; + hash_table->arrangement = tmp.arrangement; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _csi_hash_table_lookup: + * @hash_table: a hash table + * @key: the key of interest + * + * 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 _csi_hash_table_create). + * + * Return value: the matching entry, of %NULL if no match was found. + **/ +void * +_csi_hash_table_lookup (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + csi_hash_entry_t **entry; + unsigned long table_size, i, idx, step; + + 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; + + 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; +} + +/** + * _csi_hash_table_insert: + * @hash_table: a hash table + * @key_and_value: an entry to be inserted + * + * Insert the entry #key_and_value into the hash table. + * + * 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 + * + * Instead of using insert to replace an entry, consider just editing + * the entry obtained with _csi_hash_table_lookup. Or if absolutely + * necessary, use _csi_hash_table_remove first. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available. + **/ +csi_status_t +_csi_hash_table_insert (csi_hash_table_t *hash_table, + csi_hash_entry_t *key_and_value) +{ + csi_status_t status; + + hash_table->live_entries++; + status = _csi_hash_table_resize (hash_table); + if (_csi_unlikely (status)) { + /* abort the insert... */ + hash_table->live_entries--; + return status; + } + + *_csi_hash_table_lookup_unique_key (hash_table, + key_and_value) = key_and_value; + + return CAIRO_STATUS_SUCCESS; +} + +static csi_hash_entry_t ** +_csi_hash_table_lookup_exact_key (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + unsigned long table_size, i, idx, step; + csi_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); + + return NULL; +} +/** + * _csi_hash_table_remove: + * @hash_table: a hash table + * @key: key of entry to be removed + * + * 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. + **/ +void +_csi_hash_table_remove (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + *_csi_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 + * reorder elements of the table and cause the iteration to potentially + * skip some elements. */ + if (hash_table->iterating == 0) { + /* This call _can_ fail, but only in failing to allocate new + * memory to shrink the hash table. It does leave the table in a + * consistent state, and we've already succeeded in removing the + * entry, so we don't examine the failure status of this call. */ + _csi_hash_table_resize (hash_table); + } +} + +/** + * _csi_hash_table_foreach: + * @hash_table: a hash table + * @hash_callback: function to be called for each live entry + * @closure: additional argument to be passed to @hash_callback + * + * Call @hash_callback for each live entry in the hash table, in a + * non-specified order. + * + * Entries in @hash_table may be removed by code executed from @hash_callback. + * + * Entries may not be inserted to @hash_table, nor may @hash_table + * be destroyed by code executed from @hash_callback. The relevant + * functions will halt in these cases. + **/ +void +_csi_hash_table_foreach (csi_hash_table_t *hash_table, + csi_hash_callback_func_t hash_callback, + void *closure) +{ + unsigned long i; + csi_hash_entry_t *entry; + + if (hash_table == NULL) + return; + + /* Mark the table for iteration */ + ++hash_table->iterating; + for (i = 0; i < hash_table->arrangement->size; i++) { + entry = hash_table->entries[i]; + if (ENTRY_IS_LIVE(entry)) + hash_callback (entry, closure); + } + /* If some elements were deleted during the iteration, + * the table may need resizing. Just do this every time + * as the check is inexpensive. + */ + if (--hash_table->iterating == 0) { + /* Should we fail to shrink the hash table, it is left unaltered, + * and we don't need to propagate the error status. */ + _csi_hash_table_resize (hash_table); + } +} diff --git a/util/cairo-script/cairo-script-interpreter.c b/util/cairo-script/cairo-script-interpreter.c new file mode 100644 index 00000000..21630465 --- /dev/null +++ b/util/cairo-script/cairo-script-interpreter.c @@ -0,0 +1,473 @@ +/* + * 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 + */ + +#include + +#include "cairo-script-private.h" + +#include +#include +#include +#include +#include + +csi_status_t +_csi_error (csi_status_t status) +{ + return status; +} + +/* XXX track global/local memory, cap etc, mark/sweep GC */ +void * +_csi_alloc (csi_t *ctx, int size) +{ + if (_csi_unlikely (ctx->status)) + return NULL; + + return malloc (size); +} + +void * +_csi_alloc0 (csi_t *ctx, int size) +{ + void *ptr; + + ptr = _csi_alloc (ctx, size); + if (_csi_likely (ptr != NULL)) + memset (ptr, 0, size); + + return ptr; +} + +void * +_csi_realloc (csi_t *ctx, void *ptr, int size) +{ + if (_csi_unlikely (ctx->status)) + return NULL; + + return realloc (ptr, size); +} + +void +_csi_free (csi_t *ctx, void *ptr) +{ + if (_csi_unlikely (ptr == NULL)) + return; + + free (ptr); +} + +void * +_csi_slab_alloc (csi_t *ctx, int size) +{ + if (_csi_unlikely (ctx->status)) + return NULL; + + return malloc (size); +} + +void +_csi_slab_free (csi_t *ctx, void *ptr, int size) +{ + if (_csi_unlikely (ptr == NULL)) + return; + + free (ptr); +} + +static csi_status_t +_add_operator (csi_t *ctx, + csi_dictionary_t *dict, + const csi_operator_def_t *def) +{ + csi_object_t name; + csi_object_t operator; + csi_status_t status; + + status = csi_name_new_static (ctx, &name, def->name); + if (status) + return status; + + status = csi_operator_new (ctx, &operator, def->op); + if (status) + return status; + + return csi_dictionary_put (ctx, dict, name.datum.name, &operator); +} + +static csi_status_t +_add_integer_constant (csi_t *ctx, + csi_dictionary_t *dict, + const csi_integer_constant_def_t *def) +{ + csi_object_t name; + csi_object_t constant; + csi_status_t status; + + status = csi_name_new_static (ctx, &name, def->name); + if (status) + return status; + + status = csi_integer_new (ctx, &constant, def->value); + if (status) + return status; + + return csi_dictionary_put (ctx, dict, name.datum.name, &constant); +} + +static csi_status_t +_init_dictionaries (csi_t *ctx) +{ + csi_status_t status; + csi_stack_t *stack; + csi_object_t obj; + csi_dictionary_t *dict; + const csi_operator_def_t *odef; + const csi_integer_constant_def_t *idef; + + stack = &ctx->dstack; + + status = _csi_stack_init (ctx, stack, 4); + if (status) + return status; + + /* systemdict */ + status = csi_dictionary_new (ctx, &obj); + if (status) + return status; + + status = _csi_stack_push (ctx, stack, &obj); + if (status) + return status; + + dict = obj.datum.dictionary; + + /* fill systemdict with operators */ + for (odef = _csi_operators (); odef->name != NULL; odef++) { + status = _add_operator (ctx, dict, odef); + if (status) + return status; + } + + /* add constants */ + for (idef = _csi_integer_constants (); idef->name != NULL; idef++) { + status = _add_integer_constant (ctx, dict, idef); + if (status) + return status; + } + + /* and seal */ + //dict.type &= ~CSI_OBJECT_ATTR_WRITABLE; + + + /* globaldict */ + status = csi_dictionary_new (ctx, &obj); + if (status) + return status; + status = _csi_stack_push (ctx, stack, &obj); + if (status) + return status; + + /* userdict */ + status = csi_dictionary_new (ctx, &obj); + if (status) + return status; + status = _csi_stack_push (ctx, stack, &obj); + if (status) + return status; + + return CSI_STATUS_SUCCESS; +} + +/* intern string */ + +typedef struct _cairo_intern_string { + csi_hash_entry_t hash_entry; + int len; + char *string; +} csi_intern_string_t; + +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 csi_intern_string_t *a = _a; + const csi_intern_string_t *b = _b; + + if (a->len != b->len) + return FALSE; + + return memcmp (a->string, b->string, a->len) == 0; +} + +static void +_csi_init (csi_t *ctx) +{ + csi_status_t status; + + ctx->status = CSI_STATUS_SUCCESS; + ctx->ref_count = 1; + + status = _csi_hash_table_init (&ctx->strings, _intern_string_equal); + if (status) + goto FAIL; + + status = _csi_stack_init (ctx, &ctx->ostack, 2048); + if (status) + goto FAIL; + status = _init_dictionaries (ctx); + if (status) + goto FAIL; + + status = _csi_scanner_init (ctx, &ctx->scanner); + if (status) + goto FAIL; + + return; + +FAIL: + if (ctx->status == CSI_STATUS_SUCCESS) + ctx->status = status; +} + +static void +_intern_string_pluck (void *entry, void *closure) +{ + csi_t *ctx = closure; + + _csi_hash_table_remove (&ctx->strings, entry); + _csi_free (ctx, entry); +} + +static void +_csi_fini (csi_t *ctx) +{ + _csi_stack_fini (ctx, &ctx->ostack); + _csi_stack_fini (ctx, &ctx->dstack); + _csi_scanner_fini (ctx, &ctx->scanner); + + _csi_hash_table_foreach (&ctx->strings, _intern_string_pluck, ctx); + _csi_hash_table_fini (&ctx->strings); +} + +csi_status_t +_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj) +{ + return csi_dictionary_put (ctx, + ctx->dstack.objects[ctx->dstack.len-1].datum.dictionary, + name, + obj); +} + +csi_status_t +_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj) +{ + int i; + + for (i = ctx->dstack.len; i--; ) { + csi_dictionary_t *dict; + csi_dictionary_entry_t *entry; + + dict = ctx->dstack.objects[i].datum.dictionary; + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (entry != NULL) { + *obj = entry->value; + return CSI_STATUS_SUCCESS; + } + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +csi_status_t +_csi_name_undefine (csi_t *ctx, csi_name_t name) +{ + unsigned int i; + + for (i = ctx->dstack.len; --i; ) { + if (csi_dictionary_has (ctx->dstack.objects[i].datum.dictionary, + name)) + { + csi_dictionary_remove (ctx, + ctx->dstack.objects[i].datum.dictionary, + name); + return CSI_STATUS_SUCCESS; + } + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +csi_status_t +_csi_intern_string (csi_t *ctx, const char **str_inout, int len) +{ + char *str = (char *) *str_inout; + csi_intern_string_t tmpl, *istring; + csi_status_t status = CSI_STATUS_SUCCESS; + + if (len < 0) + len = strlen (str); + tmpl.hash_entry.hash = _intern_string_hash (str, len); + tmpl.len = len; + tmpl.string = (char *) str; + + istring = _csi_hash_table_lookup (&ctx->strings, &tmpl.hash_entry); + if (istring == NULL) { + istring = _csi_alloc (ctx, sizeof (csi_intern_string_t) + len + 1); + if (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 = _csi_hash_table_insert (&ctx->strings, + &istring->hash_entry); + if (_csi_unlikely (status)) { + _csi_free (ctx, istring); + return status; + } + } else + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + *str_inout = istring->string; + return CSI_STATUS_SUCCESS; +} + +/* Public */ + +static csi_t _csi_nil = { -1, CSI_STATUS_NO_MEMORY }; + +csi_t * +cairo_script_interpreter_create (void) +{ + csi_t *ctx; + + ctx = calloc (1, sizeof (csi_t)); + if (ctx == NULL) + return (csi_t *) &_csi_nil; + + _csi_init (ctx); + + return ctx; +} + +void +cairo_script_interpreter_install_hooks (csi_t *ctx, + const csi_hooks_t *hooks) +{ + if (ctx->status) + return; + + ctx->hooks = *hooks; +} + +cairo_status_t +cairo_script_interpreter_run (csi_t *ctx, const char *filename) +{ + csi_object_t file; + + if (ctx->status) + return ctx->status; + + ctx->status = csi_file_new (ctx, &file, filename, "r"); + if (ctx->status) + return ctx->status; + + file.type |= CSI_OBJECT_ATTR_EXECUTABLE; + + ctx->status = csi_object_execute (ctx, &file); + csi_object_free (ctx, &file); + + return ctx->status; +} + +cairo_status_t +cairo_script_interpreter_feed_string (csi_t *ctx, const char *line, int len) +{ + csi_object_t file; + + if (ctx->status) + return ctx->status; + + if (len < 0) + len = strlen (line); + ctx->status = csi_file_new_for_bytes (ctx, &file, line, len); + if (ctx->status) + return ctx->status; + + file.type |= CSI_OBJECT_ATTR_EXECUTABLE; + + ctx->status = csi_object_execute (ctx, &file); + csi_object_free (ctx, &file); + + return ctx->status; +} + +csi_t * +cairo_script_interpreter_reference (csi_t *ctx) +{ + ctx->ref_count++; + return ctx; +} +slim_hidden_def (cairo_script_interpreter_reference); + +cairo_status_t +cairo_script_interpreter_destroy (csi_t *ctx) +{ + csi_status_t status; + + status = ctx->status; + if (--ctx->ref_count) + return status; + + _csi_fini (ctx); + free (ctx); + + return status; +} +slim_hidden_def (cairo_script_interpreter_destroy); diff --git a/util/cairo-script/cairo-script-interpreter.h b/util/cairo-script/cairo-script-interpreter.h new file mode 100644 index 00000000..21a3a15b --- /dev/null +++ b/util/cairo-script/cairo-script-interpreter.h @@ -0,0 +1,104 @@ +/* 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 + */ + +#ifndef CAIRO_SCRIPT_INTERPRETER_H +#define CAIRO_SCRIPT_INTERPRETER_H + +#include + +#if CAIRO_HAS_SCRIPT_SURFACE + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_script_interpreter cairo_script_interpreter_t; + +/* XXX expose csi_dictionary_t and pass to hooks */ +typedef void +(*csi_destroy_func_t) (void *closure, + void *ptr); +typedef cairo_surface_t * +(*csi_surface_create_func_t) (void *closure, + double width, + double height); +typedef cairo_t * +(*csi_context_create_func_t) (void *closure, + cairo_surface_t *surface); +typedef void +(*csi_show_page_func_t) (void *closure, + cairo_t *cr); + +typedef void +(*csi_copy_page_func_t) (void *closure, + cairo_t *cr); + +typedef struct _cairo_script_interpreter_hooks { + void *closure; + csi_surface_create_func_t surface_create; + csi_destroy_func_t surface_destroy; + csi_context_create_func_t context_create; + csi_destroy_func_t context_destroy; + csi_show_page_func_t show_page; + csi_copy_page_func_t copy_page; +} cairo_script_interpreter_hooks_t; + +cairo_public cairo_script_interpreter_t * +cairo_script_interpreter_create (void); + +cairo_public void +cairo_script_interpreter_install_hooks (cairo_script_interpreter_t *ctx, + const cairo_script_interpreter_hooks_t *hooks); + +cairo_public cairo_status_t +cairo_script_interpreter_run (cairo_script_interpreter_t *ctx, + const char *filename); + +cairo_public cairo_status_t +cairo_script_interpreter_feed_string (cairo_script_interpreter_t *ctx, + const char *line, + int len); + +cairo_public cairo_script_interpreter_t * +cairo_script_interpreter_reference (cairo_script_interpreter_t *ctx); + +cairo_public cairo_status_t +cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx); + +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_INTERPRETER_H*/ diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c new file mode 100644 index 00000000..f4726cef --- /dev/null +++ b/util/cairo-script/cairo-script-objects.c @@ -0,0 +1,666 @@ +/* + * 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 + */ + +#include "cairo-script-private.h" + +#include + +csi_status_t +csi_array_new (csi_t *ctx, + csi_object_t *obj) + +{ + csi_array_t *array; + csi_status_t status; + + array = _csi_slab_alloc (ctx, sizeof (csi_array_t)); + if (_csi_unlikely (array == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + array->base.type = CSI_OBJECT_TYPE_ARRAY; + array->base.ref = 1; + status = _csi_stack_init (ctx, &array->stack, 32); + if (_csi_unlikely (status)) { + _csi_slab_free (ctx, array, sizeof (csi_array_t)); + return status; + } + + obj->type = CSI_OBJECT_TYPE_ARRAY; + obj->datum.array = array; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_array_put (csi_t *ctx, + csi_array_t *array, + csi_integer_t elem, + csi_object_t *value) +{ + if (_csi_unlikely (elem < 0)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + if (_csi_unlikely (elem >= array->stack.len)) { + csi_status_t status; + + status = _csi_stack_grow (ctx, &array->stack, elem + 1); + if (_csi_unlikely (status)) + return status; + + memset (array->stack.objects + array->stack.len, + 0, (elem - array->stack.len + 1) * sizeof (csi_object_t)); + array->stack.len = elem + 1; + } + + csi_object_free (ctx, &array->stack.objects[elem]); + array->stack.objects[elem] = *csi_object_reference (value); + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_array_get (csi_t *ctx, + csi_array_t *array, + csi_integer_t elem, + csi_object_t *value) +{ + if (_csi_unlikely (elem < 0)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + if (_csi_unlikely (elem > array->stack.len)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *value = array->stack.objects[elem]; + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_array_append (csi_t *ctx, + csi_array_t *array, + csi_object_t *obj) +{ + return _csi_stack_push (ctx, &array->stack, csi_object_reference (obj)); +} + +inline csi_status_t +_csi_array_execute (csi_t *ctx, csi_array_t *array) +{ + csi_integer_t i; + csi_status_t status; + + if (_csi_unlikely (array->stack.len == 0)) + return CSI_STATUS_SUCCESS; + + for (i = 0; i < array->stack.len; i++) { + csi_object_t *obj = &array->stack.objects[i]; + + if (obj->type & CSI_OBJECT_ATTR_EXECUTABLE) { + if (obj->type == (CSI_OBJECT_TYPE_ARRAY | + CSI_OBJECT_ATTR_EXECUTABLE)) + { + status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]); + } + else + status = csi_object_execute (ctx, &array->stack.objects[i]); + } else + status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]); + if (_csi_unlikely (status)) + return status; + } + + return CSI_STATUS_SUCCESS; +} + +void +csi_array_free (csi_t *ctx, csi_array_t *array) +{ + _csi_stack_fini (ctx, &array->stack); + _csi_slab_free (ctx, array, sizeof (csi_array_t)); +} + +csi_status_t +csi_boolean_new (csi_t *ctx, + csi_object_t *obj, + csi_boolean_t v) +{ + obj->type = CSI_OBJECT_TYPE_BOOLEAN; + obj->datum.boolean = v; + + return CSI_STATUS_SUCCESS; +} + +static cairo_bool_t +_dictionary_name_equal (const void *_a, const void *_b) +{ + const csi_dictionary_entry_t *a = _a; + const csi_dictionary_entry_t *b = _b; + return a->hash_entry.hash == b->hash_entry.hash; +} + +csi_status_t +csi_dictionary_new (csi_t *ctx, + csi_object_t *obj) + +{ + csi_dictionary_t *dict; + csi_status_t status; + + dict = _csi_slab_alloc (ctx, sizeof (csi_dictionary_t)); + if (_csi_unlikely (dict == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + dict->base.type = CSI_OBJECT_TYPE_DICTIONARY; + dict->base.ref = 1; + status = _csi_hash_table_init (&dict->hash_table, _dictionary_name_equal); + if (_csi_unlikely (status)) { + _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t)); + return status; + } + + obj->type = CSI_OBJECT_TYPE_DICTIONARY; + obj->datum.dictionary = dict; + + return CSI_STATUS_SUCCESS; +} + +struct _dictionary_entry_pluck { + csi_t *ctx; + csi_hash_table_t *hash_table; +}; + +static void +_dictionary_entry_pluck (void *entry, void *data) +{ + csi_dictionary_entry_t *dict_entry; + struct _dictionary_entry_pluck *pluck_data; + + dict_entry = entry; + pluck_data = data; + + _csi_hash_table_remove (pluck_data->hash_table, entry); + csi_object_free (pluck_data->ctx, &dict_entry->value); + _csi_slab_free (pluck_data->ctx, entry, sizeof (csi_dictionary_entry_t)); +} + +void +csi_dictionary_free (csi_t *ctx, + csi_dictionary_t *dict) +{ + struct _dictionary_entry_pluck data; + + data.ctx = ctx; + data.hash_table = &dict->hash_table; + _csi_hash_table_foreach (&dict->hash_table, + _dictionary_entry_pluck, + &data); + _csi_hash_table_fini (&dict->hash_table); + + _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t)); +} + +csi_status_t +csi_dictionary_put (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value) +{ + csi_dictionary_entry_t *entry; + csi_status_t status; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (entry != NULL) { + /* replace the existing entry */ + csi_object_free (ctx, &entry->value); + entry->value = *csi_object_reference (value); + return CSI_STATUS_SUCCESS; + } + + entry = _csi_slab_alloc (ctx, sizeof (*entry)); + if (_csi_unlikely (entry == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + entry->hash_entry.hash = name; + status = _csi_hash_table_insert (&dict->hash_table, &entry->hash_entry); + if (_csi_unlikely (status)) { + _csi_slab_free (ctx, entry, sizeof (*entry)); + return status; + } + + entry->value = *csi_object_reference (value); + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_dictionary_get (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value) +{ + csi_dictionary_entry_t *entry; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (_csi_unlikely (entry == NULL)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *value = entry->value; + return CSI_STATUS_SUCCESS; +} + +csi_boolean_t +csi_dictionary_has (csi_dictionary_t *dict, + csi_name_t name) +{ + return _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name) != NULL; +} + +void +csi_dictionary_remove (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name) +{ + csi_dictionary_entry_t *entry; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (entry != NULL) { + _csi_hash_table_remove (&dict->hash_table, &entry->hash_entry); + csi_object_free (ctx, &entry->value); + _csi_slab_free (ctx, entry, sizeof (csi_dictionary_entry_t)); + } +} + +csi_status_t +csi_integer_new (csi_t *ctx, + csi_object_t *obj, + csi_integer_t v) +{ + obj->type = CSI_OBJECT_TYPE_INTEGER; + obj->datum.integer = v; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_matrix_new (csi_t *ctx, + csi_object_t *obj) +{ + csi_matrix_t *matrix; + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + cairo_matrix_init_identity (&matrix->matrix); + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_matrix_new_from_array (csi_t *ctx, + csi_object_t *obj, + csi_array_t *array) +{ + csi_matrix_t *matrix; + + if (_csi_unlikely (array->stack.len != 6)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + cairo_matrix_init (&matrix->matrix, + csi_number_get_value (&array->stack.objects[0]), + csi_number_get_value (&array->stack.objects[1]), + csi_number_get_value (&array->stack.objects[2]), + csi_number_get_value (&array->stack.objects[3]), + csi_number_get_value (&array->stack.objects[4]), + csi_number_get_value (&array->stack.objects[5])); + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_matrix_new_from_matrix (csi_t *ctx, + csi_object_t *obj, + const cairo_matrix_t *m) +{ + csi_matrix_t *matrix; + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + matrix->matrix = *m; + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_matrix_new_from_values (csi_t *ctx, + csi_object_t *obj, + double v[6]) +{ + csi_matrix_t *matrix; + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + cairo_matrix_init (&matrix->matrix, v[0], v[1], v[2], v[3], v[4], v[5]); + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +void +csi_matrix_free (csi_t *ctx, + csi_matrix_t *obj) +{ + _csi_slab_free (ctx, obj, sizeof (csi_matrix_t)); +} + + +csi_status_t +csi_name_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len) +{ + csi_status_t status; + + status = _csi_intern_string (ctx, &str, len); + if (_csi_unlikely (status)) + return status; + + obj->type = CSI_OBJECT_TYPE_NAME; + obj->datum.name = (csi_name_t) str; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_name_new_static (csi_t *ctx, + csi_object_t *obj, + const char *str) +{ + csi_status_t status; + + status = _csi_intern_string (ctx, &str, -1); + if (_csi_unlikely (status)) + return status; + + obj->type = CSI_OBJECT_TYPE_NAME; + obj->datum.name = (csi_name_t) str; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_operator_new (csi_t *ctx, + csi_object_t *obj, + csi_operator_t op) +{ + obj->type = CSI_OBJECT_TYPE_OPERATOR | CSI_OBJECT_ATTR_EXECUTABLE; + obj->datum.op = op; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_real_new (csi_t *ctx, + csi_object_t *obj, + csi_real_t v) +{ + obj->type = CSI_OBJECT_TYPE_REAL; + obj->datum.real = v; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_string_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len) +{ + csi_string_t *string; + + string = _csi_slab_alloc (ctx, sizeof (csi_string_t)); + if (_csi_unlikely (string == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + string->base.type = CSI_OBJECT_TYPE_STRING; + string->base.ref = 1; + + if (len < 0) + len = strlen (str); + if (_csi_unlikely (len >= INT32_MAX)) { + _csi_slab_free (ctx, string, sizeof (csi_string_t)); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + string->string = _csi_alloc (ctx, len + 1); + if (_csi_unlikely (string->string == NULL)) { + _csi_slab_free (ctx, string, sizeof (csi_string_t)); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + memcpy (string->string, str, len); + string->string[len] = '\0'; + string->len = len; + + obj->type = CSI_OBJECT_TYPE_STRING; + obj->datum.string = string; + + return CSI_STATUS_SUCCESS; +} + +static inline csi_status_t +_csi_string_execute (csi_t *ctx, csi_string_t *string) +{ + csi_status_t status; + csi_object_t obj; + + if (_csi_unlikely (string->len == 0)) + return CSI_STATUS_SUCCESS; + + status = csi_file_new_for_bytes (ctx, &obj, string->string, string->len); + if (_csi_unlikely (status)) + return status; + + status = _csi_scan_file (ctx, &ctx->scanner, obj.datum.file); + csi_object_free (ctx, &obj); + + return status; +} + +void +csi_string_free (csi_t *ctx, csi_string_t *string) +{ + _csi_free (ctx, string->string); + _csi_slab_free (ctx, string, sizeof (csi_string_t)); +} + +csi_status_t +csi_object_execute (csi_t *ctx, csi_object_t *obj) +{ + csi_status_t status; + csi_object_t indirect; + + INDIRECT: + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_NAME: + status = _csi_name_lookup (ctx, obj->datum.name, &indirect); + if (_csi_unlikely (status)) + return status; + if (indirect.type & CSI_OBJECT_ATTR_EXECUTABLE) { + obj = &indirect; + goto INDIRECT; + } else + return _csi_push_ostack_copy (ctx, &indirect); + + case CSI_OBJECT_TYPE_OPERATOR: + return obj->datum.op (ctx); + + case CSI_OBJECT_TYPE_ARRAY: + return _csi_array_execute (ctx, obj->datum.array); + case CSI_OBJECT_TYPE_FILE: + return _csi_file_execute (ctx, obj->datum.file); + case CSI_OBJECT_TYPE_STRING: + return _csi_string_execute (ctx, obj->datum.string); + + default: + return _csi_push_ostack_copy (ctx, obj); + } +} + +csi_object_t * +csi_object_reference (csi_object_t *obj) +{ + if (CSI_OBJECT_IS_CAIRO (obj)) { + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_reference (obj->datum.cr); + break; + case CSI_OBJECT_TYPE_FONT: + cairo_font_face_reference (obj->datum.font_face); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_reference (obj->datum.pattern); + break; + case CSI_OBJECT_TYPE_SCALED_FONT: + cairo_scaled_font_reference (obj->datum.scaled_font); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_reference (obj->datum.surface); + break; + } + } else if (CSI_OBJECT_IS_COMPOUND (obj)) { + obj->datum.object->ref++; + } + + return obj; +} + +void +csi_object_free (csi_t *ctx, + csi_object_t *obj) +{ + if (CSI_OBJECT_IS_CAIRO (obj)) { + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_destroy (obj->datum.cr); + break; + case CSI_OBJECT_TYPE_FONT: + cairo_font_face_destroy (obj->datum.font_face); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_destroy (obj->datum.pattern); + break; + case CSI_OBJECT_TYPE_SCALED_FONT: + cairo_scaled_font_destroy (obj->datum.scaled_font); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_destroy (obj->datum.surface); + break; + } + } else if (CSI_OBJECT_IS_COMPOUND (obj)) { + if (--obj->datum.object->ref) + return; + + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_ARRAY: + csi_array_free (ctx, obj->datum.array); + break; + case CSI_OBJECT_TYPE_DICTIONARY: + csi_dictionary_free (ctx, obj->datum.dictionary); + break; + case CSI_OBJECT_TYPE_FILE: + _csi_file_free (ctx, obj->datum.file); + break; + case CSI_OBJECT_TYPE_MATRIX: + csi_matrix_free (ctx, obj->datum.matrix); + break; + case CSI_OBJECT_TYPE_STRING: + csi_string_free (ctx, obj->datum.string); + break; + default: + break; + } + } +} + +csi_status_t +csi_object_as_file (csi_t *ctx, + csi_object_t *src, + csi_object_t *file) +{ + + switch ((int) csi_object_get_type (src)) { + case CSI_OBJECT_TYPE_FILE: + *file = *csi_object_reference (src); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_STRING: + return csi_file_new_from_string (ctx, file, src->datum.string); + case CSI_OBJECT_TYPE_ARRAY: +#if 0 + if (src->type & CSI_OBJECT_ATTR_EXECUTABLE) + return _csi_file_new_from_procedure (cs, src); +#endif + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c new file mode 100644 index 00000000..dc1c208f --- /dev/null +++ b/util/cairo-script/cairo-script-operators.c @@ -0,0 +1,5791 @@ +/* + * 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 + */ + +/* TODO real matrix and path types */ + +#include "cairo-script-private.h" + +#include /* snprintf */ +#include +#include +#include +#include + +typedef struct _csi_proxy { + csi_t *ctx; + void *ptr; + csi_dictionary_t *dictionary; + csi_destroy_func_t destroy_func; + void *destroy_data; +} csi_proxy_t; + +typedef struct _csi_blob { + csi_list_t list; + unsigned long hash; + uint8_t *bytes; + unsigned int len; +} csi_blob_t; + +static const cairo_user_data_key_t _csi_proxy_key; +static const cairo_user_data_key_t _csi_blob_key; + +enum mime_type { + MIME_TYPE_NONE = 0, + MIME_TYPE_PNG +}; + +#define check(CNT) do {\ + if (_csi_unlikely (! _csi_check_ostack (ctx, (CNT)))) \ + return _csi_error (CSI_STATUS_INVALID_SCRIPT); \ +} while (0) +#define pop(CNT) _csi_pop_ostack (ctx, (CNT)) +#define push(OBJ) _csi_push_ostack (ctx, (OBJ)) + +static csi_proxy_t * +_csi_proxy_create (csi_t *ctx, + void *ptr, + csi_dictionary_t *dictionary, + csi_destroy_func_t destroy_func, + void *destroy_data) +{ + csi_proxy_t *proxy; + + proxy = _csi_slab_alloc (ctx, sizeof (csi_proxy_t)); + if (proxy == NULL) + return NULL; + + proxy->ctx = cairo_script_interpreter_reference (ctx); + proxy->ptr = ptr; + proxy->destroy_func = destroy_func; + proxy->destroy_data = destroy_data; + proxy->dictionary = dictionary; + if (dictionary != NULL) + dictionary->base.ref++; + + return proxy; +} + +static void +_csi_proxy_destroy (void *closure) +{ + csi_proxy_t *proxy = closure; + csi_t *ctx = proxy->ctx; + + /* XXX this doesn't work because user_data_destroy is called too late. + * Considering another hook into the (cairo internal) object system. + */ + if (proxy->destroy_func != NULL) + proxy->destroy_func (proxy->destroy_data, proxy->ptr); + + if (proxy->dictionary != NULL && --proxy->dictionary->base.ref == 0) + csi_dictionary_free (ctx, proxy->dictionary); + + _csi_slab_free (ctx, proxy, sizeof (csi_proxy_t)); + cairo_script_interpreter_destroy (ctx); +} + +static unsigned long +_csi_blob_hash (const uint8_t *bytes, int len) +{ + /* very simple! */ + unsigned long hash = 5381; + unsigned long *data = (unsigned long *) bytes; + len /= sizeof (unsigned long); + while (len--) { + unsigned long c = *data++; + hash *= 33; + hash ^= c; + } + return hash; +} + +static csi_boolean_t +_csi_blob_equal (const csi_list_t *link, void *data) +{ + csi_blob_t *A, *B; + + A = csi_container_of (link, csi_blob_t, list); + B = data; + + if (A->len != B->len) + return FALSE; + + if (A->hash == 0) + A->hash = _csi_blob_hash (A->bytes, A->len); + if (B->hash == 0) + B->hash = _csi_blob_hash (B->bytes, B->len); + if (A->hash != B->hash) + return FALSE; + + return memcmp (A->bytes, B->bytes, A->len) == 0; +} + +static void +_csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len) +{ + blob->hash = 0; + blob->len = len; + blob->bytes = bytes; +} + +static csi_list_t * +_csi_list_unlink (csi_list_t *head, csi_list_t *link) +{ + if (link->next != NULL) + link->next->prev = link->prev; + if (link->prev != NULL) + link->prev->next = link->next; + else + head = link->next; + return head; +} + +static csi_list_t * +_csi_list_prepend (csi_list_t *head, csi_list_t *link) +{ + if (head != NULL) + head->prev = link; + link->next = head; + link->prev = NULL; + return link; +} + +static csi_list_t * +_csi_list_find (csi_list_t *head, + csi_boolean_t (*predicate) (const csi_list_t *link, void *data), + void *data) +{ + while (head != NULL) { + if (predicate (head, data)) + return head; + head = head->next; + } + + return NULL; +} + +static csi_status_t +_csi_ostack_get_boolean (csi_t *ctx, unsigned int i, csi_boolean_t *out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *out = !! obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *out = obj->datum.real != 0.; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_integer (csi_t *ctx, unsigned int i, csi_integer_t *out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *out = obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *out = obj->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_number (csi_t *ctx, unsigned int i, double *out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *out = obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *out = obj->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_name (csi_t *ctx, unsigned int i, csi_name_t *out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.name; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_context (csi_t *ctx, unsigned int i, cairo_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_CONTEXT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.cr; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_font_face (csi_t *ctx, unsigned int i, cairo_font_face_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_FONT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.font_face; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_pattern (csi_t *ctx, unsigned int i, cairo_pattern_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_PATTERN)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.pattern; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_scaled_font (csi_t *ctx, unsigned int i, + cairo_scaled_font_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely + (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SCALED_FONT)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + *out = obj->datum.scaled_font; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SURFACE)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.surface; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_array (csi_t *ctx, unsigned int i, csi_array_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_ARRAY)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.array; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_procedure (csi_t *ctx, unsigned int i, csi_array_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (! csi_object_is_procedure (obj))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.array; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_dictionary (csi_t *ctx, unsigned int i, csi_dictionary_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely + (csi_object_get_type (obj) != CSI_OBJECT_TYPE_DICTIONARY)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + *out = obj->datum.dictionary; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_matrix (csi_t *ctx, unsigned int i, cairo_matrix_t *out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_MATRIX: + *out = obj->datum.matrix->matrix; + return CSI_STATUS_SUCCESS; + + case CSI_OBJECT_TYPE_ARRAY: + if (obj->datum.array->stack.len == 6) { + cairo_matrix_init (out, + csi_number_get_value (&obj->datum.array->stack.objects[0]), + csi_number_get_value (&obj->datum.array->stack.objects[1]), + csi_number_get_value (&obj->datum.array->stack.objects[2]), + csi_number_get_value (&obj->datum.array->stack.objects[3]), + csi_number_get_value (&obj->datum.array->stack.objects[4]), + csi_number_get_value (&obj->datum.array->stack.objects[5])); + return CSI_STATUS_SUCCESS; + } + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_csi_dictionary_get_integer (csi_t *ctx, + csi_dictionary_t *dict, + const char *name, + csi_boolean_t optional, + long *value) +{ + csi_status_t status; + csi_object_t key, obj; + + status = csi_name_new_static (ctx, &key, name); + if (_csi_unlikely (status)) + return status; + + if (optional && ! csi_dictionary_has (dict, key.datum.name)) + return CSI_STATUS_SUCCESS; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + switch ((int) csi_object_get_type (&obj)) { + case CSI_OBJECT_TYPE_BOOLEAN: + *value = obj.datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *value = obj.datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *value = obj.datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_dictionary_get_number (csi_t *ctx, + csi_dictionary_t *dict, + const char *name, + csi_boolean_t optional, + double *value) +{ + csi_status_t status; + csi_object_t key, obj; + + status = csi_name_new_static (ctx, &key, name); + if (_csi_unlikely (status)) + return status; + + if (optional && ! csi_dictionary_has (dict, key.datum.name)) + return CSI_STATUS_SUCCESS; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + *value = csi_number_get_value (&obj); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_string (csi_t *ctx, unsigned int i, csi_string_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_STRING)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.string; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_string_constant (csi_t *ctx, unsigned int i, const char **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_NAME: + *out = (const char *) obj->datum.name; + break; + case CSI_OBJECT_TYPE_STRING: + *out = obj->datum.string->string; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_do_cairo_op (csi_t *ctx, void (*op) (cairo_t *)) +{ + cairo_t *cr; + csi_status_t status; + + check (1); + + status = _csi_ostack_get_context (ctx, 0, &cr); + if (_csi_unlikely (status)) + return status; + + op (cr); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +end_dict_construction (csi_t *ctx) +{ + csi_object_t obj; + csi_dictionary_t *dict; + csi_status_t status; + + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + dict = obj.datum.dictionary; + do { + csi_object_t *name, *value; + + check (1); + + value = _csi_peek_ostack (ctx, 0); + if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) { + pop (1); + break; + } + + check (1); + + name = _csi_peek_ostack (ctx, 0); + if (_csi_unlikely + (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + status = csi_dictionary_put (ctx, dict, name->datum.name, value); + if (_csi_unlikely (status)) + return status; + + pop (2); + } while (TRUE); + + return push (&obj); +} + +static csi_status_t +end_array_construction (csi_t *ctx) +{ + csi_object_t obj; + csi_array_t *array; + csi_status_t status; + + status = csi_array_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + array = obj.datum.array; + do { + csi_object_t *value; + + check (1); + + value = _csi_peek_ostack (ctx, 0); + if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) { + pop (1); + break; + } + + status = csi_array_append (ctx, array, value); + if (_csi_unlikely (status)) + return status; + + pop (1); + } while (TRUE); + + /* and reverse */ + if (array->stack.len) { + unsigned int i, j; + + for (i = 0, j = array->stack.len; i < --j; i++) { + csi_object_t tmp; + + tmp = array->stack.objects[i]; + array->stack.objects[i] = array->stack.objects[j]; + array->stack.objects[j] = tmp; + } + } + + return push (&obj); +} + +static csi_status_t +_alpha (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double a; + + check (1); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + + pop (1); + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgba (0, 0, 0, a); + return push (&obj); +} + +static csi_status_t +_add (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real + B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer + B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v += B->datum.real; + else + v += B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_add_color_stop (csi_t *ctx) +{ + csi_status_t status; + double offset, r, g, b, a; + cairo_pattern_t *pattern; + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &offset); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_pattern (ctx, 5, &pattern); + if (_csi_unlikely (status)) + return status; + + cairo_pattern_add_color_stop_rgba (pattern, offset, r, g, b, a); + + pop (5); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_and (csi_t *ctx) +{ + csi_object_t *a, *b; + + check (2); + + a = _csi_peek_ostack (ctx, 0); + b = _csi_peek_ostack (ctx, 1); + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + pop (2); + switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_INTEGER: + return _csi_push_ostack_integer (ctx, + a->datum.integer & b->datum.integer); + case CSI_OBJECT_TYPE_BOOLEAN: + return _csi_push_ostack_boolean (ctx, + a->datum.boolean & b->datum.boolean); + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_arc (csi_t *ctx) +{ + csi_status_t status; + double x, y, r; + double theta1, theta2; + cairo_t *cr; + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &theta2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &theta1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 5, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX handle path object */ + + cairo_arc (cr, x, y, r, theta1, theta2); + pop (5); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_arc_negative (csi_t *ctx) +{ + csi_status_t status; + double x, y, r; + double theta1, theta2; + cairo_t *cr; + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &theta2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &theta1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 5, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX handle path object */ + + cairo_arc_negative (cr, x, y, r, theta1, theta2); + pop (5); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_array (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + + status = csi_array_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + return push (&obj); +} + +static csi_status_t +_bind_substitute (csi_t *ctx, csi_array_t *array) +{ + csi_status_t status; + csi_integer_t i, n; + csi_dictionary_t *dict; + + /* perform operator substitution on the executable array (procedure) */ + dict = ctx->dstack.objects[0].datum.dictionary; + n = array->stack.len; + for (i = 0; i < n; i++) { + csi_object_t *obj = &array->stack.objects[i]; + + if (obj->type == (CSI_OBJECT_TYPE_NAME | CSI_OBJECT_ATTR_EXECUTABLE)) { + csi_dictionary_entry_t *entry; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) + &obj->datum.name); + if (entry != NULL) + *obj = entry->value; + } else if (csi_object_is_procedure (obj)) { + status = _bind_substitute (ctx, obj->datum.array); + if (_csi_unlikely (status)) + return status; + } + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_idiom_substitute (csi_t *ctx, csi_array_t *array) +{ +#if 0 + csi_status_t status; + csi_integer_t i, j; + + /* XXX substring search, build array once then search for + * longest matching idiom, repeat. */ + + /* scan the top-most array for sequences we can pre-compile */ + + /* now recurse for subroutines */ + j = array->stack.len; + for (i = 0; i < j; i++) { + csi_object_t *obj = &array->stack.objects[i]; + + if (csi_object_is_procedure (obj)) { + status = _idiom_substitute (ctx, obj->datum.array); + if (_csi_unlikely (_cairo_is_error (status)) + return status; + } + } +#endif + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_bind (csi_t *ctx) +{ + csi_array_t *array; + csi_status_t status; + + check (1); + + status = _csi_ostack_get_procedure (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + + status = _bind_substitute (ctx, array); + if (_csi_unlikely (status)) + return status; + + status = _idiom_substitute (ctx, array); + if (_csi_unlikely (status)) + return status; + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_bitshift (csi_t *ctx) +{ + long v, shift; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &shift); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &v); + if (_csi_unlikely (status)) + return status; + + if (shift < 0) { + shift = -shift; + v <<= shift; + } else + v >>= shift; + + pop (1); + _csi_peek_ostack (ctx, 0)->datum.integer = v; + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_clip (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_clip); +} + +static csi_status_t +_clip_preserve (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_clip_preserve); +} + +static csi_status_t +_close_path (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_close_path); +} + +static csi_status_t +_context (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + csi_proxy_t *proxy; + + check (1); + + status = _csi_ostack_get_surface (ctx, 0, &surface); + if (_csi_unlikely (status)) + return status; + + cr = cairo_create (surface); + + proxy = _csi_proxy_create (ctx, cr, NULL, + ctx->hooks.context_destroy, + ctx->hooks.closure); + if (_csi_unlikely (proxy == NULL)) { + cairo_destroy (cr); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + status = cairo_set_user_data (cr, &_csi_proxy_key, + proxy, _csi_proxy_destroy); + if (_csi_unlikely (status)) { + _csi_proxy_destroy (proxy); + cairo_destroy (cr); + return status; + } + + pop (1); + obj.type = CSI_OBJECT_TYPE_CONTEXT; + obj.datum.cr = cr; + return push (&obj); +} + +static csi_status_t +_copy (csi_t *ctx) +{ + csi_object_t *obj; + + check (1); + + obj = csi_object_reference (_csi_peek_ostack (ctx, 0)); + pop (1); + + switch ((int) csi_object_get_type (obj)) { + /*XXX array, string, dictionary, etc */ + case CSI_OBJECT_TYPE_INTEGER: + { + long i, n; + + n = obj->datum.integer; + if (_csi_unlikely (n < 0)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + check (n); + + for (i = n; i--; ) { + csi_status_t status; + + status = _csi_push_ostack_copy (ctx, + _csi_peek_ostack (ctx, n-1)); + if (_csi_unlikely (status)) + return status; + } + break; + } + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_copy_page (csi_t *ctx) +{ + csi_object_t *obj; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_copy_page (obj->datum.cr); + if (ctx->hooks.copy_page != NULL) + ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_copy_page (obj->datum.surface); + /* XXX hook? */ + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_curve_to (csi_t *ctx) +{ + csi_status_t status; + double x1, y1; + double x2, y2; + double x3, y3; + cairo_t *cr; + + check (7); + + status = _csi_ostack_get_number (ctx, 0, &y3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 5, &x1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 6, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX handle path object */ + + cairo_curve_to (cr, x1, y1, x2, y2, x3, y3); + pop (6); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_def (csi_t *ctx) +{ + csi_name_t name; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_name (ctx, 1, &name); + if (_csi_unlikely (status)) + return status; + + status = _csi_name_define (ctx, name, _csi_peek_ostack (ctx, 0)); + if (_csi_unlikely (status)) + return status; + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_dict (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + return push (&obj); +} + +static csi_status_t +_div (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real / B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer / B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v /= B->datum.real; + else + v /= B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_dup (csi_t *ctx) +{ + check (1); + + return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, 0)); +} + +static csi_status_t +_eq (csi_t *ctx) +{ + csi_object_t *a, *b; + csi_boolean_t v; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + if (csi_object_get_type (a) != csi_object_get_type (b)) { + switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_BOOLEAN: + switch ((int) csi_object_get_type (b)) { + case CSI_OBJECT_TYPE_INTEGER: + v = a->datum.boolean == !! b->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + v = a->datum.boolean == (b->datum.real != 0); + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + break; + + case CSI_OBJECT_TYPE_INTEGER: + switch ((int) csi_object_get_type (b)) { + case CSI_OBJECT_TYPE_BOOLEAN: + v = a->datum.integer == b->datum.boolean; + break; + case CSI_OBJECT_TYPE_REAL: + v = a->datum.integer == b->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + break; + + case CSI_OBJECT_TYPE_REAL: + switch ((int) csi_object_get_type (b)) { + case CSI_OBJECT_TYPE_BOOLEAN: + v = a->datum.real == b->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + v = a->datum.real == b->datum.integer; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + } else { + if (CSI_OBJECT_IS_CAIRO (a)) { + v = a->datum.ptr == b->datum.ptr; + } else if (CSI_OBJECT_IS_COMPOUND (a)) { + v = a->datum.object == b->datum.object; + } else switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_BOOLEAN: + v = a->datum.boolean == b->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + v = a->datum.integer == b->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + v = a->datum.real == b->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + } + + pop (2); + return _csi_push_ostack_boolean (ctx, v); +} + +static csi_status_t +_exch (csi_t *ctx) +{ + return _csi_stack_exch (&ctx->ostack); +} + +static csi_status_t +_false (csi_t *ctx) +{ + return _csi_push_ostack_boolean (ctx, FALSE); +} + +static csi_status_t +_fill (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_fill); +} + +static csi_status_t +_fill_preserve (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_fill_preserve); +} + +static csi_status_t +_filter (csi_t *ctx) +{ + csi_object_t *src; + csi_dictionary_t *dict = NULL; + csi_status_t status; + const char *name; + const struct filters { + const char *name; + csi_status_t (*constructor) (csi_t *t, + csi_object_t *, + csi_dictionary_t *, + csi_object_t *); + } filters[] = { + { "ascii85", csi_file_new_ascii85_decode }, + { "deflate", csi_file_new_deflate_decode }, +#if 0 + { "lzw", csi_file_new_lzw_decode }, +#endif + { NULL, NULL } + }, *filter; + int cnt; + + check (2); + + status = _csi_ostack_get_string_constant (ctx, 0, &name); + if (_csi_unlikely (status)) + return status; + + src = _csi_peek_ostack (ctx, 1); + cnt = 2; + if (csi_object_get_type (src) == CSI_OBJECT_TYPE_DICTIONARY) { + dict = src->datum.dictionary; + + check (3); + + src = _csi_peek_ostack (ctx, 2); + cnt = 3; + } + + for (filter = filters; filter->name != NULL; filter++) { + if (strcmp (name, filter->name) == 0) { + csi_object_t file; + + status = filter->constructor (ctx, &file, dict, src); + if (_csi_unlikely (status)) + return status; + + pop (cnt); + return push (&file); + } + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +static cairo_status_t +_type3_init (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *metrics) +{ + cairo_font_face_t *face; + csi_proxy_t *proxy; + csi_t *ctx; + csi_dictionary_t *font; + csi_object_t key; + csi_object_t obj; + csi_array_t *array; + csi_status_t status; + + face = cairo_scaled_font_get_font_face (scaled_font); + proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); + if (_csi_unlikely (proxy == NULL)) + return CAIRO_STATUS_NO_MEMORY; + + ctx = proxy->ctx; + font = proxy->dictionary; + + status = csi_name_new_static (ctx, &key, "metrics"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_NO_MEMORY; + + if (! csi_dictionary_has (font, key.datum.name)) + return CAIRO_STATUS_SUCCESS; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + if (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY) + return CAIRO_STATUS_USER_FONT_ERROR; + + array = obj.datum.array; + if (array->stack.len != 5) + return CAIRO_STATUS_USER_FONT_ERROR; + + metrics->ascent = csi_number_get_value (&array->stack.objects[0]); + metrics->descent = csi_number_get_value (&array->stack.objects[1]); + metrics->height = csi_number_get_value (&array->stack.objects[2]); + metrics->max_x_advance = csi_number_get_value (&array->stack.objects[3]); + metrics->max_y_advance = csi_number_get_value (&array->stack.objects[4]); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_type3_lookup (cairo_scaled_font_t *scaled_font, + unsigned long unicode, + unsigned long *glyph) +{ + cairo_font_face_t *face; + csi_proxy_t *proxy; + csi_t *ctx; + csi_dictionary_t *font; + csi_object_t obj, key; + csi_array_t *array; + char buf[12]; + csi_integer_t i; + cairo_status_t status; + + face = cairo_scaled_font_get_font_face (scaled_font); + proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); + if (_csi_unlikely (proxy == NULL)) + return CAIRO_STATUS_USER_FONT_ERROR; + + ctx = proxy->ctx; + font = proxy->dictionary; + + status = csi_name_new_static (ctx, &key, "encoding"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (! csi_dictionary_has (font, key.datum.name)) { + *glyph = unicode; + return CAIRO_STATUS_SUCCESS; + } + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + snprintf (buf, sizeof (buf), "uni%04lu", unicode); + array = obj.datum.array; + for (i = 0; i < array->stack.len; i++) { + csi_object_t *name; + + name = &array->stack.objects[i]; + if (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME) + continue; + + if (strcmp ((char *) name->datum.name, buf) == 0) { + *glyph = i; + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_STATUS_USER_FONT_ERROR; +} + +static cairo_status_t +_type3_render (cairo_scaled_font_t *scaled_font, + unsigned long glyph_index, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + cairo_font_face_t *face; + csi_proxy_t *proxy; + csi_t *ctx; + csi_dictionary_t *font; + csi_array_t *glyphs; + csi_object_t *glyph; + csi_object_t key; + csi_object_t obj; + csi_object_t render; + csi_status_t status; + + face = cairo_scaled_font_get_font_face (scaled_font); + proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); + if (_csi_unlikely (proxy == NULL)) + return CAIRO_STATUS_USER_FONT_ERROR; + + ctx = proxy->ctx; + font = proxy->dictionary; + + status = csi_name_new_static (ctx, &key, "glyphs"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + glyphs = obj.datum.array; + glyph = &glyphs->stack.objects[glyph_index]; + if (csi_object_get_type (glyph) == CSI_OBJECT_TYPE_NULL) + return CAIRO_STATUS_SUCCESS; /* .notdef */ + + if (_csi_unlikely (csi_object_get_type (glyph) != CSI_OBJECT_TYPE_DICTIONARY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + status = csi_name_new_static (ctx, &key, "metrics"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + font = glyph->datum.dictionary; + if (csi_dictionary_has (font, key.datum.name)) { + csi_array_t *array; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (csi_object_get_type (&obj) != + CSI_OBJECT_TYPE_ARRAY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + array = obj.datum.array; + if (_csi_unlikely (array->stack.len != 6)) + return CAIRO_STATUS_USER_FONT_ERROR; + + metrics->x_bearing = csi_number_get_value (&array->stack.objects[0]); + metrics->y_bearing = csi_number_get_value (&array->stack.objects[1]); + metrics->width = csi_number_get_value (&array->stack.objects[2]); + metrics->height = csi_number_get_value (&array->stack.objects[3]); + metrics->x_advance = csi_number_get_value (&array->stack.objects[4]); + metrics->y_advance = csi_number_get_value (&array->stack.objects[5]); + } + + status = csi_name_new_static (ctx, &key, "render"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + status = csi_dictionary_get (ctx, font, key.datum.name, &render); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (! csi_object_is_procedure (&render))) + return CAIRO_STATUS_USER_FONT_ERROR; + + obj.type = CSI_OBJECT_TYPE_CONTEXT; + obj.datum.cr = cairo_reference (cr); + status = push (&obj); + if (_csi_unlikely (status)) { + cairo_destroy (cr); + return CAIRO_STATUS_USER_FONT_ERROR; + } + + status = csi_object_execute (ctx, &render); + pop (1); + return CAIRO_STATUS_USER_FONT_ERROR; +} + +static csi_status_t +_font_type3 (csi_t *ctx, + csi_dictionary_t *font, + cairo_font_face_t **font_face_out) +{ + cairo_font_face_t *font_face; + + font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (font_face, _type3_init); + cairo_user_font_face_set_unicode_to_glyph_func (font_face, _type3_lookup); + cairo_user_font_face_set_render_glyph_func (font_face, _type3_render); + + *font_face_out = font_face; + return CSI_STATUS_SUCCESS; +} + +#if CAIRO_HAS_FT_FONT +#include +#include +#include FT_FREETYPE_H + +static FT_Library _ft_lib; + +struct _ft_face_data { + csi_t *ctx; + csi_blob_t blob; + FT_Face face; + csi_string_t *source; + cairo_font_face_t *font_face; +}; + +static void +_ft_done_face (void *closure) +{ + struct _ft_face_data *data = closure; + csi_t *ctx; + + ctx = data->ctx; + + if (data->face != NULL) + FT_Done_Face (data->face); + + ctx->_faces = _csi_list_unlink (ctx->_faces, &data->blob.list); + + if (--data->source->base.ref == 0) + csi_string_free (ctx, data->source); + _csi_slab_free (ctx, data, sizeof (*data)); + + cairo_script_interpreter_destroy (ctx); +} + +static csi_status_t +_ft_create_for_source (csi_t *ctx, + csi_string_t *source, + int index, int load_flags, + cairo_font_face_t **font_face_out) +{ + csi_blob_t tmpl; + struct _ft_face_data *data; + csi_list_t *link; + FT_Face face; + FT_Error err; + cairo_font_face_t *font_face; + csi_status_t status; + + /* check for an existing FT_Face (kept alive by the font cache) */ + /* XXX index/flags */ + _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len); + link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl); + if (link) { + if (--source->base.ref == 0) + csi_string_free (ctx, source); + data = csi_container_of (link, struct _ft_face_data, blob.list); + *font_face_out = cairo_font_face_reference (data->font_face); + return CSI_STATUS_SUCCESS; + } + + /* no existing font_face, create new FT_Face */ + if (_ft_lib == NULL) { + err = FT_Init_FreeType (&_ft_lib); + if (_csi_unlikely (err != FT_Err_Ok)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + err = FT_New_Memory_Face (_ft_lib, + (uint8_t *) source->string, + source->len, index, + &face); + if (_csi_unlikely (err != FT_Err_Ok)) { + if (err == FT_Err_Out_Of_Memory) + return _csi_error (CSI_STATUS_NO_MEMORY); + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + data = _csi_slab_alloc (ctx, sizeof (*data)); + ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list); + data->ctx = cairo_script_interpreter_reference (ctx); + data->blob.hash = tmpl.hash; + data->blob.bytes = tmpl.bytes; + data->blob.len = tmpl.len; + data->face = face; + data->source = source; + + font_face = cairo_ft_font_face_create_for_ft_face (face, load_flags); + status = cairo_font_face_set_user_data (font_face, + &_csi_blob_key, + data, _ft_done_face); + if (_csi_unlikely (status)) { + _ft_done_face (data); + cairo_font_face_destroy (font_face); + return status; + } + + data->font_face = font_face; + *font_face_out = font_face; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_ft_create_for_pattern (csi_t *ctx, + csi_string_t *string, + cairo_font_face_t **font_face_out) +{ + csi_blob_t tmpl; + struct _ft_face_data *data; + csi_list_t *link; + cairo_font_face_t *font_face; + FcPattern *pattern, *resolved; + FcResult result; + csi_status_t status; + + _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len); + link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl); + if (link) { + if (--string->base.ref == 0) + csi_string_free (ctx, string); + data = csi_container_of (link, struct _ft_face_data, blob.list); + *font_face_out = cairo_font_face_reference (data->font_face); + return CSI_STATUS_SUCCESS; + } + + pattern = FcNameParse ((FcChar8 *) string->string); + if (_csi_unlikely (pattern == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + FcDefaultSubstitute (pattern); + + resolved = FcFontMatch (NULL, pattern, &result); + if (_csi_unlikely (resolved == NULL)) { + FcPatternDestroy (pattern); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + + FcPatternDestroy (resolved); + FcPatternDestroy (pattern); + + data = _csi_slab_alloc (ctx, sizeof (*data)); + ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list); + data->ctx = cairo_script_interpreter_reference (ctx); + data->blob.hash = tmpl.hash; + data->blob.bytes = tmpl.bytes; + data->blob.len = tmpl.len; + data->face = NULL; + data->source = string; + + status = cairo_font_face_set_user_data (font_face, + &_csi_blob_key, + data, _ft_done_face); + if (_csi_unlikely (status)) { + _ft_done_face (data); + cairo_font_face_destroy (font_face); + return status; + } + + data->font_face = font_face; + *font_face_out = font_face; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_ft_type42_create (csi_t *ctx, + csi_dictionary_t *font, + cairo_font_face_t **font_face_out) +{ + csi_object_t key; + csi_status_t status; + + /* two basic sub-types, either an FcPattern or embedded font */ + status = csi_name_new_static (ctx, &key, "pattern"); + if (csi_dictionary_has (font, key.datum.name)) { + csi_object_t obj; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + switch ((int) csi_object_get_type (&obj)) { + case CSI_OBJECT_TYPE_FILE: + status = _csi_file_as_string (ctx, obj.datum.file, &obj); + if (_csi_unlikely (status)) + return status; + break; + case CSI_OBJECT_TYPE_STRING: + obj.datum.object->ref++; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return _ft_create_for_pattern (ctx, + obj.datum.string, + font_face_out); + } + + status = csi_name_new_static (ctx, &key, "source"); + if (_csi_unlikely (status)) + return status; + + if (csi_dictionary_has (font, key.datum.name)) { + csi_object_t obj; + long index, flags; + + index = 0; + status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index); + if (_csi_unlikely (status)) + return status; + + flags = 0; + status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags); + if (_csi_unlikely (status)) + return status; + + status = csi_name_new_static (ctx, &key, "source"); + if (_csi_unlikely (status)) + return status; + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + switch ((int) csi_object_get_type (&obj)) { + case CSI_OBJECT_TYPE_FILE: + status = _csi_file_as_string (ctx, obj.datum.file, &obj); + if (_csi_unlikely (status)) + return status; + break; + case CSI_OBJECT_TYPE_STRING: + obj.datum.object->ref++; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return _ft_create_for_source (ctx, obj.datum.string, + index, flags, + font_face_out); + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} +#else +#define _ft_type1_create(font, face_out) CSI_INT_STATUS_UNSUPPORTED +#define _ft_type42_create(font, face_out) CSI_INT_STATUS_UNSUPPORTED +#endif + +static csi_status_t +_font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face) +{ + csi_status_t status; + + status = _ft_type42_create (ctx, font, font_face); + if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED)) + return status; + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +static csi_status_t +_font (csi_t *ctx) +{ + csi_dictionary_t *font; + csi_status_t status; + cairo_font_face_t *font_face; + csi_proxy_t *proxy; + csi_object_t obj; + long type; + + check (1); + + status = _csi_ostack_get_dictionary (ctx, 0, &font); + if (_csi_unlikely (status)) + return status; + + status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type); + if (_csi_unlikely (status)) + return status; + + switch (type) { + case 3: + status = _font_type3 (ctx, font, &font_face); + break; + case 42: + status = _font_type42 (ctx, font, &font_face); + break; + default: + status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + break; + } + + if (_csi_unlikely (status)) + return status; + + /* transfer ownership of dictionary to cairo_font_face_t */ + proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL); + if (_csi_likely (proxy == NULL)) { + cairo_font_face_destroy (font_face); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + status = cairo_font_face_set_user_data (font_face, + &_csi_proxy_key, + proxy, _csi_proxy_destroy); + if (_csi_unlikely (status)) { + _csi_proxy_destroy (proxy); + cairo_font_face_destroy (font_face); + return status; + } + + obj.type = CSI_OBJECT_TYPE_FONT; + obj.datum.font_face = font_face; + + pop (1); + status = push (&obj); + if (_csi_unlikely (status)) { + cairo_font_face_destroy (font_face); + return status; + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_for (csi_t *ctx) +{ + csi_array_t *proc; + csi_status_t status; + long i, inc, limit; + + check (4); + + status = _csi_ostack_get_procedure (ctx, 0, &proc); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &limit); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 2, &inc); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 3, &i); + if (_csi_unlikely (status)) + return status; + + proc->base.ref++; + pop (4); + + for (; i <= limit; i += inc) { + status = _csi_push_ostack_integer (ctx, i); + if (_csi_unlikely (status)) + break; + + status = _csi_array_execute (ctx, proc); + if (_csi_unlikely (status)) + break; + } + + if (--proc->base.ref == 0) + csi_array_free (ctx, proc); + return status; +} + +static csi_status_t +_ge (csi_t *ctx) +{ + csi_object_t *a, *b; + csi_boolean_t v; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + if (csi_object_get_type (a) != csi_object_get_type (b)) { + if (csi_object_is_number (a) && csi_object_is_number (b)) { + double ia, ib; + ia = csi_number_get_value (a); + ib = csi_number_get_value (b); + v = ia >= ib; + } else { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + } else switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_BOOLEAN: + v = a->datum.boolean >= b->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + v = a->datum.integer >= b->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + v = a->datum.real >= b->datum.real; + break; + case CSI_OBJECT_TYPE_STRING: + v = strcmp (a->datum.string->string, b->datum.string->string) >= 0; + break; + case CSI_OBJECT_TYPE_NAME: + v = strcmp ((char *) a->datum.name, (char *) b->datum.name) >= 0; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return _csi_push_ostack_boolean (ctx, v); +} + +static csi_status_t +_proxy_get (csi_proxy_t *proxy, + csi_name_t key) +{ + csi_object_t obj; + csi_status_t status; + + if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj); + if (_csi_unlikely (status)) + return status; + + return _csi_push_ostack_copy (proxy->ctx, &obj); +} + +static csi_status_t +_context_get (csi_t *ctx, + cairo_t *cr, + csi_name_t key) +{ + csi_status_t status; + + if (strcmp ((char *) key, "current-point") == 0) { + double x, y; + + cairo_get_current_point (cr, &x, &y); + + status = _csi_push_ostack_real (ctx, x); + if (_csi_unlikely (status)) + return status; + status = _csi_push_ostack_real (ctx, y); + if (_csi_unlikely (status)) + return status; + + return CSI_STATUS_SUCCESS; + } + + if (strcmp ((char *) key, "source") == 0) { + csi_object_t obj; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr)); + return push (&obj); + } + + if (strcmp ((char *) key, "target") == 0) { + csi_object_t obj; + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_reference (cairo_get_target (cr)); + return push (&obj); + } + + if (strcmp ((char *) key, "group-target") == 0) { + csi_object_t obj; + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr)); + return push (&obj); + } + + if (strcmp ((char *) key, "scaled-font") == 0) { + csi_object_t obj; + + obj.type = CSI_OBJECT_TYPE_SCALED_FONT; + obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr)); + return push (&obj); + } + + if (strcmp ((char *) key, "font-face") == 0) { + csi_object_t obj; + + obj.type = CSI_OBJECT_TYPE_FONT; + obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr)); + return push (&obj); + } + + return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key); +} + +static csi_status_t +_font_get (csi_t *ctx, + cairo_font_face_t *font_face, + csi_name_t key) +{ + return _proxy_get (cairo_font_face_get_user_data (font_face, + &_csi_proxy_key), + key); +} + +static csi_status_t +_pattern_get (csi_t *ctx, + cairo_pattern_t *pattern, + csi_name_t key) +{ + csi_status_t status; + + if (strcmp ((char *) key, "type") == 0) + return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern)); + + if (strcmp ((char *) key, "filter") == 0) + return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern)); + + if (strcmp ((char *) key, "extend") == 0) + return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern)); + + if (strcmp ((char *) key, "matrix") == 0) { + csi_object_t obj; + cairo_matrix_t m; + + cairo_pattern_get_matrix (pattern, &m); + status = csi_matrix_new_from_matrix (ctx, &obj, &m); + if (_csi_unlikely (status)) + return status; + + return push (&obj); + } + + return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key), + key); +} + +static csi_status_t +_scaled_font_get (csi_t *ctx, + cairo_scaled_font_t *font, + csi_name_t key) +{ + return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key), + key); +} + +static csi_status_t +_surface_get (csi_t *ctx, + cairo_surface_t *surface, + csi_name_t key) +{ + if (strcmp ((char *) key, "type") == 0) { + return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface)); + } + + if (strcmp ((char *) key, "content") == 0) { + return _csi_push_ostack_integer (ctx, + cairo_surface_get_content (surface)); + } + + return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key), + key); +} + +static csi_status_t +_get (csi_t *ctx) +{ + csi_object_t *key, *src, obj; + csi_status_t status; + + check (2); + + key = _csi_peek_ostack (ctx, 0); + src = _csi_peek_ostack (ctx, 1); + pop (1); + switch ((int) csi_object_get_type (src)) { + case CSI_OBJECT_TYPE_DICTIONARY: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_dictionary_get (ctx, + src->datum.dictionary, + key->datum.name, + &obj); + break; + case CSI_OBJECT_TYPE_ARRAY: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_INTEGER)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_array_get (ctx, + src->datum.array, + key->datum.integer, + &obj); + break; +#if 0 + case CSI_OBJECT_TYPE_STRING: + status = csi_string_get (src, key, &obj); + break; +#endif + + case CSI_OBJECT_TYPE_CONTEXT: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _context_get (ctx, src->datum.cr, key->datum.name); + + case CSI_OBJECT_TYPE_FONT: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _font_get (ctx, src->datum.font_face, key->datum.name); + + case CSI_OBJECT_TYPE_PATTERN: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _pattern_get (ctx, src->datum.pattern, key->datum.name); + + case CSI_OBJECT_TYPE_SCALED_FONT: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name); + + case CSI_OBJECT_TYPE_SURFACE: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _surface_get (ctx, src->datum.surface, key->datum.name); + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + if (_csi_unlikely (status)) + return status; + + return _csi_push_ostack_copy (ctx, &obj); +} + +static csi_status_t +_glyph_path (csi_t *ctx) +{ + csi_object_t *obj; + csi_array_t *array; + csi_array_t *glyph_array; + csi_string_t *glyph_string; + csi_status_t status; + cairo_t *cr; + cairo_scaled_font_t *scaled_font; + cairo_glyph_t stack_glyphs[256], *glyphs; + double x,y; + csi_integer_t nglyphs, i, j; + double glyph_advance[256][2]; + int have_glyph_advance[256]; + + check (2); + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + /* count glyphs */ + nglyphs = 0; + for (i = 0; i < array->stack.len; i++) { + obj = &array->stack.objects[i]; + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_ARRAY: + nglyphs += obj->datum.array->stack.len; + break; + case CSI_OBJECT_TYPE_STRING: + nglyphs += obj->datum.string->len; + break; + } + } + if (nglyphs == 0) { + pop (1); + return CSI_STATUS_SUCCESS; + } + + if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { + if (_csi_unlikely ((unsigned) nglyphs >= INT32_MAX / sizeof (cairo_glyph_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); + if (_csi_unlikely (glyphs == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + glyphs = stack_glyphs; + + scaled_font = cairo_get_scaled_font (cr); + + nglyphs = 0; + memset (have_glyph_advance, 0, sizeof (have_glyph_advance)); + x = y = 0; + for (i = 0; i < array->stack.len; i++) { + obj = &array->stack.objects[i]; + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_ARRAY: /* glyphs */ + glyph_array = obj->datum.array; + for (j = 0; j < glyph_array->stack.len; j++) { + unsigned long g; + cairo_bool_t have_advance; + + obj = &glyph_array->stack.objects[j]; + if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER) + break; + g = obj->datum.integer; + + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + if (g < ARRAY_LENGTH (have_glyph_advance)) { + if (! have_glyph_advance[g]) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + glyph_advance[g][0] = extents.x_advance; + glyph_advance[g][1] = extents.y_advance; + have_glyph_advance[g] = TRUE; + + } + + have_advance = glyph_advance[g][0] != 0.0; + x += glyph_advance[g][0]; + y += glyph_advance[g][1]; + } else { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + have_advance = extents.x_advance != 0.0; + x += extents.x_advance; + y += extents.y_advance; + } + + nglyphs += have_advance; + } + break; + + case CSI_OBJECT_TYPE_STRING: /* glyphs */ + glyph_string = obj->datum.string; + for (j = 0; j < glyph_string->len; j++) { + uint8_t g; + cairo_bool_t have_advance; + + g = glyph_string->string[j]; + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + if (! have_glyph_advance[g]) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + glyph_advance[g][0] = extents.x_advance; + glyph_advance[g][1] = extents.y_advance; + have_glyph_advance[g] = TRUE; + } + + have_advance = glyph_advance[g][0] != 0.0; + x += glyph_advance[g][0]; + y += glyph_advance[g][1]; + + nglyphs += have_advance; + } + break; + + case CSI_OBJECT_TYPE_INTEGER: + case CSI_OBJECT_TYPE_REAL: /* dx */ + x = csi_number_get_value (obj); + if (++i == array->stack.len) + break; + y = csi_number_get_value (&array->stack.objects[i]); + break; + } + } + + cairo_glyph_path (cr, glyphs, nglyphs); + + if (glyphs != stack_glyphs) + _csi_free (ctx, glyphs); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_gray (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double g; + + check (1); + + status = _csi_ostack_get_number (ctx, 0, &g); + if (_csi_unlikely (status)) + return status; + + pop (1); + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1); + return push (&obj); +} + +static csi_status_t +_gt (csi_t *ctx) +{ + csi_object_t *a, *b; + csi_boolean_t v; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { + if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))){ + double ia, ib; + ia = csi_number_get_value (a); + ib = csi_number_get_value (b); + v = ia > ib; + } else { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + } else switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_BOOLEAN: + v = a->datum.boolean > b->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + v = a->datum.integer > b->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + v = a->datum.real > b->datum.real; + break; + case CSI_OBJECT_TYPE_STRING: + v = strcmp (a->datum.string->string, b->datum.string->string) > 0; + break; + case CSI_OBJECT_TYPE_NAME: + v = strcmp ((char *) a->datum.name, (char *) b->datum.name) > 0; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return _csi_push_ostack_boolean (ctx, v); +} + +static csi_status_t +_identity (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + + status = csi_matrix_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + return push (&obj); +} + +static csi_status_t +_if (csi_t *ctx) +{ + csi_array_t *proc; + csi_boolean_t predicate; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_procedure (ctx, 0, &proc); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_boolean (ctx, 1, &predicate); + if (_csi_unlikely (status)) + return status; + + proc->base.ref++; + pop (2); + + if (predicate) + status = _csi_array_execute (ctx, proc); + + if (--proc->base.ref == 0) + csi_array_free (ctx, proc); + + return status; +} + +static csi_status_t +_ifelse (csi_t *ctx) +{ + csi_array_t *true_proc, *false_proc; + csi_boolean_t predicate; + csi_status_t status; + + check (3); + + status = _csi_ostack_get_procedure (ctx, 0, &false_proc); + if (_csi_unlikely (status)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = _csi_ostack_get_procedure (ctx, 1, &true_proc); + if (_csi_unlikely (status)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = _csi_ostack_get_boolean (ctx, 2, &predicate); + if (_csi_unlikely (status)) + return status; + + true_proc->base.ref++; + false_proc->base.ref++; + pop (3); + + if (predicate) + status = _csi_array_execute (ctx, true_proc); + else + status = _csi_array_execute (ctx, false_proc); + + if (--true_proc->base.ref == 0) + csi_array_free (ctx, true_proc); + if (--false_proc->base.ref == 0) + csi_array_free (ctx, false_proc); + + return status; +} + +static csi_status_t +_image_read_raw (csi_file_t *src, + cairo_format_t format, + int width, int height, + cairo_surface_t **image_out) +{ + cairo_surface_t *image; + uint8_t *bp, *data; + int rem, len, ret, x, stride; + cairo_status_t status; + + image = cairo_image_surface_create (format, width, height); + status = cairo_surface_status (image); + if (status) + return status; + + switch (format) { + case CAIRO_FORMAT_A1: + len = (width+7)/8 * height; + break; + case CAIRO_FORMAT_A8: + len = width * height; + break; + case CAIRO_FORMAT_RGB24: + len = 3 * width * height; + break; + case CAIRO_FORMAT_ARGB32: + len = 4 * width * height; + break; + default: + break; + } + + stride = cairo_image_surface_get_stride (image); + data = cairo_image_surface_get_data (image); + bp = data; + rem = len; + while (rem) { + ret = csi_file_read (src, bp, rem); + if (_csi_unlikely (ret == 0)) { + cairo_surface_destroy (image); + return _csi_error (CSI_STATUS_READ_ERROR); + } + rem -= ret; + bp += ret; + } + + if (len != height * stride) { + while (--height) { + uint8_t *row = data + height * stride; + + /* XXX pixel conversion */ + switch (format) { + case CAIRO_FORMAT_A1: + for (x = (width+7)/8; x--; ) { + uint8_t byte = *--bp; + row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + } + break; + case CAIRO_FORMAT_A8: + for (x = width; x--; ) + row[x] = *--bp; + break; + case CAIRO_FORMAT_RGB24: + for (x = width; x--; ) { +#ifdef WORDS_BIGENDIAN + row[4*x + 3] = *--bp; + row[4*x + 2] = *--bp; + row[4*x + 1] = *--bp; + row[4*x + 0] = 0; +#else + row[4*x + 0] = *--bp; + row[4*x + 1] = *--bp; + row[4*x + 2] = *--bp; + row[4*x + 3] = 0; +#endif + } + break; + case CAIRO_FORMAT_ARGB32: + /* stride == width */ + break; + } + } + + /* need to treat last row carefully */ + switch (format) { + case CAIRO_FORMAT_A1: + for (x = (width+7)/8; x--; ) { + uint8_t byte = *--bp; + data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + } + break; + case CAIRO_FORMAT_A8: + for (x = width; x--; ) + data[x] = *--bp; + break; + case CAIRO_FORMAT_RGB24: + for (x = width; --x>1; ) { +#ifdef WORDS_BIGENDIAN + data[4*x + 3] = *--bp; + data[4*x + 2] = *--bp; + data[4*x + 1] = *--bp; + data[4*x + 0] = 0; +#else + data[4*x + 0] = *--bp; + data[4*x + 1] = *--bp; + data[4*x + 2] = *--bp; + data[4*x + 3] = 0; +#endif + } + if (width > 1) { + uint8_t rgb[2][3]; + /* shuffle the last couple of overlapping pixels */ + rgb[1][0] = data[5]; + rgb[1][1] = data[4]; + rgb[1][2] = data[3]; + rgb[0][0] = data[2]; + rgb[0][1] = data[1]; + rgb[0][2] = data[0]; +#ifdef WORDS_BIGENDIAN + data[4] = 0; + data[5] = rgb[1][2]; + data[6] = rgb[1][1]; + data[7] = rgb[1][0]; + data[0] = 0; + data[1] = rgb[0][2]; + data[2] = rgb[0][1]; + data[3] = rgb[0][0]; +#else + data[7] = 0; + data[6] = rgb[1][2]; + data[5] = rgb[1][1]; + data[4] = rgb[1][0]; + data[3] = 0; + data[2] = rgb[0][2]; + data[1] = rgb[0][1]; + data[0] = rgb[0][0]; +#endif + } else { +#ifdef WORDS_BIGENDIAN + data[0] = 0; + data[1] = data[0]; + data[2] = data[1]; + data[3] = data[2]; +#else + data[3] = data[0]; + data[0] = data[2]; + data[2] = data[3]; + data[3] = 0; +#endif + } + break; + case CAIRO_FORMAT_ARGB32: + /* stride == width */ + break; + } + } else { +#ifndef WORDS_BIGENDIAN + switch (format) { + case CAIRO_FORMAT_A1: + for (x = 0; x < len; x++) { + uint8_t byte = data[x]; + data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + } + break; + case CAIRO_FORMAT_ARGB32: + { + uint32_t *rgba = (uint32_t *) data; + for (x = len/4; x--; rgba++) { + *rgba = bswap_32 (*rgba); + } + } + break; + + case CAIRO_FORMAT_A8: + break; + + case CAIRO_FORMAT_RGB24: + default: + break; + } +#endif + } + + *image_out = image; + return CSI_STATUS_SUCCESS; +} + +static cairo_status_t +png_read_func (void *closure, uint8_t *data, unsigned int len) +{ + int ret; + + ret = csi_file_read (closure, data, len); + if ((unsigned int) ret != len) + return CAIRO_STATUS_READ_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static csi_status_t +_image_read_png (csi_file_t *src, cairo_surface_t **out) +{ + *out = cairo_image_surface_create_from_png_stream (png_read_func, src); + return cairo_surface_status (*out); +} + +struct _image_tag { + csi_t *ctx; + csi_blob_t blob; + cairo_surface_t *surface; +}; + +static void +_image_tag_done (void *closure) +{ + struct _image_tag *tag = closure; + csi_t *ctx = tag->ctx; + + ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list); + _csi_slab_free (ctx, tag, sizeof (*tag)); + cairo_script_interpreter_destroy (ctx); +} + +static cairo_surface_t * +_image_cached (csi_t *ctx, cairo_surface_t *surface) +{ + csi_blob_t tmpl; + csi_list_t *link; + uint8_t *data; + int stride, height; + struct _image_tag *tag; + + /* check for an existing image */ + + data = cairo_image_surface_get_data (surface); + stride = cairo_image_surface_get_stride (surface); + height = cairo_image_surface_get_height (surface); + _csi_blob_init (&tmpl, data, stride * height); + link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl); + if (link) { + cairo_surface_destroy (surface); + tag = csi_container_of (link, struct _image_tag, blob.list); + return cairo_surface_reference (tag->surface); + } + + /* none found, insert a tag for this one */ + + tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag)); + if (tag == NULL) + return surface; + + ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list); + tag->ctx = cairo_script_interpreter_reference (ctx); + tag->blob.hash = tmpl.hash; + tag->blob.bytes = tmpl.bytes; + tag->blob.len = tmpl.len; + tag->surface = surface; + + if (cairo_surface_set_user_data (surface, &_csi_blob_key, + tag, _image_tag_done)) + { + _image_tag_done (tag); + } + + return surface; +} + +static csi_status_t +_image_load_from_dictionary (csi_t *ctx, + csi_dictionary_t *dict, + cairo_surface_t **image_out) +{ + csi_object_t obj, key; + long width; + long height; + long format; + cairo_surface_t *image; + csi_status_t status; + + /* check for "status? */ + + status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height); + if (_csi_unlikely (status)) + return status; + + format = CAIRO_FORMAT_ARGB32; + status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format); + if (_csi_unlikely (status)) + return status; + + status = csi_name_new_static (ctx, &key, "source"); + if (csi_dictionary_has (dict, key.datum.name)) { + enum mime_type type; + csi_object_t file; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + status = csi_name_new_static (ctx, &key, "mime-type"); + if (_csi_unlikely (status)) + return status; + + type = MIME_TYPE_NONE; + if (csi_dictionary_has (dict, key.datum.name)) { + csi_object_t type_obj; + const char *type_str; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj); + if (_csi_unlikely (status)) + return status; + + switch ((int) csi_object_get_type (&type_obj)){ + case CSI_OBJECT_TYPE_STRING: + type_str = type_obj.datum.string->string; + break; + case CSI_OBJECT_TYPE_NAME: + type_str = (char *) type_obj.datum.name; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0) + type = MIME_TYPE_PNG; + } + + status = csi_object_as_file (ctx, &obj, &file); + if (_csi_unlikely (status)) + return status; + + /* XXX hook for general mime-type decoder */ + + switch (type) { + case MIME_TYPE_NONE: + status = _image_read_raw (file.datum.file, + format, width, height, &image); + break; + case MIME_TYPE_PNG: + status = _image_read_png (file.datum.file, &image); + break; + } + csi_object_free (ctx, &file); + if (_csi_unlikely (status)) + return status; + + image = _image_cached (ctx, image); + } else + image = cairo_image_surface_create (format, width, height); + + *image_out = image; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_image (csi_t *ctx) +{ + csi_dictionary_t *dict; + cairo_surface_t *image; + csi_status_t status; + csi_object_t obj; + + check (1); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + + status = _image_load_from_dictionary (ctx, dict, &image); + if (_csi_unlikely (status)) + return status; + + pop (1); + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = image; + return push (&obj); +} + +static csi_status_t +_index (csi_t *ctx) +{ + csi_status_t status; + long n; + + check (1); + + status = _csi_ostack_get_integer (ctx, 0, &n); + if (_csi_unlikely (status)) + return status; + + pop (1); + + check (n); + return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n)); +} + +static csi_status_t +_le (csi_t *ctx) +{ + csi_object_t *a, *b; + csi_boolean_t v; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { + if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) { + double ia, ib; + ia = csi_number_get_value (a); + ib = csi_number_get_value (b); + v = ia <= ib; + } else { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + } else switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_BOOLEAN: + v = a->datum.boolean <= b->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + v = a->datum.integer <= b->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + v = a->datum.real <= b->datum.real; + break; + case CSI_OBJECT_TYPE_STRING: + v = strcmp (a->datum.string->string, b->datum.string->string) <= 0; + break; + case CSI_OBJECT_TYPE_NAME: + v = strcmp ((char *) a->datum.name, (char *) b->datum.name) <= 0; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return _csi_push_ostack_boolean (ctx, v); +} + +static csi_status_t +_linear (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double x1, y1, x2, y2; + + check (4); + + status = _csi_ostack_get_number (ctx, 0, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x1); + if (_csi_unlikely (status)) + return status; + + pop (4); + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2); + return push (&obj); +} + +static csi_status_t +_line_to (csi_t *ctx) +{ + csi_status_t status; + double x, y; + cairo_t *cr; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + pop (2); + cairo_line_to (cr, x, y); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_lt (csi_t *ctx) +{ + csi_object_t *a, *b; + csi_boolean_t v; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { + if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) { + double ia, ib; + ia = csi_number_get_value (a); + ib = csi_number_get_value (b); + v = ia < ib; + } else { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + } else switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_BOOLEAN: + v = a->datum.boolean < b->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + v = a->datum.integer < b->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + v = a->datum.real < b->datum.real; + break; + case CSI_OBJECT_TYPE_STRING: + v = strcmp (a->datum.string->string, b->datum.string->string) < 0; + break; + case CSI_OBJECT_TYPE_NAME: + v = strcmp ((char *) a->datum.name, (char *) b->datum.name) < 0; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return _csi_push_ostack_boolean (ctx, v); +} + +static csi_status_t +_mark (csi_t *ctx) +{ + return _csi_push_ostack_mark (ctx); +} + +static csi_status_t +_neg (csi_t *ctx) +{ + csi_object_t *obj; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_INTEGER: + obj->datum.integer = -obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + obj->datum.real = -obj->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_not (csi_t *ctx) +{ + csi_object_t *obj; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_BOOLEAN: + obj->datum.boolean = ! obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + obj->type = CSI_OBJECT_TYPE_BOOLEAN; + obj->datum.boolean = ! obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + obj->type = CSI_OBJECT_TYPE_BOOLEAN; + obj->datum.boolean = obj->datum.real == 0.0; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_new_path (csi_t *ctx) +{ + /* XXX handle path object */ + return _do_cairo_op (ctx, cairo_new_path); +} + +static csi_status_t +_new_sub_path (csi_t *ctx) +{ + /* XXX handle path object */ + return _do_cairo_op (ctx, cairo_new_sub_path); +} + +static csi_status_t +_mask (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + cairo_pattern_t *pattern; + + check (2); + + status = _csi_ostack_get_pattern (ctx, 0, &pattern); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_mask (cr, pattern); + pop (1); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_matrix (csi_t *ctx) +{ + csi_object_t *obj, matrix; + double v[6]; + csi_status_t status; + int n; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + if (csi_object_is_number (obj)) { + check (6); + + for (n = 6; n--; ) { + status = _csi_ostack_get_number (ctx, 5-n, &v[n]); + if (_csi_unlikely (status)) + return status; + } + status = csi_matrix_new_from_values (ctx, &matrix, v); + if (_csi_unlikely (status)) + return status; + + pop (6); + } else { + csi_array_t *array; + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + + status = csi_matrix_new_from_array (ctx, &matrix, array); + if (_csi_unlikely (status)) + return status; + + pop (1); + } + + return push (&matrix); +} + +static csi_status_t +_move_to (csi_t *ctx) +{ + csi_status_t status; + double x, y; + cairo_t *cr; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + pop (2); + cairo_move_to (cr, x, y); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_mul (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer * B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v *= B->datum.real; + else + v *= B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_or (csi_t *ctx) +{ + csi_object_t *a, *b; + + check (2); + + a = _csi_peek_ostack (ctx, 0); + b = _csi_peek_ostack (ctx, 1); + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + pop (2); + switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_INTEGER: + return _csi_push_ostack_integer (ctx, + a->datum.integer | b->datum.integer); + case CSI_OBJECT_TYPE_BOOLEAN: + return _csi_push_ostack_boolean (ctx, + a->datum.boolean | b->datum.boolean); + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_paint (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_paint); +} + +static csi_status_t +_paint_with_alpha (csi_t *ctx) +{ + cairo_t *cr; + csi_status_t status; + double alpha; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &alpha); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_paint_with_alpha (cr, alpha); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_pattern (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + cairo_surface_t *surface; + + check (1); + + status = _csi_ostack_get_surface (ctx, 0, &surface); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_for_surface (surface); + + pop (1); + return push (&obj); +} + +static csi_status_t +_pop (csi_t *ctx) +{ + check (1); + pop (1); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_pop_group (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + cairo_t *cr; + + check (1); + + status = _csi_ostack_get_context (ctx, 0, &cr); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pop_group (cr); + + return push (&obj); +} + +static csi_status_t +_push_group (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long content; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &content); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_push_group_with_content (cr, content); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_radial (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double x1, y1, r1, x2, y2, r2; + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &r2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 5, &x1); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2); + pop (6); + return push (&obj); +} + +static csi_status_t +_rectangle (csi_t *ctx) +{ + csi_status_t status; + double x, y; + double w, h; + cairo_t *cr; + + check (5); + + status = _csi_ostack_get_number (ctx, 0, &h); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &w); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 4, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + cairo_rectangle (cr, x, y, w, h); + pop(4); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_rel_curve_to (csi_t *ctx) +{ + csi_status_t status; + double x1, y1; + double x2, y2; + double x3, y3; + cairo_t *cr; + + check (7); + + status = _csi_ostack_get_number (ctx, 0, &y3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 5, &x1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 6, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3); + pop (6); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_rel_line_to (csi_t *ctx) +{ + csi_status_t status; + double x, y; + cairo_t *cr; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + cairo_rel_line_to (cr, x, y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_rel_move_to (csi_t *ctx) +{ + csi_status_t status; + double x, y; + cairo_t *cr; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + cairo_rel_move_to (cr, x, y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_reset_clip (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_reset_clip); +} + +static csi_status_t +_restore (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_restore); +} + +static csi_status_t +_rgb (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double r,g,b; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &r); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgb (r, g, b); + pop (3); + return push (&obj); +} + +static csi_status_t +_rgba (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double r,g,b,a; + + check (4); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a); + pop (4); + return push (&obj); +} + +static csi_status_t +_roll (csi_t *ctx) +{ + csi_status_t status; + long j, n; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &j); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &n); + if (_csi_unlikely (status)) + return status; + + pop (2); + check (n); + return _csi_stack_roll (ctx, &ctx->ostack, j, n); +} + +static csi_status_t +_rotate (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + double theta; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &theta); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_rotate (obj->datum.cr, theta); + break; + + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_rotate (&ctm, theta); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + + + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_rotate (&obj->datum.matrix->matrix, theta); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_save (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_save); +} + +static csi_status_t +_scale (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + double x, y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 2); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_scale (obj->datum.cr, x, y); + break; + + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_scale (&ctm, x, y); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + + + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_scale (&obj->datum.matrix->matrix, x, y); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_font_options_load_from_dictionary (csi_t *ctx, + csi_dictionary_t *dict, + cairo_font_options_t *options) +{ + const struct { + const char *key; + void (*setter) (cairo_font_options_t *, int val); + } properties[] = { + { "antialias", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_antialias }, + { "subpixel-order", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_subpixel_order }, + { "hint-style", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_hint_style }, + { "hint-metrics", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_hint_metrics }, + { NULL, NULL }, + }, *prop = properties; + + while (prop->key != NULL) { + csi_object_t key, value; + csi_status_t status; + + status = csi_name_new_static (ctx, &key, prop->key); + if (_csi_unlikely (status)) + return status; + + if (csi_dictionary_has (dict, key.datum.name)) { + status = csi_dictionary_get (ctx, dict, key.datum.name, &value); + if (_csi_unlikely (status)) + return status; + + if (_csi_unlikely (csi_object_get_type (&value) != + CSI_OBJECT_TYPE_INTEGER)) + { + csi_object_free (ctx, &value); + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + prop->setter (options, value.datum.integer); + } + + prop++; + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_scaled_font (csi_t *ctx) +{ + csi_object_t obj; + csi_dictionary_t *dict; + csi_status_t status; + cairo_font_face_t *font_face; + cairo_matrix_t font_matrix, ctm; + cairo_font_options_t *options; + + check (4); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + options = cairo_font_options_create (); + status = _font_options_load_from_dictionary (ctx, dict, options); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + status = _csi_ostack_get_matrix (ctx, 1, &ctm); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + status = _csi_ostack_get_matrix (ctx, 2, &font_matrix); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + status = _csi_ostack_get_font_face (ctx, 3, &font_face); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + obj.type = CSI_OBJECT_TYPE_SCALED_FONT; + obj.datum.scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + options); + cairo_font_options_destroy (options); + pop (4); + return push (&obj); +} + +static csi_status_t +_select_font_face (csi_t *ctx) +{ + cairo_t *cr; + long weight; + long slant; + csi_string_t *family; + csi_status_t status; + + check (4); + + status = _csi_ostack_get_integer (ctx, 0, &weight); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &slant); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_string (ctx, 2, &family); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 3, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_select_font_face (cr, family->string, slant, weight); + pop (3); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_context_set (csi_t *ctx, + cairo_t *cr, + csi_name_t key, + csi_object_t *obj) +{ + if (strcmp ((char *) key, "source") == 0) { + if (_csi_unlikely (csi_object_get_type (obj) != + CSI_OBJECT_TYPE_PATTERN)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + cairo_set_source (cr, obj->datum.pattern); + return CSI_STATUS_SUCCESS; + } + + if (strcmp ((char *) key, "scaled-font") == 0) { + if (_csi_unlikely (csi_object_get_type (obj) != + CSI_OBJECT_TYPE_SCALED_FONT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + cairo_set_scaled_font (cr, obj->datum.scaled_font); + return CSI_STATUS_SUCCESS; + } + + if (strcmp ((char *) key, "font-face") == 0) { + if (_csi_unlikely (csi_object_get_type (obj) != + CSI_OBJECT_TYPE_FONT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + cairo_set_font_face (cr, obj->datum.font_face); + return CSI_STATUS_SUCCESS; + } + + /* return _proxy_set()? */ + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +static csi_status_t +_set (csi_t *ctx) +{ + csi_object_t *key, *value, *dst; + csi_status_t status; + + check (3); + + value = _csi_peek_ostack (ctx, 0); + key = _csi_peek_ostack (ctx, 1); + dst = _csi_peek_ostack (ctx, 2); + + switch ((int) csi_object_get_type (dst)) { + case CSI_OBJECT_TYPE_DICTIONARY: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_dictionary_put (ctx, + dst->datum.dictionary, + key->datum.name, + value); + break; + case CSI_OBJECT_TYPE_ARRAY: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_INTEGER)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_array_put (ctx, + dst->datum.array, + key->datum.integer, + value); + break; + + case CSI_OBJECT_TYPE_CONTEXT: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = _context_set (ctx, + dst->datum.cr, + key->datum.name, + value); + break; + + case CSI_OBJECT_TYPE_STRING: +#if 0 + status = csi_string_put (dst, key, value); + break; +#endif + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return status; +} + +static csi_status_t +_set_antialias (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long antialias; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &antialias); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_antialias (cr, antialias); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_dash (csi_t *ctx) +{ + csi_array_t *array; + csi_status_t status; + cairo_t *cr; + double offset; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &offset); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_array (ctx, 1, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + if (array->stack.len == 0) { + cairo_set_dash (cr, NULL, 0., 0.); + } else { + double stack_dashes[8]; + double *dashes; + csi_integer_t n; + + if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) { + dashes = stack_dashes; + } else { + if (_csi_unlikely ((unsigned) array->stack.len >= INT32_MAX / sizeof (double))) + return _csi_error (CSI_STATUS_NO_MEMORY); + dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len); + if (_csi_unlikely (dashes == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + for (n = 0; n < array->stack.len; n++) { + if (_csi_unlikely (! csi_object_is_number + (&array->stack.objects[n]))) + { + if (dashes != stack_dashes) + _csi_free (ctx, dashes); + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + dashes[n] = csi_number_get_value (&array->stack.objects[n]); + } + + cairo_set_dash (cr, dashes, n, offset); + + if (dashes != stack_dashes) + _csi_free (ctx, dashes); + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_device_offset (csi_t *ctx) +{ + csi_status_t status; + cairo_surface_t *surface; + double x, y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 2, &surface); + if (_csi_unlikely (status)) + return status; + + cairo_surface_set_device_offset (surface, x, y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_extend (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + long extend; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &extend); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_pattern_set_extend (cairo_get_source (obj->datum.cr), + extend); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_set_extend (obj->datum.pattern, extend); + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_fallback_resolution (csi_t *ctx) +{ + csi_status_t status; + cairo_surface_t *surface; + double dpi_x, dpi_y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &dpi_y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &dpi_x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 2, &surface); + if (_csi_unlikely (status)) + return status; + + cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_fill_rule (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long fill_rule; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &fill_rule); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_fill_rule (cr, fill_rule); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_filter (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + long filter; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &filter); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_pattern_set_filter (cairo_get_source (obj->datum.cr), + filter); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_set_filter (obj->datum.pattern, filter); + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_face (csi_t *ctx) +{ + csi_status_t status; + cairo_font_face_t *font; + cairo_t *cr; + + check (2); + + status = _csi_ostack_get_font_face (ctx, 0, &font); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_face (cr, font); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_options (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + csi_dictionary_t *dict; + cairo_font_options_t *options; + + check (2); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + options = cairo_font_options_create (); + status = _font_options_load_from_dictionary (ctx, dict, options); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_matrix (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + cairo_matrix_t m; + + check (2); + + status = _csi_ostack_get_matrix (ctx, 0, &m); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_matrix (cr, &m); + pop(1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_size (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double size; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &size); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_size (cr, size); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_line_cap (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long line_cap; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &line_cap); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_line_cap (cr, line_cap); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_line_join (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long line_join; + + status = _csi_ostack_get_integer (ctx, 0, &line_join); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_line_join (cr, line_join); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_line_width (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double line_width; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &line_width); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_line_width (cr, line_width); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_matrix (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + cairo_matrix_t m; + + check (2); + + status = _csi_ostack_get_matrix (ctx, 0, &m); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_set_matrix (obj->datum.cr, &m); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_set_matrix (obj->datum.pattern, &m); + break; + case CSI_OBJECT_TYPE_MATRIX: + obj->datum.matrix->matrix = m; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +struct _mime_tag { + csi_t *ctx; + csi_string_t *source; +}; +static void +_mime_tag_destroy (void *closure) +{ + struct _mime_tag *tag = closure; + + if (--tag->source->base.ref) + csi_string_free (tag->ctx, tag->source); + + _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag)); +} + +static csi_status_t +_set_mime_data (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + const char *mime; + csi_object_t source; + cairo_surface_t *surface; + struct _mime_tag *tag; + + check (3); + + obj = _csi_peek_ostack (ctx, 0); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_FILE: + status = _csi_file_as_string (ctx, obj->datum.file, &source); + if (_csi_unlikely (status)) + return status; + + break; + + case CSI_OBJECT_TYPE_STRING: + source = *csi_object_reference (obj); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + status = _csi_ostack_get_string_constant (ctx, 1, &mime); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_surface (ctx, 2, &surface); + if (_csi_unlikely (status)) + return status; + + + /* XXX free source */ + tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag)); + if (_csi_unlikely (tag == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + tag->ctx = cairo_script_interpreter_reference (ctx); + tag->source = source.datum.string; + tag->source->base.ref++; + + status = cairo_surface_set_mime_data (surface, + mime, + (uint8_t *) + source.datum.string->string, + source.datum.string->len, + _mime_tag_destroy, tag); + if (_csi_unlikely (status)) { + _mime_tag_destroy (tag); + return status; + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_miter_limit (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double miter_limit; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &miter_limit); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_miter_limit (cr, miter_limit); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_operator (csi_t *ctx) +{ + cairo_t *cr; + long val; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &val); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_operator (cr, val); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_scaled_font (csi_t *ctx) +{ + csi_status_t status; + cairo_scaled_font_t *font; + cairo_t *cr; + + check (2); + + status = _csi_ostack_get_scaled_font (ctx, 0, &font); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_scaled_font (cr, font); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_source (csi_t *ctx) +{ + cairo_t *cr; + cairo_pattern_t *pattern; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_pattern (ctx, 0, &pattern); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_source (cr, pattern); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_source_image (csi_t *ctx) +{ + csi_status_t status; + cairo_surface_t *surface; + cairo_surface_t *source; + cairo_t *cr; + + check (2); + + status = _csi_ostack_get_surface (ctx, 0, &source); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 1, &surface); + if (_csi_unlikely (status)) + return status; + + cr = cairo_create (surface); + cairo_set_source_surface (cr, source, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_tolerance (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double tolerance; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &tolerance); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_tolerance (cr, tolerance); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_transform (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + cairo_matrix_t m; + + check (2); + + status = _csi_ostack_get_matrix (ctx, 0, &m); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_transform (obj->datum.cr, &m); + break; + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_multiply (&ctm, &m, &ctm); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_multiply (&obj->datum.matrix->matrix, + &m, + &obj->datum.matrix->matrix); + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + double x, y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 2); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_translate (obj->datum.cr, x, y); + break; + + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_translate (&ctm, x, y); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + + + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_translate (&obj->datum.matrix->matrix, x, y); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_true (csi_t *ctx) +{ + return _csi_push_ostack_boolean (ctx, TRUE); +} + +static csi_status_t +_show_page (csi_t *ctx) +{ + csi_object_t *obj; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_show_page (obj->datum.cr); + if (ctx->hooks.copy_page != NULL) + ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_show_page (obj->datum.surface); + /* XXX hook? */ + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_similar (csi_t *ctx) +{ + csi_object_t obj; + long content; + double width, height; + cairo_surface_t *other; + csi_status_t status; + + check (4); + + status = _csi_ostack_get_integer (ctx, 0, &content); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &height); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 3, &other); + if (_csi_unlikely (status)) + return status; + + /* silently fix-up a common bug when writing CS */ + if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) { + if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + switch ((int) content) { + default: + case CAIRO_FORMAT_ARGB32: + content = CAIRO_CONTENT_COLOR_ALPHA; + break; + case CAIRO_FORMAT_RGB24: + content = CAIRO_CONTENT_COLOR; + break; + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + content = CAIRO_CONTENT_ALPHA; + break; + } + } + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_create_similar (other, + content, width, height); + pop (4); + return push (&obj); +} + +static csi_status_t +_show_text (csi_t *ctx) +{ + csi_status_t status; + csi_string_t *text; + cairo_t *cr; + + check (2); + + status = _csi_ostack_get_string (ctx, 0, &text); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_show_text (cr, text->string); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_show_glyphs (csi_t *ctx) +{ + csi_object_t *obj; + csi_array_t *array; + csi_array_t *glyph_array; + csi_string_t *glyph_string; + csi_status_t status; + cairo_t *cr; + cairo_scaled_font_t *scaled_font; + cairo_glyph_t stack_glyphs[256], *glyphs; + double x,y; + csi_integer_t nglyphs, i, j; + double glyph_advance[256][2]; + int have_glyph_advance[256]; + + check (2); + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + /* count glyphs */ + nglyphs = 0; + for (i = 0; i < array->stack.len; i++) { + obj = &array->stack.objects[i]; + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_ARRAY: + nglyphs += obj->datum.array->stack.len; + break; + case CSI_OBJECT_TYPE_STRING: + nglyphs += obj->datum.string->len; + break; + } + } + if (nglyphs == 0) { + pop (1); + return CSI_STATUS_SUCCESS; + } + + if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { + if (_csi_unlikely ((unsigned) nglyphs >= INT32_MAX / sizeof (cairo_glyph_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); + if (_csi_unlikely (glyphs == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + glyphs = stack_glyphs; + + scaled_font = cairo_get_scaled_font (cr); + + nglyphs = 0; + memset (have_glyph_advance, 0, sizeof (have_glyph_advance)); + x = y = 0; + for (i = 0; i < array->stack.len; i++) { + obj = &array->stack.objects[i]; + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_ARRAY: /* glyphs */ + glyph_array = obj->datum.array; + for (j = 0; j < glyph_array->stack.len; j++) { + unsigned long g; + cairo_bool_t have_advance; + + obj = &glyph_array->stack.objects[j]; + if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER) + break; + g = obj->datum.integer; + + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + if (g < ARRAY_LENGTH (have_glyph_advance)) { + if (! have_glyph_advance[g]) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + glyph_advance[g][0] = extents.x_advance; + glyph_advance[g][1] = extents.y_advance; + have_glyph_advance[g] = TRUE; + + } + + have_advance = glyph_advance[g][0] != 0.0; + x += glyph_advance[g][0]; + y += glyph_advance[g][1]; + } else { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + have_advance = extents.x_advance != 0.0; + x += extents.x_advance; + y += extents.y_advance; + } + + nglyphs += have_advance; + } + break; + + case CSI_OBJECT_TYPE_STRING: /* glyphs */ + glyph_string = obj->datum.string; + for (j = 0; j < glyph_string->len; j++) { + uint8_t g; + cairo_bool_t have_advance; + + g = glyph_string->string[j]; + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + if (! have_glyph_advance[g]) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + glyph_advance[g][0] = extents.x_advance; + glyph_advance[g][1] = extents.y_advance; + have_glyph_advance[g] = TRUE; + } + + have_advance = glyph_advance[g][0] != 0.0; + x += glyph_advance[g][0]; + y += glyph_advance[g][1]; + + nglyphs += have_advance; + } + break; + + case CSI_OBJECT_TYPE_INTEGER: + case CSI_OBJECT_TYPE_REAL: /* dx */ + x = csi_number_get_value (obj); + if (++i == array->stack.len) + break; + y = csi_number_get_value (&array->stack.objects[i]); + break; + } + } + + cairo_show_glyphs (cr, glyphs, nglyphs); + cairo_move_to (cr, x, y); + + if (glyphs != stack_glyphs) + _csi_free (ctx, glyphs); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_show_text_glyphs (csi_t *ctx) +{ + csi_object_t *obj; + csi_array_t *array; + csi_string_t *string; + csi_string_t *utf8_string; + csi_string_t *glyph_string; + csi_array_t *glyph_array; + csi_status_t status; + cairo_t *cr; + cairo_scaled_font_t *scaled_font; + cairo_text_cluster_t stack_clusters[256], *clusters; + cairo_glyph_t stack_glyphs[256], *glyphs; + double x,y; + csi_integer_t nglyphs, nclusters, i, j; + double glyph_advance[256][2]; + int have_glyph_advance[256]; + long direction; + + check (5); + + status = _csi_ostack_get_integer (ctx, 0, &direction); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_ARRAY: + array = obj->datum.array; + nclusters = array->stack.len / 2; + if (nclusters > ARRAY_LENGTH (stack_clusters)) { + if (_csi_unlikely ((unsigned) nclusters >= INT32_MAX / sizeof (cairo_text_cluster_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters); + if (_csi_unlikely (clusters == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + clusters = stack_clusters; + + for (i = 0; i < nclusters; i++) { + clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]); + clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]); + } + break; + + case CSI_OBJECT_TYPE_STRING: + string = obj->datum.string; + nclusters = string->len / 2; + if (nclusters > ARRAY_LENGTH (stack_clusters)) { + if (_csi_unlikely ((unsigned) nclusters >= INT32_MAX / sizeof (cairo_text_cluster_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters); + if (_csi_unlikely (clusters == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + clusters = stack_clusters; + + for (i = 0; i < nclusters; i++) { + clusters[i].num_bytes = string->string[2*i+0]; + clusters[i].num_glyphs = string->string[2*i+1]; + } + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + status = _csi_ostack_get_array (ctx, 2, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_string (ctx, 3, &utf8_string); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 4, &cr); + if (_csi_unlikely (status)) + return status; + + /* count glyphs */ + nglyphs = 0; + for (i = 0; i < array->stack.len; i++) { + obj = &array->stack.objects[i]; + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_ARRAY: + nglyphs += obj->datum.array->stack.len; + break; + case CSI_OBJECT_TYPE_STRING: + nglyphs += obj->datum.string->len; + break; + } + } + if (nglyphs == 0) + return CSI_STATUS_SUCCESS; + + if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { + if (_csi_unlikely ((unsigned) nglyphs >= INT32_MAX / sizeof (cairo_glyph_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); + if (_csi_unlikely (glyphs == NULL)) { + return _csi_error (CSI_STATUS_NO_MEMORY); + } + } else + glyphs = stack_glyphs; + + /* amalgamate glyph strings */ + scaled_font = cairo_get_scaled_font (cr); + + nglyphs = 0; + memset (have_glyph_advance, 0, sizeof (have_glyph_advance)); + x = y = 0; + for (i = 0; i < array->stack.len; i++) { + obj = &array->stack.objects[i]; + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_ARRAY: /* glyphs */ + glyph_array = obj->datum.array; + for (j = 0; j < glyph_array->stack.len; j++) { + unsigned long g; + cairo_bool_t have_advance; + + obj = &glyph_array->stack.objects[j]; + if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER) + break; + g = obj->datum.integer; + + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + if (g < ARRAY_LENGTH (have_glyph_advance)) { + if (! have_glyph_advance[g]) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + glyph_advance[g][0] = extents.x_advance; + glyph_advance[g][1] = extents.y_advance; + have_glyph_advance[g] = TRUE; + + } + + have_advance = glyph_advance[g][0] != 0.0; + x += glyph_advance[g][0]; + y += glyph_advance[g][1]; + } else { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + have_advance = extents.x_advance != 0.0; + x += extents.x_advance; + y += extents.y_advance; + } + + nglyphs += have_advance; + } + break; + + case CSI_OBJECT_TYPE_STRING: /* glyphs */ + glyph_string = obj->datum.string; + for (j = 0; j < glyph_string->len; j++) { + uint8_t g; + cairo_bool_t have_advance; + + g = glyph_string->string[j]; + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + if (! have_glyph_advance[g]) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + glyph_advance[g][0] = extents.x_advance; + glyph_advance[g][1] = extents.y_advance; + have_glyph_advance[g] = TRUE; + } + + have_advance = glyph_advance[g][0] != 0.0; + x += glyph_advance[g][0]; + y += glyph_advance[g][1]; + + nglyphs += have_advance; + } + break; + + case CSI_OBJECT_TYPE_INTEGER: + case CSI_OBJECT_TYPE_REAL: /* dx */ + x = csi_number_get_value (obj); + if (++i == array->stack.len) + break; + y = csi_number_get_value (&array->stack.objects[i]); + break; + } + } + + cairo_show_text_glyphs (cr, + utf8_string->string, utf8_string->len, + glyphs, nglyphs, + clusters, nclusters, + direction); + cairo_move_to (cr, x, y); + + if (clusters != stack_clusters) + _csi_free (ctx, clusters); + if (glyphs != stack_glyphs) + _csi_free (ctx, glyphs); + + pop (4); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_stroke (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_stroke); +} + +static csi_status_t +_stroke_preserve (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_stroke_preserve); +} + +static csi_status_t +_sub (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer - B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v -= B->datum.real; + else + v -= B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_surface (csi_t *ctx) +{ + csi_object_t obj; + csi_dictionary_t *dict; + csi_proxy_t *proxy; + csi_object_t key; + double width, height; + csi_surface_create_func_t hook; + cairo_surface_t *surface; + csi_status_t status; + + check (1); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + + status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height); + if (_csi_unlikely (status)) + return status; + + hook = ctx->hooks.surface_create; + assert (hook != NULL); + + surface = hook (ctx->hooks.closure, width, height); + if (_csi_unlikely (surface == NULL)) { + return _csi_error (CSI_STATUS_NULL_POINTER); + } + + proxy = _csi_proxy_create (ctx, surface, dict, + ctx->hooks.surface_destroy, + ctx->hooks.closure); + if (_csi_unlikely (proxy == NULL)) { + cairo_surface_destroy (surface); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + status = cairo_surface_set_user_data (surface, + &_csi_proxy_key, + proxy, _csi_proxy_destroy); + if (_csi_unlikely (status)) { + _csi_proxy_destroy (proxy); + cairo_surface_destroy (surface); + return status; + } + + status = csi_name_new_static (ctx, &key, "fallback-resolution"); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_dictionary_has (dict, key.datum.name)) { + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { + csi_array_t *array = obj.datum.array; + if (array->stack.len == 2) { + cairo_surface_set_fallback_resolution (surface, + csi_number_get_value + (&array->stack.objects[0]), + csi_number_get_value + (&array->stack.objects[1])); + } + } + } + /* initialise surface to source */ + status = csi_name_new_static (ctx, &key, "source"); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_dictionary_has (dict, key.datum.name)) { + cairo_surface_t *image; + cairo_t *cr; + + status = _image_load_from_dictionary (ctx, dict, &image); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + + cr = cairo_create (surface); + cairo_set_source_surface (cr, image, 0, 0); + cairo_surface_destroy (image); + cairo_paint (cr); + status = cairo_status (cr); + cairo_destroy (cr); + + if (_csi_unlikely (status)) + return status; + } + + status = csi_name_new_static (ctx, &key, "device-offset"); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_dictionary_has (dict, key.datum.name)) { + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { + csi_array_t *array = obj.datum.array; + + if (array->stack.len == 2) { + cairo_surface_set_device_offset (surface, + csi_number_get_value + (&array->stack.objects[0]), + csi_number_get_value + (&array->stack.objects[1])); + } + } + } + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = surface; + pop (1); + return push (&obj); +} + +static csi_status_t +_text_path (csi_t *ctx) +{ + csi_status_t status; + csi_string_t *text; + cairo_t *cr; + + check (2); + + status = _csi_ostack_get_string (ctx, 0, &text); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_text_path (cr, text->string); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_undef (csi_t *ctx) +{ + csi_name_t name; + csi_status_t status; + + check (1); + + status = _csi_ostack_get_name (ctx, 0, &name); + if (_csi_unlikely (status)) + return status; + + status = _csi_name_undefine (ctx, name); + if (_csi_unlikely (status)) + return status; + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_unset (csi_t *ctx) +{ + csi_object_t *dst; + csi_name_t name; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_name (ctx, 0, &name); + if (_csi_unlikely (status)) + return status; + + dst = _csi_peek_ostack (ctx, 1); + switch ((int) csi_object_get_type (dst)) { + case CSI_OBJECT_TYPE_DICTIONARY: + csi_dictionary_remove (ctx, dst->datum.dictionary, name); + break; + case CSI_OBJECT_TYPE_STRING: + case CSI_OBJECT_TYPE_ARRAY: + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_write_to_png (csi_t *ctx) +{ + csi_status_t status; + csi_string_t *filename; + cairo_surface_t *surface; + + check (2); + + status = _csi_ostack_get_string (ctx, 0, &filename); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 1, &surface); + if (_csi_unlikely (status)) + return status; + + status = cairo_surface_write_to_png (surface, filename->string); + if (_csi_unlikely (status)) + return status; + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_xor (csi_t *ctx) +{ + csi_object_t *a, *b; + + check (2); + + a = _csi_peek_ostack (ctx, 0); + b = _csi_peek_ostack (ctx, 1); + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + pop (2); + switch ((int) csi_object_get_type (a)) { + case CSI_OBJECT_TYPE_INTEGER: + return _csi_push_ostack_integer (ctx, + a->datum.integer ^ b->datum.integer); + case CSI_OBJECT_TYPE_BOOLEAN: + return _csi_push_ostack_boolean (ctx, + a->datum.boolean ^ b->datum.boolean); + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_debug_print (csi_t *ctx) +{ + csi_object_t *obj; + + check (1); + obj = _csi_peek_ostack (ctx, 0); + switch (csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_NULL: + fprintf (stderr, "NULL\n"); + break; + + /* atomics */ + case CSI_OBJECT_TYPE_BOOLEAN: + fprintf (stderr, "boolean: %s\n", + obj->datum.boolean ? "true" : "false"); + break; + case CSI_OBJECT_TYPE_INTEGER: + fprintf (stderr, "integer: %ld\n", obj->datum.integer); + break; + case CSI_OBJECT_TYPE_MARK: + fprintf (stderr, "mark\n"); + break; + case CSI_OBJECT_TYPE_NAME: + fprintf (stderr, "name: %s\n", (char *) obj->datum.name); + break; + case CSI_OBJECT_TYPE_OPERATOR: + fprintf (stderr, "operator: %p\n", obj->datum.op); + break; + case CSI_OBJECT_TYPE_REAL: + fprintf (stderr, "real: %g\n", obj->datum.real); + break; + + /* compound */ + case CSI_OBJECT_TYPE_ARRAY: + fprintf (stderr, "array\n"); + break; + case CSI_OBJECT_TYPE_DICTIONARY: + fprintf (stderr, "dictionary\n"); + break; + case CSI_OBJECT_TYPE_FILE: + fprintf (stderr, "file\n"); + break; + case CSI_OBJECT_TYPE_MATRIX: + fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n", + obj->datum.matrix->matrix.xx, + obj->datum.matrix->matrix.yx, + obj->datum.matrix->matrix.xy, + obj->datum.matrix->matrix.yy, + obj->datum.matrix->matrix.x0, + obj->datum.matrix->matrix.y0); + break; + case CSI_OBJECT_TYPE_STRING: + fprintf (stderr, "string: %s\n", obj->datum.string->string); + break; + + /* cairo */ + case CSI_OBJECT_TYPE_CONTEXT: + fprintf (stderr, "context\n"); + break; + case CSI_OBJECT_TYPE_FONT: + fprintf (stderr, "font\n"); + break; + case CSI_OBJECT_TYPE_PATTERN: + fprintf (stderr, "pattern\n"); + break; + case CSI_OBJECT_TYPE_SCALED_FONT: + fprintf (stderr, "scaled_font\n"); + break; + case CSI_OBJECT_TYPE_SURFACE: + fprintf (stderr, "surface\n"); + break; + } + pop (1); + return CSI_STATUS_SUCCESS; +} + +static const csi_operator_def_t +_defs[] = { + { "<<", _mark }, + { ">>", end_dict_construction }, + { "[", _mark }, + { "]", end_array_construction }, + { "a", _alpha }, + { "abs", NULL }, + { "add", _add }, + { "add_color_stop", _add_color_stop }, + { "and", _and }, + { "arc", _arc }, + { "arc_negative", _arc_negative }, + { "arc-", _arc_negative }, + //{ "arc_to", NULL }, + { "array", _array }, + { "astore", NULL }, + { "atan", NULL }, + { "bind", _bind }, + { "bitshift", _bitshift }, + { "c", _curve_to }, + { "C", _rel_curve_to }, + { "ceiling", NULL }, + { "clear", NULL }, + { "clear_to_mark", NULL }, + { "clip", _clip }, + { "clip_extents", NULL }, + { "clip_preserve", _clip_preserve }, + { "clip+", _clip_preserve }, + { "close_path", _close_path }, + { "context", _context }, + { "copy", _copy }, + { "copy_page", _copy_page }, + { "cos", NULL }, + { "count", NULL }, + { "count_to_mark", NULL }, + { "curve_to", _curve_to }, + { "def", _def }, + { "device_to_user", NULL }, + { "device_to_user_distance", NULL }, + { "dict", _dict }, + { "div", _div }, + { "dup", _dup }, + { "eq", _eq }, + { "exch", _exch }, + { "exec", NULL }, + { "exp", NULL }, + { "false", _false }, + { "fill", _fill }, + { "fill_extents", NULL }, + { "fill_preserve", _fill_preserve }, + { "fill+", _fill_preserve }, + { "filter", _filter }, + { "floor", NULL }, + { "font", _font }, + { "for", _for }, + { "forall", NULL }, + { "g", _gray }, + { "ge", _ge }, + { "get", _get }, + { "glyph_path", _glyph_path }, + { "gt", _gt }, + { "h", _close_path }, + { "identity", _identity }, + { "if", _if }, + { "ifelse", _ifelse }, + { "image", _image }, + { "index", _index }, + { "invert", NULL }, + { "in_stroke", NULL }, + { "in_fill", NULL }, + { "known", NULL }, + { "l", _line_to }, + { "L", _rel_line_to }, + { "languagelevel", NULL }, + { "le", _le }, + { "length", NULL }, + { "linear", _linear }, + { "line_to", _line_to }, + { "ln", NULL }, + { "load", NULL }, + { "log", NULL }, + { "loop", NULL }, + { "lt", _lt }, + { "m", _move_to }, + { "M", _rel_move_to }, + { "mark", _mark }, + { "mask", _mask }, + { "matrix", _matrix }, + { "mod", NULL }, + { "move_to", _move_to }, + { "mul", _mul }, + { "multiply", NULL }, + { "n", _new_path }, + { "N", _new_sub_path }, + { "ne", NULL }, + { "neg", _neg }, + { "new_path", _new_path }, + { "new_sub_path", _new_sub_path }, + { "not", _not }, + { "null", NULL }, + { "or", _or }, + { "paint", _paint }, + { "paint_with_alpha", _paint_with_alpha }, + { "pattern", _pattern }, + { "pop", _pop }, + { "pop_group", _pop_group }, + { "push_group", _push_group }, + { "radial", _radial }, + { "rand", NULL }, + { "rectangle", _rectangle }, + { "repeat", NULL }, + { "restore", _restore }, + { "rel_curve_to", _rel_curve_to }, + { "rel_line_to", _rel_line_to }, + { "rel_move_to", _rel_move_to }, + { "reset_clip", _reset_clip }, + { "rgb", _rgb }, + { "rgba", _rgba }, + { "roll", _roll }, + { "rotate", _rotate }, + { "round", NULL }, + { "run", NULL }, + { "save", _save }, + { "scale", _scale }, + { "scaled_font", _scaled_font }, + { "select_font_face", _select_font_face }, + { "set", _set }, + { "set_antialias", _set_antialias }, + { "set_dash", _set_dash }, + { "set_device_offset", _set_device_offset }, + { "set_extend", _set_extend }, + { "set_fallback_resolution", _set_fallback_resolution }, + { "set_fill_rule", _set_fill_rule }, + { "set_filter", _set_filter }, + { "set_font_face", _set_font_face }, + { "set_font_options", _set_font_options }, + { "set_font_matrix", _set_font_matrix }, + { "set_font_size", _set_font_size }, + { "set_line_cap", _set_line_cap }, + { "set_line_join", _set_line_join }, + { "set_line_width", _set_line_width }, + { "set_matrix", _set_matrix }, + { "set_miter_limit", _set_miter_limit }, + { "set_mime_data", _set_mime_data }, + { "set_operator", _set_operator }, + { "set_scaled_font", _set_scaled_font }, + { "set_source", _set_source }, + { "set_source_image", _set_source_image }, + { "set_tolerance", _set_tolerance }, + { "show_glyphs", _show_glyphs }, + { "show_text", _show_text }, + { "show_text_glyphs", _show_text_glyphs }, + { "show_page", _show_page }, + { "similar", _similar }, + { "sin", NULL }, + { "sqrt", NULL }, + { "sub", _sub }, + { "surface", _surface }, + { "string", NULL }, + { "stroke", _stroke }, + { "stroke_extents", NULL }, + { "stroke_preserve", _stroke_preserve }, + { "stroke+", _stroke_preserve }, + { "text_path", _text_path }, + { "transform", _transform }, + { "transform_distance", NULL }, + { "transform_point", NULL }, + { "translate", _translate }, + { "true", _true }, + { "type", NULL }, + { "undef", _undef }, + { "unset", _unset }, + { "user_to_device", NULL }, + { "user_to_device_distance", NULL }, + { "where", NULL }, + { "write_to_png", _write_to_png }, + { "xor", _xor }, + + { "=", _debug_print }, + + { NULL, NULL }, +}; + +const csi_operator_def_t * +_csi_operators (void) +{ + return _defs; +} + +static const csi_integer_constant_def_t +_integer_constants[] = { + { "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 }, + + { "WINDING", CAIRO_FILL_RULE_WINDING }, + { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD }, + + { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT }, + { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE }, + { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY }, + { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL }, + + { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT }, + { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND }, + { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE }, + + { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER }, + { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND }, + { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL }, + + { "EXTEND_NONE", CAIRO_EXTEND_NONE }, + { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT }, + { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT }, + { "EXTEND_PAD", CAIRO_EXTEND_PAD }, + + { "FILTER_FAST", CAIRO_FILTER_FAST }, + { "FILTER_GOOD", CAIRO_FILTER_GOOD }, + { "FILTER_BEST", CAIRO_FILTER_BEST }, + { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR }, + { "FILTER_NEAREST", CAIRO_FILTER_NEAREST }, + { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN }, + + { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL }, + { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC }, + { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE }, + + { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL }, + { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD }, + + { "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 }, + + { "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 }, + + { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT }, + { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF }, + { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON }, + + { "FORWARD", 0 }, + { "BACKWARD", 1 }, + + { "COLOR", CAIRO_CONTENT_COLOR }, + { "ALPHA", CAIRO_CONTENT_ALPHA }, + { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA }, + + { "A1", CAIRO_FORMAT_A1 }, + { "A8", CAIRO_FORMAT_A8 }, + { "RGB24", CAIRO_FORMAT_RGB24 }, + { "ARGB32", CAIRO_FORMAT_ARGB32 }, + + { NULL, 0 } +}; + +const csi_integer_constant_def_t * +_csi_integer_constants (void) +{ + return _integer_constants; +} diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h new file mode 100644 index 00000000..b7009770 --- /dev/null +++ b/util/cairo-script/cairo-script-private.h @@ -0,0 +1,853 @@ +/* + * 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 + */ + +#ifndef CAIRO_SCRIPT_PRIVATE_H +#define CAIRO_SCRIPT_PRIVATE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cairo-script-interpreter.h" + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#ifndef NULL +#define NULL (void *) 0 +#endif + +#if HAVE_STDINT_H +# include +#elif HAVE_INTTYPES_H +# include +#elif HAVE_SYS_INT_TYPES_H +# include +#elif defined(_MSC_VER) + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif +#else +#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) +#endif + +#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun) +# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private +# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private_no_warn +# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name)) +# define slim_hidden_int_name(name) INT_##name +# define slim_hidden_proto1(name, internal) \ + extern __typeof (name) name \ + __asm__ (slim_hidden_asmname (internal)) +# define slim_hidden_def1(name, internal) \ + extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \ + __attribute__((__alias__(slim_hidden_asmname(internal)))) +# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__) +# define slim_hidden_ulp1(x) slim_hidden_ulp2(x) +# define slim_hidden_ulp2(x) #x +# define slim_hidden_asmname(name) slim_hidden_asmname1(name) +# define slim_hidden_asmname1(name) slim_hidden_ulp #name +#else +# define slim_hidden_proto(name) int _csi_dummy_prototype(void) +# define slim_hidden_proto_no_warn(name) int _csi_dummy_prototype(void) +# define slim_hidden_def(name) int _csi_dummy_prototype(void) +#endif + +#if __GNUC__ >= 3 +#define csi_pure __attribute__((pure)) +#define csi_const __attribute__((const)) +#else +#define csi_pure +#define csi_const +#endif + +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define _CSI_BOOLEAN_EXPR(expr) \ + __extension__ ({ \ + int _csi_boolean_var_; \ + if (expr) \ + _csi_boolean_var_ = 1; \ + else \ + _csi_boolean_var_ = 0; \ + _csi_boolean_var_; \ +}) +#define _csi_likely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 1)) +#define _csi_unlikely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 0)) +#else +#define _csi_likely(expr) (expr) +#define _csi_unlikely(expr) (expr) +#endif + +#ifdef __GNUC__ +#ifndef offsetof +#define offsetof(type, member) \ + ((char *) &((type *) 0)->member - (char *) 0) +#endif +#define csi_container_of(ptr, type, member) ({ \ + const typeof(((type *) 0)->member) *mptr__ = (ptr); \ + (type *) ((char *) mptr__ - offsetof (type, member)); \ +}) +#else +#define csi_container_of(ptr, type, member) \ + (type *)((char *) (ptr) - (char *) &((type *)0)->member) +#endif + +/* slim_internal.h */ +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun) +#define csi_private_no_warn __attribute__((__visibility__("hidden"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) +#define csi_private_no_warn __hidden +#else /* not gcc >= 3.3 and not Sun Studio >= 8 */ +#define csi_private_no_warn +#endif + +#undef ARRAY_LENGTH +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) + +#ifndef WARN_UNUSED_RESULT +#define WARN_UNUSED_RESULT +#endif +/* Add attribute(warn_unused_result) if supported */ +#define csi_warn WARN_UNUSED_RESULT +#define csi_private csi_private_no_warn csi_warn + +#define CSI_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16) +#ifdef WORDS_BIGENDIAN +#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) (c) +#else +#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) CSI_BITSWAP8(c) +#endif + +typedef enum _csi_status { + CSI_STATUS_SUCCESS = CAIRO_STATUS_SUCCESS, + CSI_STATUS_NO_MEMORY = CAIRO_STATUS_NO_MEMORY, + CSI_STATUS_INVALID_RESTORE = CAIRO_STATUS_INVALID_RESTORE, + CSI_STATUS_INVALID_POP_GROUP = CAIRO_STATUS_INVALID_POP_GROUP, + CSI_STATUS_NO_CURRENT_POINT = CAIRO_STATUS_NO_CURRENT_POINT, + CSI_STATUS_INVALID_MATRIX = CAIRO_STATUS_INVALID_MATRIX, + CSI_STATUS_INVALID_STATUS = CAIRO_STATUS_INVALID_STATUS, + CSI_STATUS_NULL_POINTER = CAIRO_STATUS_NULL_POINTER, + CSI_STATUS_INVALID_STRING = CAIRO_STATUS_INVALID_STRING, + CSI_STATUS_INVALID_PATH_DATA = CAIRO_STATUS_INVALID_PATH_DATA, + CSI_STATUS_READ_ERROR = CAIRO_STATUS_READ_ERROR, + CSI_STATUS_WRITE_ERROR = CAIRO_STATUS_WRITE_ERROR, + CSI_STATUS_SURFACE_FINISHED = CAIRO_STATUS_SURFACE_FINISHED, + CSI_STATUS_SURFACE_TYPE_MISMATCH = CAIRO_STATUS_SURFACE_TYPE_MISMATCH, + CSI_STATUS_PATTERN_TYPE_MISMATCH = CAIRO_STATUS_PATTERN_TYPE_MISMATCH, + CSI_STATUS_INVALID_CONTENT = CAIRO_STATUS_INVALID_CONTENT, + CSI_STATUS_INVALID_FORMAT = CAIRO_STATUS_INVALID_FORMAT, + CSI_STATUS_INVALID_VISUAL = CAIRO_STATUS_INVALID_VISUAL, + CSI_STATUS_FILE_NOT_FOUND = CAIRO_STATUS_FILE_NOT_FOUND, + CSI_STATUS_INVALID_DASH = CAIRO_STATUS_INVALID_DASH, + CSI_STATUS_INVALID_DSC_COMMENT = CAIRO_STATUS_INVALID_DSC_COMMENT, + CSI_STATUS_INVALID_INDEX = CAIRO_STATUS_INVALID_INDEX, + CSI_STATUS_CLIP_NOT_REPRESENTABLE = CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, + CSI_STATUS_TEMP_FILE_ERROR = CAIRO_STATUS_TEMP_FILE_ERROR, + CSI_STATUS_INVALID_STRIDE = CAIRO_STATUS_INVALID_STRIDE, + CSI_STATUS_FONT_TYPE_MISMATCH = CAIRO_STATUS_FONT_TYPE_MISMATCH, + CSI_STATUS_USER_FONT_IMMUTABLE = CAIRO_STATUS_USER_FONT_IMMUTABLE, + CSI_STATUS_USER_FONT_ERROR = CAIRO_STATUS_USER_FONT_ERROR, + CSI_STATUS_NEGATIVE_COUNT = CAIRO_STATUS_NEGATIVE_COUNT, + CSI_STATUS_INVALID_CLUSTERS = CAIRO_STATUS_INVALID_CLUSTERS, + CSI_STATUS_INVALID_SLANT = CAIRO_STATUS_INVALID_SLANT, + CSI_STATUS_INVALID_WEIGHT = CAIRO_STATUS_INVALID_WEIGHT, + + /* cairo-script-interpreter specific errors */ + + CSI_STATUS_INVALID_SCRIPT, + CSI_STATUS_SCRIPT_INVALID_TYPE, + CSI_STATUS_SCRIPT_INVALID_INDEX, + CSI_STATUS_SCRIPT_UNDEFINED_NAME, + + _CSI_STATUS_SCRIPT_LAST_ERROR, + CSI_INT_STATUS_UNSUPPORTED +} csi_status_t; + +typedef enum { + CSI_OBJECT_TYPE_NULL = 0, + + /* atomics */ + CSI_OBJECT_TYPE_BOOLEAN, + CSI_OBJECT_TYPE_INTEGER, + CSI_OBJECT_TYPE_MARK, + CSI_OBJECT_TYPE_NAME, + CSI_OBJECT_TYPE_OPERATOR, + CSI_OBJECT_TYPE_REAL, + + /* compound */ + CSI_OBJECT_TYPE_ARRAY = 0x8, + CSI_OBJECT_TYPE_DICTIONARY, + CSI_OBJECT_TYPE_FILE, + CSI_OBJECT_TYPE_MATRIX, + CSI_OBJECT_TYPE_STRING, + + /* cairo */ + CSI_OBJECT_TYPE_CONTEXT = 0x10, + CSI_OBJECT_TYPE_FONT, + CSI_OBJECT_TYPE_PATTERN, + CSI_OBJECT_TYPE_SCALED_FONT, + CSI_OBJECT_TYPE_SURFACE, +} csi_object_type_t; + +#define CSI_OBJECT_IS_ATOM(OBJ) (((OBJ)->type & CSI_OBJECT_TYPE_MASK) < 0x08) +#define CSI_OBJECT_IS_COMPOUND(OBJ) ((OBJ)->type & 0x08) +#define CSI_OBJECT_IS_CAIRO(OBJ) ((OBJ)->type & 0x10) + +enum { /* attributes */ + CSI_OBJECT_ATTR_EXECUTABLE = 1 << 6, + CSI_OBJECT_ATTR_WRITABLE = 1 << 7, +}; +#define CSI_OBJECT_ATTR_MASK (CSI_OBJECT_ATTR_EXECUTABLE | \ + CSI_OBJECT_ATTR_WRITABLE) +#define CSI_OBJECT_TYPE_MASK (~CSI_OBJECT_ATTR_MASK) + +typedef struct _cairo_script_interpreter csi_t; + +typedef cairo_bool_t csi_boolean_t; +typedef csi_status_t (*csi_operator_t) (csi_t *); +typedef float csi_real_t; +typedef long csi_integer_t; +typedef long csi_name_t; +typedef struct _csi_array csi_array_t; +typedef struct _csi_buffer csi_buffer_t; +typedef struct _csi_compound_object csi_compound_object_t; +typedef struct _csi_dictionary csi_dictionary_t; +typedef struct _csi_file csi_file_t; +typedef struct _csi_hash_entry csi_hash_entry_t; +typedef struct _csi_hash_table csi_hash_table_t; +typedef struct _csi_hash_table_arrangement csi_hash_table_arrangement_t; +typedef struct _csi_list csi_list_t; +typedef struct _csi_matrix csi_matrix_t; +typedef struct _csi_object csi_object_t; +typedef struct _csi_scanner csi_scanner_t; +typedef struct _csi_stack csi_stack_t; +typedef struct _csi_string csi_string_t; + +typedef cairo_bool_t +(*csi_hash_predicate_func_t) (void *entry); + +typedef void +(*csi_hash_callback_func_t) (void *entry, + void *closure); + +typedef cairo_bool_t +(*csi_hash_keys_equal_func_t) (const void *key_a, const void *key_b); + +struct _csi_object { + csi_object_type_t type; + union { + cairo_t *cr; + cairo_font_face_t *font_face; + cairo_pattern_t *pattern; + cairo_scaled_font_t *scaled_font; + cairo_surface_t *surface; + csi_array_t *array; + csi_boolean_t boolean; + csi_compound_object_t *object; + csi_dictionary_t *dictionary; + csi_file_t *file; + csi_integer_t integer; + csi_matrix_t *matrix; + csi_operator_t op; + csi_name_t name; + csi_real_t real; + csi_string_t *string; + void *ptr; + } datum; +}; + +struct _csi_compound_object { + csi_object_type_t type; + unsigned int ref; +}; + +struct _csi_hash_entry { + unsigned long hash; +}; + +struct _csi_hash_table_arrangement { + unsigned long high_water_mark; + unsigned long size; + unsigned long rehash; +}; + +struct _csi_hash_table { + csi_hash_keys_equal_func_t keys_equal; + + const csi_hash_table_arrangement_t *arrangement; + csi_hash_entry_t **entries; + + unsigned long live_entries; + unsigned long iterating; /* Iterating, no insert, no resize */ +}; + + +/* simple, embedded doubly-linked links */ +struct _csi_list { + struct _csi_list *next, *prev; +}; + +struct _csi_buffer { + csi_status_t status; + + char *base, *ptr, *end; + unsigned int size; +}; + +struct _csi_stack { + csi_object_t *objects; + csi_integer_t len; + csi_integer_t size; +}; + +struct _csi_array { + csi_compound_object_t base; + csi_stack_t stack; +}; + +typedef struct _csi_dictionary_entry { + csi_hash_entry_t hash_entry; + csi_object_t value; +} csi_dictionary_entry_t; + +struct _csi_dictionary { + csi_compound_object_t base; + csi_hash_table_t hash_table; +}; + +struct _csi_matrix { + csi_compound_object_t base; + cairo_matrix_t matrix; +}; + +struct _csi_string { + csi_compound_object_t base; + csi_integer_t len; + char *string; +}; + +typedef struct _csi_filter_funcs { + int (*filter_getc) (csi_file_t *); + void (*filter_putc) (csi_file_t *, int); + int (*filter_read) (csi_file_t *, uint8_t *, int); + void (*filter_destroy) (csi_t *, void *); +} csi_filter_funcs_t; + +struct _csi_file { + csi_compound_object_t base; + enum { + STDIO, + BYTES, + PROCEDURE, + FILTER, + } type; + void *src; + void *data; + uint8_t *bp; + int rem; + const csi_filter_funcs_t *filter; +}; + +struct _csi_scanner { + csi_status_t status; + + enum { + NONE, + TOKEN, + COMMENT, + STRING, + HEX, + BASE85, + } state; + + csi_buffer_t buffer; + csi_stack_t procedure_stack; + csi_object_t build_procedure; + + int string_p; + unsigned int accumulator; + unsigned int accumulator_count; +}; + +typedef cairo_script_interpreter_hooks_t csi_hooks_t; + +struct _cairo_script_interpreter { + int ref_count; + csi_status_t status; + + csi_hooks_t hooks; + + csi_hash_table_t strings; + + csi_stack_t ostack; + csi_stack_t dstack; + + csi_scanner_t scanner; + + /* caches of live data */ + csi_list_t *_images; + csi_list_t *_faces; +}; + +typedef struct _csi_operator_def { + const char *name; + csi_operator_t op; +} csi_operator_def_t; + +typedef struct _csi_integer_constant_def { + const char *name; + csi_integer_t value; +} csi_integer_constant_def_t; + +/* cairo-script-file.c */ + +csi_private csi_status_t +csi_file_new (csi_t *ctx, + csi_object_t *obj, + const char *path, const char *mode); + +csi_private csi_status_t +csi_file_new_for_bytes (csi_t *ctx, + csi_object_t *obj, + const char *bytes, + unsigned int length); + +csi_private csi_status_t +csi_file_new_from_string (csi_t *ctx, + csi_object_t *obj, + csi_string_t *src); + +csi_private csi_status_t +csi_file_new_ascii85_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src); + +csi_private csi_status_t +csi_file_new_deflate_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src); + +csi_private csi_status_t +_csi_file_execute (csi_t *ctx, csi_file_t *obj); + +csi_private int +csi_file_getc (csi_file_t *obj); + +csi_private int +csi_file_read (csi_file_t *obj, void *buf, int len); + +csi_private void +csi_file_putc (csi_file_t *obj, int c); + +csi_private void +csi_file_flush (csi_file_t *obj); + +csi_private void +csi_file_close (csi_t *ctx, csi_file_t *obj); + +csi_private void +_csi_file_free (csi_t *ctx, csi_file_t *obj); + +csi_private csi_status_t +_csi_file_as_string (csi_t *ctx, + csi_file_t *file, + csi_object_t *obj); + +/* cairo-script-hash.c */ + +csi_private csi_status_t +_csi_hash_table_init (csi_hash_table_t *hash_table, + csi_hash_keys_equal_func_t keys_equal); + +csi_private void +_csi_hash_table_fini (csi_hash_table_t *hash_table); + +csi_private void * +_csi_hash_table_lookup (csi_hash_table_t *hash_table, + csi_hash_entry_t *key); + +csi_private csi_status_t +_csi_hash_table_insert (csi_hash_table_t *hash_table, + csi_hash_entry_t *entry); + +csi_private void +_csi_hash_table_remove (csi_hash_table_t *hash_table, + csi_hash_entry_t *key); + +csi_private void +_csi_hash_table_foreach (csi_hash_table_t *hash_table, + csi_hash_callback_func_t hash_callback, + void *closure); + +/* cairo-script-interpreter.c */ + +csi_private void * +_csi_alloc (csi_t *ctx, int size); + +csi_private void * +_csi_alloc0 (csi_t *ctx, int size); + +csi_private void * +_csi_realloc (csi_t *ctx, void *ptr, int size); + +csi_private void +_csi_free (csi_t *ctx, void *ptr); + +csi_private void * +_csi_slab_alloc (csi_t *ctx, int size); + +csi_private void +_csi_slab_free (csi_t *ctx, void *ptr, int size); + +csi_private csi_status_t +csi_push_ostack (csi_t *ctx, csi_object_t *obj); + +csi_private csi_status_t +_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj); + +csi_private csi_status_t +_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj); + +csi_private csi_status_t +_csi_name_undefine (csi_t *ctx, csi_name_t name); + +csi_private csi_status_t +_csi_intern_string (csi_t *ctx, const char **str_inout, int len); + +csi_private csi_status_t +_csi_error (csi_status_t status); + +/* cairo-script-objects.c */ + +csi_private csi_status_t +csi_array_new (csi_t *ctx, + csi_object_t *obj); + +csi_private csi_status_t +_csi_array_execute (csi_t *ctx, csi_array_t *array); + +csi_private csi_status_t +csi_array_get (csi_t *ctx, + csi_array_t *array, + long elem, + csi_object_t *value); + +csi_private csi_status_t +csi_array_put (csi_t *ctx, + csi_array_t *array, + csi_integer_t elem, + csi_object_t *value); + +csi_private csi_status_t +csi_array_append (csi_t *ctx, + csi_array_t *array, + csi_object_t *obj); + +csi_private void +csi_array_free (csi_t *ctx, csi_array_t *array); + +csi_private csi_status_t +csi_boolean_new (csi_t *ctx, + csi_object_t *obj, + csi_boolean_t v); + +csi_private csi_status_t +csi_dictionary_new (csi_t *ctx, + csi_object_t *obj); + +csi_private csi_status_t +csi_dictionary_put (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value); + +csi_private csi_status_t +csi_dictionary_get (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value); + +csi_private csi_boolean_t +csi_dictionary_has (csi_dictionary_t *dict, + csi_name_t name); + +csi_private void +csi_dictionary_remove (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name); + +csi_private void +csi_dictionary_free (csi_t *ctx, + csi_dictionary_t *dict); + +csi_private csi_status_t +csi_integer_new (csi_t *ctx, + csi_object_t *obj, + csi_integer_t v); + +csi_private csi_status_t +csi_matrix_new (csi_t *ctx, + csi_object_t *obj); + +csi_private csi_status_t +csi_matrix_new_from_array (csi_t *ctx, + csi_object_t *obj, + csi_array_t *array); + +csi_private csi_status_t +csi_matrix_new_from_matrix (csi_t *ctx, + csi_object_t *obj, + const cairo_matrix_t *m); + +csi_private csi_status_t +csi_matrix_new_from_values (csi_t *ctx, + csi_object_t *obj, + double v[6]); + +csi_private void +csi_matrix_free (csi_t *ctx, + csi_matrix_t *obj); + +csi_private csi_status_t +csi_name_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len); + +csi_private csi_status_t +csi_name_new_static (csi_t *ctx, + csi_object_t *obj, + const char *str); + +csi_private csi_status_t +csi_operator_new (csi_t *ctx, + csi_object_t *obj, + csi_operator_t op); + +csi_private csi_status_t +csi_real_new (csi_t *ctx, + csi_object_t *obj, + csi_real_t v); + +csi_private csi_status_t +csi_string_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len); + +csi_private void +csi_string_free (csi_t *ctx, csi_string_t *string); + +csi_private csi_status_t +csi_object_execute (csi_t *ctx, csi_object_t *obj); + +csi_private csi_object_t * +csi_object_reference (csi_object_t *obj); + +csi_private void +csi_object_free (csi_t *ctx, + csi_object_t *obj); + +csi_private csi_status_t +csi_object_as_file (csi_t *ctx, + csi_object_t *src, + csi_object_t *file); + +/* cairo-script-operators.c */ + +csi_private const csi_operator_def_t * +_csi_operators (void); + +csi_private const csi_integer_constant_def_t * +_csi_integer_constants (void); + +/* cairo-script-scanner.c */ + +csi_private csi_status_t +_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner); + +csi_private csi_status_t +_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src); + +csi_private void +_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner); + +/* cairo-script-stack.c */ + +csi_private csi_status_t +_csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size); + +csi_private void +_csi_stack_fini (csi_t *ctx, csi_stack_t *stack); + +csi_private csi_status_t +_csi_stack_roll (csi_t *ctx, + csi_stack_t *stack, + csi_integer_t mod, + csi_integer_t n); + +csi_private csi_status_t +_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt); + +csi_private csi_status_t +_csi_stack_push (csi_t *ctx, csi_stack_t *stack, const csi_object_t *obj); + +csi_private csi_object_t * +_csi_stack_peek (csi_stack_t *stack, csi_integer_t i); + +csi_private void +_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count); + +csi_private csi_status_t +_csi_stack_exch (csi_stack_t *stack); + +static inline csi_object_type_t +csi_object_get_type (const csi_object_t *obj) +{ + return obj->type & CSI_OBJECT_TYPE_MASK; +} + +static inline csi_boolean_t +csi_object_is_procedure (const csi_object_t *obj) +{ + return obj->type == (CSI_OBJECT_TYPE_ARRAY | CSI_OBJECT_ATTR_EXECUTABLE); +} + +static inline csi_boolean_t +csi_object_is_number (const csi_object_t *obj) +{ + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_BOOLEAN: + case CSI_OBJECT_TYPE_INTEGER: + case CSI_OBJECT_TYPE_REAL: + return 1; + default: + return 0; + } +} + +static inline double +csi_number_get_value (const csi_object_t *obj) +{ + switch ((int) csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_BOOLEAN: return obj->datum.boolean; + case CSI_OBJECT_TYPE_INTEGER: return obj->datum.integer; + case CSI_OBJECT_TYPE_REAL: return obj->datum.real; + default: return 0.; + } +} + +static inline csi_boolean_t +_csi_check_ostack (csi_t *ctx, csi_integer_t count) +{ + return ctx->ostack.len >= count; +} + +static inline csi_object_t * +_csi_peek_ostack (csi_t *ctx, csi_integer_t i) +{ + return &ctx->ostack.objects[ctx->ostack.len - i -1]; +} + +static inline void +_csi_pop_ostack (csi_t *ctx, csi_integer_t count) +{ + do + csi_object_free (ctx, &ctx->ostack.objects[--ctx->ostack.len]); + while (--count); +} + +static inline csi_status_t +_csi_push_ostack_copy (csi_t *ctx, csi_object_t *obj) +{ + return _csi_stack_push (ctx, &ctx->ostack, csi_object_reference (obj)); +} + +static inline csi_status_t +_csi_push_ostack (csi_t *ctx, csi_object_t *obj) +{ + return _csi_stack_push (ctx, &ctx->ostack, obj); +} + +static inline csi_status_t +_csi_push_ostack_boolean (csi_t *ctx, csi_boolean_t v) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_BOOLEAN; + obj.datum.boolean = v; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} +static inline csi_status_t +_csi_push_ostack_integer (csi_t *ctx, csi_integer_t v) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_INTEGER; + obj.datum.integer = v; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} +static inline csi_status_t +_csi_push_ostack_mark (csi_t *ctx) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_MARK; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} +static inline csi_status_t +_csi_push_ostack_real (csi_t *ctx, csi_real_t v) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_REAL; + obj.datum.real = v; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} + +slim_hidden_proto_no_warn (cairo_script_interpreter_destroy); +slim_hidden_proto_no_warn (cairo_script_interpreter_reference); + +#endif /* CAIRO_SCRIPT_PRIVATE_H */ diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c new file mode 100644 index 00000000..bc3ff2cf --- /dev/null +++ b/util/cairo-script/cairo-script-scanner.c @@ -0,0 +1,1180 @@ +/* + * 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 + */ + +#include "cairo-script-private.h" + +#include /* EOF */ +#include /* memset */ +#include /* pow */ +#include /* bswap_32 */ + +/* + * whitespace: + * 0 - nul + * 9 - tab + * A - LF + * C - FF + * D - CR + * + * syntax delimiters + * ( = 28, ) = 29 - literal strings + * < = 3C, > = 3E - hex/base85 strings, dictionary name + * [ = 5B, ] = 5D - array + * { = 7B, } = 7C - procedure + * / = 5C - literal marker + * % = 25 - comment + */ + +static cairo_status_t +_csi_buffer_init (csi_t *ctx, csi_buffer_t *buffer) +{ + buffer->status = CSI_STATUS_SUCCESS; + buffer->size = 16384; + buffer->base = _csi_alloc (ctx, buffer->size); + if (_csi_unlikely (buffer->base == NULL)) { + buffer->status = _csi_error (CSI_STATUS_NO_MEMORY); + buffer->size = 0; + } + + buffer->ptr = buffer->base; + buffer->end = buffer->base + buffer->size; + + return buffer->status; +} + +static void +_csi_buffer_fini (csi_t *ctx, csi_buffer_t *buffer) +{ + _csi_free (ctx, buffer->base); +} + +static cairo_status_t +_csi_buffer_grow (csi_t *ctx, csi_buffer_t *buffer) +{ + int newsize; + int offset; + char *base; + + if (_csi_unlikely (buffer->status)) + return buffer->status; + + if (_csi_unlikely (buffer->size > INT32_MAX / 2)) + return buffer->status = _csi_error (CSI_STATUS_NO_MEMORY); + + offset = buffer->ptr - buffer->base; + newsize = buffer->size * 2; + base = _csi_realloc (ctx, buffer->base, newsize); + if (_csi_unlikely (base == NULL)) + return buffer->status = _csi_error (CSI_STATUS_NO_MEMORY); + + buffer->base = base; + buffer->ptr = base + offset; + buffer->end = base + newsize; + buffer->size = newsize; + + return CSI_STATUS_SUCCESS; +} + +static inline csi_boolean_t +_csi_buffer_check (csi_t *ctx, csi_buffer_t *buffer, int count) +{ + if (_csi_unlikely (buffer->ptr + count > buffer->end)) { + if (_csi_buffer_grow (ctx, buffer)) + return FALSE; + } + + return TRUE; +} + +static inline void +_csi_buffer_add (csi_buffer_t *buffer, int c) +{ + *buffer->ptr++ = c; +} + +static inline void +_csi_buffer_reset (csi_buffer_t *buffer) +{ + buffer->ptr = buffer->base; +} + +static inline int +scan_getc (csi_scanner_t *scan, csi_file_t *src) +{ + if (_csi_unlikely (scan->status)) + return EOF; + + return csi_file_getc (src); +} + +static inline int +scan_read (csi_scanner_t *scan, csi_file_t *src, void *buf, int len) +{ + return csi_file_read (src, buf, len); +} + +static inline void +scan_putc (csi_scanner_t *scan, csi_file_t *src, int c) +{ + csi_file_putc (src, c); +} + +static inline void +reset (csi_scanner_t *scan) +{ + scan->state = NONE; +} + +static void +token_start (csi_scanner_t *scan) +{ + scan->state = TOKEN; + _csi_buffer_reset (&scan->buffer); +} + +static void +token_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 1))) + _csi_buffer_add (&scan->buffer, c); +} + +static void +token_add_unchecked (csi_scanner_t *scan, int c) +{ + _csi_buffer_add (&scan->buffer, c); +} + +static csi_boolean_t +parse_number (csi_object_t *obj, const char *s, int len) +{ + int radix = 0; + long long mantissa = 0; + int exponent = 0; + int sign = 1; + int decimal = -1; + int exponent_sign = 0; + const char * const end = s + len; + + switch (*s) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + mantissa = *s - '0'; + case '+': + break; + case '-': + sign = -1; + break; + case '.': + decimal = 0; + break; + default: + return FALSE; + } + + while (++s < end) { + if (*s < '0') { + if (*s == '.') { + if (radix) + return FALSE; + if (decimal != -1) + return FALSE; + if (exponent_sign) + return FALSE; + + decimal = 0; + } else if (*s == '!') { + if (radix) + return FALSE; + if (decimal != -1) + return FALSE; + if (exponent_sign) + return FALSE; + + radix = mantissa; + mantissa = 0; + + if (radix < 2 || radix > 36) + return FALSE; + } else + return FALSE; + } else if (*s <= '9') { + int v = *s - '0'; + if (radix && v >= radix) + return FALSE; + + if (exponent_sign) { + exponent = 10 * exponent + v; + } else { + if (radix) + mantissa = radix * mantissa + v; + else + mantissa = 10 * mantissa + v; + if (decimal != -1) + decimal++; + } + } else if (*s == 'E' || * s== 'e') { + if (radix == 0) { + if (s + 1 == end) + return FALSE; + + exponent_sign = 1; + if (s[1] == '-') { + exponent_sign = -1; + s++; + } else if (s[1] == '+') + s++; + } else { + int v = 0xe; + + if (v >= radix) + return FALSE; + + mantissa = radix * mantissa + v; + } + } else if (*s < 'A') { + return FALSE; + } else if (*s <= 'Z') { + int v = *s - 'A' + 0xA; + + if (v >= radix) + return FALSE; + + mantissa = radix * mantissa + v; + } else if (*s < 'a') { + return FALSE; + } else if (*s <= 'z') { + int v = *s - 'a' + 0xa; + + if (v >= radix) + return FALSE; + + mantissa = radix * mantissa + v; + } else + return FALSE; + } + + if (exponent_sign || decimal != -1) { + if (mantissa == 0) { + obj->type = CSI_OBJECT_TYPE_REAL; + obj->datum.real = 0.; + return TRUE; + } else { + int e; + double v; + + v = mantissa; + e = exponent * exponent_sign; + if (decimal != -1) + e -= decimal; + if (e != 0) + v *= pow (10, e); /* XXX */ + + obj->type = CSI_OBJECT_TYPE_REAL; + obj->datum.real = sign * v; + return TRUE; + } + } else { + obj->type = CSI_OBJECT_TYPE_INTEGER; + obj->datum.integer = sign * mantissa; + return TRUE; + } +} + +static void +token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + char *s; + csi_object_t obj; + int len; + + /* + * Any token that consists entirely of regular characters and + * cannot be interpreted as a number is treated as a name object + * (more precisely, an executable name). All characters except + * delimiters and white-space characters can appear in names, + * including characters ordinarily considered to be punctuation. + */ + + if (_csi_unlikely (scan->buffer.ptr == scan->buffer.base)) + return; + + scan->status = scan->buffer.status; + if (_csi_unlikely (scan->status)) + return; + + s = scan->buffer.base; + len = scan->buffer.ptr - scan->buffer.base; + + if (s[0] == '{') { /* special case procedures */ + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + scan->status = _csi_stack_push (ctx, + &scan->procedure_stack, + &scan->build_procedure); + + scan->status = csi_array_new (ctx, &scan->build_procedure); + scan->build_procedure.type |= CSI_OBJECT_ATTR_EXECUTABLE; + reset (scan); + return; + } else if (s[0] == '}') { + csi_object_t *next; + + if (_csi_unlikely + (scan->build_procedure.type == CSI_OBJECT_TYPE_NULL)) + { + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return; + } + + if (scan->procedure_stack.len) { + next = _csi_stack_peek (&scan->procedure_stack, 0); + scan->status = csi_array_append (ctx, next->datum.array, + &scan->build_procedure); + scan->build_procedure = *next; + scan->procedure_stack.len--; + } else { + scan->status = _csi_push_ostack (ctx, &scan->build_procedure); + scan->build_procedure.type = CSI_OBJECT_TYPE_NULL; + } + + reset (scan); + return; + } + + if (s[0] == '/') { + if (len >= 2 && s[1] == '/') { /* substituted name */ + scan->status = csi_name_new (ctx, &obj, s + 2, len - 2); + if (_csi_unlikely (scan->status)) + return; + + scan->status = _csi_name_lookup (ctx, obj.datum.name, &obj); + } else { /* literal name */ + scan->status = csi_name_new (ctx, &obj, s + 1, len - 1); + } + } else { + if (! parse_number (&obj, s, len)) { + scan->status = csi_name_new (ctx, &obj, s, len); + obj.type |= CSI_OBJECT_ATTR_EXECUTABLE; + } + } + if (_csi_unlikely (scan->status)) + return; + + /* consume whitespace after token, before calling the interpreter */ + reset (scan); + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) { + scan->status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + } else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) { + scan->status = csi_object_execute (ctx, csi_object_reference (&obj)); + csi_object_free (ctx, &obj); + } else + scan->status = _csi_push_ostack (ctx, &obj); +} + +static void +comment_start (csi_scanner_t *scan) +{ + /* XXX check for '!' interpreter mode?, '%' dsc setup? */ + scan->state = COMMENT; +} + +static void +comment_end (csi_scanner_t *scan) +{ + reset (scan); +} + +static void +string_start (csi_scanner_t *scan) +{ + scan->state = STRING; + scan->string_p = 1; + _csi_buffer_reset (&scan->buffer); +} + +static void +string_inc_p (csi_scanner_t *scan) +{ + scan->string_p++; +} + +static int +string_dec_p (csi_scanner_t *scan) +{ + return --scan->string_p == 0; +} + +static void +string_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 1))) + _csi_buffer_add (&scan->buffer, c); +} + +static void +string_end (csi_t *ctx, csi_scanner_t *scan) +{ + csi_object_t obj; + + scan->status = scan->buffer.status; + if (_csi_unlikely (scan->status)) + return; + + scan->status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (scan->status)) + return; + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + scan->status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + scan->status = _csi_push_ostack (ctx, &obj); + + reset (scan); +} + +static void +hex_start (csi_scanner_t *scan) +{ + scan->state = HEX; + scan->accumulator_count = 0; + scan->accumulator = 0; + + _csi_buffer_reset (&scan->buffer); +} + +static int +hex_value (int c) +{ + if (c < '0') + return EOF; + if (c <= '9') + return c - '0'; + c |= 32; + if (c < 'a') + return EOF; + if (c <= 'f') + return c - 'a' + 0xa; + return EOF; +} + +static void +hex_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + if (scan->accumulator_count == 0) { + scan->accumulator |= hex_value (c) << 4; + scan->accumulator_count = 1; + } else { + scan->accumulator |= hex_value (c) << 0; + if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 1))) + _csi_buffer_add (&scan->buffer, scan->accumulator); + scan->accumulator = 0; + scan->accumulator_count = 0; + } +} + +static void +hex_end (csi_t *ctx, csi_scanner_t *scan) +{ + csi_object_t obj; + + if (scan->accumulator_count) + hex_add (ctx, scan, '0'); + + scan->status = scan->buffer.status; + if (_csi_unlikely (scan->status)) + return; + + scan->status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (scan->status)) + return; + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + scan->status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + scan->status = _csi_push_ostack (ctx, &obj); + + reset (scan); +} + +static void +base85_start (csi_scanner_t *scan) +{ + scan->state = BASE85; + scan->accumulator = 0; + scan->accumulator_count = 0; + + _csi_buffer_reset (&scan->buffer); +} + +static void +base85_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + if (c == 'z') { + if (_csi_unlikely (scan->accumulator_count != 0)) { + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return; + } + if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 4))) { + _csi_buffer_add (&scan->buffer, 0); + _csi_buffer_add (&scan->buffer, 0); + _csi_buffer_add (&scan->buffer, 0); + _csi_buffer_add (&scan->buffer, 0); + } + } else if (_csi_unlikely (c < '!' || c > 'u')) { + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return; + } else { + scan->accumulator = scan->accumulator*85 + c - '!'; + if (++scan->accumulator_count == 5) { + if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 4))) { + _csi_buffer_add (&scan->buffer, + (scan->accumulator >> 24) & 0xff); + _csi_buffer_add (&scan->buffer, + (scan->accumulator >> 16) & 0xff); + _csi_buffer_add (&scan->buffer, + (scan->accumulator >> 8) & 0xff); + _csi_buffer_add (&scan->buffer, + (scan->accumulator >> 0) & 0xff); + } + + scan->accumulator = 0; + scan->accumulator_count = 0; + } + } +} + +static void +base85_end (csi_t *ctx, csi_scanner_t *scan) +{ + csi_object_t obj; + + if (_csi_unlikely (! _csi_buffer_check (ctx, &scan->buffer, 4))) { + scan->status = scan->buffer.status; + return; + } + + switch (scan->accumulator_count) { + case 0: + break; + case 1: + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + break; + + case 2: + scan->accumulator = scan->accumulator * (85*85*85) + 85*85*85 -1; + _csi_buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff); + break; + case 3: + scan->accumulator = scan->accumulator * (85*85) + 85*85 -1; + _csi_buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff); + _csi_buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff); + break; + case 4: + scan->accumulator = scan->accumulator * 85 + 84; + _csi_buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff); + _csi_buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff); + _csi_buffer_add (&scan->buffer, (scan->accumulator >> 8) & 0xff); + break; + } + + scan->status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (scan->status)) + return; + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + scan->status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + scan->status = _csi_push_ostack (ctx, &obj); + + reset (scan); +} + +static int +scan_none (csi_t *ctx, + csi_scanner_t *scan, + csi_file_t *src) +{ + int c, next; + union { + int i; + float f; + } u; + + while ((c = scan_getc (scan, src)) != EOF) { + csi_object_t obj = { CSI_OBJECT_TYPE_NULL }; + + switch (c) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: /* ignore whitespace */ + break; + + case '%': + comment_start (scan); + return 1; + + case '(': + string_start (scan); + return 1; + + case '[': /* needs special case */ + case ']': + case '{': + case '}': + token_start (scan); + token_add_unchecked (scan, c); + token_end (ctx, scan, src); + return 1; + + case '<': + next = scan_getc (scan, src); + switch (next) { + case EOF: + scan_putc (scan, src, '<'); + return 0; + case '<': + /* dictionary name */ + token_start (scan); + token_add_unchecked (scan, '<'); + token_add_unchecked (scan, '<'); + token_end (ctx, scan, src); + return 1; + case '~': + base85_start (scan); + return 1; + default: + scan_putc (scan, src, next); + hex_start (scan); + return 1; + } + break; + + /* binary token */ + case 128: + case 129: + case 130: + case 131: + /* binary object sequence */ + break; + case 132: /* 32-bit integer, MSB */ + break; + case 133: /* 32-bit integer, LSB */ + break; + case 134: /* 16-bit integer, MSB */ + break; + case 135: /* 16-bit integer, LSB */ + break; + case 136: /* 8-bit integer */ + break; + case 137: /* 16/32-bit fixed point */ + break; + case 138: /* 32-bit real, MSB */ + scan_read (scan, src, &u.i, 4); +#if ! WORDS_BIGENDIAN + u.i = bswap_32 (u.i); +#endif + scan->status = csi_real_new (ctx, &obj, u.f); + break; + case 139: /* 32-bit real, LSB */ + scan_read (scan, src, &u.f, 4); +#if WORDS_BIGENDIAN + u.i = bswap_32 (u.i); +#endif + scan->status = csi_real_new (ctx, &obj, u.f); + break; + case 140: /* 32-bit real, native */ + scan_read (scan, src, &u.f, 4); + scan->status = csi_real_new (ctx, &obj, u.f); + break; + case 141: /* boolean */ + break; + case 142: /* string of length 1n */ + break; + case 143: /* string of length 2n (MSB) */ + break; + case 144: /* string of length 2n (LSB) */ + break; + case 145: /* literal system name */ + break; + case 146: /* executable system name */ + break; + case 147: /* reserved */ + break; + case 148: /* reserved */ + break; + case 149: /* homogeneous array */ + break; + + /* unassigned */ + case 150: + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + case 157: + case 158: + case 159: + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return 0; + + case '#': /* PDF 1.2 escape code */ + { + int c_hi = scan_getc (scan, src); + int c_lo = scan_getc (scan, src); + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } + /* fall-through */ + default: + token_start (scan); + token_add_unchecked (scan, c); + return 1; + } + + if (obj.type != CSI_OBJECT_TYPE_NULL) { + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + scan->status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + scan->status = csi_object_execute (ctx, &obj); + } + } + + return 0; +} + +static int +scan_token (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + int c; + + while ((c = scan_getc (scan, src)) != EOF) { + switch (c) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + token_end (ctx, scan, src); + return 1; + + /* syntax delimiters */ + case '%': + token_end (ctx, scan, src); + comment_start (scan); + return 1; + /* syntax error? */ + case '(': + token_end (ctx, scan, src); + string_start (scan); + return 1; + /* XXX syntax error? */ + case ')': + token_end (ctx, scan, src); + return 1; + case '/': + /* need to special case '^//?' */ + if (scan->buffer.ptr > scan->buffer.base+1 || + scan->buffer.base[0] != '/') + { + token_end (ctx, scan, src); + token_start (scan); + } + token_add_unchecked (scan, '/'); + return 1; + + case '{': + case '}': + case ']': + token_end (ctx, scan, src); + token_start (scan); + token_add_unchecked (scan, c); + token_end (ctx, scan, src); + return 1; + + case '<': + scan_putc (scan, src, '<'); + token_end (ctx, scan, src); + return 1; + + case '#': /* PDF 1.2 escape code */ + { + int c_hi = scan_getc (scan, src); + int c_lo = scan_getc (scan, src); + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } + /* fall-through */ + default: + token_add (ctx, scan, c); + break; + } + } + token_end (ctx, scan, src); + + return 0; +} + +static int +scan_hex (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + int c; + + while ((c = scan_getc (scan, src)) != EOF) { + switch (c) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: /* ignore whitespace */ + break; + + case '>': + hex_end (ctx, scan); /* fixup odd digit with '0' */ + return 1; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + hex_add (ctx, scan, c); + break; + + default: + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return 0; + } + } + + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return 0; +} + +static int +scan_base85 (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + int c, next; + + while ((c = scan_getc (scan, src)) != EOF) { + switch (c) { + case '~': + next = scan_getc (scan, src); + switch (next) { + case EOF: + return 0; + + case '>': + base85_end (ctx, scan); + return 1; + } + scan_putc (scan, src, next); + + /* fall-through */ + default: + base85_add (ctx, scan, c); + break; + } + } + + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return 0; +} + +static int +scan_string (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + int c, next; + + while ((c = scan_getc (scan, src)) != EOF) { + switch (c) { + case '\\': /* escape */ + next = scan_getc (scan, src); + switch (next) { + case EOF: + return 0; + + case 'n': + string_add (ctx, scan, '\n'); + break; + case 'r': + string_add (ctx, scan, '\r'); + break; + case 't': + string_add (ctx, scan, '\r'); + break; + case 'b': + string_add (ctx, scan, '\b'); + break; + case 'f': + string_add (ctx, scan, '\f'); + break; + case '\\': + string_add (ctx, scan, '\\'); + break; + case '(': + string_add (ctx, scan, '('); + break; + case ')': + string_add (ctx, scan, ')'); + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + { /* octal code: \d{1,3} */ + int i; + + c = next - '0'; + + for (i = 0; i < 2; i++) { + next = scan_getc (scan, src); + switch (next) { + case EOF: + return 0; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = 8*c + next-'0'; + break; + + default: + scan_putc (scan, src, next); + goto octal_code_done; + } + } + octal_code_done: + string_add (ctx, scan, c); + } + break; + + case 0xa: + /* skip the newline */ + next = scan_getc (scan, src); /* might be compound LFCR */ + switch (next) { + case EOF: + return 0; + case 0xc: + break; + default: + scan_putc (scan, src, next); + break; + } + break; + case 0xc: + break; + + default: + /* ignore the '\' */ + break; + } + break; + + case '(': + string_inc_p (scan); + string_add (ctx, scan, c); + break; + + case ')': + if (string_dec_p (scan)) { + string_end (ctx, scan); + return 1; + } else + string_add (ctx, scan, c); + break; + + default: + string_add (ctx, scan, c); + break; + } + } + + scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + return 0; +} + +static int +scan_comment (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + int c; + + /* discard until newline */ + while ((c = scan_getc (scan, src)) != EOF) { + switch (c) { + case 0xa: + case 0xc: + comment_end (scan); + return 1; + } + } + + return 0; +} + +csi_status_t +_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + static int (* const func[]) (csi_t *, csi_scanner_t *, csi_file_t *) = { + scan_none, + scan_token, + scan_comment, + scan_string, + scan_hex, + scan_base85, + }; + + while (func[scan->state] (ctx, scan, src)) + ; + + return scan->status; +} + +#if 0 +cairo_status_t +_csi_tokenize_string (csi_t *ctx, + const char *code, int len, + csi_object_t **array_out) +{ + csi_scanner_t scan; + csi_object_t *src; + cairo_status_t status; + + status = _csi_scanner_init (&scan, ctx); + if (status) + return status; + + scan.build_procedure = csi_array_new (ctx, 0); + if (scan.build_procedure == NULL) + goto CLEANUP_SCAN; + csi_object_set_literal (scan.build_procedure, FALSE); + + src = csi_file_new_for_string (ctx, (const uint8_t *) code, len); + if (src == NULL) { + status = _csi_error (CSI_STATUS_NO_MEMORY); + goto CLEANUP_SCAN; + } + + status = _csi_scan_object (&scan, src); + if (status) + goto CLEANUP_SRC; + + *array_out = scan.build_procedure; + scan.build_procedure = NULL; + +CLEANUP_SRC: + csi_object_free (src); + +CLEANUP_SCAN: + _csi_scanner_fini (&scan); + + return status; +} +#endif + +csi_status_t +_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner) +{ + csi_status_t status; + + memset (scanner, 0, sizeof (csi_scanner_t)); + + status = _csi_buffer_init (ctx, &scanner->buffer); + if (status) + return status; + + status = _csi_stack_init (ctx, &scanner->procedure_stack, 4); + if (status) + return status; + + reset (scanner); + + return CSI_STATUS_SUCCESS; +} + +void +_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner) +{ + _csi_buffer_fini (ctx, &scanner->buffer); + _csi_stack_fini (ctx, &scanner->procedure_stack); + if (scanner->build_procedure.type != CSI_OBJECT_TYPE_NULL) + csi_object_free (ctx, &scanner->build_procedure); +} diff --git a/util/cairo-script/cairo-script-stack.c b/util/cairo-script/cairo-script-stack.c new file mode 100644 index 00000000..bc1d889e --- /dev/null +++ b/util/cairo-script/cairo-script-stack.c @@ -0,0 +1,196 @@ +/* + * 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 + */ + +#include "cairo-script-private.h" + +#include + +csi_status_t +_csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size) +{ + csi_status_t status = CSI_STATUS_SUCCESS; + + stack->len = 0; + stack->size = size; + /* assert ((unsigned) size < INT32_MAX / sizeof (csi_object_t)); */ + stack->objects = _csi_alloc (ctx, stack->size * sizeof (csi_object_t)); + if (_csi_unlikely (stack->objects == NULL)) + status = _csi_error (CSI_STATUS_NO_MEMORY); + + return status; +} + +void +_csi_stack_fini (csi_t *ctx, csi_stack_t *stack) +{ + csi_integer_t n; + + for (n = 0; n < stack->len; n++) + csi_object_free (ctx, &stack->objects[n]); + + _csi_free (ctx, stack->objects); +} + +csi_status_t +_csi_stack_roll (csi_t *ctx, + csi_stack_t *stack, + csi_integer_t mod, csi_integer_t n) +{ + csi_object_t stack_copy[128]; + csi_object_t *copy; + csi_integer_t last, i, len; + + switch (mod) { /* special cases */ + case 1: + last = stack->len - 1; + stack_copy[0] = stack->objects[last]; + for (i = last; --n; i--) + stack->objects[i] = stack->objects[i-1]; + stack->objects[i] = stack_copy[0]; + return CSI_STATUS_SUCCESS; + case -1: + last = stack->len - 1; + stack_copy[0] = stack->objects[i = last - n + 1]; + for (; --n; i++) + stack->objects[i] = stack->objects[i+1]; + stack->objects[i] = stack_copy[0]; + return CSI_STATUS_SUCCESS; + } + + /* fall back to a copy */ + if (n > ARRAY_LENGTH (stack_copy)) { + if (_csi_unlikely ((unsigned) n > INT32_MAX / sizeof (csi_object_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + copy = _csi_alloc (ctx, n * sizeof (csi_object_t)); + if (copy == NULL) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + copy = stack_copy; + + i = stack->len - n; + memcpy (copy, stack->objects + i, n * sizeof (csi_object_t)); + mod = -mod; + if (mod < 0) + mod += n; + last = mod; + for (len = n; n--; i++) { + stack->objects[i] = copy[last]; + if (++last == len) + last = 0; + } + + if (copy != stack_copy) + _csi_free (ctx, copy); + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt) +{ + csi_integer_t newsize; + csi_object_t *newstack; + + if (_csi_likely (cnt <= stack->size)) + return CSI_STATUS_SUCCESS; + if (_csi_unlikely ((unsigned) cnt >= INT32_MAX / sizeof (csi_object_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + + newsize = stack->size; + do { + newsize *= 2; + } while (newsize <= cnt); + + newstack = _csi_realloc (ctx, + stack->objects, + newsize * sizeof (csi_object_t)); + if (_csi_unlikely (newstack == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + stack->objects = newstack; + stack->size = newsize; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +_csi_stack_push (csi_t *ctx, csi_stack_t *stack, const csi_object_t *obj) +{ + if (_csi_unlikely (stack->len == stack->size)) { + csi_status_t status; + + status = _csi_stack_grow (ctx, stack, stack->size + 1); + if (status) + return status; + } + + stack->objects[stack->len++] = *obj; + return CSI_STATUS_SUCCESS; +} + +csi_object_t * +_csi_stack_peek (csi_stack_t *stack, csi_integer_t i) +{ + if (_csi_unlikely (stack->len < i)) + return NULL; + + return &stack->objects[stack->len - i -1]; +} + +void +_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count) +{ + if (_csi_unlikely (stack->len < count)) + count = stack->len; + + while (count--) + csi_object_free (ctx, &stack->objects[--stack->len]); +} + +csi_status_t +_csi_stack_exch (csi_stack_t *stack) +{ + csi_object_t tmp; + csi_integer_t n; + + if (_csi_unlikely (stack->len < 2)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + n = stack->len - 1; + tmp = stack->objects[n]; + stack->objects[n] = stack->objects[n - 1]; + stack->objects[n - 1] = tmp; + + return CSI_STATUS_SUCCESS; +} -- cgit v1.2.3 From 35a1ba0ddc45f9cc785c6f8a37b6bb49c953e047 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 13 Nov 2008 16:36:20 +0100 Subject: Document the buggy_repeat workaround more carefully. It's a confusing condition, so let's be explicit about where the various numbers come from. --- src/cairo-xlib-display.c | 54 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index 5e6dba11..fae0f233 100644 --- a/src/cairo-xlib-display.c +++ b/src/cairo-xlib-display.c @@ -283,25 +283,47 @@ _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" < 10400000 (new numbering scheme) + */ 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) 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) { -- cgit v1.2.3 From d654d528de16769932131da80f4b925151d50103 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 13 Nov 2008 16:45:15 +0100 Subject: Blacklist "X.Org" < 7.0 with the buggy_repeat workaround. This is in response to a report that a 6.9 server crashes with cairo's extend-reflect test: https://bugs.freedesktop.org/show_bug.cgi?id=15628#c2 --- src/cairo-xlib-display.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index fae0f233..b2e2755d 100644 --- a/src/cairo-xlib-display.c +++ b/src/cairo-xlib-display.c @@ -319,10 +319,17 @@ _cairo_xlib_display_get (Display *dpy) * by using the same buggy_repeat workaround. Confirmed X * servers with this bug include: * - * "X.org" < 10400000 (new numbering scheme) + * "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) { - if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) <= 60802000) + if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) < 70000000) display->buggy_repeat = TRUE; if (VendorRelease (dpy) < 10400000) display->buggy_repeat = TRUE; -- cgit v1.2.3 From 3b11997a23baa9e38e87b584ee29f4888a5d92f7 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Thu, 13 Nov 2008 18:01:47 +0200 Subject: [cairo-script] Remove outdated #error to allow compilation to succeed. The interpreter doesn't depend on the script surface anymore. --- util/cairo-script/cairo-script-interpreter.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/util/cairo-script/cairo-script-interpreter.h b/util/cairo-script/cairo-script-interpreter.h index 21a3a15b..d619388e 100644 --- a/util/cairo-script/cairo-script-interpreter.h +++ b/util/cairo-script/cairo-script-interpreter.h @@ -38,8 +38,6 @@ #include -#if CAIRO_HAS_SCRIPT_SURFACE - CAIRO_BEGIN_DECLS typedef struct _cairo_script_interpreter cairo_script_interpreter_t; @@ -97,8 +95,4 @@ cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx); 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_INTERPRETER_H*/ -- cgit v1.2.3 From b9c1344ad82d38bb86fa85fbb565b2de64aa0e35 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 14 Nov 2008 11:07:10 +0100 Subject: NEWS: Add notes for cairo 1.8.4 Just a few bug fixes here. --- NEWS | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/NEWS b/NEWS index 7a9150eb..5be426cd 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,55 @@ +Release 1.8.4 (2008-11-14 Carl Worth ) +========================================================= +The cairo community is pleased to announce the 1.8.4 release of the +cairo graphics library. This is the second update to cairo's stable +1.8 series and contains a small number of bug fixes, (in particular a +few fixes for build failures of cairo 1.8.2 on various systems). This +is being released just over two weeks after cairo 1.8.2. + +We recommend that everyone using cairo upgrade to 1.8.4. + +-Carl + +Build fixes +----------- +Fix build with older XRender that doesn't define RepeatNone: + + Build of xlib backend fails against old XRender (RepeatNone undeclared) + https://bugs.freedesktop.org/show_bug.cgi?id=18385 + +Fix build with bash version <= 3.0: + + doltlibtool broken on linux with bash 3.00.0 + https://bugs.freedesktop.org/show_bug.cgi?id=18363 + +Bug fixes +--------- +Avoid triggering a bug in X.org server 6.9 resulting in a hung machine +requiring a reboot: + + https://bugs.freedesktop.org/show_bug.cgi?id=15628#c2 + +Fix display of user fonts as exercised by proposed support for type3 +fonts in poppler (unsigned promotion fixes): + + Use cairo user-font for Type 3 fonts + http://lists.freedesktop.org/archives/poppler/2008-October/004181.html + +Avoid miscomputing size of fallback images required when rendering +with CLEAR, IN, or SOURCE operator to vector surfaces, (PS, PDF, SVG, +etc.). + +Be more tolerant of broken fonts when subsetting type1 fonts: + + Error handling in cairo_type1_font_subset_get_glyph_names_and_widths + http://lists.cairographics.org/archives/cairo/2008-October/015569.html + +Fix cairo_fill_extents, cairo_stroke_extents, cairo_path_extents, to +correctly allow NULL parameters as documented. + +Fix potential crash on emitting a type3 glyph after having drawn text +paths from the same font, (for example with cairo_text_path). + Release 1.8.2 (2008-10-29 Carl Worth ) ========================================================= The cairo community is pleased to announce the 1.8.2 release of the -- cgit v1.2.3 From 66e8f142e381501d114888c2d1fc1e7f6d6a9857 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 14 Nov 2008 11:08:40 +0100 Subject: Increment version to 1.8.4 --- cairo-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo-version.h b/cairo-version.h index 0a2f40a7..879ec719 100644 --- a/cairo-version.h +++ b/cairo-version.h @@ -3,6 +3,6 @@ #define CAIRO_VERSION_MAJOR 1 #define CAIRO_VERSION_MINOR 8 -#define CAIRO_VERSION_MICRO 3 +#define CAIRO_VERSION_MICRO 4 #endif -- cgit v1.2.3 From ab61544b30406a49abc1f559d81129edce6d41ec Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 14 Nov 2008 13:17:01 +0100 Subject: Increment version to 1.8.5 after the 1.8.4 release. --- cairo-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo-version.h b/cairo-version.h index 879ec719..e3897600 100644 --- a/cairo-version.h +++ b/cairo-version.h @@ -3,6 +3,6 @@ #define CAIRO_VERSION_MAJOR 1 #define CAIRO_VERSION_MINOR 8 -#define CAIRO_VERSION_MICRO 4 +#define CAIRO_VERSION_MICRO 5 #endif -- cgit v1.2.3 From a4c5371b5e6d0df71efc75fee6f6a8fe8c6d3488 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 14:56:38 +0000 Subject: [os2] Move include cairo.h before os2.h The defines need to come first, but we specify that cairo.h is the first header file to be included by files. --- src/cairo-os2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cairo-os2.h b/src/cairo-os2.h index 17f02634..0d18674b 100644 --- a/src/cairo-os2.h +++ b/src/cairo-os2.h @@ -44,10 +44,10 @@ #define INCL_WIN #define INCL_GPI -#include - #include "cairo.h" +#include + CAIRO_BEGIN_DECLS /* The OS/2 Specific Cairo API */ -- cgit v1.2.3 From e44c1f26e48cfb2f74834b6a8ef8532b0bd28982 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Sat, 18 Oct 2008 01:15:44 +0300 Subject: Use a smaller and faster random number generator. The previous LFSR generator used a large table to be speedy. The replacement generator is the single stage generator (1) from section 5.4 of [HP2007], requires no tables or extra state. I've run the generator through Rob Brown's extended Dieharder test suite and it passes all but one self-proclaimed buggy test (-d2) and the 2D sphere minimum distance test (-d12). [HP2007] Hars L. and Petruska G., ``Pseudorandom Recursions: Small and Fast Pseurodandom Number Generators for Embedded Applications'', Hindawi Publishing Corporation EURASIP Journal on Embedded Systems Volume 2007, Article ID 98417, 13 pages doi:10.1155/2007/98417 http://www.hindawi.com/getarticle.aspx?doi=10.1155/2007/98417&e=cta --- src/cairo-skiplist.c | 200 +++------------------------------------------------ 1 file changed, 11 insertions(+), 189 deletions(-) diff --git a/src/cairo-skiplist.c b/src/cairo-skiplist.c index e2b793e1..40377150 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; @@ -273,7 +95,7 @@ random_level (void) /* 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(); + uint32_t bits = hars_petruska_f54_1_random (); bits |= bits >> 16; while (++level < MAX_LEVEL) -- cgit v1.2.3 From 032be9849dfc32ec8802a4f086619755a3a397f5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 16:36:01 +0000 Subject: [skiplist] Inline testing. Add a loop to create a skip list to allow manual checking. --- src/Makefile.am | 5 ++++- src/cairo-skiplist.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) 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/cairo-skiplist.c b/src/cairo-skiplist.c index 40377150..b08453b0 100644 --- a/src/cairo-skiplist.c +++ b/src/cairo-skiplist.c @@ -305,3 +305,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 -- cgit v1.2.3 From db9ed77d8aa4f4b4c8410e52e5bbd16ffa94ee24 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 20:36:14 +0000 Subject: [cairo] FLush surface on cairo_destroy() When discussing the implications of snapshot cow, one of the questions that we raised was what happens on cairo_destroy()? The lifetime of the context implicitly marks the extents of the drawing operations, typically the expose event (or perhaps one phase of it). Therefore at the end of the sequence we implicitly wish to flush the graphics events to the surface. --- src/cairo.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/cairo.c b/src/cairo.c index 56f99e49..bd31063d 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -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; -- cgit v1.2.3 From 3bf8379408ce9b1e08d130bcd1076766e36f1bef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 14 Nov 2008 09:50:29 +0000 Subject: [type1] Propagate fatal NO_MEMORY erro from FreeType. If FreeType fails to load the glyph, check for a fatal error before falling back (and effectively masking the fatal condition). --- src/cairo-type1-subset.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index bbff33d9..e5557585 100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -553,14 +553,24 @@ 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) + 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) + 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) -- cgit v1.2.3 From d7873eecc598a558a2a862add8e9b056c4a23a4a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 14 Nov 2008 17:18:47 +0000 Subject: [spline] Eliminate intermediate allocations during spline decomposition. The spline decomposition code allocates and stores points in a temporary buffer which is immediately consumed by the caller. If the caller supplies a callback that handles each point computed along the spline, then we can use the point immediately and avoid the allocation. --- src/cairo-bentley-ottmann.c | 12 +-- src/cairo-path-fill.c | 23 ++-- src/cairo-path-fixed.c | 27 ++--- src/cairo-path-in-fill.c | 21 ++-- src/cairo-path-stroke.c | 101 +++++++++--------- src/cairo-pen.c | 254 +++++++++++++++++++++++++++++--------------- src/cairo-polygon.c | 23 ++-- src/cairo-spline.c | 121 ++++----------------- src/cairo-types-private.h | 13 ++- src/cairoint.h | 65 ++++++++---- 10 files changed, 331 insertions(+), 329 deletions(-) diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c index b22731df..eca28d5b 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; @@ -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) @@ -1734,10 +1731,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-path-fill.c b/src/cairo-path-fill.c index 1cef20e4..46046bb9 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 diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 027ebedf..b36f4d8e 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -890,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 diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c index fcac9b13..2b9b057d 100644 --- a/src/cairo-path-in-fill.c +++ b/src/cairo-path-in-fill.c @@ -165,8 +165,6 @@ _cairo_in_fill_curve_to (void *closure, cairo_in_fill_t *in_fill = closure; cairo_spline_t spline; cairo_fixed_t top, bot, left; - cairo_status_t status; - int i; /* first reject based on bbox */ bot = top = in_fill->current_point.y; @@ -187,21 +185,18 @@ _cairo_in_fill_curve_to (void *closure, return CAIRO_STATUS_SUCCESS; /* XXX Investigate direct inspection of the inflections? */ - status = _cairo_spline_init (&spline, &in_fill->current_point, b, c, d); - if (status == CAIRO_INT_STATUS_DEGENERATE) + 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; + } - status = _cairo_spline_decompose (&spline, in_fill->tolerance); - if (status) - goto CLEANUP_SPLINE; - - for (i = 1; i < spline.num_points; i++) - _cairo_in_fill_line_to (in_fill, &spline.points[i]); - - CLEANUP_SPLINE: + _cairo_spline_decompose (&spline, in_fill->tolerance); _cairo_spline_fini (&spline); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index efccbcfe..3c02a94c 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -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; @@ -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 (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) 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); + status = _cairo_pen_add_points (&spline_pen.pen, extra_points, 4); if (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 diff --git a/src/cairo-pen.c b/src/cairo-pen.c index 425b3b96..43d344a1 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 + * Chris Wilson */ #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, @@ -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; @@ -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); + /* 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 (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 (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-polygon.c b/src/cairo-polygon.c index 1392bfa1..95cadc9c 100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c @@ -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-spline.c b/src/cairo-spline.c index b39257e2..7ec1c56c 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,28 @@ _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); _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-types-private.h b/src/cairo-types-private.h index 905bc401..6f1354d6 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -265,9 +265,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 { @@ -287,15 +285,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 { diff --git a/src/cairoint.h b/src/cairoint.h index 940e33c5..c0e9b217 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -2114,7 +2114,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); @@ -2129,21 +2129,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 @@ -2152,6 +2171,12 @@ _cairo_polygon_init (cairo_polygon_t *polygon); 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); @@ -2166,14 +2191,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 -- cgit v1.2.3 From bf309aab6072ee1004073e71bccdf3c8040a8ad6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 15 Nov 2008 11:36:41 +0000 Subject: [configure] Delete CAN_TEST_SCRIPT A CairoScript interpreter is built under utils and so is always available. --- configure.ac | 3 --- test/any2ppm.c | 8 -------- 2 files changed, 11 deletions(-) diff --git a/configure.ac b/configure.ac index 9bc22e1d..7384ccc4 100644 --- a/configure.ac +++ b/configure.ac @@ -238,10 +238,7 @@ dnl =========================================================================== any2ppm_cs=no CAIRO_ENABLE_SURFACE_BACKEND(script, script, no, [ - test_script=yes any2ppm_cs=yes - AC_DEFINE([CAIRO_CAN_TEST_SCRIPT_SURFACE], 1, - [Define to 1 if the CairoScript backend can be tested]) ]) dnl =========================================================================== diff --git a/test/any2ppm.c b/test/any2ppm.c index c4cf085e..e39775b9 100644 --- a/test/any2ppm.c +++ b/test/any2ppm.c @@ -236,7 +236,6 @@ write_ppm (cairo_surface_t *surface, int fd) return NULL; } -#if CAIRO_CAN_TEST_SCRIPT_SURFACE static cairo_surface_t * _create_image (void *closure, double width, double height) @@ -293,13 +292,6 @@ cs_convert (char **argv, int fd) return err; } -#else -static const char * -cs_convert (char **argv, int fd) -{ - return "compiled without CairoScript support."; -} -#endif #if CAIRO_CAN_TEST_PDF_SURFACE /* adapted from pdf2png.c */ -- cgit v1.2.3 From a2eff7c7deb9b41c387472bb91b9a7b9c8f319f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 16 Nov 2008 16:19:25 +0000 Subject: [test] Add build rule for libcairo-script-interpreter.la Add a rule to build the cairo-script-interpreter on behalf of any2ppm. --- test/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/Makefile.am b/test/Makefile.am index 55179778..749b309a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1155,6 +1155,9 @@ $(top_builddir)/src/libcairo.la: $(top_builddir)/test/pdiff/libpdiff.la: cd $(top_builddir)/test/pdiff && $(MAKE) $(AM_MAKEFLAGS) libpdiff.la +$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la: $(top_builddir)/src/libcairo.la + cd $(top_builddir)/util/cair-script && $(MAKE) $(AM_MAKEFLAGS) libcairo-script-interpreter.la + EXTRA_PROGRAMS += imagediff png-flatten imagediff_SOURCES = \ -- cgit v1.2.3 From 997fa6a7729b72b25d9275929bf190e71eed1b9d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 16 Nov 2008 17:43:40 +0000 Subject: [configure] Remove old line for CairoScript testing. CairoScript testing should now be unconditional so remove the surplus message. --- build/configure.ac.features | 1 - 1 file changed, 1 deletion(-) diff --git a/build/configure.ac.features b/build/configure.ac.features index 9970fde0..71738083 100644 --- a/build/configure.ac.features +++ b/build/configure.ac.features @@ -390,7 +390,6 @@ AC_DEFUN([CAIRO_REPORT], echo " test surfaces: $use_test_surfaces" echo " ps testing: $test_ps" echo " pdf testing: $test_pdf" - echo " cs testing: $test_script" echo " svg testing: $test_svg" if test x"$use_win32" = "xyes"; then echo " win32 printing testing: $test_win32_printing" -- cgit v1.2.3 From 3a82f943988413e0d3fada9932bb385f4cbdb3c7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 16 Nov 2008 18:21:52 +0000 Subject: [test] Add util/cairo-script to include path. any2ppm needs the include path for cairo-script-interpreter so that it can be built without an existing install. --- test/Makefile.am | 3 ++- test/any2ppm.c | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index 749b309a..e0924292 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1142,6 +1142,7 @@ AM_CPPFLAGS = \ -I$(srcdir) \ -I$(srcdir)/pdiff \ -I$(top_srcdir)/boilerplate \ + -I$(top_srcdir)/util/cairo-script \ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ $(CAIRO_CFLAGS) @@ -1156,7 +1157,7 @@ $(top_builddir)/test/pdiff/libpdiff.la: cd $(top_builddir)/test/pdiff && $(MAKE) $(AM_MAKEFLAGS) libpdiff.la $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la: $(top_builddir)/src/libcairo.la - cd $(top_builddir)/util/cair-script && $(MAKE) $(AM_MAKEFLAGS) libcairo-script-interpreter.la + cd $(top_builddir)/util/cairo-script && $(MAKE) $(AM_MAKEFLAGS) libcairo-script-interpreter.la EXTRA_PROGRAMS += imagediff png-flatten diff --git a/test/any2ppm.c b/test/any2ppm.c index e39775b9..ae5de325 100644 --- a/test/any2ppm.c +++ b/test/any2ppm.c @@ -62,10 +62,7 @@ #include #include - -#if CAIRO_CAN_TEST_SCRIPT_SURFACE #include -#endif #if CAIRO_CAN_TEST_PDF_SURFACE #include -- cgit v1.2.3 From b091c5bfcad170fd563699a1c8b11e7d25d159a2 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Tue, 18 Nov 2008 00:20:38 +0200 Subject: BIBLIOGRAPHY: Cite Hars & Petruska's Pseudorandom Recursions paper. --- BIBLIOGRAPHY | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/BIBLIOGRAPHY b/BIBLIOGRAPHY index dacd5321..90a6cef2 100644 --- a/BIBLIOGRAPHY +++ b/BIBLIOGRAPHY @@ -68,6 +68,21 @@ of Bentley-Ottmann: http://citeseer.ist.psu.edu/pugh90skip.html +The random number generator used in our skip list implementation is a +very small generator by Hars and Petruska. The generator is based on +an invertable function on Z_{2^32} with full period and is described +in + + Hars L. and Petruska G., + ``Pseudorandom Recursions: Small and Fast Pseurodandom + Number Generators for Embedded Applications'', + Hindawi Publishing Corporation + EURASIP Journal on Embedded Systems + Volume 2007, Article ID 98417, 13 pages + doi:10.1155/2007/98417 + + http://www.hindawi.com/getarticle.aspx?doi=10.1155/2007/98417&e=cta + From the result of the intersection-finding pass, we are currently computing a tessellation of trapezoids, (the exact manner is undergoing some work right now with some important speedup), but we -- cgit v1.2.3 From 2839a0e800d6cc12b28da44f30a9e278ceac65aa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 16 Nov 2008 20:04:55 +0000 Subject: [script] Add a simple replay. A very simple replay program for trace replay. --- util/cairo-script/.gitignore | 1 + util/cairo-script/Makefile.am | 7 +++- util/cairo-script/csi-replay.c | 85 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 util/cairo-script/.gitignore create mode 100644 util/cairo-script/csi-replay.c diff --git a/util/cairo-script/.gitignore b/util/cairo-script/.gitignore new file mode 100644 index 00000000..d56f76e8 --- /dev/null +++ b/util/cairo-script/.gitignore @@ -0,0 +1 @@ +csi-replay diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am index 348519f6..03cb13e6 100644 --- a/util/cairo-script/Makefile.am +++ b/util/cairo-script/Makefile.am @@ -1,4 +1,7 @@ lib_LTLIBRARIES = libcairo-script-interpreter.la +noinst_PROGRAMS = csi-replay + +AM_CPPFLAGS = -I$(top_srcdir)/src cairoincludedir=$(includedir)/cairo cairoinclude_HEADERS = cairo-script-interpreter.h @@ -12,10 +15,12 @@ libcairo_script_interpreter_la_SOURCES = \ cairo-script-scanner.c \ cairo-script-stack.c \ $(NULL) -libcairo_script_interpreter_la_CPPFLAGS = -I$(top_srcdir)/src libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS) libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols) libcairo_script_interpreter_la_LIBADD = -lz $(CAIRO_LIBS) -L$(top_builddir)/src -lcairo +csi_replay_SOURCES = csi-replay.c +csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la + EXTRA_DIST = \ COPYING diff --git a/util/cairo-script/csi-replay.c b/util/cairo-script/csi-replay.c new file mode 100644 index 00000000..5ca035f2 --- /dev/null +++ b/util/cairo-script/csi-replay.c @@ -0,0 +1,85 @@ +#include +#include + +#include +#include + +static const cairo_user_data_key_t _key; + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +#include +#include + +static Display * +_get_display (void) +{ + static Display *dpy; + + if (dpy != NULL) + return dpy; + + dpy = XOpenDisplay (NULL); + if (dpy == NULL) { + fprintf (stderr, "Failed to open display.\n"); + exit (1); + } + + return dpy; +} + +static void +_destroy_window (void *closure) +{ + XFlush (_get_display ()); + XDestroyWindow (_get_display(), (Window) closure); +} + +static cairo_surface_t * +_surface_create (void *closure, + double width, double height) +{ + Display *dpy; + Visual *visual; + XRenderPictFormat *xrender_format; + XSetWindowAttributes attr; + Window w; + cairo_surface_t *surface; + + dpy = _get_display (); + + visual = DefaultVisual (dpy, DefaultScreen (dpy)); + xrender_format = XRenderFindVisualFormat (dpy, visual); + if (xrender_format == NULL) { + fprintf (stderr, "X server does not have the Render extension.\n"); + exit (1); + } + + attr.override_redirect = True; + w = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0, + width, height, 0, xrender_format->depth, + InputOutput, visual, CWOverrideRedirect, &attr); + XMapWindow (dpy, w); + + surface = cairo_xlib_surface_create_with_xrender_format (dpy, w, + DefaultScreenOfDisplay (dpy), + xrender_format, + width, height); + cairo_surface_set_user_data (surface, &_key, (void *) w, _destroy_window); + + return surface; +} +#endif + +int +main (int argc, char **argv) +{ + cairo_script_interpreter_t *csi; + const cairo_script_interpreter_hooks_t hooks = { + .surface_create = _surface_create + }; + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + cairo_script_interpreter_run (csi, argv[1]); + return cairo_script_interpreter_destroy (csi); +} -- cgit v1.2.3 From 91c17d33324b51a3876bc6ce778c684111139303 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Nov 2008 00:32:54 +0000 Subject: [trace] Simple unbounded cache for symbol lookups. Reparsing the dwarf info for every lookup is very slow, so cache the symbol lookups. This initial implementation is unbounded in the simple belief that the actual number of unique lookups during a program's lifetime should be fairly small. (Extending to a bounded MRU list is left as an exercise for the reader.) --- util/cairo-trace/lookup-symbol.c | 70 ++++++++++++++++++++++++++++++++++------ util/cairo-trace/trace.c | 9 +++--- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/util/cairo-trace/lookup-symbol.c b/util/cairo-trace/lookup-symbol.c index 42c9c955..eb1a656d 100644 --- a/util/cairo-trace/lookup-symbol.c +++ b/util/cairo-trace/lookup-symbol.c @@ -61,6 +61,7 @@ #include #include #include +#include #if HAVE_BFD #include @@ -246,6 +247,15 @@ find_matching_file (struct dl_phdr_info *info, size_t size, void *data) return 0; } +struct symbol_cache_entry { + const void *ptr; + struct symbol_cache_entry *hash_prev, *hash_next; + char name[0]; +}; + +static struct symbol_cache_entry *symbol_cache_hash[13477]; +static pthread_mutex_t symbol_cache_mutex = PTHREAD_MUTEX_INITIALIZER; + char * lookup_symbol (char *buf, int buflen, const void *ptr) { @@ -254,6 +264,32 @@ lookup_symbol (char *buf, int buflen, const void *ptr) struct symtab symtab; struct symbol symbol; #endif + struct symbol_cache_entry *cache; + int bucket; + int len; + + bucket = (unsigned long) ptr % (sizeof (symbol_cache_hash) / sizeof (symbol_cache_hash[0])); + pthread_mutex_lock (&symbol_cache_mutex); + for (cache = symbol_cache_hash[bucket]; + cache != NULL; + cache = cache->hash_next) + { + if (cache->ptr == ptr) { + if (cache->hash_prev != NULL) { + cache->hash_prev->hash_next = cache->hash_next; + if (cache->hash_next != NULL) + cache->hash_next->hash_prev = cache->hash_prev; + cache->hash_prev = NULL; + cache->hash_next = symbol_cache_hash[bucket]; + symbol_cache_hash[bucket]->hash_prev = cache; + symbol_cache_hash[bucket] = cache; + } + + pthread_mutex_unlock (&symbol_cache_mutex); + return cache->name; + } + } + pthread_mutex_unlock (&symbol_cache_mutex); match.file = NULL; match.address = (ElfW(Addr)) ptr; @@ -266,17 +302,31 @@ lookup_symbol (char *buf, int buflen, const void *ptr) match.file = "/proc/self/exe"; #if HAVE_BFD - if (! _symtab_init (&symtab, match.file)) - return buf; - - _symbol_init (&symbol, &symtab, match.address - match.base); - bfd_map_over_sections (symtab.bfd, find_address_in_section, &symbol); - if (symbol.found) - _symbol_print (&symbol, buf, buflen, match.file); - _symbol_fini (&symbol); - - _symtab_fini (&symtab); + if (_symtab_init (&symtab, match.file)) { + _symbol_init (&symbol, &symtab, match.address - match.base); + bfd_map_over_sections (symtab.bfd, find_address_in_section, &symbol); + if (symbol.found) + _symbol_print (&symbol, buf, buflen, match.file); + _symbol_fini (&symbol); + + _symtab_fini (&symtab); + } #endif + len = strlen (buf); + cache = malloc (sizeof (struct symbol_cache_entry) + len + 1); + if (cache != NULL) { + cache->ptr = ptr; + memcpy (cache->name, buf, len + 1); + + pthread_mutex_lock (&symbol_cache_mutex); + cache->hash_prev = NULL; + cache->hash_next = symbol_cache_hash[bucket]; + if (symbol_cache_hash[bucket] != NULL) + symbol_cache_hash[bucket]->hash_prev = cache; + symbol_cache_hash[bucket] = cache; + pthread_mutex_unlock (&symbol_cache_mutex); + } + return buf; } diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index fb3a38cc..1b94ea1e 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -157,8 +157,8 @@ static const cairo_user_data_key_t destroy_key; if (_line_info && _write_lock ()) { \ void *addr = __builtin_return_address(0); \ char caller[1024]; \ - lookup_symbol (caller, sizeof (caller), addr); \ - fprintf (logfile, "%% %s() called by %s\n", __FUNCTION__, caller); \ + fprintf (logfile, "%% %s() called by %s\n", __FUNCTION__, \ + lookup_symbol (caller, sizeof (caller), addr)); \ _write_unlock (); \ } \ } while (0) @@ -2983,8 +2983,9 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface, char symbol[1024]; fprintf (logfile, "%% s%ld ", _get_surface_id (surface)); - lookup_symbol (symbol, sizeof (symbol), write_func); - _emit_string_literal (symbol, -1); + _emit_string_literal (lookup_symbol (symbol, sizeof (symbol), + write_func), + -1); fprintf (logfile, " write_to_png_stream\n"); _write_unlock (); } -- cgit v1.2.3 From e50538863a2c063eba61b36cc08eff6eeb712956 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Nov 2008 10:45:19 +0000 Subject: [twin] Tweak line width. Slightly increase line width to eliminate internal holes in the characters where the strokes were not quite overlapping. --- src/cairo-font-face-twin.c | 2 +- test/twin.c | 2 +- test/twin.ps2.ref.png | Bin 1167 -> 1095 bytes test/twin.ps3.ref.png | Bin 1167 -> 1095 bytes test/twin.ref.png | Bin 1836 -> 1673 bytes test/twin.svg11.ref.png | Bin 1773 -> 1662 bytes test/twin.svg12.ref.png | Bin 1773 -> 1662 bytes 7 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c index d8e662f1..5485476e 100644 --- a/src/cairo-font-face-twin.c +++ b/src/cairo-font-face-twin.c @@ -119,7 +119,7 @@ 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_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/test/twin.c b/test/twin.c index 34851f47..a53b796e 100644 --- a/test/twin.c +++ b/test/twin.c @@ -48,5 +48,5 @@ CAIRO_TEST (twin, "Tests the internal font", "twin, font", /* keywords */ NULL, /* requirements */ - 128, 20, + 132, 20, NULL, draw) diff --git a/test/twin.ps2.ref.png b/test/twin.ps2.ref.png index a58dc5b6..7fc3f35a 100644 Binary files a/test/twin.ps2.ref.png and b/test/twin.ps2.ref.png differ diff --git a/test/twin.ps3.ref.png b/test/twin.ps3.ref.png index a58dc5b6..7fc3f35a 100644 Binary files a/test/twin.ps3.ref.png and b/test/twin.ps3.ref.png differ diff --git a/test/twin.ref.png b/test/twin.ref.png index f2a5636d..b9121e06 100644 Binary files a/test/twin.ref.png and b/test/twin.ref.png differ diff --git a/test/twin.svg11.ref.png b/test/twin.svg11.ref.png index 5b7d67d4..46503966 100644 Binary files a/test/twin.svg11.ref.png and b/test/twin.svg11.ref.png differ diff --git a/test/twin.svg12.ref.png b/test/twin.svg12.ref.png index 5b7d67d4..46503966 100644 Binary files a/test/twin.svg12.ref.png and b/test/twin.svg12.ref.png differ -- cgit v1.2.3 From 97edc680c189205ac2f4e150009f1f1cbe55ba1a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Nov 2008 10:49:27 +0000 Subject: [twin] Reduce tolerance. As the glyphs are rendered to cache, ensure that they are rendered at the highest quality settings. --- src/cairo-font-face-twin.c | 1 + src/cairo.c | 1 + src/cairoint.h | 1 + test/Makefile.am | 1 + test/twin.pdf.ref.png | Bin 0 -> 1673 bytes test/twin.ref.png | Bin 1673 -> 1718 bytes 6 files changed, 4 insertions(+) create mode 100644 test/twin.pdf.ref.png diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c index 5485476e..5ac2cd2f 100644 --- a/src/cairo-font-face-twin.c +++ b/src/cairo-font-face-twin.c @@ -119,6 +119,7 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, int n_snap_y; } info = {FALSE}; + 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.c b/src/cairo.c index bd31063d..ac128dd7 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -841,6 +841,7 @@ cairo_set_tolerance (cairo_t *cr, double tolerance) if (status) _cairo_set_error (cr, status); } +slim_hidden_def (cairo_set_tolerance); /** * cairo_set_antialias: diff --git a/src/cairoint.h b/src/cairoint.h index c0e9b217..3aad4d77 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -2567,6 +2567,7 @@ slim_hidden_proto (cairo_set_matrix); slim_hidden_proto (cairo_set_operator); 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); diff --git a/test/Makefile.am b/test/Makefile.am index e0924292..eab23283 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -971,6 +971,7 @@ REFERENCE_IMAGES = \ trap-clip.ps2.argb32.ref.png \ trap-clip.ps2.rgb24.ref.png \ twin.ref.png \ + twin.pdf.ref.png \ twin.ps2.ref.png \ twin.ps3.ref.png \ twin.svg11.ref.png \ diff --git a/test/twin.pdf.ref.png b/test/twin.pdf.ref.png new file mode 100644 index 00000000..b9121e06 Binary files /dev/null and b/test/twin.pdf.ref.png differ diff --git a/test/twin.ref.png b/test/twin.ref.png index b9121e06..29c2e9e0 100644 Binary files a/test/twin.ref.png and b/test/twin.ref.png differ -- cgit v1.2.3 From 2fdee490745a6c3a75691907aadf8ae38c57234c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 17 Nov 2008 12:22:39 +0000 Subject: [compiler] likelihood macros Behdad prefers these to be upper-case to be consistent with G_UNLIKELY and friends. However, as I intend to use these for nearly all instances of if(status), I suggest that we keep to the short and not so loud: if (unlikely (status)) return status; --- src/cairo-compiler-private.h | 8 ++++---- src/cairo-hash.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h index 76b8e801..44d9de30 100644 --- a/src/cairo-compiler-private.h +++ b/src/cairo-compiler-private.h @@ -149,11 +149,11 @@ _cairo_boolean_var_ = 0; \ _cairo_boolean_var_; \ }) -#define _cairo_likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1)) -#define _cairo_unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0)) +#define likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1)) +#define unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0)) #else -#define _cairo_likely(expr) (expr) -#define _cairo_unlikely(expr) (expr) +#define likely(expr) (expr) +#define unlikely(expr) (expr) #endif #ifndef __GNUC__ diff --git a/src/cairo-hash.c b/src/cairo-hash.c index 78ea56bc..b3f43b05 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -434,7 +434,7 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table, hash_table->live_entries++; status = _cairo_hash_table_resize (hash_table); - if (_cairo_unlikely (status)) { + if (unlikely (status)) { /* abort the insert... */ hash_table->live_entries--; return status; -- cgit v1.2.3 From 645df0c6d2a3d9999bb18ddb8bb9995b3d597554 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Nov 2008 16:37:59 +0000 Subject: [scaled-font] Clean-up compiler warning. gcc warns that the status may be used uninitialized, so fix it. --- src/cairo-scaled-font-subsets.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index 7ec2a2dc..d8771bba 100644 --- a/src/cairo-scaled-font-subsets.c +++ b/src/cairo-scaled-font-subsets.c @@ -965,17 +965,24 @@ 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) @@ -1047,17 +1054,10 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset } 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) { -- cgit v1.2.3 From 7894abbe6d43b10ab2a92d99bdd6a08878e9022c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 08:37:26 +0000 Subject: [test] Support foreground only execution. Add an option to prevent forking - which makes it difficult to valgrind/gdb individual tests. --- test/Makefile.am | 1 + test/cairo-test-runner.c | 120 ++++++++++++++++++++++++++--------------------- 2 files changed, 67 insertions(+), 54 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index eab23283..3afac519 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1296,6 +1296,7 @@ run: $(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) $(top_builddir)/libtool --mode=execute env $(TOOL)' # Check tests under valgrind. Saves log to valgrind-log +check-valgrind: MODE+=,foreground check-valgrind: $(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c index 34a57257..4fb0cbea 100644 --- a/test/cairo-test-runner.c +++ b/test/cairo-test-runner.c @@ -51,6 +51,31 @@ typedef struct _cairo_test_list { struct _cairo_test_list *next; } cairo_test_list_t; +typedef struct _cairo_test_runner { + cairo_test_context_t base; + + unsigned int num_device_offsets; + + int num_passed; + int num_xpassed; + int num_skipped; + int num_failed; + int num_xfailed; + int num_crashed; + + cairo_test_list_t **crashes_per_target; + cairo_test_list_t **fails_per_target; + cairo_test_list_t **xpasses_per_target; + + int *num_failed_per_target; + int *num_crashed_per_target; + int *num_xpassed_per_target; + + cairo_bool_t foreground; + cairo_bool_t list_only; + cairo_bool_t full_test; +} cairo_test_runner_t; + typedef enum { GE, GT @@ -137,50 +162,54 @@ _cairo_test_wait (pid_t pid) #endif static cairo_test_status_t -_cairo_test_runner_preamble (cairo_test_context_t *ctx) +_cairo_test_runner_preamble (cairo_test_runner_t *runner, + cairo_test_context_t *ctx) { #if HAVE_FORK && HAVE_WAITPID - pid_t pid; + if (! runner->foreground) { + pid_t pid; - switch ((pid = fork ())) { - case -1: /* error */ - return CAIRO_TEST_UNTESTED; + switch ((pid = fork ())) { + case -1: /* error */ + return CAIRO_TEST_UNTESTED; - case 0: /* child */ - exit (ctx->test->preamble (ctx)); + case 0: /* child */ + exit (ctx->test->preamble (ctx)); - default: - return _cairo_test_wait (pid); + default: + return _cairo_test_wait (pid); + } } -#else - return ctx->test->preamble (ctx); #endif + return ctx->test->preamble (ctx); } static cairo_test_status_t -_cairo_test_runner_draw (cairo_test_context_t *ctx, +_cairo_test_runner_draw (cairo_test_runner_t *runner, + cairo_test_context_t *ctx, const cairo_boilerplate_target_t *target, cairo_bool_t similar, int device_offset) { #if HAVE_FORK && HAVE_WAITPID - pid_t pid; + if (! runner->foreground) { + pid_t pid; - switch ((pid = fork ())) { - case -1: /* error */ - return CAIRO_TEST_UNTESTED; + switch ((pid = fork ())) { + case -1: /* error */ + return CAIRO_TEST_UNTESTED; - case 0: /* child */ - exit (_cairo_test_context_run_for_target (ctx, target, - similar, device_offset)); + case 0: /* child */ + exit (_cairo_test_context_run_for_target (ctx, target, + similar, device_offset)); - default: - return _cairo_test_wait (pid); + default: + return _cairo_test_wait (pid); + } } -#else +#endif return _cairo_test_context_run_for_target (ctx, target, similar, device_offset); -#endif } static void @@ -243,43 +272,20 @@ append_argv (int *argc, char ***argv, const char *str) *argc += i; } -typedef struct _cairo_test_runner { - cairo_test_context_t base; - - unsigned int num_device_offsets; - - int num_passed; - int num_xpassed; - int num_skipped; - int num_failed; - int num_xfailed; - int num_crashed; - - cairo_test_list_t **crashes_per_target; - cairo_test_list_t **fails_per_target; - cairo_test_list_t **xpasses_per_target; - - int *num_failed_per_target; - int *num_crashed_per_target; - int *num_xpassed_per_target; - - cairo_bool_t list_only; - cairo_bool_t full_test; -} cairo_test_runner_t; - static void usage (const char *argv0) { fprintf (stderr, - "Usage: %s [-f] [test-names|keywords ...]\n" + "Usage: %s [-af] [test-names|keywords ...]\n" " %s -l\n" "\n" "Run the cairo conformance test suite over the given tests (all by default)\n" "The command-line arguments are interpreted as follows:\n" "\n" - " -l list only; just list selected test case names without executing\n" - " -f full; run the full set of tests. By default the test suite\n" + " -a all; run the full set of tests. By default the test suite\n" " skips similar surface and device offset testing.\n" + " -f foreground; do not fork\n" + " -l list only; just list selected test case names without executing\n" "\n" "If test names are given they are used as exact matches either to a specific\n" "test case or to a keyword, so a command such as\n" @@ -293,16 +299,19 @@ _parse_cmdline (cairo_test_runner_t *runner, int *argc, char **argv[]) int c; while (1) { - c = _cairo_getopt (*argc, *argv, ":l"); + c = _cairo_getopt (*argc, *argv, ":afl"); if (c == -1) break; switch (c) { + case 'a': + runner->full_test = TRUE; + break; case 'l': runner->list_only = TRUE; break; case 'f': - runner->full_test = TRUE; + runner->foreground = TRUE; break; default: fprintf (stderr, "Internal error: unhandled option: %c\n", c); @@ -585,6 +594,9 @@ main (int argc, char **argv) if (strstr (env, "full")) { runner.full_test = TRUE; } + if (strstr (env, "foreground")) { + runner.foreground = TRUE; + } } _parse_cmdline (&runner, &argc, &argv); @@ -706,7 +718,7 @@ main (int argc, char **argv) sizeof (cairo_test_status_t) * ctx.num_targets); if (ctx.test->preamble != NULL) { - status = _cairo_test_runner_preamble (&ctx); + status = _cairo_test_runner_preamble (&runner, &ctx); switch (status) { case CAIRO_TEST_SUCCESS: skipped = FALSE; @@ -766,7 +778,7 @@ main (int argc, char **argv) int similar; for (similar = 0; similar <= has_similar; similar++) { - status = _cairo_test_runner_draw (&ctx, target, + status = _cairo_test_runner_draw (&runner, &ctx, target, similar, dev_offset); switch (status) { case CAIRO_TEST_SUCCESS: -- cgit v1.2.3 From b6c371a47f33ec10d4d6130cc15677761df2bdfd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 08:44:24 +0000 Subject: [pattern] Cosmetic. surface is equal to pattern->surface at this point. --- src/cairo-pattern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index c78317eb..bdcafe7c 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -1842,7 +1842,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat if (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); -- cgit v1.2.3 From 8345fedbe4d4d003c1f26a78ac7c512c04d04173 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 11:44:42 +0000 Subject: [spline] Fix compile. Do not return the result of a void function. gcc chose to not warn about this when removing the return parameter... --- src/cairo-spline.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cairo-spline.c b/src/cairo-spline.c index 7ec1c56c..b5285447 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -186,8 +186,10 @@ _cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared { cairo_spline_knots_t s2; - 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); -- cgit v1.2.3 From c41b99268dd2424d09ab12ca560d5db30b6b6faf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 11:49:04 +0000 Subject: Conditionally include byteswap.h Fixup compilation by copying the checks from cairo-wideint-private.h to conditionally include byteswap.h and provide fallback implementations. --- util/cairo-script/cairo-script-interpreter.c | 1 - util/cairo-script/cairo-script-operators.c | 1 - util/cairo-script/cairo-script-private.h | 17 +++++++++++++++++ util/cairo-script/cairo-script-scanner.c | 1 - util/cairo-trace/trace.c | 17 ++++++++++++++++- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/util/cairo-script/cairo-script-interpreter.c b/util/cairo-script/cairo-script-interpreter.c index 21630465..fea6a4ad 100644 --- a/util/cairo-script/cairo-script-interpreter.c +++ b/util/cairo-script/cairo-script-interpreter.c @@ -39,7 +39,6 @@ #include #include #include -#include #include csi_status_t diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c index dc1c208f..03bd5216 100644 --- a/util/cairo-script/cairo-script-operators.c +++ b/util/cairo-script/cairo-script-operators.c @@ -40,7 +40,6 @@ #include #include #include -#include typedef struct _csi_proxy { csi_t *ctx; diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h index b7009770..8ab1f63a 100644 --- a/util/cairo-script/cairo-script-private.h +++ b/util/cairo-script/cairo-script-private.h @@ -75,6 +75,23 @@ #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #endif +#if HAVE_BYTESWAP_H +# include +#endif +#ifndef bswap_16 +# define bswap_16(p) \ + (((((uint16_t)(p)) & 0x00ff) << 8) | \ + (((uint16_t)(p)) >> 8)); +#endif +#ifndef bswap_32 +# define bswap_32(p) \ + (((((uint32_t)(p)) & 0x000000ff) << 24) | \ + ((((uint32_t)(p)) & 0x0000ff00) << 8) | \ + ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \ + ((((uint32_t)(p))) >> 24)); +#endif + + #if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun) # define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private # define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private_no_warn diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c index bc3ff2cf..484acd96 100644 --- a/util/cairo-script/cairo-script-scanner.c +++ b/util/cairo-script/cairo-script-scanner.c @@ -37,7 +37,6 @@ #include /* EOF */ #include /* memset */ #include /* pow */ -#include /* bswap_32 */ /* * whitespace: diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 1b94ea1e..30c915d5 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -45,6 +44,22 @@ #define CAIRO_TRACE_OUTDIR "." #endif +#if HAVE_BYTESWAP_H +# include +#endif +#ifndef bswap_16 +# define bswap_16(p) \ + (((((uint16_t)(p)) & 0x00ff) << 8) | \ + (((uint16_t)(p)) >> 8)); +#endif +#ifndef bswap_32 +# define bswap_32(p) \ + (((((uint32_t)(p)) & 0x000000ff) << 24) | \ + ((((uint32_t)(p)) & 0x0000ff00) << 8) | \ + ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \ + ((((uint32_t)(p))) >> 24)); +#endif + #include "lookup-symbol.h" /* Reverse the bits in a byte with 7 operations (no 64-bit): -- cgit v1.2.3 From 81ef772aa0bf512ec5ad8752da160117498bdb30 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 11:00:35 +0000 Subject: [xlib] Mark GC as dirty if we have an outstanding clip. Ginn Chen reported a regression with Firefox where "the whole area of web page is transparent until it redraws", and bisected it to the change to lazily clear the clip. The bug would appears to be when we have an inconsistent GC clip - i.e. the clip on the surface has been cleared, but we have not yet used and thus cleared the GC, so that we did not mark the GC as having a clip set when we freed it. --- src/cairo-xlib-surface.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 12c2cccb..840e7f53 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -307,7 +307,9 @@ _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->have_clip_rects | + (surface->clip_dirty & + CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)); surface->gc = NULL; if (status == CAIRO_STATUS_SUCCESS) status = status2; -- cgit v1.2.3 From abd0a2627d198eddb628bbc1f2974435a74655a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Dec 2007 10:49:23 +0000 Subject: [perf/dragon] Add a dragon curve perf case. Inspired by http://labs.trolltech.com/blogs/2007/08/31/rasterizing-dragons/ and http://en.wikipedia.org/wiki/Dragon_curve, add a performance test case to measure drawing this space-filling fractal curve. --- perf/Makefile.am | 3 +- perf/cairo-perf.c | 1 + perf/cairo-perf.h | 1 + perf/dragon.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 perf/dragon.c diff --git a/perf/Makefile.am b/perf/Makefile.am index edd4c685..3c4dea6e 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -41,7 +41,8 @@ cairo_perf_SOURCES = \ world-map.h \ zrusin.c \ zrusin-another.h \ - long-dashed-lines.c + long-dashed-lines.c \ + dragon.c if CAIRO_HAS_WIN32_SURFACE cairo_perf_SOURCES += cairo-perf-win32.c diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c index a6d59a57..984ef546 100644 --- a/perf/cairo-perf.c +++ b/perf/cairo-perf.c @@ -459,5 +459,6 @@ const cairo_perf_case_t perf_cases[] = { { long_dashed_lines, 512, 512}, { composite_checker, 16, 512}, { twin, 800, 800}, + { dragon, 1024, 1024 }, { NULL } }; diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h index 0cedb691..8d8b960f 100644 --- a/perf/cairo-perf.h +++ b/perf/cairo-perf.h @@ -173,5 +173,6 @@ CAIRO_PERF_DECL (rounded_rectangles); CAIRO_PERF_DECL (long_dashed_lines); CAIRO_PERF_DECL (composite_checker); CAIRO_PERF_DECL (twin); +CAIRO_PERF_DECL (dragon); #endif diff --git a/perf/dragon.c b/perf/dragon.c new file mode 100644 index 00000000..6d0328eb --- /dev/null +++ b/perf/dragon.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2007 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + * + * Inspiration (and path!) taken from + * http://labs.trolltech.com/blogs/2007/08/31/rasterizing-dragons/ + */ + +#include "cairo-perf.h" + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +static inline int +next_pot (int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +static cairo_bool_t +direction (int i) +{ + int pivot, np2; + + if (i < 2) + return TRUE; + + np2 = next_pot (i + 1); + if (np2 == i + 1) + return TRUE; + + pivot = np2 / 2 - 1; + return ! direction (2 * pivot - i); +} + + +static void +path (cairo_t *cr, int step, int dir, int iterations) +{ + double dx, dy; + int i; + + switch (dir) { + case 0: dx = step; dy = 0; break; + case 1: dx = -step; dy = 0; break; + case 2: dx = 0; dy = step; break; + case 3: dx = 0; dy = -step; break; + } + + for (i = 0; i < iterations; i++) { + cairo_rel_line_to (cr, dx, dy); + + if (direction (i)) { + double t = dx; + dx = dy; + dy = -t; + } else { + double t = dx; + dx = -dy; + dy = t; + } + } +} + +static cairo_perf_ticks_t +do_dragon (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + double cx, cy, r; + + cx = cy = .5 * MAX (width, height); + r = .5 * MIN (width, height); + + cairo_perf_timer_start (); + + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 0., .0, .0, .0); + cairo_pattern_add_color_stop_rgb (pattern, 0.25, .5, .4, .4); + cairo_pattern_add_color_stop_rgb (pattern, .5, .8, .8, .9); + cairo_pattern_add_color_stop_rgb (pattern, 1., .9, .9, 1.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_paint (cr); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width (cr, 4.); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 0, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 1., 1.); + cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 0., 0.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 1, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 1., 0.); + cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 0., 0.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 2, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 1., 1.); + cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 1., 0.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 3, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 0., 1.); + cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 0., 1.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +void +dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "dragon", do_dragon); +} -- cgit v1.2.3 From 7657bda0172f823fba61db4f66e0166c7619fbd2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Dec 2007 11:23:33 +0000 Subject: [perf/pythagoras_tree] Another fractal. Test lots of rectangles and recursion path construction. --- perf/Makefile.am | 3 +- perf/cairo-perf.c | 1 + perf/cairo-perf.h | 1 + perf/pythagoras-tree.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 perf/pythagoras-tree.c diff --git a/perf/Makefile.am b/perf/Makefile.am index 3c4dea6e..737e96a4 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -42,7 +42,8 @@ cairo_perf_SOURCES = \ zrusin.c \ zrusin-another.h \ long-dashed-lines.c \ - dragon.c + dragon.c \ + pythagoras-tree.c if CAIRO_HAS_WIN32_SURFACE cairo_perf_SOURCES += cairo-perf-win32.c diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c index 984ef546..d5f69201 100644 --- a/perf/cairo-perf.c +++ b/perf/cairo-perf.c @@ -460,5 +460,6 @@ const cairo_perf_case_t perf_cases[] = { { composite_checker, 16, 512}, { twin, 800, 800}, { dragon, 1024, 1024 }, + { pythagoras_tree, 768, 768 }, { NULL } }; diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h index 8d8b960f..d18be033 100644 --- a/perf/cairo-perf.h +++ b/perf/cairo-perf.h @@ -174,5 +174,6 @@ CAIRO_PERF_DECL (long_dashed_lines); CAIRO_PERF_DECL (composite_checker); CAIRO_PERF_DECL (twin); CAIRO_PERF_DECL (dragon); +CAIRO_PERF_DECL (pythagoras_tree); #endif diff --git a/perf/pythagoras-tree.c b/perf/pythagoras-tree.c new file mode 100644 index 00000000..5a78d8a7 --- /dev/null +++ b/perf/pythagoras-tree.c @@ -0,0 +1,86 @@ +/* + * Copyright © 2007 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-perf.h" +#include + +static void +add_rectangle (cairo_t *cr, double size) +{ + double x, y; + + if (size < 1) + return; + + cairo_get_current_point (cr, &x, &y); + + cairo_rel_move_to (cr, -size/2., -size/2.); + cairo_rel_line_to (cr, size, 0); + cairo_rel_line_to (cr, 0, size); + cairo_rel_line_to (cr, -size, 0); + cairo_close_path (cr); + + cairo_save (cr); + cairo_translate (cr, -size/2., size); + cairo_move_to (cr, x, y); + cairo_rotate (cr, M_PI/4); + add_rectangle (cr, size / M_SQRT2); + cairo_restore (cr); + + cairo_save (cr); + cairo_translate (cr, size/2., size); + cairo_move_to (cr, x, y); + cairo_rotate (cr, -M_PI/4); + add_rectangle (cr, size / M_SQRT2); + cairo_restore (cr); +} + +static cairo_perf_ticks_t +do_pythagoras_tree (cairo_t *cr, int width, int height) +{ + double size = 128; + + cairo_perf_timer_start (); + + cairo_save (cr); + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + cairo_move_to (cr, width/2, size/2); + add_rectangle (cr, size); + cairo_set_source_rgb (cr, 0., 0., 0.); + cairo_fill (cr); + cairo_restore (cr); + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +void +pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "pythagoras_tree", do_pythagoras_tree); +} -- cgit v1.2.3 From 63a86a470fb88ee876414164e7e26789c1065b82 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 14:04:01 +0000 Subject: [surface] Replay meta surfaces to a similar surface. When cloning a meta-surface, first attempt to replay it to a similar surface rather than a full-sized image buffer. --- src/cairo-surface.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/cairo-surface.c b/src/cairo-surface.c index c419bd5f..77e83522 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -40,6 +40,7 @@ #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 = { \ @@ -1297,10 +1298,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) { @@ -1312,6 +1313,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) { -- cgit v1.2.3 From 727ff2bd7260f26c9390079258c43e6890ef2284 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 14:25:20 +0000 Subject: [xlib] Explicitly track whether the GC has clip_rects. Simplify the logic and remove some pessimism from the code by explicitly tracking when we set clip rectangles on the GC. --- src/cairo-xlib-surface-private.h | 1 + src/cairo-xlib-surface.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h index e06fd978..87be9e6a 100644 --- a/src/cairo-xlib-surface-private.h +++ b/src/cairo-xlib-surface-private.h @@ -85,6 +85,7 @@ struct _cairo_xlib_surface { unsigned int clip_dirty; cairo_bool_t have_clip_rects; + cairo_bool_t gc_has_clip_rects; XRectangle embedded_clip_rects[4]; XRectangle *clip_rects; int num_clip_rects; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 840e7f53..368f4e45 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -307,9 +307,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->clip_dirty & - CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)); + surface->gc_has_clip_rects); surface->gc = NULL; if (status == CAIRO_STATUS_SUCCESS) status = status2; @@ -873,6 +871,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, @@ -2635,6 +2634,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; -- cgit v1.2.3 From b426346b482e2687081433213ae107cb7b2ebe58 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 16:04:57 +0000 Subject: [trace] Construct matrices directly Avoid building a temporary array by constructing the matrix directly. --- util/cairo-trace/trace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 30c915d5..f94671bc 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -1896,7 +1896,7 @@ void cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) { _emit_line_info (); - _emit_cairo_op (cr, "[%g %g %g %g %g %g] transform\n", + _emit_cairo_op (cr, "%g %g %g %g %g %g matrix transform\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); @@ -1910,7 +1910,7 @@ cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix) if (_matrix_is_identity (matrix)) { _emit_cairo_op (cr, "identity set_matrix\n"); } else { - _emit_cairo_op (cr, "[%g %g %g %g %g %g] set_matrix\n", + _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set_matrix\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); @@ -2294,7 +2294,7 @@ void cairo_set_font_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { _emit_line_info (); - _emit_cairo_op (cr, "[%g %g %g %g %g %g] set_font_matrix\n", + _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set_font_matrix\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); @@ -2446,7 +2446,7 @@ _emit_matrix (const cairo_matrix_t *m) else { fprintf (logfile, - "[%g %g %g %g %g %g]", + "%g %g %g %g %g %g matrix", m->xx, m->yx, m->xy, m->yy, m->x0, m->y0); @@ -3169,7 +3169,7 @@ cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix _emit_pattern_op (pattern, "identity set_matrix\n"); } else { _emit_pattern_op (pattern, - "[%g %g %g %g %g %g] set_matrix\n", + "%g %g %g %g %g %g matrix set_matrix\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); -- cgit v1.2.3 From 0d5e533b6cc43c4ebc030140933247cf160d47cd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Nov 2008 17:03:13 +0000 Subject: [trace] Correctly push font-face onto the operand stack. We tried to push a reference to an undefined font-face, now we just copy from the operand stack. --- util/cairo-trace/trace.c | 61 ++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index f94671bc..b272dd89 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -779,6 +779,22 @@ _has_font_face_id (cairo_font_face_t *font_face) return _has_id (FONT_FACE, font_face); } +static void +_emit_font_face_id (cairo_font_face_t *font_face) +{ + Object *obj = _get_object (FONT_FACE, font_face); + if (obj == NULL) { + fprintf (logfile, "null "); + } else { + if (obj->defined) { + fprintf (logfile, "f%ld ", obj->token); + } else { + fprintf (logfile, "%d index ", + current_stack_depth - obj->operand - 1); + } + } +} + static bool _has_pattern_id (cairo_pattern_t *pattern) { @@ -2251,32 +2267,27 @@ void cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face) { _emit_line_info (); - if (cr != NULL && font_face != NULL) { - if (_pop_operands_to (FONT_FACE, font_face)) { - if (_is_current (CONTEXT, cr, 1)) { - if (_write_lock ()) { - _consume_operand (); - fprintf (logfile, "set_font_face\n"); - _write_unlock (); - } - } else { - if (_get_object (CONTEXT, cr)->defined) { - if (_write_lock ()) { - _consume_operand (); - fprintf (logfile, - "c%ld exch set_font_face pop\n", - _get_context_id (cr)); - _write_unlock (); - } - } else { - _emit_cairo_op (cr, "f%ld set_font_face\n", - _get_font_face_id (font_face)); - } - } - } else { - _emit_cairo_op (cr, "f%ld set_font_face\n", - _get_font_face_id (font_face)); + if (cr != NULL && font_face != NULL && _write_lock ()) { + if (_is_current (FONT_FACE, font_face, 0) && + _is_current (CONTEXT, cr, 1)) + { + _consume_operand (); + } + else if (_is_current (FONT_FACE, font_face, 1) && + _is_current (CONTEXT, cr, 0)) + { + fprintf (logfile, "exch "); + _exch_operands (); + _consume_operand (); } + else + { + _emit_context (cr); + _emit_font_face_id (font_face); + } + + fprintf (logfile, "set_font_face\n"); + _write_unlock (); } return DLCALL (cairo_set_font_face, cr, font_face); -- cgit v1.2.3 From 1f48b36933b5ff082edf3e221563c15c3bf16b75 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 Nov 2008 12:41:18 +0000 Subject: [script] Build fix for ! HAS_FT_FONT Correct the macro definition used when compiling without FreeType. --- util/cairo-script/cairo-script-operators.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c index 03bd5216..a70b55d5 100644 --- a/util/cairo-script/cairo-script-operators.c +++ b/util/cairo-script/cairo-script-operators.c @@ -32,7 +32,7 @@ * Chris Wilson */ -/* TODO real matrix and path types */ +/* TODO real path type */ #include "cairo-script-private.h" @@ -1823,8 +1823,7 @@ _ft_type42_create (csi_t *ctx, return _csi_error (CSI_STATUS_INVALID_SCRIPT); } #else -#define _ft_type1_create(font, face_out) CSI_INT_STATUS_UNSUPPORTED -#define _ft_type42_create(font, face_out) CSI_INT_STATUS_UNSUPPORTED +#define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED #endif static csi_status_t -- cgit v1.2.3 From cfd2c73826f5bf20624fbdf5b16fd08fbe18a914 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 Nov 2008 09:36:02 +0000 Subject: [image] Trim image surface size by a few bytes Convert an infrequently accessed series of cairo_bool_t and short enums to a common bitfield. --- src/cairo-image-surface.c | 11 ++++++----- src/cairoint.h | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 0efdb7a9..234a6f90 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -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 @@ -1064,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); } diff --git a/src/cairoint.h b/src/cairoint.h index 3aad4d77..c7904442 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -835,9 +835,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; @@ -845,6 +842,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; -- cgit v1.2.3 From 9556266ffcb1c34187730af90bb847950d6db66e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 Nov 2008 09:40:25 +0000 Subject: [surface] Make the error surfaces have a NULL backend. By using a NULL backend for the error surfaces, instead of a pointer to the image surface backend end, we save a few lookup/redirections during dynamic linking. --- src/cairo-surface.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 77e83522..e3a31d79 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -44,25 +44,15 @@ #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 */ \ -- cgit v1.2.3 From a11442154d958d5c9694eb944a715a6c689fda85 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 Nov 2008 18:00:40 +0000 Subject: [cairo] Allocate glyphs on the stack for show_text(). First try to use a stack buffer for the glyphs and clusters if the user calls cairo_show_text() - for example, as pango does to draw the unknown hex box. --- src/cairo.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cairo.c b/src/cairo.c index ac128dd7..f53d0b03 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -3086,12 +3086,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; @@ -3106,6 +3108,12 @@ 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, @@ -3138,8 +3146,10 @@ 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) _cairo_set_error (cr, status); -- cgit v1.2.3 From 9d2c55c661885c06eed44e810004c2ebe07038d3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 Nov 2008 21:53:34 +0000 Subject: [traps] Embed sufficient traps to accommodate a stroke rectangle Small numbers of traps are frequently generated from either a path of a single line, or that of a rectangle. Therefore should embed sufficient storage with cairo_traps_t to accommodate the stroke of a single rectangle (e.g. a pango unknown glyph hexbox) to avoid frequent allocations. --- src/cairoint.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cairoint.h b/src/cairoint.h index c7904442..d219061d 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -942,7 +942,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; -- cgit v1.2.3 From f15b1f26becf28457e9ccf8903257a0dec25d547 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 Nov 2008 23:19:19 +0000 Subject: [region] Use the caller supplied array for extracting boxes. Allow the user to pass in a pre-allocated array and use it if the number of boxes permits. This eliminates the frequent allocations during clipping by toolkits. --- src/cairo-directfb-surface.c | 6 ++++-- src/cairo-glitz-surface.c | 1 + src/cairo-paginated-surface.c | 3 +++ src/cairo-region.c | 11 ++++++----- src/cairo-sdl-surface.c | 1 + src/cairo-surface.c | 15 ++++++++------- src/cairo-win32-surface.c | 3 ++- src/cairo-xcb-surface.c | 1 + src/cairo-xlib-surface-private.h | 2 +- src/cairo-xlib-surface.c | 13 ++++++++----- 10 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index 5a970b94..8cbd3bcd 100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -1305,12 +1305,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); diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 5bdfa700..203c0633 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -153,6 +153,7 @@ _cairo_glitz_get_boxes_from_region (cairo_region_t *region, glitz_box_t **boxes, cairo_status_t status; int n, i; + n = 0; status = _cairo_region_get_boxes (region, &n, &cboxes); if (status) return status; diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index 94a599e0..bb542ff0 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -397,9 +397,12 @@ _paint_page (cairo_paginated_surface_t *surface) goto FAIL; region = _cairo_analysis_surface_get_unsupported (analysis); + + num_boxes = 0; status = _cairo_region_get_boxes (region, &num_boxes, &boxes); if (status) goto FAIL; + for (i = 0; i < num_boxes; i++) { status = _paint_fallback_image (surface, &boxes[i]); if (status) { diff --git a/src/cairo-region.c b/src/cairo-region.c index a89c4d07..146ae60b 100644 --- a/src/cairo-region.c +++ b/src/cairo-region.c @@ -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-sdl-surface.c b/src/cairo-sdl-surface.c index b9d604e6..18f13eaf 100644 --- a/src/cairo-sdl-surface.c +++ b/src/cairo-sdl-surface.c @@ -322,6 +322,7 @@ _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) return status; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index e3a31d79..eaff47a2 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -1535,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, @@ -1542,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; @@ -1554,12 +1555,12 @@ _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) return status; @@ -1567,18 +1568,18 @@ _cairo_surface_fill_region (cairo_surface_t *surface, 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]); @@ -1586,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) diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 70af72bb..863f9d52 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -1469,11 +1469,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 && diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 63618bb0..999f7d54 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; diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h index 87be9e6a..fe37e5fb 100644 --- a/src/cairo-xlib-surface-private.h +++ b/src/cairo-xlib-surface-private.h @@ -86,7 +86,7 @@ struct _cairo_xlib_surface { unsigned int clip_dirty; cairo_bool_t have_clip_rects; cairo_bool_t gc_has_clip_rects; - XRectangle embedded_clip_rects[4]; + 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 368f4e45..2ae727f1 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -2261,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) @@ -2304,6 +2305,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, 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) { _cairo_region_fini (&bound); @@ -2319,18 +2322,18 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, _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); -- cgit v1.2.3 From 361962b7fb4385f164673991670b6fce0839d32a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 31 Oct 2008 08:42:30 +0000 Subject: [directfb] Compile fix with debug enabled. Fix a trivial compile failure reported here: Bug 18322 - bug in _cairo_directfb_surface_release_source_image function (http://bugs.freedesktop.org/show_bug.cgi?id=18322) --- src/cairo-directfb-surface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index aa67b023..bb02dbfb 100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -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, -- cgit v1.2.3 From 77e60df32fa59328bd32095c77f8c360805b5db7 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 8 Nov 2008 15:29:40 +0100 Subject: cairo-xcb: avoid leaking memory --- src/cairo-xcb-surface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index dede00f3..9b7eb4b7 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -2416,6 +2416,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; } -- cgit v1.2.3 From c8b70aacc6b5523e2f73bebf4f61e876de1c3b3f Mon Sep 17 00:00:00 2001 From: Nicolas Bruguier Date: Sat, 22 Nov 2008 18:16:17 +0800 Subject: glitz: bring glitz backend to more or less working state. Thanks Nicolas Bruguier for writing the original patch and thanks Paolo Bonzini for pointing out. This patch converts 24.8 fixed point values into 16.16 ones before passing them down to glitz. And I fixed a use-after-free issue in _cairo_glitz_surface_set_clip_region. glitz_surface_set_clip_region takes the pointer and doesn't copy the clip boxes, the original code frees the clip boxes immediately after setting clip region. Keeping the box around with the life time of clip region fixes the bug. --- src/cairo-glitz-surface.c | 329 +++++++++++++++++++++++----------------------- 1 file changed, 163 insertions(+), 166 deletions(-) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 203c0633..eb066432 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -34,7 +34,8 @@ typedef struct _cairo_glitz_surface { glitz_surface_t *surface; glitz_format_t *format; cairo_bool_t has_clip; - cairo_region_t clip; + glitz_box_t *clip_boxes; + int num_clip_boxes; } cairo_glitz_surface_t; static const cairo_surface_backend_t * @@ -47,7 +48,7 @@ _cairo_glitz_surface_finish (void *abstract_surface) if (surface->has_clip) { glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - _cairo_region_fini (&surface->clip); + free (surface->clip_boxes); } glitz_surface_destroy (surface->surface); @@ -106,60 +107,19 @@ _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_box_int_t *cboxes; - cairo_status_t status; + pixman_box32_t *pboxes; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + int n, i; n = 0; - status = _cairo_region_get_boxes (region, &n, &cboxes); - if (status) - return status; - + pboxes = pixman_region32_rectangles (®ion->rgn, &n); if (n == 0) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + *nboxes = 0; + *boxes = NULL; goto done; } @@ -170,18 +130,19 @@ _cairo_glitz_get_boxes_from_region (cairo_region_t *region, glitz_box_t **boxes, } 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; } +#define STRIDE_ALIGNMENT (sizeof (uint32_t)) + static cairo_status_t _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, cairo_rectangle_int_t *interest, @@ -195,7 +156,8 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, cairo_format_masks_t masks; glitz_buffer_t *buffer; glitz_pixel_format_t pf; - cairo_format_t format; + cairo_status_t status; + pixman_format_code_t pixman_format; x1 = 0; y1 = 0; @@ -208,9 +170,9 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, x1 = interest->x; if (interest->y > y1) y1 = interest->y; - if (interest->x + interest->width < x2) + if (interest->x + interest->width < (unsigned int)x2) x2 = interest->x + interest->width; - if (interest->y + interest->height < y2) + if (interest->y + interest->height < (unsigned int)y2) y2 = interest->y + interest->height; if (x1 >= x2 || y1 >= y2) @@ -267,7 +229,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, /* 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 = ((masks.bpp * width + 7) / 8 + STRIDE_ALIGNMENT - 1) & ~(STRIDE_ALIGNMENT - 1); pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; pixels = _cairo_malloc_ab (height, pf.bytes_per_line); @@ -294,51 +256,24 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, glitz_buffer_destroy (buffer); /* 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; + if (surface->has_clip) + glitz_surface_set_clip_region (surface->surface, 0, 0, + surface->clip_boxes, + surface->num_clip_boxes); + + status = _pixman_format_from_masks (&masks, &pixman_format); + if (status) { + free (pixels); + return status; } + image = (cairo_image_surface_t*) + _cairo_image_surface_create_with_pixman_format ((unsigned char *) pixels, + pixman_format, + width, + height, + pf.bytes_per_line); + if (image->base.status) + goto FAIL; _cairo_image_surface_assume_ownership_of_data (image); @@ -346,7 +281,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, return CAIRO_STATUS_SUCCESS; -FAIL: + FAIL: free (pixels); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -558,15 +493,16 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface, 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); - if (status) { - cairo_surface_destroy (&clone->base); - return status; + if (_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); + if (status) { + cairo_surface_destroy (&clone->base); + return status; + } } *clone_out = &clone->base; @@ -583,17 +519,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); } @@ -1121,6 +1057,22 @@ _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; + 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_SOURCE: { @@ -1131,14 +1083,14 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, 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); + glitz_set_rectangles (dst->surface, &glitz_color, + glitz_rects, n_rects); } break; case CAIRO_OPERATOR_CLEAR: { static const glitz_color_t glitz_color = { 0, 0, 0, 0 }; glitz_set_rectangles (dst->surface, &glitz_color, - (glitz_rectangle_t *) rects, n_rects); + glitz_rects, n_rects); } break; case CAIRO_OPERATOR_SATURATE: return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1155,7 +1107,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, @@ -1163,7 +1119,11 @@ _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); @@ -1175,8 +1135,8 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, dst->surface, 0, 0, 0, 0, - rects->x, rects->y, - rects->width, rects->height); + glitz_rects->x, glitz_rects->y, + glitz_rects->width, glitz_rects->height); rects++; } @@ -1184,6 +1144,9 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, 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; @@ -1214,25 +1177,60 @@ _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; + + /* 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); + } + + 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); + } if (antialias != CAIRO_ANTIALIAS_DEFAULT && antialias != CAIRO_ANTIALIAS_GRAY) - return CAIRO_INT_STATUS_UNSUPPORTED; + { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto finish; + } if (dst->base.status) - return dst->base.status; + { + status = dst->base.status; + goto finish; + } if (op == CAIRO_OPERATOR_SATURATE) - return CAIRO_INT_STATUS_UNSUPPORTED; + { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto finish; + } if (_glitz_ensure_target (dst->surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; + { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto finish; + } if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { status = _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern); if (status) - return status; + goto finish; status = _cairo_glitz_pattern_acquire_surface (&tmp_src_pattern.base, dst, @@ -1252,7 +1250,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, alpha = 0xffff; if (status) - return status; + goto finish; if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) { @@ -1287,7 +1285,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, if (src_pattern == &tmp_src_pattern.base) _cairo_pattern_fini (&tmp_src_pattern.base); - return mask->base.status; + status = mask->base.status; + goto finish; } color.red = color.green = color.blue = color.alpha = 0xffff; @@ -1329,7 +1328,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, &attributes); if (src_pattern == &tmp_src_pattern.base) _cairo_pattern_fini (&tmp_src_pattern.base); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto finish; } } @@ -1337,7 +1337,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; @@ -1365,7 +1365,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, _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); + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto finish; } /* using negative stride */ @@ -1380,11 +1381,12 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, { cairo_surface_destroy (&src->base); free (data); - return image->base.status; + status = image->base.status; + goto finish; } 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, @@ -1394,7 +1396,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); free (data); cairo_surface_destroy (&image->base); - return mask->base.status; + status = mask->base.status; + goto finish; } status = _cairo_glitz_surface_set_image (mask, image, @@ -1403,7 +1406,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, cairo_surface_destroy(&image->base); if (status) - return status; + goto finish; } _cairo_glitz_surface_set_attributes (src, &attributes); @@ -1438,9 +1441,13 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, cairo_surface_destroy (&mask->base); if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + status = CAIRO_INT_STATUS_UNSUPPORTED; - return CAIRO_STATUS_SUCCESS; +finish: + if (pixman_traps != stack_traps) + free (pixman_traps); + + return status; } static cairo_int_status_t @@ -1455,35 +1462,25 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface, int n; 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 (region, &box, &n); + if (status) + return status; - status = _cairo_glitz_get_boxes_from_region (&surface->clip, &box, &n); - if (status) { - _cairo_region_fini (&surface->clip); - surface->has_clip = FALSE; - return status; - } + if (surface->has_clip) + free (surface->clip_boxes); glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); - free (box); + surface->has_clip = TRUE; + surface->clip_boxes = box; + surface->num_clip_boxes = n; } else { glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); if (surface->has_clip) { - _cairo_region_fini (&surface->clip); + free (surface->clip_boxes); surface->has_clip = FALSE; } } @@ -1997,7 +1994,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; @@ -2052,14 +2049,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; -- cgit v1.2.3 From 36c1b3e5919f119a054e425ca03f7ce810d3e7ec Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Sun, 23 Nov 2008 10:27:49 +0800 Subject: glitz: fixup a stupid bug in get_image. _pixman_format_from_masks returns a boolean instead of cairo status code. Without this fix, get_image bails out over and over again even operations was completed successfully. :-( --- src/cairo-glitz-surface.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index eb066432..3c3fe16d 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -261,11 +261,12 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, surface->clip_boxes, surface->num_clip_boxes); - status = _pixman_format_from_masks (&masks, &pixman_format); - if (status) { - free (pixels); - return status; + if (! _pixman_format_from_masks (&masks, &pixman_format)) + { + status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT); + goto FAIL; } + image = (cairo_image_surface_t*) _cairo_image_surface_create_with_pixman_format ((unsigned char *) pixels, pixman_format, @@ -273,7 +274,10 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, height, pf.bytes_per_line); if (image->base.status) + { + status = image->base.status; goto FAIL; + } _cairo_image_surface_assume_ownership_of_data (image); @@ -283,7 +287,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, FAIL: free (pixels); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + return status; } static void -- cgit v1.2.3 From 63180edf6f7cc81beda626190ca1055efa330fda Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Sun, 23 Nov 2008 11:42:26 +0800 Subject: glitz: set clone_offset_{x, y} on success in clone_similar. With this fix, glitz backend passes 135 test cases and fails 66 test cases. --- src/cairo-glitz-surface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 3c3fe16d..db1d29e7 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -510,6 +510,8 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface, } *clone_out = &clone->base; + *clone_offset_x = 0; + *clone_offset_y = 0; return CAIRO_STATUS_SUCCESS; } -- cgit v1.2.3 From 5de1e4de938d03406ce3364c6c1baa958f210410 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 18:33:58 +1030 Subject: Move cairo-jpeg-info.c to cairo-image-info.c Other image formats will be added to the same file. --- src/Makefile.sources | 4 +- src/cairo-image-info-private.h | 54 ++++++++++++++ src/cairo-image-info.c | 141 +++++++++++++++++++++++++++++++++++++ src/cairo-jpeg-info-private.h | 54 -------------- src/cairo-jpeg-info.c | 141 ------------------------------------- src/cairo-pdf-surface.c | 6 +- src/cairo-ps-surface.c | 6 +- src/cairo-svg-surface.c | 6 +- src/cairo-win32-printing-surface.c | 6 +- 9 files changed, 209 insertions(+), 209 deletions(-) create mode 100644 src/cairo-image-info-private.h create mode 100644 src/cairo-image-info.c delete mode 100644 src/cairo-jpeg-info-private.h delete mode 100644 src/cairo-jpeg-info.c diff --git a/src/Makefile.sources b/src/Makefile.sources index 58781dd9..5d643dcb 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -64,7 +64,7 @@ cairo_private = \ cairo-freelist-private.h \ cairo-gstate-private.h \ cairo-hash-private.h \ - cairo-jpeg-info-private.h \ + cairo-image-info-private.h \ cairo-malloc-private.h \ cairo-meta-surface-private.h \ cairo-mutex-impl-private.h \ @@ -109,8 +109,8 @@ cairo_sources = \ cairo-gstate.c \ cairo-hash.c \ cairo-hull.c \ + cairo-image-info.c \ cairo-image-surface.c \ - cairo-jpeg-info.c \ cairo-lzw.c \ cairo-matrix.c \ cairo-meta-surface.c \ diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h new file mode 100644 index 00000000..42878cbf --- /dev/null +++ b/src/cairo-image-info-private.h @@ -0,0 +1,54 @@ +/* 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 + */ + +#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); + + +#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..bac0bd08 --- /dev/null +++ b/src/cairo-image-info.c @@ -0,0 +1,141 @@ +/* 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 + */ + +#include "cairoint.h" +#include "cairo-image-info-private.h" + +/* 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; +} diff --git a/src/cairo-jpeg-info-private.h b/src/cairo-jpeg-info-private.h deleted file mode 100644 index 365825ca..00000000 --- a/src/cairo-jpeg-info-private.h +++ /dev/null @@ -1,54 +0,0 @@ -/* 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 - */ - -#ifndef CAIRO_JPEG_INFO_PRIVATE_H -#define CAIRO_JPEG_INFO_PRIVATE_H - -#include "cairoint.h" - -typedef struct _cairo_jpeg_info { - int width; - int height; - int num_components; - int bits_per_component; -} cairo_jpeg_info_t; - -cairo_private cairo_int_status_t -_cairo_jpeg_get_info (const unsigned char *data, - long length, - cairo_jpeg_info_t *info); - - -#endif /* CAIRO_JPEG_INFO_PRIVATE_H */ diff --git a/src/cairo-jpeg-info.c b/src/cairo-jpeg-info.c deleted file mode 100644 index ca85ceff..00000000 --- a/src/cairo-jpeg-info.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 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 - */ - -#include "cairoint.h" -#include "cairo-jpeg-info-private.h" - -/* 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 * -_skip_segment (const unsigned char *p) -{ - int len; - - p++; - len = (p[0] << 8) | p[1]; - - return p + len; -} - -static void -_extract_info (cairo_jpeg_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_jpeg_get_info (const unsigned char *data, - long length, - cairo_jpeg_info_t *info) -{ - 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; - - _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 = _skip_segment (p); - break; - } - } - - return CAIRO_STATUS_SUCCESS; -} diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 6edea4a5..afc56da6 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -45,12 +45,12 @@ #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" #include "cairo-scaled-font-subsets-private.h" #include "cairo-type3-glyph-surface-private.h" -#include "cairo-jpeg-info-private.h" #include #include @@ -1561,14 +1561,14 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, cairo_status_t status; const unsigned char *mime_data; unsigned int mime_data_length; - cairo_jpeg_info_t info; + 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_jpeg_get_info (mime_data, mime_data_length, &info); + status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); if (status) return status; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index f4431fa0..0c9ef7f4 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -63,7 +63,7 @@ #include "cairo-meta-surface-private.h" #include "cairo-output-stream-private.h" #include "cairo-type3-glyph-surface-private.h" -#include "cairo-jpeg-info-private.h" +#include "cairo-image-info-private.h" #include #include @@ -2130,14 +2130,14 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface, cairo_status_t status; const unsigned char *mime_data; unsigned int mime_data_length; - cairo_jpeg_info_t info; + 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_jpeg_get_info (mime_data, mime_data_length, &info); + status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); if (status) return status; diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index cfc56c43..ab2e4b94 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -43,7 +43,7 @@ #include "cairoint.h" #include "cairo-svg.h" #include "cairo-analysis-surface-private.h" -#include "cairo-jpeg-info-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" @@ -982,7 +982,7 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, { const unsigned char *mime_data; unsigned int mime_data_length; - cairo_jpeg_info_t jpeg_info; + cairo_image_info_t image_info; base64_write_closure_t info; cairo_status_t status; @@ -991,7 +991,7 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, if (mime_data == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; - status = _cairo_jpeg_get_info (mime_data, mime_data_length, &jpeg_info); + status = _cairo_image_info_get_jpeg_info (&image_info, mime_data, mime_data_length); if (status) return status; diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 34b31c7d..625f4b00 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -52,7 +52,7 @@ #include "cairo-win32-private.h" #include "cairo-meta-surface-private.h" #include "cairo-scaled-font-subsets-private.h" -#include "cairo-jpeg-info-private.h" +#include "cairo-image-info-private.h" #include @@ -511,7 +511,7 @@ _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, { const unsigned char *mime_data; unsigned int mime_data_length; - cairo_jpeg_info_t info; + cairo_image_info_t info; cairo_int_status_t status; DWORD result; @@ -523,7 +523,7 @@ _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, if (mime_data == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; - status = _cairo_jpeg_get_info (mime_data, mime_data_length, &info); + status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); if (status) return status; -- cgit v1.2.3 From 0746efbf0718095920d9258942d32a7023d22131 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 18:47:13 +1030 Subject: Add JPEG2000 mimetype and image info function --- src/cairo-image-info-private.h | 4 ++ src/cairo-image-info.c | 100 +++++++++++++++++++++++++++++++++++++++++ src/cairo-surface-fallback.c | 1 + src/cairo.h | 1 + 4 files changed, 106 insertions(+) diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h index 42878cbf..030b1d04 100644 --- a/src/cairo-image-info-private.h +++ b/src/cairo-image-info-private.h @@ -50,5 +50,9 @@ _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); #endif /* CAIRO_IMAGE_INFO_PRIVATE_H */ diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c index bac0bd08..e793ba51 100644 --- a/src/cairo-image-info.c +++ b/src/cairo-image-info.c @@ -139,3 +139,103 @@ _cairo_image_info_get_jpeg_info (cairo_image_info_t *info, return CAIRO_STATUS_SUCCESS; } + +#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 uint32_t +_get_be32 (const unsigned char *p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +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) +{ + uint 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; +} diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index bb29a9f0..2dcaa58e 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -1039,6 +1039,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) const char *mime_types[] = { CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_PNG, + CAIRO_MIME_TYPE_JP2, NULL }, **mime_type; diff --git a/src/cairo.h b/src/cairo.h index 33655232..8f57ae08 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1951,6 +1951,7 @@ cairo_surface_set_user_data (cairo_surface_t *surface, #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, -- cgit v1.2.3 From 7fdb712cbaadc95c02f607a9f6c995f8beb01342 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 18:56:12 +1030 Subject: PDF: Add JPEG2000 image embedding Requires increasing the PDF version to 1.5. --- src/cairo-pdf-surface.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index afc56da6..6d007adc 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -296,7 +296,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, /* Document header */ _cairo_output_stream_printf (surface->output, - "%%PDF-1.4\n"); + "%%PDF-1.5\n"); _cairo_output_stream_printf (surface->output, "%%%c%c%c%c\n", 181, 237, 174, 251); @@ -1551,6 +1551,51 @@ 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; + + 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); + 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, @@ -1619,6 +1664,11 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, 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) -- cgit v1.2.3 From b87d81ef0bb52570385a3c9e331651cbeb87b2bb Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 19:29:26 +1030 Subject: Add image/jp2 to mime-data test --- test/jp2.jp2 | Bin 0 -> 2999 bytes test/mime-data.c | 7 ++++++- test/mime-data.pdf.ref.png | Bin 4466 -> 6482 bytes test/mime-data.ps.ref.png | Bin 4466 -> 4554 bytes test/mime-data.ref.png | Bin 155 -> 185 bytes test/mime-data.svg.ref.png | Bin 6153 -> 6264 bytes 6 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 test/jp2.jp2 diff --git a/test/jp2.jp2 b/test/jp2.jp2 new file mode 100644 index 00000000..fe8dd6e5 Binary files /dev/null and b/test/jp2.jp2 differ diff --git a/test/mime-data.c b/test/mime-data.c index ec855f85..febc3226 100644 --- a/test/mime-data.c +++ b/test/mime-data.c @@ -116,6 +116,7 @@ draw (cairo_t *cr, int width, int height) { const char jpg_filename[] = "jpeg.jpg"; const char png_filename[] = "png.png"; + const char jp2_filename[] = "jp2.jp2"; cairo_test_status_t status; status = paint_file (cr, jpg_filename, CAIRO_MIME_TYPE_JPEG, 0, 0); @@ -126,6 +127,10 @@ draw (cairo_t *cr, int width, int height) if (status) return status; + status = paint_file (cr, jp2_filename, CAIRO_MIME_TYPE_JP2, 0, 100); + if (status) + return status; + return CAIRO_TEST_SUCCESS; } @@ -133,5 +138,5 @@ CAIRO_TEST (mime_data, "Check that the mime-data embedding works", "jpeg, api", /* keywords */ NULL, /* requirements */ - 200, 100, + 200, 150, NULL, draw) diff --git a/test/mime-data.pdf.ref.png b/test/mime-data.pdf.ref.png index ebfcb790..90a08f59 100644 Binary files a/test/mime-data.pdf.ref.png and b/test/mime-data.pdf.ref.png differ diff --git a/test/mime-data.ps.ref.png b/test/mime-data.ps.ref.png index ebfcb790..721fb9c8 100644 Binary files a/test/mime-data.ps.ref.png and b/test/mime-data.ps.ref.png differ diff --git a/test/mime-data.ref.png b/test/mime-data.ref.png index ccbf1b63..3a912c54 100644 Binary files a/test/mime-data.ref.png and b/test/mime-data.ref.png differ diff --git a/test/mime-data.svg.ref.png b/test/mime-data.svg.ref.png index 96a7bec4..81fde726 100644 Binary files a/test/mime-data.svg.ref.png and b/test/mime-data.svg.ref.png differ -- cgit v1.2.3 From d85e836911d661275c29f2348a047e5d911f9004 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 21:03:22 +1030 Subject: PDF: Add newline to end of binary streams PDF requires white space before the "endstream" --- src/cairo-pdf-surface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 6d007adc..322c7737 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1588,6 +1588,7 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, *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; @@ -1639,6 +1640,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, *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; -- cgit v1.2.3 From c4a57385fa2e69020f43519bea21b98182bf5fd7 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 21:12:08 +1030 Subject: PDF: Add cairo_pdf_surface_restrict_to_version API Now that we are using PDF 1.5 features, add an api to select between version 1.4 or 1.5. --- src/cairo-pdf-surface-private.h | 2 + src/cairo-pdf-surface.c | 116 +++++++++++++++++++++++++++++++++++++--- src/cairo-pdf.h | 24 +++++++++ 3 files changed, 136 insertions(+), 6 deletions(-) diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index 7f2764ff..d2fa43c4 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -128,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 322c7737..bf80a944 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -111,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; @@ -273,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; @@ -285,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, @@ -294,12 +310,6 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, _cairo_pdf_surface_add_font, surface); - /* Document header */ - _cairo_output_stream_printf (surface->output, - "%%PDF-1.5\n"); - _cairo_output_stream_printf (surface->output, - "%%%c%c%c%c\n", 181, 237, 174, 251); - surface->paginated_surface = _cairo_paginated_surface_create ( &surface->base, CAIRO_CONTENT_COLOR_ALPHA, @@ -437,6 +447,80 @@ _extract_pdf_surface (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +/** + * 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_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 @@ -1291,6 +1375,26 @@ _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; + 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; 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, @@ -54,6 +67,17 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, double width_in_points, 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, -- cgit v1.2.3 From 1892907e24d9f9f31942c6962aaa6d2ff9553ce7 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 21:36:40 +1030 Subject: PDF: Disable PDF 1.5 features when version 1.4 is selected JPEG 2000 image embedding and ActualText marked content are PDF 1.5 features. --- src/cairo-pdf-operators-private.h | 5 +++++ src/cairo-pdf-operators.c | 8 ++++++++ src/cairo-pdf-surface.c | 7 +++++++ 3 files changed, 20 insertions(+) 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 f335a37e..d363805f 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. diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index bf80a944..b98f7d75 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -309,6 +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); + _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, TRUE); surface->paginated_surface = _cairo_paginated_surface_create ( &surface->base, @@ -477,6 +478,9 @@ cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface, 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); } /** @@ -1667,6 +1671,9 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, 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) -- cgit v1.2.3 From f59a3e03fc91dc4a1769b07bda77a364cc570bc8 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 23 Nov 2008 22:27:49 +1030 Subject: Add PNG get info function --- src/cairo-image-info-private.h | 5 +++++ src/cairo-image-info.c | 46 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h index 030b1d04..6e1c4ad7 100644 --- a/src/cairo-image-info-private.h +++ b/src/cairo-image-info-private.h @@ -55,4 +55,9 @@ _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 index e793ba51..7742c882 100644 --- a/src/cairo-image-info.c +++ b/src/cairo-image-info.c @@ -36,6 +36,12 @@ #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]; +} + /* Markers with no parameters. All other markers are followed by a two * byte length of the parameters. */ #define TEM 0x01 @@ -148,12 +154,6 @@ static const unsigned char _jpx_signature[] = { 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a }; -static uint32_t -_get_be32 (const unsigned char *p) -{ - return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; -} - static const unsigned char * _jpx_next_box (const unsigned char *p) { @@ -239,3 +239,37 @@ _cairo_image_info_get_jpx_info (cairo_image_info_t *info, return CAIRO_STATUS_SUCCESS; } + +#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; +} -- cgit v1.2.3 From 4ca644af274bda4603e7d02dbeca8641bbb3ff79 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 24 Nov 2008 00:29:54 +1030 Subject: Win32-print: Add PNG embedding support --- src/cairo-win32-printing-surface.c | 106 +++++++++++++++++++++++++++---------- src/cairo-win32-private.h | 3 ++ 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 625f4b00..41330198 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -80,6 +80,10 @@ # 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; @@ -112,6 +116,10 @@ _cairo_win32_printing_surface_init_image_support (cairo_win32_surface_t *surface 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 @@ -504,14 +512,12 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa static cairo_int_status_t _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, cairo_surface_t *source, - const unsigned char **jpeg_data, - unsigned int *jpeg_length, - int *jpeg_width, - int *jpeg_height) + const unsigned char **data, + unsigned int *length, + cairo_image_info_t *info) { const unsigned char *mime_data; unsigned int mime_data_length; - cairo_image_info_t info; cairo_int_status_t status; DWORD result; @@ -523,7 +529,7 @@ _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, if (mime_data == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; - status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); + status = _cairo_image_info_get_jpeg_info (info, mime_data, mime_data_length); if (status) return status; @@ -535,10 +541,47 @@ _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, if (result != 1) return CAIRO_INT_STATUS_UNSUPPORTED; - *jpeg_data = mime_data; - *jpeg_length = mime_data_length; - *jpeg_width = info.width; - *jpeg_height = info.height; + *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; } @@ -560,10 +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 *jpeg_data; - unsigned int jpeg_size; - int jpeg_width, jpeg_height; - cairo_bool_t use_jpeg; + 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. @@ -593,18 +637,26 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf goto CLEANUP_IMAGE; } + mime_type = BI_JPEG; status = _cairo_win32_printing_surface_check_jpeg (surface, pattern->surface, - &jpeg_data, - &jpeg_size, - &jpeg_width, - &jpeg_height); + &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_jpeg = (status == CAIRO_STATUS_SUCCESS); + use_mime = (status == CAIRO_STATUS_SUCCESS); - if (!use_jpeg && image->format != CAIRO_FORMAT_RGB24) { + if (!use_mime && image->format != CAIRO_FORMAT_RGB24) { cairo_surface_pattern_t opaque_pattern; opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, @@ -649,14 +701,14 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf } bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = use_jpeg ? jpeg_width : opaque_image->width; - bi.bmiHeader.biHeight = use_jpeg ? - jpeg_height : -opaque_image->height; - bi.bmiHeader.biSizeImage = use_jpeg ? jpeg_size : 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 = use_jpeg ? BI_JPEG : BI_RGB; + bi.bmiHeader.biCompression = use_mime ? mime_type : BI_RGB; bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrImportant = 0; @@ -698,9 +750,9 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf opaque_image->height, 0, 0, - use_jpeg ? jpeg_width : opaque_image->width, - use_jpeg ? jpeg_height : opaque_image->height, - use_jpeg ? jpeg_data : 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)) diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h index 7b07a864..51564d04 100644 --- a/src/cairo-win32-private.h +++ b/src/cairo-win32-private.h @@ -120,6 +120,9 @@ enum { /* 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 -- cgit v1.2.3 From 70e4c532722bbcad1eca50438e6ab2cdd0ea9b53 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 24 Nov 2008 22:38:30 +1030 Subject: Document location of image format specifications --- src/cairo-image-info.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c index 7742c882..f84bcaf0 100644 --- a/src/cairo-image-info.c +++ b/src/cairo-image-info.c @@ -42,6 +42,11 @@ _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 @@ -146,6 +151,11 @@ _cairo_image_info_get_jpeg_info (cairo_image_info_t *info, 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 @@ -240,6 +250,11 @@ _cairo_image_info_get_jpx_info (cairo_image_info_t *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 }; -- cgit v1.2.3 From 721cad9b24c2ad049320950d231ed84046c5b8ab Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 24 Nov 2008 22:41:03 +1030 Subject: Fix typo --- src/cairo-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-misc.c b/src/cairo-misc.c index 5d258ff3..397b0efe 100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -617,7 +617,7 @@ _cairo_lround (double d) #include #include -/* 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. -- cgit v1.2.3 From b6bf047494fc308fff00d818b2920d8ba4aa7aed Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 21 Nov 2008 15:27:31 +0000 Subject: [clip] Check for error surface The update to use a NULL backend with an error surface broke creating a context from an error surface. --- src/cairo-clip.c | 2 +- src/cairo.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 726896e8..83ba28c1 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; diff --git a/src/cairo.c b/src/cairo.c index f53d0b03..c80589d2 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -166,8 +166,8 @@ cairo_create (cairo_surface_t *target) cr->gstate = cr->gstate_tail; cr->gstate_freelist = NULL; - status = _cairo_gstate_init (cr->gstate, target); + status = _cairo_gstate_init (cr->gstate, target); if (status) _cairo_set_error (cr, status); -- cgit v1.2.3 From 59de6fb89e80ee6aeeb2984b545ceb9bb9f0f7bb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2008 10:04:50 +0000 Subject: [path] Compute approximate extents. When computing the bounds of the clip path, we care more for a fast result than absolute precision as the extents are only used as a guide to trim the future operations. So computing the extents of the path suffices. --- src/cairo-analysis-surface.c | 16 +++-------- src/cairo-clip.c | 25 +++--------------- src/cairo-gstate.c | 13 +++------ src/cairo-path-bounds.c | 63 ++++++++++++++++++++++++++++++++++++++++---- src/cairo-surface.c | 8 +++--- src/cairo.c | 10 +++---- src/cairoint.h | 8 ++++-- 7 files changed, 82 insertions(+), 61 deletions(-) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index d5b63e8e..431f98eb 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); } diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 83ba28c1..ce2a2409 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -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; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 33880d84..3acbc100 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -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 diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 70867e31..54df5bff 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -131,14 +131,68 @@ _cairo_path_bounder_line_to (void *closure, cairo_point_t *point) return CAIRO_STATUS_SUCCESS; } +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 = bounder.min_x; + extents->y = bounder.min_y; + extents->width = bounder.max_x - extents->x; + extents->height = 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 +209,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 +224,4 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path, } _cairo_path_bounder_fini (&bounder); - - return status; } diff --git a/src/cairo-surface.c b/src/cairo-surface.c index eaff47a2..4c10f958 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -2132,11 +2132,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 diff --git a/src/cairo.c b/src/cairo.c index c80589d2..d1892fd2 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -1907,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; @@ -1922,11 +1920,9 @@ 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); } /** diff --git a/src/cairoint.h b/src/cairoint.h index d219061d..32cc7591 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1139,7 +1139,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, @@ -1511,7 +1511,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, -- cgit v1.2.3 From b8991a1c69ae5d8fb630296a3c689aa8d1546671 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2008 10:11:59 +0000 Subject: [in-fill] Add the implicit close-path during move-to. When interpreting a fixed-path for a fill operation, any move-to implicitly closes the current path. --- src/cairo-gstate.c | 12 ++++++------ src/cairo-path-in-fill.c | 23 +++++++++++++---------- src/cairo.c | 11 ++++------- src/cairoint.h | 4 ++-- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 3acbc100..9f7892a4 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1060,7 +1060,7 @@ _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, @@ -1069,11 +1069,11 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, { _cairo_gstate_user_to_backend (gstate, &x, &y); - return _cairo_path_fixed_in_fill (path, - gstate->fill_rule, - gstate->tolerance, - x, y, - inside_ret); + _cairo_path_fixed_in_fill (path, + gstate->fill_rule, + gstate->tolerance, + x, y, + inside_ret); } cairo_status_t diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c index 2b9b057d..0362bfb6 100644 --- a/src/cairo-path-in-fill.c +++ b/src/cairo-path-in-fill.c @@ -136,9 +136,14 @@ _cairo_in_fill_move_to (void *closure, cairo_point_t *point) { cairo_in_fill_t *in_fill = closure; - if (! in_fill->has_current_point) - in_fill->first_point = *point; + /* 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; @@ -153,7 +158,10 @@ _cairo_in_fill_line_to (void *closure, cairo_point_t *point) if (in_fill->has_current_point) _cairo_in_fill_add_edge (in_fill, &in_fill->current_point, point); - return _cairo_in_fill_move_to (in_fill, point); + in_fill->current_point = *point; + in_fill->has_current_point = TRUE; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -215,7 +223,7 @@ _cairo_in_fill_close_path (void *closure) return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_path_fixed_in_fill (cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, @@ -235,8 +243,7 @@ _cairo_path_fixed_in_fill (cairo_path_fixed_t *path, _cairo_in_fill_curve_to, _cairo_in_fill_close_path, &in_fill); - if (status) - goto BAIL; + assert (status == CAIRO_STATUS_SUCCESS); switch (fill_rule) { case CAIRO_FILL_RULE_EVEN_ODD: @@ -251,9 +258,5 @@ _cairo_path_fixed_in_fill (cairo_path_fixed_t *path, break; } - status = CAIRO_STATUS_SUCCESS; - -BAIL: _cairo_in_fill_fini (&in_fill); - return status; } diff --git a/src/cairo.c b/src/cairo.c index d1892fd2..3dc30014 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -2269,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; } diff --git a/src/cairoint.h b/src/cairoint.h index 32cc7591..34ea874a 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1183,7 +1183,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, @@ -1537,7 +1537,7 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, cairo_box_t *box); /* cairo-path-in-fill.c */ -cairo_private cairo_status_t +cairo_private void _cairo_path_fixed_in_fill (cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, -- cgit v1.2.3 From ca80b8c652dde4449216da9d11691202eef97bbd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2008 10:25:24 +0000 Subject: [pdf] Add a default case to silence the compiler. The foolish compiler was emitting a warning about a potential uninitialized variable even though the switch was fully populated. --- src/cairo-pdf-surface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index b98f7d75..97902505 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1387,6 +1387,7 @@ _cairo_pdf_surface_start_page (void *abstract_surface) case CAIRO_PDF_VERSION_1_4: version = "1.4"; break; + default: case CAIRO_PDF_VERSION_1_5: version = "1.5"; break; -- cgit v1.2.3 From 487c708b3b6727eb2f8d3714edeae356a7cbbd40 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 25 Nov 2008 20:40:37 +0800 Subject: [boilerplate] fix compilation for glitz-agl As suggested on the list, this splits the cairo-boilerplate-glitz.c file in three separate files, one for each backend. Furthermore, it fixes a few problems in compilation of the AGL backend test harness. --- boilerplate/Makefile.sources | 6 +- boilerplate/cairo-boilerplate-glitz-agl.c | 166 +++++++++ boilerplate/cairo-boilerplate-glitz-glx.c | 244 ++++++++++++ boilerplate/cairo-boilerplate-glitz-private.h | 6 + boilerplate/cairo-boilerplate-glitz-wgl.c | 164 ++++++++ boilerplate/cairo-boilerplate-glitz.c | 517 -------------------------- 6 files changed, 585 insertions(+), 518 deletions(-) create mode 100644 boilerplate/cairo-boilerplate-glitz-agl.c create mode 100644 boilerplate/cairo-boilerplate-glitz-glx.c create mode 100644 boilerplate/cairo-boilerplate-glitz-wgl.c delete mode 100644 boilerplate/cairo-boilerplate-glitz.c diff --git a/boilerplate/Makefile.sources b/boilerplate/Makefile.sources index 7be44672..b3cea817 100644 --- a/boilerplate/Makefile.sources +++ b/boilerplate/Makefile.sources @@ -25,7 +25,11 @@ cairo_boilerplate_directfb_private = cairo-boilerplate-directfb-private.h cairo_boilerplate_directfb_sources = cairo-boilerplate-directfb.c cairo_boilerplate_glitz_private = cairo-boilerplate-glitz-private.h -cairo_boilerplate_glitz_sources = cairo-boilerplate-glitz.c +cairo_boilerplate_glitz_sources = \ + cairo-boilerplate-glitz-agl.c \ + cairo-boilerplate-glitz-glx.c \ + cairo-boilerplate-glitz-wgl.c \ + $(NULL) cairo_boilerplate_pdf_private = cairo-boilerplate-pdf-private.h cairo_boilerplate_pdf_sources = cairo-boilerplate-pdf.c diff --git a/boilerplate/cairo-boilerplate-glitz-agl.c b/boilerplate/cairo-boilerplate-glitz-agl.c new file mode 100644 index 00000000..06b90308 --- /dev/null +++ b/boilerplate/cairo-boilerplate-glitz-agl.c @@ -0,0 +1,166 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate.h" +#include "cairo-boilerplate-glitz-private.h" + +#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE +#include +#include + +static const cairo_user_data_key_t glitz_closure_key; + +typedef struct _glitz_agl_target_closure { + glitz_target_closure_base_t base; +} glitz_agl_target_closure_t; + +static glitz_surface_t * +_cairo_boilerplate_glitz_agl_create_surface_internal (glitz_format_name_t formatname, + int width, + int height, + glitz_agl_target_closure_t *closure) +{ + glitz_drawable_format_t *dformat; + glitz_drawable_format_t templ; + glitz_drawable_t *gdraw; + glitz_format_t *format; + glitz_surface_t *sr = NULL; + unsigned long mask; + + memset(&templ, 0, sizeof(templ)); + templ.color.red_size = 8; + templ.color.green_size = 8; + templ.color.blue_size = 8; + templ.color.alpha_size = 8; + templ.color.fourcc = GLITZ_FOURCC_RGB; + templ.samples = 1; + + mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK | + GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | + GLITZ_FORMAT_BLUE_SIZE_MASK; + if (formatname == GLITZ_STANDARD_ARGB32) + mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; + + dformat = glitz_agl_find_pbuffer_format (mask, &templ, 0); + if (!dformat) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template."); + goto FAIL; + } + + gdraw = glitz_agl_create_pbuffer_drawable (dformat, width, height); + if (!gdraw) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable."); + goto FAIL; + } + + format = glitz_find_standard_format (gdraw, formatname); + if (!format) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable."); + goto DESTROY_DRAWABLE; + } + + sr = glitz_surface_create (gdraw, format, width, height, 0, NULL); + if (!sr) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface."); + goto DESTROY_DRAWABLE; + } + + glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); + + DESTROY_DRAWABLE: + glitz_drawable_destroy (gdraw); + return sr; + + FAIL: + return NULL; +} + +cairo_surface_t * +_cairo_boilerplate_glitz_agl_create_surface (const char *name, + cairo_content_t content, + int width, + int height, + int max_width, + int max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure) +{ + glitz_surface_t *glitz_surface; + cairo_surface_t *surface = NULL; + glitz_agl_target_closure_t *aglc; + int status; + + glitz_agl_init (); + + *closure = aglc = xmalloc (sizeof (glitz_agl_target_closure_t)); + + switch (content) { + case CAIRO_CONTENT_COLOR: + glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL); + break; + case CAIRO_CONTENT_COLOR_ALPHA: + glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL); + break; + case CAIRO_CONTENT_ALPHA: + default: + CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-agl test: %d\n", content); + goto FAIL; + } + + if (!glitz_surface) + goto FAIL; + + surface = cairo_glitz_surface_create (glitz_surface); + glitz_surface_destroy (glitz_surface); + + if (cairo_surface_status (surface)) + goto FAIL; + + aglc->base.width = width; + aglc->base.height = height; + aglc->base.content = content; + status = cairo_surface_set_user_data (surface, + &glitz_closure_key, aglc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + FAIL: + glitz_agl_fini (); + return surface; +} + +void +_cairo_boilerplate_glitz_agl_cleanup (void *closure) +{ + free (closure); + glitz_agl_fini (); +} + +#endif diff --git a/boilerplate/cairo-boilerplate-glitz-glx.c b/boilerplate/cairo-boilerplate-glitz-glx.c new file mode 100644 index 00000000..5dcf8b69 --- /dev/null +++ b/boilerplate/cairo-boilerplate-glitz-glx.c @@ -0,0 +1,244 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate.h" +#include "cairo-boilerplate-glitz-private.h" + +#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE +#include +#include + +static const cairo_user_data_key_t glitz_closure_key; + +typedef struct _glitz_glx_target_closure { + glitz_target_closure_base_t base; + Display *dpy; + int scr; + Window win; +} glitz_glx_target_closure_t; + +static glitz_surface_t * +_cairo_boilerplate_glitz_glx_create_surface_internal (glitz_format_name_t formatname, + int width, + int height, + glitz_glx_target_closure_t *closure) +{ + Display * dpy = closure->dpy; + int scr = closure->scr; + glitz_drawable_format_t templ; + glitz_drawable_format_t * dformat = NULL; + unsigned long mask; + glitz_drawable_t * drawable = NULL; + glitz_format_t * format; + glitz_surface_t * sr; + + XSizeHints xsh; + XSetWindowAttributes xswa; + XVisualInfo * vinfo; + + memset(&templ, 0, sizeof(templ)); + templ.color.red_size = 8; + templ.color.green_size = 8; + templ.color.blue_size = 8; + templ.color.alpha_size = 8; + templ.color.fourcc = GLITZ_FOURCC_RGB; + templ.samples = 1; + + glitz_glx_init (NULL); + + mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK | + GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | + GLITZ_FORMAT_BLUE_SIZE_MASK; + if (formatname == GLITZ_STANDARD_ARGB32) + mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; + + /* Try for a pbuffer first */ + if (!getenv("CAIRO_TEST_FORCE_GLITZ_WINDOW")) + dformat = glitz_glx_find_pbuffer_format (dpy, scr, mask, &templ, 0); + + if (dformat) { + closure->win = None; + + drawable = glitz_glx_create_pbuffer_drawable (dpy, scr, dformat, + width, height); + if (!drawable) + goto FAIL; + } else { + /* No pbuffer, try window */ + dformat = glitz_glx_find_window_format (dpy, scr, mask, &templ, 0); + + if (!dformat) + goto FAIL; + + vinfo = glitz_glx_get_visual_info_from_format(dpy, + DefaultScreen(dpy), + dformat); + + if (!vinfo) + goto FAIL; + + xsh.flags = PSize; + xsh.x = 0; + xsh.y = 0; + xsh.width = width; + xsh.height = height; + + xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr), + vinfo->visual, AllocNone); + closure->win = XCreateWindow (dpy, RootWindow(dpy, scr), + xsh.x, xsh.y, xsh.width, xsh.height, + 0, vinfo->depth, CopyFromParent, + vinfo->visual, CWColormap, &xswa); + XFree (vinfo); + + drawable = + glitz_glx_create_drawable_for_window (dpy, scr, + dformat, closure->win, + width, height); + + if (!drawable) + goto DESTROY_WINDOW; + } + + format = glitz_find_standard_format (drawable, formatname); + if (!format) + goto DESTROY_DRAWABLE; + + sr = glitz_surface_create (drawable, format, width, height, 0, NULL); + if (!sr) + goto DESTROY_DRAWABLE; + + if (closure->win == None || dformat->doublebuffer) { + glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_BACK_COLOR); + } else { + XMapWindow (closure->dpy, closure->win); + glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); + } + + glitz_drawable_destroy (drawable); + + return sr; + + DESTROY_DRAWABLE: + glitz_drawable_destroy (drawable); + DESTROY_WINDOW: + if (closure->win) + XDestroyWindow (dpy, closure->win); + FAIL: + return NULL; +} + +cairo_surface_t * +_cairo_boilerplate_glitz_glx_create_surface (const char *name, + cairo_content_t content, + int width, + int height, + int max_width, + int max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure) +{ + glitz_glx_target_closure_t *gxtc; + glitz_surface_t * glitz_surface; + cairo_surface_t * surface = NULL; + cairo_status_t status; + + *closure = gxtc = xmalloc (sizeof (glitz_glx_target_closure_t)); + + if (width == 0) + width = 1; + if (height == 0) + height = 1; + + gxtc->dpy = XOpenDisplay (getenv("CAIRO_TEST_GLITZ_DISPLAY")); + if (!gxtc->dpy) { + CAIRO_BOILERPLATE_LOG ("Failed to open display: %s\n", XDisplayName(0)); + goto FAIL; + } + + XSynchronize (gxtc->dpy, 1); + + gxtc->scr = DefaultScreen(gxtc->dpy); + + switch (content) { + case CAIRO_CONTENT_COLOR: + glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, gxtc); + break; + case CAIRO_CONTENT_COLOR_ALPHA: + glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, gxtc); + break; + case CAIRO_CONTENT_ALPHA: + default: + CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-glx test: %d\n", content); + goto FAIL_CLOSE_DISPLAY; + } + if (!glitz_surface) { + CAIRO_BOILERPLATE_LOG ("Failed to create glitz-glx surface\n"); + goto FAIL_CLOSE_DISPLAY; + } + + surface = cairo_glitz_surface_create (glitz_surface); + glitz_surface_destroy (glitz_surface); + + if (cairo_surface_status (surface)) + goto FAIL_CLOSE_DISPLAY; + + gxtc->base.width = width; + gxtc->base.height = height; + gxtc->base.content = content; + status = cairo_surface_set_user_data (surface, + &glitz_closure_key, gxtc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + FAIL_CLOSE_DISPLAY: + glitz_glx_fini (); + XCloseDisplay (gxtc->dpy); + FAIL: + free (gxtc); + return surface; +} + +void +_cairo_boilerplate_glitz_glx_cleanup (void *closure) +{ + glitz_glx_target_closure_t *gxtc = closure; + + glitz_glx_fini (); + + if (gxtc->win) + XDestroyWindow (gxtc->dpy, gxtc->win); + + XCloseDisplay (gxtc->dpy); + + free (gxtc); +} + +#endif diff --git a/boilerplate/cairo-boilerplate-glitz-private.h b/boilerplate/cairo-boilerplate-glitz-private.h index faeeb630..052c7e06 100644 --- a/boilerplate/cairo-boilerplate-glitz-private.h +++ b/boilerplate/cairo-boilerplate-glitz-private.h @@ -31,6 +31,12 @@ #include "config.h" #endif +typedef struct _glitz_target_closure_base { + int width; + int height; + cairo_content_t content; +} glitz_target_closure_base_t; + #if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE cairo_surface_t * _cairo_boilerplate_glitz_glx_create_surface (const char *name, diff --git a/boilerplate/cairo-boilerplate-glitz-wgl.c b/boilerplate/cairo-boilerplate-glitz-wgl.c new file mode 100644 index 00000000..b11a8189 --- /dev/null +++ b/boilerplate/cairo-boilerplate-glitz-wgl.c @@ -0,0 +1,164 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate.h" +#include "cairo-boilerplate-glitz-private.h" + +#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE +#include +#include + +static const cairo_user_data_key_t glitz_closure_key; + +typedef struct _glitz_wgl_target_closure { + glitz_target_closure_base_t base; +} glitz_wgl_target_closure_t; + +glitz_surface_t * +_cairo_boilerplate_glitz_wgl_create_surface_internal (glitz_format_name_t formatname, + int width, + int height, + glitz_wgl_target_closure_t *closure) +{ + glitz_drawable_format_t *dformat; + glitz_drawable_format_t templ; + glitz_drawable_t *gdraw; + glitz_format_t *format; + glitz_surface_t *sr = NULL; + unsigned long mask; + + memset(&templ, 0, sizeof(templ)); + templ.color.red_size = 8; + templ.color.green_size = 8; + templ.color.blue_size = 8; + templ.color.alpha_size = 8; + templ.color.fourcc = GLITZ_FOURCC_RGB; + templ.samples = 1; + + mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK | + GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | + GLITZ_FORMAT_BLUE_SIZE_MASK; + if (formatname == GLITZ_STANDARD_ARGB32) + mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; + + dformat = glitz_wgl_find_pbuffer_format (mask, &templ, 0); + if (!dformat) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template."); + goto FAIL; + } + + gdraw = glitz_wgl_create_pbuffer_drawable (dformat, width, height); + if (!gdraw) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable."); + goto FAIL; + } + + format = glitz_find_standard_format (gdraw, formatname); + if (!format) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable."); + goto DESTROY_DRAWABLE; + } + + sr = glitz_surface_create (gdraw, format, width, height, 0, NULL); + if (!sr) { + CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface."); + goto DESTROY_DRAWABLE; + } + + glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); + + DESTROY_DRAWABLE: + glitz_drawable_destroy (gdraw); + + FAIL: + return sr; /* will be NULL unless we create it and attach */ +} + +cairo_surface_t * +_cairo_boilerplate_glitz_wgl_create_surface (const char *name, + cairo_content_t content, + int width, + int height, + int max_width, + int max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure) +{ + glitz_surface_t *glitz_surface; + cairo_surface_t *surface = NULL; + glitz_wgl_target_closure_t *wglc; + + glitz_wgl_init (NULL); + + *closure = wglc = xmalloc (sizeof (glitz_wgl_target_closure_t)); + + switch (content) { + case CAIRO_CONTENT_COLOR: + glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL); + break; + case CAIRO_CONTENT_COLOR_ALPHA: + glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL); + break; + default: + CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-wgl test: %d\n", content); + goto FAIL; + } + + if (!glitz_surface) + goto FAIL; + + surface = cairo_glitz_surface_create (glitz_surface); + glitz_surface_destroy (glitz_surface); + + if (cairo_surface_status (surface)) + goto FAIL; + + wglc->base.width = width; + wglc->base.height = height; + wglc->base.content = content; + status = cairo_surface_set_user_data (surface, + &glitz_closure_key, wglc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + FAIL: + glitz_wgl_fini (); + free (wglc); + return surface; +} + +void +_cairo_boilerplate_glitz_wgl_cleanup (void *closure) +{ + free (closure); + glitz_wgl_fini (); +} + +#endif diff --git a/boilerplate/cairo-boilerplate-glitz.c b/boilerplate/cairo-boilerplate-glitz.c deleted file mode 100644 index a7640801..00000000 --- a/boilerplate/cairo-boilerplate-glitz.c +++ /dev/null @@ -1,517 +0,0 @@ -/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ -/* - * Copyright © 2004,2006 Red Hat, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without - * fee, provided that the above copyright notice appear in all copies - * and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of - * Red Hat, Inc. not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. Red Hat, Inc. makes no representations about the - * suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR - * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Author: Carl D. Worth - */ - -#include "cairo-boilerplate.h" -#include "cairo-boilerplate-glitz-private.h" - -#include - -static const cairo_user_data_key_t glitz_closure_key; - -typedef struct _glitz_target_closure_base { - int width; - int height; - cairo_content_t content; -} glitz_target_closure_base_t; - -#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE -#include - -typedef struct _glitz_glx_target_closure { - glitz_target_closure_base_t base; - Display *dpy; - int scr; - Window win; -} glitz_glx_target_closure_t; - -static glitz_surface_t * -_cairo_boilerplate_glitz_glx_create_surface_internal (glitz_format_name_t formatname, - int width, - int height, - glitz_glx_target_closure_t *closure) -{ - Display * dpy = closure->dpy; - int scr = closure->scr; - glitz_drawable_format_t templ; - glitz_drawable_format_t * dformat = NULL; - unsigned long mask; - glitz_drawable_t * drawable = NULL; - glitz_format_t * format; - glitz_surface_t * sr; - - XSizeHints xsh; - XSetWindowAttributes xswa; - XVisualInfo * vinfo; - - memset(&templ, 0, sizeof(templ)); - templ.color.red_size = 8; - templ.color.green_size = 8; - templ.color.blue_size = 8; - templ.color.alpha_size = 8; - templ.color.fourcc = GLITZ_FOURCC_RGB; - templ.samples = 1; - - glitz_glx_init (NULL); - - mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK | - GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | - GLITZ_FORMAT_BLUE_SIZE_MASK; - if (formatname == GLITZ_STANDARD_ARGB32) - mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; - - /* Try for a pbuffer first */ - if (!getenv("CAIRO_TEST_FORCE_GLITZ_WINDOW")) - dformat = glitz_glx_find_pbuffer_format (dpy, scr, mask, &templ, 0); - - if (dformat) { - closure->win = None; - - drawable = glitz_glx_create_pbuffer_drawable (dpy, scr, dformat, - width, height); - if (!drawable) - goto FAIL; - } else { - /* No pbuffer, try window */ - dformat = glitz_glx_find_window_format (dpy, scr, mask, &templ, 0); - - if (!dformat) - goto FAIL; - - vinfo = glitz_glx_get_visual_info_from_format(dpy, - DefaultScreen(dpy), - dformat); - - if (!vinfo) - goto FAIL; - - xsh.flags = PSize; - xsh.x = 0; - xsh.y = 0; - xsh.width = width; - xsh.height = height; - - xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr), - vinfo->visual, AllocNone); - closure->win = XCreateWindow (dpy, RootWindow(dpy, scr), - xsh.x, xsh.y, xsh.width, xsh.height, - 0, vinfo->depth, CopyFromParent, - vinfo->visual, CWColormap, &xswa); - XFree (vinfo); - - drawable = - glitz_glx_create_drawable_for_window (dpy, scr, - dformat, closure->win, - width, height); - - if (!drawable) - goto DESTROY_WINDOW; - } - - format = glitz_find_standard_format (drawable, formatname); - if (!format) - goto DESTROY_DRAWABLE; - - sr = glitz_surface_create (drawable, format, width, height, 0, NULL); - if (!sr) - goto DESTROY_DRAWABLE; - - if (closure->win == None || dformat->doublebuffer) { - glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_BACK_COLOR); - } else { - XMapWindow (closure->dpy, closure->win); - glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); - } - - glitz_drawable_destroy (drawable); - - return sr; - - DESTROY_DRAWABLE: - glitz_drawable_destroy (drawable); - DESTROY_WINDOW: - if (closure->win) - XDestroyWindow (dpy, closure->win); - FAIL: - return NULL; -} - -cairo_surface_t * -_cairo_boilerplate_glitz_glx_create_surface (const char *name, - cairo_content_t content, - int width, - int height, - int max_width, - int max_height, - cairo_boilerplate_mode_t mode, - int id, - void **closure) -{ - glitz_glx_target_closure_t *gxtc; - glitz_surface_t * glitz_surface; - cairo_surface_t * surface = NULL; - cairo_status_t status; - - *closure = gxtc = xmalloc (sizeof (glitz_glx_target_closure_t)); - - if (width == 0) - width = 1; - if (height == 0) - height = 1; - - gxtc->dpy = XOpenDisplay (getenv("CAIRO_TEST_GLITZ_DISPLAY")); - if (!gxtc->dpy) { - CAIRO_BOILERPLATE_LOG ("Failed to open display: %s\n", XDisplayName(0)); - goto FAIL; - } - - XSynchronize (gxtc->dpy, 1); - - gxtc->scr = DefaultScreen(gxtc->dpy); - - switch (content) { - case CAIRO_CONTENT_COLOR: - glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, gxtc); - break; - case CAIRO_CONTENT_COLOR_ALPHA: - glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, gxtc); - break; - case CAIRO_CONTENT_ALPHA: - default: - CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-glx test: %d\n", content); - goto FAIL_CLOSE_DISPLAY; - } - if (!glitz_surface) { - CAIRO_BOILERPLATE_LOG ("Failed to create glitz-glx surface\n"); - goto FAIL_CLOSE_DISPLAY; - } - - surface = cairo_glitz_surface_create (glitz_surface); - glitz_surface_destroy (glitz_surface); - - if (cairo_surface_status (surface)) - goto FAIL_CLOSE_DISPLAY; - - gxtc->base.width = width; - gxtc->base.height = height; - gxtc->base.content = content; - status = cairo_surface_set_user_data (surface, - &glitz_closure_key, gxtc, NULL); - if (status == CAIRO_STATUS_SUCCESS) - return surface; - - cairo_surface_destroy (surface); - surface = cairo_boilerplate_surface_create_in_error (status); - - FAIL_CLOSE_DISPLAY: - glitz_glx_fini (); - XCloseDisplay (gxtc->dpy); - FAIL: - free (gxtc); - return surface; -} - -void -_cairo_boilerplate_glitz_glx_cleanup (void *closure) -{ - glitz_glx_target_closure_t *gxtc = closure; - - glitz_glx_fini (); - - if (gxtc->win) - XDestroyWindow (gxtc->dpy, gxtc->win); - - XCloseDisplay (gxtc->dpy); - - free (gxtc); -} - -#endif /* CAIRO_CAN_TEST_GLITZ_GLX_SURFACE */ - -#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE -#include - -typedef struct _glitz_agl_target_closure { - glitz_target_closure_base_t base; -} glitz_agl_target_closure_t; - -glitz_surface_t * -_cairo_boilerplate_glitz_agl_create_surface_internal (glitz_format_name_t formatname, - int width, - int height, - glitz_agl_target_closure_t *closure) -{ - glitz_drawable_format_t *dformat; - glitz_drawable_format_t templ; - glitz_drawable_t *gdraw; - glitz_format_t *format; - glitz_surface_t *sr = NULL; - unsigned long mask; - - memset(&templ, 0, sizeof(templ)); - templ.color.red_size = 8; - templ.color.green_size = 8; - templ.color.blue_size = 8; - templ.color.alpha_size = 8; - templ.color.fourcc = GLITZ_FOURCC_RGB; - templ.samples = 1; - - mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK | - GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | - GLITZ_FORMAT_BLUE_SIZE_MASK; - if (formatname == GLITZ_STANDARD_ARGB32) - mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; - - dformat = glitz_agl_find_pbuffer_format (mask, &templ, 0); - if (!dformat) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template."); - goto FAIL; - } - - gdraw = glitz_agl_create_pbuffer_drawable (dformat, width, height); - if (!gdraw) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable."); - goto FAIL; - } - - format = glitz_find_standard_format (gdraw, formatname); - if (!format) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable."); - goto DESTROY_DRAWABLE; - } - - sr = glitz_surface_create (gdraw, format, width, height, 0, NULL); - if (!sr) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface."); - goto DESTROY_DRAWABLE; - } - - glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); - - DESTROY_DRAWABLE: - glitz_drawable_destroy (gdraw); - return sr; - - FAIL: - return NULL; -} - -cairo_surface_t * -_cairo_boilerplate_glitz_agl_create_surface (const char *name, - cairo_content_t content, - int width, - int height, - int max_width, - int max_height, - cairo_boilerplate_mode_t mode, - int id, - void **closure) -{ - glitz_surface_t *glitz_surface; - cairo_surface_t *surface = NULL; - glitz_agl_target_closure_t *aglc; - - glitz_agl_init (); - - *closure = aglc = xmalloc (sizeof (glitz_agl_target_closure_t)); - - switch (content) { - case CAIRO_CONTENT_COLOR: - glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL); - break; - case CAIRO_CONTENT_COLOR_ALPHA: - glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL); - break; - default: - CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-agl test: %d\n", content); - goto FAIL; - } - - if (!glitz_surface) - goto FAIL; - - surface = cairo_glitz_surface_create (glitz_surface); - glitz_surface_destroy (glitz_surface); - - if (cairo_surface_status (surface)) - goto FAIL; - - aglc->base.width = width; - aglc->base.height = height; - aglc->base.content = content; - status = cairo_surface_set_user_data (surface, - &glitz_closure_key, aglc, NULL); - if (status == CAIRO_STATUS_SUCCESS) - return surface; - - cairo_surface_destroy (surface); - surface = cairo_boilerplate_surface_create_in_error (status); - - FAIL: - glitz_agl_fini (); - return surface; -} - -void -_cairo_boilerplate_glitz_agl_cleanup (void *closure) -{ - free (closure); - glitz_agl_fini (); -} - -#endif /* CAIRO_CAN_TEST_GLITZ_AGL_SURFACE */ - -#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE -#include - -typedef struct _glitz_wgl_target_closure { - glitz_target_closure_base_t base; -} glitz_wgl_target_closure_t; - -glitz_surface_t * -_cairo_boilerplate_glitz_wgl_create_surface_internal (glitz_format_name_t formatname, - int width, - int height, - glitz_wgl_target_closure_t *closure) -{ - glitz_drawable_format_t *dformat; - glitz_drawable_format_t templ; - glitz_drawable_t *gdraw; - glitz_format_t *format; - glitz_surface_t *sr = NULL; - unsigned long mask; - - memset(&templ, 0, sizeof(templ)); - templ.color.red_size = 8; - templ.color.green_size = 8; - templ.color.blue_size = 8; - templ.color.alpha_size = 8; - templ.color.fourcc = GLITZ_FOURCC_RGB; - templ.samples = 1; - - mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK | - GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | - GLITZ_FORMAT_BLUE_SIZE_MASK; - if (formatname == GLITZ_STANDARD_ARGB32) - mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; - - dformat = glitz_wgl_find_pbuffer_format (mask, &templ, 0); - if (!dformat) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template."); - goto FAIL; - } - - gdraw = glitz_wgl_create_pbuffer_drawable (dformat, width, height); - if (!gdraw) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable."); - goto FAIL; - } - - format = glitz_find_standard_format (gdraw, formatname); - if (!format) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable."); - goto DESTROY_DRAWABLE; - } - - sr = glitz_surface_create (gdraw, format, width, height, 0, NULL); - if (!sr) { - CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface."); - goto DESTROY_DRAWABLE; - } - - glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); - - DESTROY_DRAWABLE: - glitz_drawable_destroy (gdraw); - - FAIL: - return sr; /* will be NULL unless we create it and attach */ -} - -cairo_surface_t * -_cairo_boilerplate_glitz_wgl_create_surface (const char *name, - cairo_content_t content, - int width, - int height, - int max_width, - int max_height, - cairo_boilerplate_mode_t mode, - int id, - void **closure) -{ - glitz_surface_t *glitz_surface; - cairo_surface_t *surface = NULL; - glitz_wgl_target_closure_t *wglc; - - glitz_wgl_init (NULL); - - *closure = wglc = xmalloc (sizeof (glitz_wgl_target_closure_t)); - - switch (content) { - case CAIRO_CONTENT_COLOR: - glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL); - break; - case CAIRO_CONTENT_COLOR_ALPHA: - glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL); - break; - default: - CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-wgl test: %d\n", content); - goto FAIL; - } - - if (!glitz_surface) - goto FAIL; - - surface = cairo_glitz_surface_create (glitz_surface); - glitz_surface_destroy (glitz_surface); - - if (cairo_surface_status (surface)) - goto FAIL; - - wglc->base.width = width; - wglc->base.height = height; - wglc->base.content = content; - status = cairo_surface_set_user_data (surface, - &glitz_closure_key, wglc, NULL); - if (status == CAIRO_STATUS_SUCCESS) - return surface; - - cairo_surface_destroy (surface); - surface = cairo_boilerplate_surface_create_in_error (status); - - FAIL: - glitz_wgl_fini (); - free (wglc); - return surface; -} - -void -_cairo_boilerplate_glitz_wgl_cleanup (void *closure) -{ - free (closure); - glitz_wgl_fini (); -} - -#endif /* CAIRO_CAN_TEST_GLITZ_WGL_SURFACE */ -- cgit v1.2.3 From 1f44fb97f3973aa90c4f27bcf9341149370c825d Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Tue, 25 Nov 2008 20:45:03 +0800 Subject: cairo-script: add $(top_builddir)/src to CPPPATH. $(top_builddir)/src is needed to find cairo-features.h while building out of tree. --- util/cairo-script/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am index 03cb13e6..4d228128 100644 --- a/util/cairo-script/Makefile.am +++ b/util/cairo-script/Makefile.am @@ -1,7 +1,7 @@ lib_LTLIBRARIES = libcairo-script-interpreter.la noinst_PROGRAMS = csi-replay -AM_CPPFLAGS = -I$(top_srcdir)/src +AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src cairoincludedir=$(includedir)/cairo cairoinclude_HEADERS = cairo-script-interpreter.h -- cgit v1.2.3 From 06fabd6cbd0ad187f5f9f155d6b7962f76ec5dda Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2008 12:05:26 +0000 Subject: [path] Fix up extents. Forgot to round the box to the integer rectangle and missed why only testing on image. Very naughty. --- src/cairo-analysis-surface.c | 2 +- src/cairo-path-bounds.c | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 431f98eb..3109deed 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -290,7 +290,7 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface, surface->current_clip.width = surface->width; surface->current_clip.height = surface->height; } else { - cairo_rectangle_int_t extent; + cairo_rectangle_int_t extent; cairo_bool_t is_empty; _cairo_path_fixed_approximate_extents (path, &extent); diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 54df5bff..6245cd26 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -172,18 +172,20 @@ _cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path, _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); + _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 = bounder.min_x; - extents->y = bounder.min_y; - extents->width = bounder.max_x - extents->x; - extents->height = bounder.max_y - extents->y; + 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; -- cgit v1.2.3 From 23df74e5ffd6be876f3c19ee9d71683f5a0ed6f4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2008 11:45:30 +0000 Subject: [xlib] Cosmetic tweak. Tightly scope the local rects. --- src/cairo-xlib-surface.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 2ae727f1..136e5546 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -1924,8 +1924,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); @@ -1961,6 +1959,9 @@ _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) -- cgit v1.2.3 From 4ac38f7c2bde67cab37805cab8a2effb2a8617e4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2008 11:52:01 +0000 Subject: [fill] Emit rectangles for GdkRegion Scan the path for a series of consistently wound rectangles. --- src/cairo-path-fill.c | 85 ++++++++++++++++++++++------ src/cairo-path-fixed-private.h | 17 ++++++ src/cairo-path-fixed.c | 124 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 201 insertions(+), 25 deletions(-) diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index 46046bb9..a6dea083 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -150,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 @@ -163,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; @@ -205,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_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 43c33c18..c995e2a9 100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -88,4 +88,21 @@ 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; + int n_op; + 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_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 b36f4d8e..ffaf58c1 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -1002,10 +1002,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; } @@ -1014,10 +1012,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; } @@ -1049,3 +1045,115 @@ _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_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; + + /* 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. */ + 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) { + 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->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO && + iter->buf->num_ops == iter->n_op + 1) + { + return TRUE; + } + + return FALSE; +} -- cgit v1.2.3 From 3bde440e00ba19e968b854c1505dc4d1ace83504 Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Tue, 25 Nov 2008 22:36:53 +0800 Subject: glitz: fixup another stupid bug in fill_rectangles. Wny I doesn't notice them before. Without fixes it fills n_rect times of the first one in the rectangle list. --- src/cairo-glitz-surface.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index db1d29e7..b08fc52e 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -1065,6 +1065,7 @@ _cairo_glitz_surface_fill_rectangles (void *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)) { @@ -1133,6 +1134,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); + current_rect = glitz_rects; while (n_rects--) { glitz_composite (_glitz_operator (op), @@ -1141,9 +1143,9 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, dst->surface, 0, 0, 0, 0, - glitz_rects->x, glitz_rects->y, - glitz_rects->width, glitz_rects->height); - rects++; + current_rect->x, current_rect->y, + current_rect->width, current_rect->height); + current_rect++; } cairo_surface_destroy (&src->base); -- cgit v1.2.3 From 449e7518bee5d0238138176b3b71d137c6fc01e7 Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Tue, 25 Nov 2008 22:55:24 +0800 Subject: glitz: set correct parameters for linear and radial pattern. Glitz expects 16.16 fixed point, but we use 24.8 fixed point by default. --- src/cairo-glitz-surface.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index b08fc52e..146bcb09 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -779,22 +779,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; } -- cgit v1.2.3 From e828f7330633cd839f094bf8409de0bcff17c95c Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Wed, 26 Nov 2008 00:09:11 +0800 Subject: glitz: Apply fixup to unbounded operators to clear area outside of mask --- src/cairo-glitz-surface.c | 79 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 146bcb09..3916f8f1 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -1024,11 +1024,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 { @@ -1043,14 +1038,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; } @@ -1286,7 +1317,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, _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 finish; } if (mask->base.status) { _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); @@ -1322,7 +1354,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, &attributes); if (src_pattern == &tmp_src_pattern.base) _cairo_pattern_fini (&tmp_src_pattern.base); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto finish; } data = p; @@ -1441,6 +1474,25 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, free (data); + 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_mask (op)) + { + int src_width, src_height; + + src_width = glitz_surface_get_width (src->surface); + src_height = glitz_surface_get_height (src->surface); + status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, + &attributes.base, + src_width, src_height, + width, height, + src_x, src_y, + 0, 0, + dst_x, dst_y, + width, height); + } + _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); if (src_pattern == &tmp_src_pattern.base) _cairo_pattern_fini (&tmp_src_pattern.base); @@ -1448,9 +1500,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, if (mask) cairo_surface_destroy (&mask->base); - if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) - status = CAIRO_INT_STATUS_UNSUPPORTED; - finish: if (pixman_traps != stack_traps) free (pixman_traps); @@ -2146,6 +2195,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; -- cgit v1.2.3 From 8fa3cd95641e9138406d651b0734ee84f1da60d2 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 26 Nov 2008 06:40:47 +1030 Subject: Change uint to uint32_t --- src/cairo-image-info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c index f84bcaf0..8fc77055 100644 --- a/src/cairo-image-info.c +++ b/src/cairo-image-info.c @@ -179,7 +179,7 @@ _jpx_get_box_contents (const unsigned char *p) static cairo_bool_t _jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type) { - uint length; + uint32_t length; if (p + 8 < end) { length = _get_be32 (p); -- cgit v1.2.3 From 039437c9cfaeed7a2cc1977623ab8bda9854b58a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 10:31:09 +0000 Subject: [png] Use FILE* instead of void*. Adrian Johnson reported that cygwin complained about the use of the void * within feof() as it was using a macro and attempted a to deference the void*... --- src/cairo-png.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cairo-png.c b/src/cairo-png.c index e8f61b5d..5bb658cb 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -462,14 +462,16 @@ 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, closure); + ret = fread (data, 1, size, file); size -= ret; data += ret; - if (size && (feof (closure) || ferror (closure))) + if (size && (feof (file) || ferror (file))) return _cairo_error (CAIRO_STATUS_READ_ERROR); } -- cgit v1.2.3 From 4218699642c621eb3098a5251ef88d8c7d8a96d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 11:54:29 +0000 Subject: [skiplist] Use ffs() Use ffs() [find-first-set-bit] instead of open-coding, which is about 25% faster on my test machine. --- src/cairo-skiplist.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/cairo-skiplist.c b/src/cairo-skiplist.c index b08453b0..5f46ec0f 100644 --- a/src/cairo-skiplist.c +++ b/src/cairo-skiplist.c @@ -91,20 +91,11 @@ _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 */ uint32_t bits = hars_petruska_f54_1_random (); - bits |= bits >> 16; - - while (++level < MAX_LEVEL) - { - if (bits & 1) - break; - bits >>= 1; - } - return level; + return ffs (-(1<> 16); } static void * -- cgit v1.2.3 From 8a5b55ca6c69671a138f65ab15bcf93163f24a37 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 13:26:40 +0000 Subject: [matrix] Impose a maximum number of refinement iterations Ensure we do not loop forever trying to minimise the error between the pixman and cairo matrices - for instance when the FPU is not running at full precision. --- src/cairo-matrix.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index 05589833..6dfe537f 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -879,6 +879,7 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, *pixman_transform = pixman_identity_transform; } else { cairo_matrix_t inv; + 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); @@ -913,6 +914,7 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, /* 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; @@ -942,6 +944,6 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, if (dx == 0 && dy == 0) break; - } while (TRUE); + } while (--max_iterations); } } -- cgit v1.2.3 From 993941cfd701eb222b81cdddeabf6f7ff2daa150 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 26 Nov 2008 13:32:11 +0000 Subject: [perf] Fix SDL compilation for MacOS X The attached patch makes the SDL tests compile under Mac OS X. The problem is: 1) that should be included in files that define the main function for SDL Mac OS X programs (this is not true with the upcoming SDL 1.3 release). 2) that -lSDLmain, because it is statically linked, needs the Cocoa framework in the LDADD of the main program. Again, 1.3 will not require this. --- perf/Makefile.am | 4 ++++ perf/cairo-perf.c | 4 ++++ test/Makefile.am | 4 ++++ test/cairo-test-runner.c | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/perf/Makefile.am b/perf/Makefile.am index 737e96a4..18eed9f2 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -55,6 +55,10 @@ cairo_perf_SOURCES += cairo-perf-posix.c endif endif +if CAIRO_HAS_SDL_SURFACE +cairo_perf_LDADD = $(LDADD) $(sdl_LIBS) +endif + libcairoperf_la_SOURCES = \ cairo-perf-report.c \ cairo-stats.c \ diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c index d5f69201..c96e6c23 100644 --- a/perf/cairo-perf.c +++ b/perf/cairo-perf.c @@ -33,6 +33,10 @@ #include "cairo-boilerplate-getopt.h" +#if CAIRO_HAS_SDL_SURFACE +#include +#endif + /* For basename */ #ifdef HAVE_LIBGEN_H #include diff --git a/test/Makefile.am b/test/Makefile.am index 3afac519..9c664b1e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -294,6 +294,10 @@ if HAVE_PTHREAD cairo_test_suite_LDADD += -lpthread endif +if CAIRO_HAS_SDL_SURFACE +cairo_test_suite_LDADD += $(sdl_LIBS) +endif + BUILT_SOURCES += cairo-test-constructors.c noinst_SCRIPTS = make-cairo-test-constructors.pl EXTRA_DIST += $(BUILT_SOURCES) $(noinst_SCRIPTS) COPYING diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c index 4fb0cbea..aec90ff7 100644 --- a/test/cairo-test-runner.c +++ b/test/cairo-test-runner.c @@ -33,6 +33,10 @@ #undef CAIRO_VERSION_MICRO #include "../cairo-version.h" +#if CAIRO_HAS_SDL_SURFACE +#include +#endif + #include /* for version information */ #if HAVE_FORK && HAVE_WAITPID -- cgit v1.2.3 From a84ea7829065b7e1d33d6fed6bcf0c7c8abd383a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 26 Nov 2008 15:49:00 +0100 Subject: [test] Add quartz-surface-source test Add a simple test to exercise using a Quartz surface as a source. --- test/Makefile.am | 6 ++++- test/quartz-surface-source.c | 42 +++++++++++++++++++++++++++++++++ test/quartz-surface-source.ps2.ref.png | Bin 0 -> 376 bytes test/quartz-surface-source.ps3.ref.png | Bin 0 -> 376 bytes test/quartz-surface-source.ref.png | Bin 0 -> 332 bytes 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 test/quartz-surface-source.c create mode 100644 test/quartz-surface-source.ps2.ref.png create mode 100644 test/quartz-surface-source.ps3.ref.png create mode 100644 test/quartz-surface-source.ref.png diff --git a/test/Makefile.am b/test/Makefile.am index 9c664b1e..95341985 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -212,7 +212,11 @@ test_sources += ft-text-vertical-layout-type3.c test_sources += ft-text-antialias-none.c endif -# Need to add win32-surface-source, quartz-surface-source +# Need to add quartz-surface-source +if CAIRO_HAS_QUARTZ_SURFACE +test_sources += quartz-surface-source.c +endif + if CAIRO_HAS_GLITZ_SURFACE test_sources += glitz-surface-source.c endif diff --git a/test/quartz-surface-source.c b/test/quartz-surface-source.c new file mode 100644 index 00000000..b0c86d0f --- /dev/null +++ b/test/quartz-surface-source.c @@ -0,0 +1,42 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" +#include "cairo-quartz.h" + +#include "surface-source.c" + +static cairo_surface_t * +create_source_surface (int size) +{ + return cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, size, size); +} + +CAIRO_TEST (quartz_surface_source, + "Test using a Quartz surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/test/quartz-surface-source.ps2.ref.png b/test/quartz-surface-source.ps2.ref.png new file mode 100644 index 00000000..10231581 Binary files /dev/null and b/test/quartz-surface-source.ps2.ref.png differ diff --git a/test/quartz-surface-source.ps3.ref.png b/test/quartz-surface-source.ps3.ref.png new file mode 100644 index 00000000..10231581 Binary files /dev/null and b/test/quartz-surface-source.ps3.ref.png differ diff --git a/test/quartz-surface-source.ref.png b/test/quartz-surface-source.ref.png new file mode 100644 index 00000000..9fbbedd5 Binary files /dev/null and b/test/quartz-surface-source.ref.png differ -- cgit v1.2.3 From 47275c7ece06c0d02f2d7c9aa81d87a7144392b0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 26 Nov 2008 15:56:48 +0100 Subject: [test] Fix glitz-surface-source test The recent changes to separate glitz/agl broke the compilation of the glitz-surface-source test. --- test/glitz-surface-source.c | 96 +++++++++++++++++++++++++++++++++- test/glitz-surface-source.ps2.ref.png | Bin 0 -> 376 bytes test/glitz-surface-source.ps3.ref.png | Bin 0 -> 376 bytes 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 test/glitz-surface-source.ps2.ref.png create mode 100644 test/glitz-surface-source.ps3.ref.png diff --git a/test/glitz-surface-source.c b/test/glitz-surface-source.c index 2dfa7355..89094e48 100644 --- a/test/glitz-surface-source.c +++ b/test/glitz-surface-source.c @@ -25,8 +25,6 @@ #include "cairo-test.h" #include -#include -#include #define NAME "glitz" #include "surface-source.c" @@ -34,6 +32,8 @@ static cairo_user_data_key_t closure_key; #if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE +#include +#include #include struct closure { @@ -198,4 +198,96 @@ create_source_surface (int size) return surface; } + +#elif CAIRO_CAN_TEST_GLITZ_AGL_SURFACE +#include + +static void +cleanup (void *data) +{ + glitz_agl_fini (); +} + +static glitz_surface_t * +_glitz_agl_create_surface (glitz_format_name_t formatname, + int width, + int height) +{ + glitz_drawable_format_t * dformat = NULL; + glitz_drawable_t * drawable = NULL; + glitz_format_t * format; + glitz_format_t templ; + glitz_surface_t * sr; + int i; + int alpha_size; + + glitz_agl_init (); + + /* Find a reasonably lame window format and use it to create a pbuffer. */ + i = 0; + alpha_size = (formatname == GLITZ_STANDARD_ARGB32) ? 8 : 0; + while ((dformat = glitz_agl_find_window_format (0, 0, i)) != NULL + && !(dformat->doublebuffer == 0 + && dformat->stencil_size == 0 + && dformat->depth_size == 0 + && dformat->color.fourcc == GLITZ_FOURCC_RGB + && dformat->color.alpha_size == alpha_size)) + i++; + + if (!dformat) + goto FAIL; + + /* Try for a pbuffer first */ + drawable = glitz_agl_create_pbuffer_drawable (dformat, width, height); + if (!drawable) + goto FAIL; + + templ.color = dformat->color; + format = glitz_find_format (drawable, + GLITZ_FORMAT_FOURCC_MASK | + GLITZ_FORMAT_RED_SIZE_MASK | + GLITZ_FORMAT_GREEN_SIZE_MASK | + GLITZ_FORMAT_BLUE_SIZE_MASK | + GLITZ_FORMAT_ALPHA_SIZE_MASK, + &templ, + 0); + if (!format) { + fprintf (stderr, "Error: couldn't find surface format\n"); + return NULL; + } + + sr = glitz_surface_create (drawable, format, width, height, 0, NULL); + if (!sr) + goto DESTROY_DRAWABLE; + + glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); + glitz_drawable_destroy (drawable); + + return sr; + DESTROY_DRAWABLE: + glitz_drawable_destroy (drawable); + FAIL: + return NULL; +} + +static cairo_surface_t * +create_source_surface (int size) +{ + glitz_surface_t *glitz_surface; + cairo_surface_t *surface; + + glitz_surface = _glitz_agl_create_surface (GLITZ_STANDARD_ARGB32, + size, size); + + surface = cairo_glitz_surface_create (glitz_surface); + cairo_surface_set_user_data (surface, &closure_key, NULL, cleanup); + return surface; +} #endif + +CAIRO_TEST (glitz_surface_source, + "Test using a Glitz surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/test/glitz-surface-source.ps2.ref.png b/test/glitz-surface-source.ps2.ref.png new file mode 100644 index 00000000..10231581 Binary files /dev/null and b/test/glitz-surface-source.ps2.ref.png differ diff --git a/test/glitz-surface-source.ps3.ref.png b/test/glitz-surface-source.ps3.ref.png new file mode 100644 index 00000000..10231581 Binary files /dev/null and b/test/glitz-surface-source.ps3.ref.png differ -- cgit v1.2.3 From 60282b866aab359840b4bcaa6aaccaca2eccd3d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 16:58:29 +0000 Subject: [glitz] Fix clone_similar(). Clone similar open-coded various image surface functions and failed to clone a sub-region resulting in failures for mask-transformed-* and large-source. --- src/cairo-glitz-surface.c | 458 ++++++++++++++-------------------------------- 1 file changed, 137 insertions(+), 321 deletions(-) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 3916f8f1..d4eb0681 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -33,7 +33,8 @@ typedef struct _cairo_glitz_surface { glitz_surface_t *surface; glitz_format_t *format; - cairo_bool_t has_clip; + + cairo_bool_t has_clip; glitz_box_t *clip_boxes; int num_clip_boxes; } cairo_glitz_surface_t; @@ -46,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); + if (surface->clip_boxes) free (surface->clip_boxes); - } glitz_surface_destroy (surface->surface); @@ -108,7 +107,9 @@ _cairo_glitz_surface_create_similar (void *abstract_src, } 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) { pixman_box32_t *pboxes; cairo_status_t status = CAIRO_STATUS_SUCCESS; @@ -118,15 +119,16 @@ _cairo_glitz_get_boxes_from_region (cairo_region_t *region, glitz_box_t **boxes, n = 0; pboxes = pixman_region32_rectangles (®ion->rgn, &n); if (n == 0) { - *nboxes = 0; - *boxes = NULL; - 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++) { @@ -141,8 +143,6 @@ done: return status; } -#define STRIDE_ALIGNMENT (sizeof (uint32_t)) - static cairo_status_t _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, cairo_rectangle_int_t *interest, @@ -150,95 +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_status_t status; - pixman_format_code_t pixman_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 < (unsigned int)x2) - x2 = interest->x + interest->width; - if (interest->y + interest->height < (unsigned int)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 = ((masks.bpp * width + 7) / 8 + STRIDE_ALIGNMENT - 1) & ~(STRIDE_ALIGNMENT - 1); + 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); } @@ -248,83 +215,24 @@ _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); glitz_buffer_destroy (buffer); /* restore the clip, if any */ - if (surface->has_clip) - glitz_surface_set_clip_region (surface->surface, 0, 0, + if (surface->has_clip) { + glitz_surface_set_clip_region (surface->surface, + 0, 0, surface->clip_boxes, surface->num_clip_boxes); - - if (! _pixman_format_from_masks (&masks, &pixman_format)) - { - status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT); - goto FAIL; } - image = (cairo_image_surface_t*) - _cairo_image_surface_create_with_pixman_format ((unsigned char *) pixels, - pixman_format, - width, - height, - pf.bytes_per_line); - if (image->base.status) - { - status = image->base.status; - goto FAIL; - } - - _cairo_image_surface_assume_ownership_of_data (image); - *image_out = image; return CAIRO_STATUS_SUCCESS; - - FAIL: - free (pixels); - return status; -} - -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 @@ -340,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, @@ -473,46 +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; - - if (_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); - if (status) { - cairo_surface_destroy (&clone->base); - return status; - } + status = _cairo_glitz_surface_set_image (clone, image_src, + src_x, src_y, + width, height, + 0, 0); + if (status) { + cairo_surface_destroy (&clone->base); + return status; } *clone_out = &clone->base; - *clone_offset_x = 0; - *clone_offset_y = 0; - + *clone_offset_x = src_x; + *clone_offset_y = src_y; return CAIRO_STATUS_SUCCESS; } @@ -1206,8 +1092,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; @@ -1216,10 +1100,22 @@ _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; + 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 (op == CAIRO_OPERATOR_SATURATE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (_glitz_ensure_target (dst->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + /* Convert traps to pixman traps */ if (n_traps > ARRAY_LENGTH (stack_traps)) { pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t)); @@ -1240,59 +1136,16 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y); } - if (antialias != CAIRO_ANTIALIAS_DEFAULT && - antialias != CAIRO_ANTIALIAS_GRAY) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto finish; - } - - if (dst->base.status) - { - status = dst->base.status; - goto finish; - } - - if (op == CAIRO_OPERATOR_SATURATE) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto finish; - } - - if (_glitz_ensure_target (dst->surface)) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto finish; - } - - if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) - { - status = _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern); - if (status) - goto finish; + status = _cairo_glitz_pattern_acquire_surface (pattern, dst, + src_x, src_y, + width, height, + &src, &attributes); + if (status) + goto FAIL; - 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; - } - else - { - status = _cairo_glitz_pattern_acquire_surface (pattern, dst, - src_x, src_y, - width, height, - &src, &attributes); - src_pattern = pattern; - } alpha = 0xffff; - if (status) - goto finish; - - if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) - { + 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; @@ -1314,19 +1167,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); - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto finish; + 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); - status = mask->base.status; - goto finish; + goto FAIL; } color.red = color.green = color.blue = color.alpha = 0xffff; @@ -1341,21 +1187,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); + if (p == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto finish; + goto FAIL; } data = p; @@ -1363,14 +1203,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, glitz_buffer_destroy (buffer); buffer = glitz_buffer_create_for_data (data); - if (!buffer) { - 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 (buffer == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto finish; + free (data); + goto FAIL; } } @@ -1392,22 +1228,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); + if (data == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto finish; + goto FAIL; } /* using negative stride */ @@ -1418,12 +1248,10 @@ _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); - status = image->base.status; - goto finish; + goto FAIL; } pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y, @@ -1433,21 +1261,20 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, _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); - status = mask->base.status; - goto finish; + 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) - goto finish; + goto FAIL; } _cairo_glitz_surface_set_attributes (src, &attributes); @@ -1474,18 +1301,16 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, free (data); - if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) { status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } - if (status == CAIRO_STATUS_SUCCESS && ! _cairo_operator_bounded_by_mask (op)) - { - int src_width, src_height; - - src_width = glitz_surface_get_width (src->surface); - src_height = glitz_surface_get_height (src->surface); + if (! _cairo_operator_bounded_by_mask (op)) { status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, &attributes.base, - src_width, src_height, + glitz_surface_get_width (src->surface), + glitz_surface_get_height (src->surface), width, height, src_x, src_y, 0, 0, @@ -1493,14 +1318,12 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, width, height); } - _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); - if (src_pattern == &tmp_src_pattern.base) - _cairo_pattern_fini (&tmp_src_pattern.base); +FAIL: + _cairo_glitz_pattern_release_surface (pattern, src, &attributes); - if (mask) + if (mask != NULL) cairo_surface_destroy (&mask->base); -finish: if (pixman_traps != stack_traps) free (pixman_traps); @@ -1513,33 +1336,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; - status = _cairo_glitz_get_boxes_from_region (region, &box, &n); + status = _cairo_glitz_get_boxes_from_region (region, + &surface->clip_boxes, + &surface->num_clip_boxes); if (status) - return status; - - if (surface->has_clip) - free (surface->clip_boxes); - - glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); + return status; + glitz_surface_set_clip_region (surface->surface, + 0, 0, + surface->clip_boxes, + surface->num_clip_boxes); surface->has_clip = TRUE; - surface->clip_boxes = box; - surface->num_clip_boxes = n; - } - else - { + } else { glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - - if (surface->has_clip) { - free (surface->clip_boxes); - surface->has_clip = FALSE; - } + surface->has_clip = FALSE; } return CAIRO_STATUS_SUCCESS; @@ -1553,7 +1366,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; @@ -2535,14 +2348,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); -- cgit v1.2.3 From 5e376523628d5e2078e395ea7263a04bacd37c47 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 17:26:57 +0000 Subject: [skiplist] Check for ffs() Wine at least does not provide ffs(), so check at configure time and open-code a replacement. --- build/configure.ac.system | 2 +- src/cairo-skiplist.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/build/configure.ac.system b/build/configure.ac.system index d06b7989..4544a54f 100644 --- a/build/configure.ac.system +++ b/build/configure.ac.system @@ -69,7 +69,7 @@ AC_CHECK_HEADER(fenv.h, dnl check for misc headers and functions AC_CHECK_HEADERS([libgen.h byteswap.h signal.h setjmp.h]) -AC_CHECK_FUNCS([vasnprintf link ctime_r drand48 flockfile]) +AC_CHECK_FUNCS([vasnprintf link ctime_r drand48 flockfile ffs]) dnl check for win32 headers (this detects mingw as well) AC_CHECK_HEADERS([windows.h], have_windows=yes, have_windows=no) diff --git a/src/cairo-skiplist.c b/src/cairo-skiplist.c index 5f46ec0f..02e15565 100644 --- a/src/cairo-skiplist.c +++ b/src/cairo-skiplist.c @@ -95,7 +95,18 @@ random_level (void) * This works because we only use the lower MAX_LEVEL * bits, and MAX_LEVEL < 16 */ uint32_t bits = hars_petruska_f54_1_random (); +#if HAVE_FFS return ffs (-(1<> 16); +#else + int level = 1; + + bits |= -(1<> 16; + while ((bits & 1) == 0) { + level++; + bits >>= 1; + } + return level; +#endif } static void * -- cgit v1.2.3 From 815e5b962ef8477c344da0f0b52c1f85c9854777 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 17:30:29 +0000 Subject: [script] Add a fallback image surface for replay If we do not have a native windowing surface compiled into the library, just replay the script to an image surface. --- util/cairo-script/csi-replay.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/util/cairo-script/csi-replay.c b/util/cairo-script/csi-replay.c index 5ca035f2..e5a847e4 100644 --- a/util/cairo-script/csi-replay.c +++ b/util/cairo-script/csi-replay.c @@ -68,6 +68,14 @@ _surface_create (void *closure, return surface; } +#else +/* fallback: just use an image surface */ +static cairo_surface_t * +_surface_create (void *closure, + double width, double height) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); +} #endif int -- cgit v1.2.3 From 9432c0c9b89ed6b3d369b377cf884918cd6180db Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 17:33:35 +0000 Subject: [script] Link the interpreter against the built library. Ensure we correctly link against the version of cairo just built. --- util/cairo-script/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am index 4d228128..465adf44 100644 --- a/util/cairo-script/Makefile.am +++ b/util/cairo-script/Makefile.am @@ -17,10 +17,10 @@ libcairo_script_interpreter_la_SOURCES = \ $(NULL) libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS) libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols) -libcairo_script_interpreter_la_LIBADD = -lz $(CAIRO_LIBS) -L$(top_builddir)/src -lcairo +libcairo_script_interpreter_la_LIBADD = -lz $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) csi_replay_SOURCES = csi-replay.c -csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la +csi_replay_LDADD = libcairo-script-interpreter.la EXTRA_DIST = \ COPYING -- cgit v1.2.3 From 5591cb58fd94483ec3dc7c169ae8cf0a6b7841bd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 17:43:22 +0000 Subject: [script] Only use zlib if available. Conditionally link against zlib - replaying a script will fail if the trace uses a compressed format. --- configure.ac | 5 ++++- util/cairo-script/Makefile.am | 2 +- util/cairo-script/cairo-script-file.c | 5 ++++- util/cairo-script/cairo-script-operators.c | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 7384ccc4..47a3ac60 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,10 @@ AC_CACHE_SAVE dnl =========================================================================== AC_CHECK_LIB(z, compress, - [AC_CHECK_HEADER(zlib.h, [have_libz=yes], + [AC_CHECK_HEADER(zlib.h, [ + have_libz=yes + AC_DEFINE(HAVE_ZLIB, 1, [Define to 1 if you have zlib available]) + ], [have_libz="no (requires zlib http://www.gzip.org/zlib/)"])], [have_libz="no (requires zlib http://www.gzip.org/zlib/)"]) diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am index 465adf44..829b06e3 100644 --- a/util/cairo-script/Makefile.am +++ b/util/cairo-script/Makefile.am @@ -17,7 +17,7 @@ libcairo_script_interpreter_la_SOURCES = \ $(NULL) libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS) libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols) -libcairo_script_interpreter_la_LIBADD = -lz $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) +libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) csi_replay_SOURCES = csi-replay.c csi_replay_LDADD = libcairo-script-interpreter.la diff --git a/util/cairo-script/cairo-script-file.c b/util/cairo-script/cairo-script-file.c index c21ef630..fcdccf14 100644 --- a/util/cairo-script/cairo-script-file.c +++ b/util/cairo-script/cairo-script-file.c @@ -36,7 +36,6 @@ #include #include -#include #define CHUNK_SIZE 32768 @@ -372,6 +371,9 @@ csi_file_new_ascii85_decode (csi_t *ctx, return _csi_file_new_filter (ctx, obj, src, &funcs, data); } +#if HAVE_ZLIB +#include + typedef struct _deflate_decode_data { z_stream zlib_stream; @@ -503,6 +505,7 @@ csi_file_new_deflate_decode (csi_t *ctx, return _csi_file_new_filter (ctx, obj, src, &funcs, data); } +#endif #if 0 static int diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c index a70b55d5..13d6f766 100644 --- a/util/cairo-script/cairo-script-operators.c +++ b/util/cairo-script/cairo-script-operators.c @@ -1317,7 +1317,9 @@ _filter (csi_t *ctx) csi_object_t *); } filters[] = { { "ascii85", csi_file_new_ascii85_decode }, +#if HAVE_ZLIB { "deflate", csi_file_new_deflate_decode }, +#endif #if 0 { "lzw", csi_file_new_lzw_decode }, #endif -- cgit v1.2.3 From 2f0f9a1a593db43dd04507c5989cd0af4b1486de Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Thu, 13 Nov 2008 10:50:41 +0100 Subject: [os2] Fix includes Patch from Dave Yeo to make cairo-os2.h include os2.h directly so the header is standalone. --- src/cairo-os2-private.h | 11 ----------- src/cairo-os2-surface.c | 5 ----- src/cairo-os2.h | 8 ++++++++ 3 files changed, 8 insertions(+), 16 deletions(-) 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 -#else -# include -#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..e4cef052 100644 --- a/src/cairo-os2-surface.c +++ b/src/cairo-os2-surface.c @@ -43,11 +43,6 @@ #include #ifdef BUILD_CAIRO_DLL -# define INCL_WIN -# define INCL_GPI -# define INCL_DOS -# define INCL_DOSERRORS -# include # include "cairo-os2.h" # ifndef __WATCOMC__ # include diff --git a/src/cairo-os2.h b/src/cairo-os2.h index d0a13e47..17f02634 100644 --- a/src/cairo-os2.h +++ b/src/cairo-os2.h @@ -38,6 +38,14 @@ #ifndef _CAIRO_OS2_H_ #define _CAIRO_OS2_H_ +#define INCL_DOS +#define INCL_DOSSEMAPHORES +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_GPI + +#include + #include "cairo.h" CAIRO_BEGIN_DECLS -- cgit v1.2.3 From f5634818f1e5cc0adaa326662c099a75f4e615eb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Nov 2008 14:56:38 +0000 Subject: [os2] Move include cairo.h before os2.h The defines need to come first, but we specify that cairo.h is the first header file to be included by files. --- src/cairo-os2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cairo-os2.h b/src/cairo-os2.h index 17f02634..0d18674b 100644 --- a/src/cairo-os2.h +++ b/src/cairo-os2.h @@ -44,10 +44,10 @@ #define INCL_WIN #define INCL_GPI -#include - #include "cairo.h" +#include + CAIRO_BEGIN_DECLS /* The OS/2 Specific Cairo API */ -- cgit v1.2.3 From 41cb91d417e7c0dc1cc767ea0fb38a1f8b3f4e43 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Wed, 26 Nov 2008 23:49:12 +0200 Subject: [script] Use the in-tree libcairo for csi-replay. csi-replay was missing the in-tree libcairo.la so the build was failing while looking for new symbols from the system libcairo. --- util/cairo-script/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am index 829b06e3..b6ab355e 100644 --- a/util/cairo-script/Makefile.am +++ b/util/cairo-script/Makefile.am @@ -20,7 +20,7 @@ libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_I libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) csi_replay_SOURCES = csi-replay.c -csi_replay_LDADD = libcairo-script-interpreter.la +csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) EXTRA_DIST = \ COPYING -- cgit v1.2.3 From ed6bd4766cb47e97b1a6ecb81eff5bf4673d549b Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Fri, 28 Nov 2008 07:54:41 +0800 Subject: image: Use unsigned long to compute color masks. Use unsigned long in the first place to prevent compiler from expanding signed bit to all upper bits. e.g, a alpha mask 0xff0000 will expand to 0xffffffffff00000 on 64 bit platform which is not what we expected. --- src/cairo-image-surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 234a6f90..b7a4f6cf 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -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, -- cgit v1.2.3 From 36147140ce56d8d3492b971a9b6ceff97e212e01 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 28 Nov 2008 18:54:02 +0000 Subject: [perf] Fix build If automake detects the use of cairo_perf_LDADD in an unused conditional that overrides the default - so we need to manually set cairo_perf_LDADD. --- perf/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/perf/Makefile.am b/perf/Makefile.am index 18eed9f2..ae39dbc1 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -54,9 +54,10 @@ else cairo_perf_SOURCES += cairo-perf-posix.c endif endif +cairo_perf_LDADD = $(LDADD) if CAIRO_HAS_SDL_SURFACE -cairo_perf_LDADD = $(LDADD) $(sdl_LIBS) +cairo_perf_LDADD += $(sdl_LIBS) endif libcairoperf_la_SOURCES = \ -- cgit v1.2.3 From 424aba9be558e89b4d42554ca6a5042574e3df75 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Nov 2008 20:38:24 +0000 Subject: [check] Search for the word NOTE Add word boundary markers around the regexp so that we only match for the word NOTE and not on substrings like GL_NOTEQUAL. --- src/check-doc-syntax.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 '//,/<\/program echo " '$func_regexp'" fi >&2 -note_regexp='NOTE' +note_regexp='\' if echo $FILES | xargs grep "$note_regexp" /dev/null; then stat=1 echo Error: some source files contain the string 'NOTE'. -- cgit v1.2.3 From d2bcf1d76defda861e1a7f2271046851083ad694 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 28 Nov 2008 17:12:03 +0000 Subject: [path] Carefully check for no more points. As the empty path points to an embedded buf, we cannot rely on the buf pointer being NULL to mark end-of-path. --- src/cairo-path-fixed-private.h | 10 +++++----- src/cairo-path-fixed.c | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h index c995e2a9..c7a09855 100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -54,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; @@ -90,8 +90,8 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a, typedef struct _cairo_path_fixed_iter { cairo_path_buf_t *buf; - int n_op; - int n_point; + unsigned int n_op; + unsigned int n_point; } cairo_path_fixed_iter_t; cairo_private void diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index ffaf58c1..eee67dc1 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -759,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++) { @@ -790,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) { @@ -1058,7 +1058,7 @@ _cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, static cairo_bool_t _cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter) { - if (++iter->n_op == iter->buf->num_ops) { + if (++iter->n_op >= iter->buf->num_ops) { iter->buf = iter->buf->next; iter->n_op = 0; iter->n_point = 0; @@ -1079,6 +1079,12 @@ _cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter, 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; @@ -1149,6 +1155,9 @@ _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) { -- cgit v1.2.3 From f2982e103c27cad1edf648dadcfffe1a15763efd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2008 17:23:33 +0000 Subject: [fill] Allow rectangles to be implicitly closed. Also scan for appendages of simple rectangles. --- src/cairo-path-fill.c | 2 +- src/cairo-path-fixed-private.h | 4 ++-- src/cairo-path-fixed.c | 14 +++++++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index a6dea083..d37b3755 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -237,7 +237,7 @@ _cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, * GdkRegion clip region during exposes. */ _cairo_path_fixed_iter_init (&iter, path); - while (_cairo_path_fixed_iter_is_box (&iter, &box)) { + while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { cairo_status_t status; int cw = 0; diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h index c7a09855..0ade9880 100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -99,8 +99,8 @@ _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_box (cairo_path_fixed_iter_t *_iter, - cairo_box_t *box); +_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); diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index eee67dc1..ba467608 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -1068,8 +1068,8 @@ _cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter) } cairo_bool_t -_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter, - cairo_box_t *box) +_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; @@ -1112,12 +1112,16 @@ _cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter, /* Now, there are choices. The rectangle might end with a LINE_TO * (to the original point), but this isn't required. If it - * doesn't, then it must end with a CLOSE_PATH. */ - if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) { + * 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) { + } + 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)) -- cgit v1.2.3 From f39dd86e292e9af3438acb041a3a7330fb4a3b22 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 Nov 2008 00:23:11 +0000 Subject: [test] Add simple cap test. Add a test case that only exercises capping, useful for developing new strokers. --- test/Makefile.am | 3 ++ test/caps.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/caps.ps.ref.png | Bin 0 -> 1466 bytes test/caps.ref.png | Bin 0 -> 1601 bytes 4 files changed, 90 insertions(+) create mode 100644 test/caps.c create mode 100644 test/caps.ps.ref.png create mode 100644 test/caps.ref.png diff --git a/test/Makefile.am b/test/Makefile.am index 95341985..7ab086d0 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -13,6 +13,7 @@ test_sources = \ big-line.c \ big-trap.c \ bilevel-image.c \ + caps.c \ caps-joins.c \ caps-joins-alpha.c \ caps-sub-paths.c \ @@ -326,6 +327,8 @@ REFERENCE_IMAGES = \ bilevel-image.ref.png \ bitmap-font.ref.png \ bitmap-font.rgb24.ref.png \ + caps.ref.png \ + caps.ps.ref.png \ caps-joins-alpha.quartz.ref.png \ caps-joins-alpha.ref.png \ caps-joins-alpha.svg12.ref.png \ diff --git a/test/caps.c b/test/caps.c new file mode 100644 index 00000000..7f561179 --- /dev/null +++ b/test/caps.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + int i; + + cairo_save (cr); + for (i = 0; i <= 3; i++) { + cairo_new_sub_path (cr); + cairo_move_to (cr, -SIZE / 2, 0.); + cairo_line_to (cr, SIZE / 2, 0.); + cairo_rotate (cr, M_PI / 4.); + } + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + cairo_translate (cr, PAD + SIZE / 2., PAD + SIZE / 2.); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + make_path (cr); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (caps, + "Test caps", + "stroke caps", /* keywords */ + NULL, /* requirements */ + PAD + SIZE + PAD, + 3 * (PAD + SIZE) + PAD, + NULL, draw) + diff --git a/test/caps.ps.ref.png b/test/caps.ps.ref.png new file mode 100644 index 00000000..b1f4a72a Binary files /dev/null and b/test/caps.ps.ref.png differ diff --git a/test/caps.ref.png b/test/caps.ref.png new file mode 100644 index 00000000..a46e0366 Binary files /dev/null and b/test/caps.ref.png differ -- cgit v1.2.3 From f0804d4856496a46d0b2270d5815856bf63b4cf8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 28 Nov 2008 23:58:55 +0000 Subject: [test] Exercise caps and joins under reflection. The nature of the joins depends critically upon whether the joint is clockwise or counter-clockwise, so extend the basic caps-joins test to exercise both conditions i.e. repeat the test under a reflection. --- test/Makefile.am | 6 ++- test/caps-joins-curve.c | 111 +++++++++++++++++++++++++++++++++++++++ test/caps-joins-curve.ps.ref.png | Bin 0 -> 3728 bytes test/caps-joins-curve.ref.png | Bin 0 -> 5132 bytes test/caps-joins.c | 40 +++++++++----- test/caps-joins.ps.ref.png | Bin 0 -> 2282 bytes test/caps-joins.ps2.ref.png | Bin 1459 -> 0 bytes test/caps-joins.ps3.ref.png | Bin 1459 -> 0 bytes test/caps-joins.ref.png | Bin 1488 -> 2380 bytes test/dash-curve.ref.png | Bin 39642 -> 39696 bytes 10 files changed, 143 insertions(+), 14 deletions(-) create mode 100644 test/caps-joins-curve.c create mode 100644 test/caps-joins-curve.ps.ref.png create mode 100644 test/caps-joins-curve.ref.png create mode 100644 test/caps-joins.ps.ref.png delete mode 100644 test/caps-joins.ps2.ref.png delete mode 100644 test/caps-joins.ps3.ref.png diff --git a/test/Makefile.am b/test/Makefile.am index 7ab086d0..de9f9c47 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -16,6 +16,7 @@ test_sources = \ caps.c \ caps-joins.c \ caps-joins-alpha.c \ + caps-joins-curve.c \ caps-sub-paths.c \ clip-all.c \ clip-empty.c \ @@ -333,9 +334,10 @@ REFERENCE_IMAGES = \ caps-joins-alpha.ref.png \ caps-joins-alpha.svg12.ref.png \ caps-joins-alpha.svg11.ref.png \ + caps-joins-curve.ref.png \ + caps-joins-curve.ps.ref.png \ caps-joins.ref.png \ - caps-joins.ps2.ref.png \ - caps-joins.ps3.ref.png \ + caps-joins.ps.ref.png \ caps-sub-paths.ref.png \ clip-all.ref.png \ clip-empty.ref.png \ diff --git a/test/caps-joins-curve.c b/test/caps-joins-curve.c new file mode 100644 index 00000000..1b2fc7f0 --- /dev/null +++ b/test/caps-joins-curve.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (3 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0, 0); + cairo_rel_curve_to (cr, + -SIZE/4, SIZE/3, + -SIZE/4, SIZE/3, + 0, SIZE); + cairo_rel_curve_to (cr, + SIZE/3, -SIZE/4, + SIZE/3, -SIZE/4, + SIZE, 0); + cairo_close_path (cr); + + cairo_move_to (cr, 5 * LINE_WIDTH, 3 * LINE_WIDTH); + cairo_rel_curve_to (cr, + 0, -3 * LINE_WIDTH, + 0, -3 * LINE_WIDTH, + -3 * LINE_WIDTH, -3 * LINE_WIDTH); +} + +static void +draw_caps_joins (cairo_t *cr) +{ + cairo_save (cr); + + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + + draw_caps_joins (cr); + + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + draw_caps_joins (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (caps_joins_curve, + "Test caps and joins on curves", + "stroke cap join", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 2 * (PAD + SIZE) + PAD, + NULL, draw) + diff --git a/test/caps-joins-curve.ps.ref.png b/test/caps-joins-curve.ps.ref.png new file mode 100644 index 00000000..1f7e2000 Binary files /dev/null and b/test/caps-joins-curve.ps.ref.png differ diff --git a/test/caps-joins-curve.ref.png b/test/caps-joins-curve.ref.png new file mode 100644 index 00000000..9f763013 Binary files /dev/null and b/test/caps-joins-curve.ref.png differ diff --git a/test/caps-joins.c b/test/caps-joins.c index 5ec6a817..9d1c2a88 100644 --- a/test/caps-joins.c +++ b/test/caps-joins.c @@ -37,21 +37,15 @@ make_path (cairo_t *cr) cairo_rel_line_to (cr, SIZE, 0.); cairo_close_path (cr); - cairo_move_to (cr, 2 * LINE_WIDTH, 0.); - cairo_rel_line_to (cr, 3 * LINE_WIDTH, 0.); - cairo_rel_line_to (cr, 0., 3 * LINE_WIDTH); + cairo_move_to (cr, 5 * LINE_WIDTH, 3 * LINE_WIDTH); + cairo_rel_line_to (cr, 0., -3 * LINE_WIDTH); + cairo_rel_line_to (cr, -3 * LINE_WIDTH, 0.); } -static cairo_test_status_t -draw (cairo_t *cr, int width, int height) +static void +draw_caps_joins (cairo_t *cr) { - /* We draw in the default black, so paint white first. */ cairo_save (cr); - cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ - cairo_paint (cr); - cairo_restore (cr); - - cairo_set_line_width (cr, LINE_WIDTH); cairo_translate (cr, PAD, PAD); @@ -74,6 +68,28 @@ draw (cairo_t *cr, int width, int height) cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); cairo_stroke (cr); + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + + draw_caps_joins (cr); + + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + draw_caps_joins (cr); + return CAIRO_TEST_SUCCESS; } @@ -82,6 +98,6 @@ CAIRO_TEST (caps_joins, "stroke", /* keywords */ NULL, /* requirements */ 3 * (PAD + SIZE) + PAD, - PAD + SIZE + PAD, + 2 * (PAD + SIZE) + PAD, NULL, draw) diff --git a/test/caps-joins.ps.ref.png b/test/caps-joins.ps.ref.png new file mode 100644 index 00000000..e61aafce Binary files /dev/null and b/test/caps-joins.ps.ref.png differ diff --git a/test/caps-joins.ps2.ref.png b/test/caps-joins.ps2.ref.png deleted file mode 100644 index 1d473ac7..00000000 Binary files a/test/caps-joins.ps2.ref.png and /dev/null differ diff --git a/test/caps-joins.ps3.ref.png b/test/caps-joins.ps3.ref.png deleted file mode 100644 index 1d473ac7..00000000 Binary files a/test/caps-joins.ps3.ref.png and /dev/null differ diff --git a/test/caps-joins.ref.png b/test/caps-joins.ref.png index 9297ac4d..d83f9561 100644 Binary files a/test/caps-joins.ref.png and b/test/caps-joins.ref.png differ diff --git a/test/dash-curve.ref.png b/test/dash-curve.ref.png index 542b2d82..a590fc43 100644 Binary files a/test/dash-curve.ref.png and b/test/dash-curve.ref.png differ -- cgit v1.2.3 From d1801c23fae3777c7c59e084894a3410f7a1f932 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Nov 2008 15:38:37 +0000 Subject: Mark if(status) as being unlikely. The error paths should be hit very rarely during normal operation, so mark them as being unlikely so gcc may emit better code. --- src/cairo-analysis-surface.c | 24 +-- src/cairo-array.c | 6 +- src/cairo-cache.c | 4 +- src/cairo-cff-subset.c | 208 ++++++++++++------------- src/cairo-clip.c | 23 ++- src/cairo-font-face.c | 14 +- src/cairo-ft-font.c | 44 +++--- src/cairo-gstate.c | 66 ++++---- src/cairo-image-surface.c | 16 +- src/cairo-lzw.c | 4 +- src/cairo-meta-surface.c | 42 ++--- src/cairo-misc.c | 6 +- src/cairo-output-stream.c | 2 +- src/cairo-paginated-surface.c | 38 ++--- src/cairo-path-fill.c | 6 +- src/cairo-path-fixed.c | 14 +- src/cairo-path-stroke.c | 56 +++---- src/cairo-path.c | 6 +- src/cairo-pattern.c | 34 ++-- src/cairo-pdf-operators.c | 60 ++++---- src/cairo-pdf-surface.c | 334 ++++++++++++++++++++-------------------- src/cairo-pen.c | 6 +- src/cairo-png.c | 14 +- src/cairo-ps-surface.c | 122 +++++++-------- src/cairo-scaled-font-subsets.c | 30 ++-- src/cairo-scaled-font.c | 72 ++++----- src/cairo-script-surface.c | 160 +++++++++---------- src/cairo-sdl-surface.c | 4 +- src/cairo-surface-fallback.c | 82 +++++----- src/cairo-surface.c | 60 ++++---- src/cairo-svg-surface.c | 84 +++++----- src/cairo-traps.c | 12 +- src/cairo-truetype-subset.c | 98 ++++++------ src/cairo-type1-fallback.c | 44 +++--- src/cairo-type1-subset.c | 46 +++--- src/cairo-type3-glyph-surface.c | 10 +- src/cairo-user-font.c | 18 +-- src/cairo-xlib-screen.c | 4 +- src/cairo-xlib-surface.c | 92 +++++------ src/cairo.c | 138 ++++++++--------- 40 files changed, 1053 insertions(+), 1050 deletions(-) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 3109deed..9fb19a87 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -337,7 +337,7 @@ _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); @@ -407,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); @@ -417,7 +417,7 @@ _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); @@ -469,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); @@ -489,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; } @@ -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; } @@ -622,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); @@ -635,7 +635,7 @@ _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); @@ -708,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); @@ -721,7 +721,7 @@ _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); @@ -780,7 +780,7 @@ _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)); diff --git a/src/cairo-array.c b/src/cairo-array.c index f38cfe3e..ef50684f 100644 --- a/src/cairo-array.c +++ b/src/cairo-array.c @@ -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-cache.c b/src/cairo-cache.c index f5caba4b..73172642 100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c @@ -131,7 +131,7 @@ _cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal, } status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size); - if (status) { + if (unlikely (status)) { free (cache); return NULL; } @@ -293,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; diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index 45be5d1c..2d1fd8fd 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; @@ -405,7 +405,7 @@ cff_index_append_copy (cairo_array_t *index, memcpy (element.data, object, element.length); status = _cairo_array_append (index, &element); - if (status) { + if (unlikely (status)) { free (element.data); return status; } @@ -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); @@ -577,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; } @@ -724,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); @@ -732,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; } @@ -793,7 +793,7 @@ 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); @@ -818,12 +818,12 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) 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); @@ -834,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]); @@ -843,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 @@ -851,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; } @@ -878,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) @@ -895,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); @@ -903,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); @@ -920,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; } @@ -928,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); @@ -991,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; } @@ -1012,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; @@ -1060,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; @@ -1092,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; } @@ -1112,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; } @@ -1196,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; @@ -1209,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 { @@ -1235,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; @@ -1298,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: @@ -1326,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; @@ -1381,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 { @@ -1395,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; @@ -1431,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; @@ -1470,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); } @@ -1509,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]; @@ -1548,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; } @@ -1569,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; } @@ -1579,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 { @@ -1587,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; } @@ -1625,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; } @@ -1640,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); @@ -1674,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); @@ -1687,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 @@ -1696,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)); @@ -1727,33 +1727,33 @@ _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); @@ -1763,7 +1763,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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)); @@ -1777,7 +1777,7 @@ _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); @@ -1840,7 +1840,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, } status = cairo_cff_font_create_set_widths (font); - if (status) + if (unlikely (status)) goto fail5; font->data_length = data_length; @@ -1852,17 +1852,17 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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); @@ -1971,11 +1971,11 @@ _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); @@ -2047,7 +2047,7 @@ _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); @@ -2080,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); @@ -2147,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 */ @@ -2188,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); @@ -2215,15 +2215,15 @@ _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); diff --git a/src/cairo-clip.c b/src/cairo-clip.c index ce2a2409..5c197fff 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -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; @@ -174,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; } @@ -191,7 +191,7 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, _cairo_region_fini (&intersection); - if (status) + if (unlikely (status)) return status; } @@ -228,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; } @@ -241,7 +241,7 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip, _cairo_region_fini (&clip_rect); - if (status) + if (unlikely (status)) return status; } @@ -302,7 +302,7 @@ _cairo_clip_intersect_path (cairo_clip_t *clip, 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; } @@ -362,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; @@ -492,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; } @@ -517,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; } @@ -581,7 +580,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); @@ -664,7 +663,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; @@ -679,7 +678,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; diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c index eb4921e3..06377588 100644 --- a/src/cairo-font-face.c +++ b/src/cairo-font-face.c @@ -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: @@ -523,11 +525,11 @@ cairo_toy_font_face_create (const char *family, } 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 (); @@ -614,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 4245448e..a8d41013 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -438,12 +438,12 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, } 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 +621,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 +671,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; @@ -1084,7 +1084,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 +1125,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 +1212,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 +1227,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 +1245,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, _cairo_pattern_fini (&pattern.base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (image); return status; } @@ -1527,7 +1527,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 +1535,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 +1626,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 +1686,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 +1863,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 +1918,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 +2066,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 +2117,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, @@ -2665,7 +2667,7 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) 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; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 9f7892a4..d7d91c90 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); @@ -227,7 +227,7 @@ _cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist) *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; @@ -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); @@ -827,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; @@ -839,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; @@ -884,12 +884,12 @@ _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, @@ -917,17 +917,17 @@ _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, @@ -958,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, @@ -1015,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); @@ -1037,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, @@ -1219,7 +1219,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); @@ -1239,7 +1239,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; @@ -1358,7 +1358,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; @@ -1373,7 +1373,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; @@ -1489,7 +1489,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); @@ -1501,7 +1501,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; @@ -1514,7 +1514,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); @@ -1537,7 +1537,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, @@ -1574,7 +1574,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, @@ -1604,11 +1604,11 @@ _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)) { @@ -1629,7 +1629,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 */ @@ -1698,7 +1698,7 @@ _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)) @@ -1712,7 +1712,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *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-image-surface.c b/src/cairo-image-surface.c index b7a4f6cf..ab8ab5ed 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -870,7 +870,7 @@ _cairo_image_surface_set_attributes (cairo_image_surface_t *surface, status = _cairo_image_surface_set_matrix (surface, &attributes->matrix, xc, yc); - if (status) + if (unlikely (status)) return status; switch (attributes->extend) { @@ -889,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; @@ -968,13 +968,13 @@ _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, dst_x + width / 2., dst_y + height / 2.); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACES; if (mask) @@ -982,7 +982,7 @@ _cairo_image_surface_composite (cairo_operator_t op, status = _cairo_image_surface_set_attributes (mask, &mask_attr, dst_x + width / 2., dst_y + height / 2.); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACES; pixman_image_composite (_pixman_operator (op), @@ -1156,13 +1156,13 @@ _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, dst_x + width / 2., dst_y + height / 2.); - if (status) + if (unlikely (status)) goto CLEANUP_SOURCE; switch (antialias) { @@ -1353,7 +1353,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..c1791765 100644 --- a/src/cairo-lzw.c +++ b/src/cairo-lzw.c @@ -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-meta-surface.c b/src/cairo-meta-surface.c index cfaaf304..f32f4893 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -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; } @@ -239,11 +239,11 @@ _cairo_meta_surface_paint (void *abstract_surface, 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 @@ -285,15 +285,15 @@ _cairo_meta_surface_mask (void *abstract_surface, 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; @@ -336,15 +336,15 @@ _cairo_meta_surface_stroke (void *abstract_surface, 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; @@ -353,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; @@ -396,11 +396,11 @@ _cairo_meta_surface_fill (void *abstract_surface, 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; @@ -408,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; @@ -459,7 +459,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, command->op = op; status = _cairo_pattern_init_snapshot (&command->source.base, source); - if (status) + if (unlikely (status)) goto CLEANUP_COMMAND; command->utf8 = NULL; @@ -499,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; @@ -575,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; } @@ -590,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); @@ -766,7 +766,7 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, ASSERT_NOT_REACHED; } - if (status) + if (unlikely (status)) break; } @@ -814,14 +814,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; @@ -986,7 +986,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 397b0efe..c4876031 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 ; @@ -730,7 +730,7 @@ _cairo_intern_string (const char **str_inout, int len) status = _cairo_hash_table_insert (_cairo_intern_string_ht, &istring->hash_entry); - if (status) + if (unlikely (status)) free (istring); } else status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -738,7 +738,7 @@ _cairo_intern_string (const char **str_inout, int len) CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); - if (status == CAIRO_STATUS_SUCCESS) + if (likely (status == CAIRO_STATUS_SUCCESS)) *str_inout = istring->string; return status; diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c index 9a58aac2..780bd50c 100644 --- a/src/cairo-output-stream.c +++ b/src/cairo-output-stream.c @@ -696,7 +696,7 @@ _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, cairo_status_t status; status = abstract_stream->status; - if (status) + if (unlikely (status)) return _cairo_output_stream_destroy (abstract_stream); stream = (memory_stream_t *) abstract_stream; diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index bb542ff0..70b728ea 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -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); @@ -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,19 +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; } @@ -439,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++; @@ -466,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); @@ -488,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++; diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index d37b3755..7af91d20 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -177,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: diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index ba467608..04d547ca 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -372,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; } @@ -426,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; @@ -467,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]; @@ -519,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; @@ -692,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) { diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index 3c02a94c..f2b9e7ae 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; @@ -658,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; } @@ -761,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; @@ -806,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 */ @@ -890,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) { @@ -898,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; @@ -909,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; @@ -927,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; @@ -955,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; @@ -986,7 +986,7 @@ _cairo_stroker_curve_to (void *closure, a, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) return _cairo_stroker_line_to (closure, d); - else if (status) + else if (unlikely (status)) return status; initial_slope_dx = _cairo_fixed_to_double (spline_pen.spline.initial_slope.dx); @@ -1014,7 +1014,7 @@ _cairo_stroker_curve_to (void *closure, 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) { stroker->first_face = start; @@ -1037,7 +1037,7 @@ _cairo_stroker_curve_to (void *closure, extra_points[3].y -= end.point.y; status = _cairo_pen_add_points (&spline_pen.pen, extra_points, 4); - if (status) + if (unlikely (status)) goto CLEANUP_PEN; status = _cairo_pen_stroke_spline (&spline_pen, @@ -1121,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; } @@ -1175,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) @@ -1194,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 */ @@ -1386,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; } @@ -1403,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; @@ -1449,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; @@ -1512,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); @@ -1520,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..855b85fe 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 */ @@ -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 bdcafe7c..56fa28a5 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -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 @@ -276,7 +276,7 @@ _cairo_pattern_create_copy (cairo_pattern_t **pattern, return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_pattern_init_copy (*pattern, other); - if (status) { + if (unlikely (status)) { free (*pattern); return status; } @@ -872,7 +872,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; } @@ -1063,7 +1063,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); @@ -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, 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) { @@ -2184,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) { @@ -2196,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: @@ -2237,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 diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c index d363805f..9d5bcba1 100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -447,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; @@ -488,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; } @@ -714,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; } @@ -753,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); @@ -762,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) { @@ -778,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); @@ -815,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; } @@ -823,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) { @@ -964,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 */ @@ -1023,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; @@ -1112,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; @@ -1143,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"); @@ -1177,7 +1177,7 @@ _cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators, _cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText 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; @@ -1241,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; @@ -1296,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; @@ -1313,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; @@ -1329,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)) @@ -1344,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); @@ -1374,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 @@ -1401,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; @@ -1412,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; } @@ -1432,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; @@ -1448,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.c b/src/cairo-pdf-surface.c index 97902505..9926e6ff 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -207,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; } @@ -551,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; } @@ -562,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); } @@ -639,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; @@ -702,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); @@ -898,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); @@ -936,7 +936,7 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, *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; } @@ -1022,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) { @@ -1151,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; @@ -1169,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) { @@ -1237,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; @@ -1256,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); @@ -1414,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; @@ -1515,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; @@ -1601,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) @@ -1645,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 @@ -1727,7 +1727,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); - if (status) + if (unlikely (status)) return status; if (info.num_components != 1 && info.num_components != 3) @@ -1747,7 +1747,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, info.height, info.num_components == 1 ? "/DeviceGray" : "/DeviceRGB", info.bits_per_component); - if (status) + if (unlikely (status)) return status; *res = surface->pdf_stream.self; @@ -1789,7 +1789,7 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, return status; status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); - if (status) + if (unlikely (status)) goto BAIL; pad_image = &image->base; @@ -1826,13 +1826,13 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, rect.width, rect.height); _cairo_pattern_fini (&pad_pattern.base); - if (status) + if (unlikely (status)) goto BAIL; } status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image, resource, pattern->base.filter); - if (status) + if (unlikely (status)) goto BAIL; *width = ((cairo_image_surface_t *)pad_image)->width; @@ -1862,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; @@ -1879,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, @@ -1898,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); @@ -1940,11 +1940,11 @@ _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; @@ -1957,12 +1957,12 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, &pattern_height, &origin_x, &origin_y); - if (status) + 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; @@ -2074,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)) { @@ -2112,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); @@ -2244,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; } } @@ -2380,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) { @@ -2388,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 { @@ -2399,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) { @@ -2408,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; } } @@ -2510,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, @@ -2525,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); @@ -2648,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 || @@ -2658,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) { @@ -2667,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; } } @@ -2747,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; } @@ -2779,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; @@ -2870,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; } @@ -2953,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, @@ -2977,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, @@ -2993,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 @@ -3035,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"); @@ -3053,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); @@ -3096,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"); @@ -3183,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; } @@ -3225,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, @@ -3277,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, @@ -3317,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, @@ -3432,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); @@ -3453,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); @@ -3490,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, @@ -3584,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); @@ -3605,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); @@ -3634,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, @@ -3642,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; } @@ -3651,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; } @@ -3822,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; } @@ -3880,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; @@ -3889,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) { @@ -3913,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; @@ -4072,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, @@ -4159,14 +4159,14 @@ _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, NULL, &pattern_res, &gstate_res); - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { @@ -4178,17 +4178,17 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, 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, @@ -4197,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, @@ -4205,24 +4205,24 @@ _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, NULL, &pattern_res, &gstate_res); - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { @@ -4234,17 +4234,17 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, 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, @@ -4253,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, @@ -4261,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 */ @@ -4319,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) { @@ -4359,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); @@ -4398,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; } } @@ -4423,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); @@ -4433,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; } @@ -4490,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; @@ -4512,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) @@ -4697,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); @@ -4723,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; } @@ -4735,7 +4735,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, &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) { @@ -4745,27 +4745,27 @@ _cairo_pdf_surface_paint (void *abstract_surface, 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, @@ -4774,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, @@ -4782,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; } @@ -4815,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; } @@ -4828,12 +4828,12 @@ _cairo_pdf_surface_mask (void *abstract_surface, 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; } @@ -4844,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, @@ -4897,7 +4897,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, &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) { @@ -4907,13 +4907,13 @@ _cairo_pdf_surface_stroke (void *abstract_surface, 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; } @@ -4922,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, @@ -4945,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, @@ -4953,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; } @@ -4983,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; } @@ -4995,7 +4995,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, &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) { @@ -5005,34 +5005,34 @@ _cairo_pdf_surface_fill (void *abstract_surface, 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, @@ -5041,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; } @@ -5104,7 +5104,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, extents, &fill_pattern_res, &gstate_res); - if (status) + if (unlikely (status)) return status; assert (gstate_res.id == 0); @@ -5116,7 +5116,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, extents, &stroke_pattern_res, &gstate_res); - if (status) + if (unlikely (status)) return status; assert (gstate_res.id == 0); @@ -5125,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, @@ -5139,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); @@ -5185,7 +5185,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, &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) { @@ -5195,7 +5195,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, 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; } @@ -5233,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, @@ -5256,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 @@ -5265,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; } @@ -5275,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; } diff --git a/src/cairo-pen.c b/src/cairo-pen.c index 43d344a1..21ed8e35 100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c @@ -162,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); @@ -491,7 +491,7 @@ _cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *stroker, 1); status = _cairo_polygon_status (&stroker->polygon); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_bentley_ottmann_tessellate_polygon (traps, @@ -548,7 +548,7 @@ _cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker, } status = _cairo_pen_init_copy (&stroker->pen, pen); - if (status) { + if (unlikely (status)) { _cairo_spline_fini (&stroker->spline); return status; } diff --git a/src/cairo-png.c b/src/cairo-png.c index 5bb658cb..69df0f3e 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -159,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" */ @@ -361,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; @@ -486,7 +486,7 @@ stream_read_func (png_structp png, png_bytep data, png_size_t size) png_closure = png_get_io_ptr (png); status = png_closure->read_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; @@ -544,7 +544,7 @@ read_png (struct png_read_closure_t *png_closure) 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; } @@ -637,7 +637,7 @@ read_png (struct png_read_closure_t *png_closure) 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; } @@ -654,7 +654,7 @@ read_png (struct png_read_closure_t *png_closure) status = _cairo_memory_stream_destroy (png_closure->png_data, &mime_data, &mime_data_length); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (surface); surface = _cairo_surface_create_in_error (status); goto BAIL; @@ -666,7 +666,7 @@ read_png (struct png_read_closure_t *png_closure) mime_data_length, free, mime_data); - if (status) { + if (unlikely (status)) { free (mime_data); cairo_surface_destroy (surface); surface = _cairo_surface_create_in_error (status); diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 0c9ef7f4..43219e5b 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -262,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 */ @@ -293,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 */ @@ -322,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 */ @@ -463,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; } @@ -527,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, @@ -549,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, @@ -635,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, @@ -730,7 +730,7 @@ _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 (); @@ -935,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; } @@ -1010,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; } @@ -1035,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; } @@ -1069,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; } @@ -1082,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); } @@ -1183,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; } @@ -1207,7 +1207,7 @@ cairo_ps_surface_dsc_comment (cairo_surface_t *surface, } 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; @@ -1237,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; } @@ -1272,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; } @@ -1304,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); @@ -1362,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, @@ -1378,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"); @@ -1407,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) @@ -1809,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, @@ -1821,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); @@ -1851,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); } @@ -1918,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; @@ -2004,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, @@ -2138,7 +2138,7 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); - if (status) + if (unlikely (status)) return status; if (info.num_components != 1 && info.num_components != 3) @@ -2154,7 +2154,7 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface, mime_data, mime_data_length, TRUE); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, @@ -2219,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; @@ -2251,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, @@ -2267,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, @@ -2337,7 +2337,7 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *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; @@ -2346,7 +2346,7 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, status = _cairo_surface_acquire_source_image (pattern->surface, &surface->acquired_image, &surface->image_extra); - if (status) + if (unlikely (status)) return status; pad_image = &surface->acquired_image->base; @@ -2383,7 +2383,7 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, rect.width, rect.height); _cairo_pattern_fini (&pad_pattern.base); - if (status) + if (unlikely (status)) goto BAIL; } @@ -2458,7 +2458,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, extents, &width, &height, &origin_x, &origin_y); - if (status) + if (unlikely (status)) return status; cairo_p2d = pattern->base.matrix; @@ -2540,7 +2540,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, extents, &pattern_width, &pattern_height, &origin_x, &origin_y); - if (status) + if (unlikely (status)) return status; switch (pattern->base.extend) { @@ -2602,7 +2602,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, } status = _cairo_ps_surface_emit_surface (surface, pattern, op, pattern_width, pattern_height); - if (status) + if (unlikely (status)) return status; surface->use_string_datasource = old_use_string_datasource; @@ -2649,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; @@ -2955,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 || @@ -2964,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; } @@ -3042,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, @@ -3092,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); @@ -3106,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) { @@ -3120,21 +3120,21 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *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; } @@ -3163,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"); @@ -3230,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 && @@ -3248,7 +3248,7 @@ _cairo_ps_surface_paint (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, paint_extents, op); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (stream, "Q\n"); @@ -3257,7 +3257,7 @@ _cairo_ps_surface_paint (void *abstract_surface, 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", @@ -3332,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"); @@ -3340,13 +3340,13 @@ _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, extents, op); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, "Q\n"); @@ -3356,7 +3356,7 @@ _cairo_ps_surface_fill (void *abstract_surface, 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, @@ -3397,7 +3397,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, 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, diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index d8771bba..a1b4c22c 100644 --- a/src/cairo-scaled-font-subsets.c +++ b/src/cairo-scaled-font-subsets.c @@ -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; } @@ -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; } @@ -495,13 +495,13 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, 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; } @@ -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; } @@ -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; } @@ -1003,11 +1003,11 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset } 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; } @@ -1020,7 +1020,7 @@ _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 */ } @@ -1043,11 +1043,11 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset } 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; } diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 8b749940..76572a54 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -425,7 +425,7 @@ _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)); @@ -439,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); @@ -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. @@ -697,7 +697,7 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font, 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; /* @@ -782,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. @@ -791,7 +791,7 @@ 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; @@ -889,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); @@ -905,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. */ @@ -1221,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; } @@ -1304,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; } @@ -1521,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 */ @@ -1584,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); @@ -1682,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; } @@ -1693,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); @@ -1752,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 */ @@ -1771,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) { @@ -1853,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; @@ -1912,7 +1912,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; } @@ -1940,7 +1940,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; } @@ -2027,29 +2027,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; @@ -2089,7 +2089,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; } @@ -2104,7 +2104,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; } } @@ -2129,7 +2129,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; @@ -2153,7 +2153,7 @@ _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 (); @@ -2163,7 +2163,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, } status = _trace_mask_to_path (scaled_glyph->surface, glyph_path); - if (status) { + if (unlikely (status)) { _cairo_path_fixed_destroy (glyph_path); goto BAIL; } @@ -2182,7 +2182,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: @@ -2377,7 +2377,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; } @@ -2385,7 +2385,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; } @@ -2410,7 +2410,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 @@ -2438,7 +2438,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 index 9118d66d..fc3164d7 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -335,7 +335,7 @@ _emit_context (cairo_script_surface_t *surface) status = _bitmap_next_id (&surface->ctx->surface_id, &surface->id); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->ctx->stream, @@ -586,25 +586,25 @@ _emit_stroke_style (cairo_script_surface_t *surface, assert (_cairo_script_surface_owns_context (surface)); status = _emit_line_width (surface, style->line_width, force); - if (status) + if (unlikely (status)) return status; status = _emit_line_cap (surface, style->line_cap); - if (status) + if (unlikely (status)) return status; status = _emit_line_join (surface, style->line_join); - if (status) + if (unlikely (status)) return status; status = _emit_miter_limit (surface, style->miter_limit, force); - if (status) + if (unlikely (status)) return status; status = _emit_dash (surface, style->dash, style->num_dashes, style->dash_offset, force); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -750,13 +750,13 @@ _emit_meta_surface_pattern (cairo_script_surface_t *surface, cairo_surface_destroy (null_surface); status = analysis_surface->status; - if (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 (status) + if (unlikely (status)) return status; similar = cairo_surface_create_similar (&surface->base, @@ -767,13 +767,13 @@ _emit_meta_surface_pattern (cairo_script_surface_t *surface, return similar->status; status = _cairo_meta_surface_replay (source, similar); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (similar); return status; } status = _emit_context (surface); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (similar); return status; } @@ -936,7 +936,7 @@ _emit_png_surface (cairo_script_surface_t *surface, 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 (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, @@ -979,7 +979,7 @@ _emit_image_surface (cairo_script_surface_t *surface, status2 = _cairo_output_stream_destroy (base85_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, @@ -1006,7 +1006,7 @@ _emit_image_surface (cairo_script_surface_t *surface, 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 (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, @@ -1034,7 +1034,7 @@ _emit_image_surface_pattern (cairo_script_surface_t *surface, /* XXX snapshot-cow */ status = _cairo_surface_acquire_source_image (source, &image, &image_extra); - if (status) + if (unlikely (status)) return status; status = _emit_image_surface (surface, image); @@ -1089,7 +1089,7 @@ _emit_pattern (cairo_script_surface_t *surface, ASSERT_NOT_REACHED; status = CAIRO_INT_STATUS_UNSUPPORTED; } - if (status) + if (unlikely (status)) return status; if (! _cairo_matrix_is_identity (&pattern->matrix)) { @@ -1151,15 +1151,15 @@ _emit_source (cairo_script_surface_t *surface, cairo_pattern_destroy (surface->cr.current_source); status = _cairo_pattern_create_copy (&surface->cr.current_source, source); - if (status) + if (unlikely (status)) return status; status = _emit_identity (surface, &matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_pattern (surface, source); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, @@ -1242,7 +1242,7 @@ _emit_path (cairo_script_surface_t *surface, double y2 = _cairo_fixed_to_double (box.p2.y); status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->ctx->stream, @@ -1252,7 +1252,7 @@ _emit_path (cairo_script_surface_t *surface, cairo_status_t status; status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path); - if (status) + if (unlikely (status)) return status; status = _cairo_path_fixed_interpret (path, @@ -1262,7 +1262,7 @@ _emit_path (cairo_script_surface_t *surface, _path_curve_to, _path_close, surface->ctx->stream); - if (status) + if (unlikely (status)) return status; } @@ -1356,7 +1356,7 @@ _cairo_script_surface_create_similar (void *abstract_surface, status = _bitmap_next_id (&ctx->surface_id, &other->id); - if (status) + if (unlikely (status)) return _cairo_surface_create_in_error (status); _cairo_output_stream_printf (ctx->stream, @@ -1378,7 +1378,7 @@ _cairo_script_surface_create_similar (void *abstract_surface, status = _bitmap_next_id (&ctx->surface_id, &surface->id); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (&surface->base); return _cairo_surface_create_in_error (status); } @@ -1455,7 +1455,7 @@ _cairo_script_surface_copy_page (void *abstract_surface) cairo_status_t status; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "copy_page\n"); @@ -1470,7 +1470,7 @@ _cairo_script_surface_show_page (void *abstract_surface) cairo_status_t status; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "show_page\n"); @@ -1490,7 +1490,7 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface, cairo_status_t status; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; if (path == NULL) { @@ -1499,23 +1499,23 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface, } status = _emit_identity (surface, &matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_fill_rule (surface, fill_rule); - if (status) + if (unlikely (status)) return status; status = _emit_tolerance (surface, tolerance, matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_antialias (surface, antialias); - if (status) + if (unlikely (status)) return status; status = _emit_path (surface, path); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "clip+\n"); @@ -1533,15 +1533,15 @@ _cairo_script_surface_paint (void *abstract_surface, cairo_status_t status; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; status = _emit_operator (surface, op); - if (status) + if (unlikely (status)) return status; status = _emit_source (surface, op, source); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, @@ -1561,19 +1561,19 @@ _cairo_script_surface_mask (void *abstract_surface, cairo_status_t status; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; status = _emit_operator (surface, op); - if (status) + if (unlikely (status)) return status; status = _emit_source (surface, op, source); - if (status) + if (unlikely (status)) return status; status = _emit_pattern (surface, mask); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, @@ -1599,39 +1599,39 @@ _cairo_script_surface_stroke (void *abstract_surface, cairo_status_t status; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; status = _emit_identity (surface, &matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_path (surface, path); - if (status) + if (unlikely (status)) return status; status = _emit_source (surface, op, source); - if (status) + if (unlikely (status)) return status; status = _emit_matrix (surface, ctm, &matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_operator (surface, op); - if (status) + if (unlikely (status)) return status; status = _emit_stroke_style (surface, style, matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_tolerance (surface, tolerance, matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_antialias (surface, antialias); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n"); @@ -1654,35 +1654,35 @@ _cairo_script_surface_fill (void *abstract_surface, cairo_status_t status; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; status = _emit_operator (surface, op); - if (status) + if (unlikely (status)) return status; status = _emit_identity (surface, &matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_source (surface, op, source); - if (status) + if (unlikely (status)) return status; status = _emit_fill_rule (surface, fill_rule); - if (status) + if (unlikely (status)) return status; status = _emit_tolerance (surface, tolerance, matrix_updated); - if (status) + if (unlikely (status)) return status; status = _emit_antialias (surface, antialias); - if (status) + if (unlikely (status)) return status; status = _emit_path (surface, path); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "fill+\n"); @@ -1828,7 +1828,7 @@ _emit_type42_font (cairo_script_surface_t *surface, size = 0; status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size); - if (status) + if (unlikely (status)) return status; buf = malloc (size); @@ -1836,7 +1836,7 @@ _emit_type42_font (cairo_script_surface_t *surface, return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL); - if (status) { + if (unlikely (status)) { free (buf); return status; } @@ -1898,7 +1898,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, status = _bitmap_next_id (&surface->ctx->font_id, &font_private->id); - if (status) { + if (unlikely (status)) { free (font_private); return status; } @@ -1907,7 +1907,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, scaled_font->surface_backend = &_cairo_script_surface_backend; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; status = _emit_type42_font (surface, scaled_font); @@ -1943,7 +1943,7 @@ _emit_scaled_font (cairo_script_surface_t *surface, cairo_scaled_font_get_ctm (scaled_font, &matrix); status = _emit_matrix (surface, &matrix, &matrix_updated); - if (status) + if (unlikely (status)) return status; if (! matrix_updated && surface->cr.current_scaled_font == scaled_font) @@ -1951,12 +1951,12 @@ _emit_scaled_font (cairo_script_surface_t *surface, cairo_scaled_font_get_font_matrix (scaled_font, &matrix); status = _emit_font_matrix (surface, &matrix); - if (status) + if (unlikely (status)) return status; cairo_scaled_font_get_font_options (scaled_font, &options); status = _emit_font_options (surface, &options); - if (status) + if (unlikely (status)) return status; surface->cr.current_scaled_font = scaled_font; @@ -1967,11 +1967,11 @@ _emit_scaled_font (cairo_script_surface_t *surface, font_private = scaled_font->surface_private; if (font_private == NULL) { status = _emit_scaled_font_init (surface, scaled_font); - if (status) + if (unlikely (status)) return status; } else { status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->ctx->stream, @@ -2059,7 +2059,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, scaled_glyph->fs_metrics.y_bearing); status = _emit_image_surface (surface, scaled_glyph->surface); - if (status) + if (unlikely (status)) return status; if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) { @@ -2121,7 +2121,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, glyphs[n].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status) + if (unlikely (status)) break; if (scaled_glyph->surface_private != NULL) @@ -2137,7 +2137,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, if (status == CAIRO_STATUS_SUCCESS) { if (! have_glyph_prologue) { status = _emit_scaled_glyph_prologue (surface, scaled_font); - if (status) + if (unlikely (status)) break; have_glyph_prologue = TRUE; @@ -2146,7 +2146,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, status = _emit_scaled_glyph_vector (surface, scaled_font, scaled_glyph); - if (status) + if (unlikely (status)) break; continue; @@ -2162,7 +2162,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, if (status == CAIRO_STATUS_SUCCESS) { if (! have_glyph_prologue) { status = _emit_scaled_glyph_prologue (surface, scaled_font); - if (status) + if (unlikely (status)) break; have_glyph_prologue = TRUE; @@ -2171,7 +2171,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, status = _emit_scaled_glyph_bitmap (surface, scaled_font, scaled_glyph); - if (status) + if (unlikely (status)) break; continue; @@ -2210,23 +2210,23 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, cairo_output_stream_t *base85_stream = NULL; status = _emit_context (surface); - if (status) + if (unlikely (status)) return status; status = _emit_operator (surface, op); - if (status) + if (unlikely (status)) return status; status = _emit_source (surface, op, source); - if (status) + if (unlikely (status)) return status; status = _emit_scaled_font (surface, scaled_font); - if (status) + if (unlikely (status)) return status; status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); - if (status) + if (unlikely (status)) return status; /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */ @@ -2264,7 +2264,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, glyphs[n].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status) { + if (unlikely (status)) { _cairo_scaled_font_thaw_cache (scaled_font); return status; } @@ -2284,7 +2284,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, glyphs[n].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status) + if (unlikely (status)) break; if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) { @@ -2295,7 +2295,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, iy -= scaled_font->font_matrix.y0; if (base85_stream != NULL) { status = _cairo_output_stream_destroy (base85_stream); - if (status) { + if (unlikely (status)) { base85_stream = NULL; break; } @@ -2345,7 +2345,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } else { _cairo_output_stream_puts (surface->ctx->stream, " ]"); } - if (status) + if (unlikely (status)) return status; if (utf8 != NULL && clusters != NULL) { @@ -2378,7 +2378,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, _cairo_output_stream_write (base85_stream, c, 2); } status = _cairo_output_stream_destroy (base85_stream); - if (status) + if (unlikely (status)) return status; } diff --git a/src/cairo-sdl-surface.c b/src/cairo-sdl-surface.c index 18f13eaf..800ad83a 100644 --- a/src/cairo-sdl-surface.c +++ b/src/cairo-sdl-surface.c @@ -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 = @@ -324,7 +324,7 @@ _cairo_sdl_surface_flush (void *abstract_surface) 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; diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index 2dcaa58e..bb80538f 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) { @@ -681,14 +681,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 +696,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 +752,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 +766,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 +774,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 +804,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 +818,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 +834,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 +865,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,7 +880,7 @@ _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) @@ -895,7 +895,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 +992,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 +1002,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 +1010,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; @@ -1045,7 +1045,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) 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, @@ -1073,7 +1073,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); } @@ -1083,7 +1083,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) for (mime_type = mime_types; *mime_type; mime_type++) { status = _cairo_surface_copy_mime_data (snapshot, surface, *mime_type); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (snapshot); return _cairo_surface_create_in_error (status); } @@ -1112,7 +1112,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; @@ -1173,7 +1173,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; @@ -1229,7 +1229,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 4c10f958..a6c97f23 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -322,7 +322,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, _cairo_pattern_fini (&solid_pattern.base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } @@ -455,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); } @@ -523,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); } @@ -608,7 +608,7 @@ cairo_surface_get_mime_data (cairo_surface_t *surface, return; status = _cairo_intern_string (&mime_type, -1); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -672,7 +672,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, return surface->status; status = _cairo_intern_string (&mime_type, -1); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); if (data != NULL) { @@ -693,7 +693,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, (cairo_user_data_key_t *) mime_type, mime_data, _cairo_mime_data_destroy); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); return CAIRO_STATUS_SUCCESS; @@ -715,7 +715,7 @@ _cairo_surface_copy_mime_data (cairo_surface_t *dst, return _cairo_surface_set_error (dst, src->status); status = _cairo_intern_string (&mime_type, -1); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (dst, status); mime_data = _cairo_user_data_array_get_data (&src->user_data, @@ -729,7 +729,7 @@ _cairo_surface_copy_mime_data (cairo_surface_t *dst, (cairo_user_data_key_t *) mime_type, mime_data, _cairo_mime_data_destroy); - if (status) { + if (unlikely (status)) { _cairo_mime_data_destroy (mime_data); return _cairo_surface_set_error (dst, status); } @@ -839,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); } } @@ -917,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); } } @@ -1355,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 @@ -1562,7 +1562,7 @@ _cairo_surface_fill_region (cairo_surface_t *surface, 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)) { @@ -1661,7 +1661,7 @@ _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) { @@ -1698,13 +1698,13 @@ _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) { @@ -1757,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); @@ -1792,13 +1792,13 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, status = _cairo_surface_fill (surface, fill_op, fill_source, path, fill_rule, fill_tolerance, fill_antialias, NULL); - if (status) + 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, NULL); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); return CAIRO_STATUS_SUCCESS; @@ -1831,7 +1831,7 @@ _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) { @@ -1880,7 +1880,7 @@ _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) { @@ -2097,13 +2097,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); } @@ -2181,7 +2181,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, @@ -2220,11 +2220,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; @@ -2458,7 +2458,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) && @@ -2477,7 +2477,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); @@ -2644,7 +2644,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: @@ -2833,7 +2833,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 ab2e4b94..35e256fd 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -285,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; } @@ -366,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)); @@ -378,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; } @@ -421,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); @@ -614,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, "\""); @@ -635,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, "xml_node_glyphs, scaled_glyph->path, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (document->xml_node_glyphs, @@ -668,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; @@ -724,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, "\n"); @@ -746,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); @@ -762,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, @@ -992,7 +992,7 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_image_info_get_jpeg_info (&image_info, mime_data, mime_data_length); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (output, "data:image/jpeg;base64,"); @@ -1002,7 +1002,7 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, info.trailing = 0; status = base64_write_func (&info, mime_data, mime_data_length); - if (status) + if (unlikely (status)) return status; if (info.in_mem > 0) { @@ -1036,7 +1036,7 @@ _cairo_surface_base64_encode_png (cairo_surface_t *surface, info.trailing = 0; status = base64_write_func (&info, mime_data, mime_data_length); - if (status) + if (unlikely (status)) return status; if (info.in_mem > 0) { @@ -1073,7 +1073,7 @@ _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) { @@ -1126,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; @@ -1214,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; @@ -1222,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; @@ -1231,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; @@ -1321,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) { @@ -1407,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, @@ -1634,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, @@ -1812,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) @@ -1927,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); @@ -1979,18 +1979,18 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "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); @@ -2019,13 +2019,13 @@ _cairo_svg_surface_fill (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "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"); @@ -2079,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;\""); @@ -2116,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; } @@ -2204,7 +2204,7 @@ _cairo_svg_surface_mask (void *abstract_surface, mask_id, discard_filter ? "" : " \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; @@ -2217,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; @@ -2252,13 +2252,13 @@ _cairo_svg_surface_stroke (void *abstract_dst, _cairo_output_stream_printf (surface->xml_node, "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); @@ -2301,7 +2301,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "xml_node, FALSE, NULL); - if (status) + if (unlikely (status)) return status; _cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op); @@ -2321,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, @@ -2341,7 +2341,7 @@ 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; } @@ -2379,7 +2379,7 @@ _cairo_svg_surface_intersect_clip_path (void *dst, " 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, @@ -2485,12 +2485,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; diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 4fa3656a..a8717029 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -666,7 +666,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; @@ -705,15 +705,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..b3a48151 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,7 +170,7 @@ _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); @@ -181,7 +181,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, TT_TAG_name, 0, (unsigned char *) name, &size); - if (status) + if (unlikely (status)) goto fail0; font = malloc (sizeof (cairo_truetype_font_t)); @@ -198,7 +198,7 @@ _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)); @@ -277,7 +277,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, _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,7 +575,7 @@ 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) @@ -589,7 +589,7 @@ 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_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,20 +1081,20 @@ _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); @@ -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 */ @@ -1216,7 +1216,7 @@ _cairo_truetype_reverse_cmap (cairo_scaled_font_t *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,7 +1299,7 @@ _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; @@ -1313,7 +1313,7 @@ _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *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 1f39a3f0..d54215de 100644 --- a/src/cairo-type1-fallback.c +++ b/src/cairo-type1-fallback.c @@ -112,7 +112,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 +227,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 +251,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 +277,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 +309,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 +363,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 +385,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 +413,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 +437,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 +449,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); @@ -599,7 +599,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 +651,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 +671,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 +679,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,11 +714,11 @@ _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); @@ -816,7 +816,7 @@ _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)); @@ -831,18 +831,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 e5557585..a62a2613 100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -866,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; @@ -906,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; @@ -983,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; } } @@ -1040,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 @@ -1052,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"); @@ -1060,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); @@ -1076,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 @@ -1100,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); @@ -1158,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. */ @@ -1181,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 = @@ -1239,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); @@ -1249,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); @@ -1306,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++) { @@ -1315,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) { diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c index 6f9eb43e..7106040f 100644 --- a/src/cairo-type3-glyph-surface.c +++ b/src/cairo-type3-glyph-surface.c @@ -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; } @@ -196,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, @@ -282,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); @@ -357,7 +357,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; @@ -419,7 +419,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-user-font.c b/src/cairo-user-font.c index c272966a..5e2077f3 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; @@ -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-xlib-screen.c b/src/cairo-xlib-screen.c index 9dd411ed..1878f8e7 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -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.c b/src/cairo-xlib-surface.c index 136e5546..75d4de3f 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -672,7 +672,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, @@ -717,7 +717,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 */ @@ -778,14 +778,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); @@ -822,7 +822,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; @@ -1014,7 +1014,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; } @@ -1071,7 +1071,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, @@ -1097,7 +1097,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; @@ -1128,7 +1128,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; @@ -1217,7 +1217,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; } @@ -1264,7 +1264,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, @@ -1280,26 +1280,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, NULL); - if (status) + 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); @@ -1426,7 +1426,7 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix, xc, yc); - if (status) + if (unlikely (status)) return status; switch (attributes->extend) { @@ -1443,7 +1443,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; @@ -1728,7 +1728,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 ... */ @@ -1757,7 +1757,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, status = _cairo_xlib_surface_set_attributes (src, &src_attr, dst_x + width / 2., dst_y + height / 2.); - if (status) + if (unlikely (status)) goto BAIL; _cairo_xlib_surface_ensure_dst_picture (dst); @@ -1765,7 +1765,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, status = _cairo_xlib_surface_set_attributes (mask, &mask_attr, dst_x + width / 2., dst_y + height/ 2.); - if (status) + if (unlikely (status)) goto BAIL; XRenderComposite (dst->dpy, @@ -1796,7 +1796,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, @@ -1824,7 +1824,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); @@ -1879,7 +1879,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, @@ -1888,7 +1888,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)) { @@ -2136,7 +2136,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, @@ -2177,7 +2177,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, status = _cairo_xlib_surface_set_attributes (src, &attributes, dst_x + width / 2., dst_y + height / 2.); - if (status) + if (unlikely (status)) goto BAIL; if (!_cairo_operator_bounded_by_mask (op)) { @@ -2300,7 +2300,7 @@ _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; @@ -2309,7 +2309,7 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, 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; @@ -2429,7 +2429,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; @@ -2564,11 +2564,11 @@ _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); } @@ -2903,7 +2903,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; } @@ -2916,7 +2916,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; } @@ -3173,7 +3173,7 @@ _cairo_xlib_surface_font_init (Display *dpy, 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; } @@ -3289,7 +3289,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; @@ -3445,7 +3445,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; @@ -3457,7 +3457,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; } @@ -3484,7 +3484,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); @@ -3498,7 +3498,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, glyph_surface = (cairo_image_surface_t *) tmp_surface; - if (status) + if (unlikely (status)) goto BAIL; } @@ -3514,7 +3514,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; @@ -3529,7 +3529,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, glyph_surface = (cairo_image_surface_t *) tmp_surface; - if (status) + if (unlikely (status)) goto BAIL; } @@ -3864,7 +3864,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 */ @@ -4055,7 +4055,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; @@ -4064,7 +4064,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, @@ -4072,7 +4072,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; } @@ -4084,7 +4084,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, } status = _cairo_xlib_surface_set_attributes (src, &attributes, 0, 0); - if (status) + if (unlikely (status)) goto BAIL1; _cairo_scaled_font_freeze_cache (scaled_font); diff --git a/src/cairo.c b/src/cairo.c index 3dc30014..924f7caa 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -168,7 +168,7 @@ cairo_create (cairo_surface_t *target) cr->gstate_freelist = NULL; status = _cairo_gstate_init (cr->gstate, target); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); return cr; @@ -349,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); @@ -371,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); @@ -458,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), @@ -469,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 @@ -490,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); @@ -628,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); @@ -790,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); @@ -838,7 +838,7 @@ 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); @@ -865,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); } @@ -891,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); } @@ -932,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); @@ -962,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); @@ -992,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); @@ -1042,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); } @@ -1132,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); } @@ -1157,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); } @@ -1181,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); @@ -1207,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); } @@ -1230,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); } @@ -1252,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); @@ -1393,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); @@ -1452,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); @@ -1507,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); @@ -1641,7 +1641,7 @@ cairo_arc_to (cairo_t *cr, x1, y1, x2, y2, radius); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } */ @@ -1677,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); } @@ -1714,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); @@ -1775,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); } @@ -1827,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 @@ -1867,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); @@ -1941,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); @@ -1980,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); @@ -2016,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); @@ -2118,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); @@ -2161,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); @@ -2187,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); } @@ -2210,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); } @@ -2244,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; @@ -2332,7 +2332,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); } @@ -2383,7 +2383,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); } @@ -2448,7 +2448,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); @@ -2478,7 +2478,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); } @@ -2516,7 +2516,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); } @@ -2622,7 +2622,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); } @@ -2650,7 +2650,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); } @@ -2673,7 +2673,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); } @@ -2705,7 +2705,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; } @@ -2737,7 +2737,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); @@ -2765,7 +2765,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); } @@ -2809,7 +2809,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; } @@ -2873,15 +2873,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); @@ -2922,7 +2922,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); } @@ -2988,7 +2988,7 @@ cairo_text_extents (cairo_t *cr, extents); cairo_glyph_free (glyphs); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3043,7 +3043,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); } @@ -3113,7 +3113,7 @@ cairo_show_text (cairo_t *cr, const char *utf8) &glyphs, &num_glyphs, has_show_text_glyphs ? &clusters : NULL, &num_clusters, &cluster_flags); - if (status) + if (unlikely (status)) goto BAIL; if (num_glyphs == 0) @@ -3124,14 +3124,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; @@ -3144,7 +3144,7 @@ cairo_show_text (cairo_t *cr, const char *utf8) if (clusters != stack_clusters) cairo_text_cluster_free (clusters); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3184,7 +3184,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); } @@ -3287,7 +3287,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); } @@ -3339,7 +3339,7 @@ cairo_text_path (cairo_t *cr, const char *utf8) NULL, NULL, NULL); - if (status) + if (unlikely (status)) goto BAIL; if (num_glyphs == 0) @@ -3349,7 +3349,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]; @@ -3357,7 +3357,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; @@ -3367,7 +3367,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); } @@ -3405,7 +3405,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); } @@ -3825,7 +3825,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); } -- cgit v1.2.3 From e6963a5bfebda69a1ef0a986cede84bcd955b6d4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 Nov 2008 17:26:55 +0000 Subject: Mark allocation failures as unlikely. Use the gcc likelihood annotation to indicate that allocation failures are extremely unlikely. --- src/cairo-analysis-surface.c | 4 +-- src/cairo-array.c | 4 +-- src/cairo-base85-stream.c | 2 +- src/cairo-bentley-ottmann.c | 13 ++++---- src/cairo-cache.c | 6 ++-- src/cairo-cff-subset.c | 66 ++++++++++++++++++++--------------------- src/cairo-clip.c | 8 ++--- src/cairo-deflate-stream.c | 2 +- src/cairo-directfb-surface.c | 2 +- src/cairo-font-face.c | 6 ++-- src/cairo-ft-font.c | 25 ++++++++-------- src/cairo-gstate.c | 17 ++++++----- src/cairo-hash.c | 6 ++-- src/cairo-hull.c | 2 +- src/cairo-image-surface.c | 12 ++++---- src/cairo-lzw.c | 4 +-- src/cairo-meta-surface.c | 24 +++++++-------- src/cairo-misc.c | 24 ++++++++++----- src/cairo-output-stream.c | 14 ++++----- src/cairo-paginated-surface.c | 2 +- src/cairo-path-fixed.c | 4 +-- src/cairo-path-stroke.c | 4 +-- src/cairo-path.c | 8 ++--- src/cairo-pattern.c | 36 +++++++++++----------- src/cairo-pdf-operators.c | 6 ++-- src/cairo-pdf-surface.c | 34 ++++++++++----------- src/cairo-pen.c | 8 ++--- src/cairo-png.c | 14 ++++----- src/cairo-polygon.c | 2 +- src/cairo-ps-surface.c | 16 +++++----- src/cairo-region.c | 2 +- src/cairo-scaled-font-subsets.c | 28 ++++++++--------- src/cairo-scaled-font.c | 29 +++++++++--------- src/cairo-script-surface.c | 14 ++++----- src/cairo-sdl-surface.c | 2 +- src/cairo-skiplist.c | 2 +- src/cairo-stroke-style.c | 2 +- src/cairo-surface-fallback.c | 2 +- src/cairo-surface.c | 4 +-- src/cairo-svg-surface.c | 16 +++++----- src/cairo-traps.c | 4 +-- src/cairo-truetype-subset.c | 30 +++++++++---------- src/cairo-type1-fallback.c | 15 +++++----- src/cairo-type1-subset.c | 22 +++++++------- src/cairo-type3-glyph-surface.c | 2 +- src/cairo-user-font.c | 2 +- src/cairo-xlib-display.c | 4 +-- src/cairo-xlib-screen.c | 2 +- src/cairo-xlib-surface.c | 25 ++++++++-------- src/cairo-xlib-visual.c | 2 +- src/cairo.c | 4 +-- src/test-fallback-surface.c | 2 +- src/test-meta-surface.c | 2 +- src/test-paginated-surface.c | 2 +- 54 files changed, 300 insertions(+), 294 deletions(-) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 9fb19a87..a19ff10c 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -784,7 +784,7 @@ _cairo_analysis_surface_create (cairo_surface_t *target, 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 @@ -992,7 +992,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 ef50684f..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); } diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c index 4d5a4652..9d42ef48 100644 --- a/src/cairo-base85-stream.c +++ b/src/cairo-base85-stream.c @@ -117,7 +117,7 @@ _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; } diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c index eca28d5b..cd150218 100644 --- a/src/cairo-bentley-ottmann.c +++ b/src/cairo-bentley-ottmann.c @@ -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]; @@ -1659,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); } diff --git a/src/cairo-cache.c b/src/cairo-cache.c index 73172642..07c8b71f 100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c @@ -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; @@ -125,7 +125,7 @@ _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; } @@ -240,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); diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index 2d1fd8fd..d1e5a6dd 100644 --- a/src/cairo-cff-subset.c +++ b/src/cairo-cff-subset.c @@ -399,7 +399,7 @@ 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); @@ -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); } @@ -568,7 +568,7 @@ cff_dict_set_operands (cairo_hash_table_t *dict, 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); @@ -751,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++; @@ -799,19 +799,19 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) 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; } @@ -1128,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++) @@ -1170,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])) { @@ -1181,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; @@ -1757,7 +1757,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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, @@ -1767,7 +1767,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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,7 +1781,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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; } @@ -1817,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; } @@ -1834,7 +1834,7 @@ _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; } @@ -1845,7 +1845,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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; } @@ -1979,13 +1979,13 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset, 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; } @@ -2000,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; } @@ -2039,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,13 +2051,13 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset 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; } @@ -2070,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; } @@ -2227,13 +2227,13 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, 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 (likely (cff_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -2248,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 (likely (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 5c197fff..35082f94 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -298,7 +298,7 @@ _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 (likely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_path_fixed_init_copy (&clip_path->path, path); @@ -759,7 +759,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; @@ -789,7 +789,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; } @@ -805,7 +805,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-deflate-stream.c b/src/cairo-deflate-stream.c index 3bb884ca..863189f4 100644 --- a/src/cairo-deflate-stream.c +++ b/src/cairo-deflate-stream.c @@ -121,7 +121,7 @@ _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; } diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index 8cbd3bcd..cab7104c 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; diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c index 06377588..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, @@ -495,7 +495,7 @@ 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); @@ -519,7 +519,7 @@ cairo_toy_font_face_create (const char *family, /* 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; } diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index a8d41013..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,7 +417,7 @@ _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); @@ -432,7 +433,7 @@ _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; } @@ -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); @@ -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; } @@ -2532,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; } @@ -2599,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; } @@ -2660,7 +2661,7 @@ 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; } diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index d7d91c90..09161aa4 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -221,7 +221,7 @@ _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; @@ -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); } @@ -1615,7 +1615,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, 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); } @@ -1701,12 +1701,13 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, 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, diff --git a/src/cairo-hash.c b/src/cairo-hash.c index b3f43b05..973281d4 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -148,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; } @@ -159,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; @@ -280,7 +280,7 @@ _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) { 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-surface.c b/src/cairo-image-surface.c index ab8ab5ed..2bf45430 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, @@ -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, @@ -1051,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); } @@ -1110,7 +1110,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); } @@ -1181,14 +1181,14 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, /* The image must be initially transparent */ mask_data = calloc (mask_stride, height); - if (mask_data == NULL) { + if (unlikely (mask_data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_SOURCE; } mask = pixman_image_create_bits (format, width, height, mask_data, mask_stride); - if (mask == NULL) { + if (unlikely (mask == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_IMAGE_DATA; } diff --git a/src/cairo-lzw.c b/src/cairo-lzw.c index c1791765..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); diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c index f32f4893..e69df21c 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, @@ -227,7 +227,7 @@ _cairo_meta_surface_paint (void *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; @@ -273,7 +273,7 @@ _cairo_meta_surface_mask (void *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; @@ -324,7 +324,7 @@ _cairo_meta_surface_stroke (void *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; @@ -384,7 +384,7 @@ _cairo_meta_surface_fill (void *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; @@ -447,7 +447,7 @@ _cairo_meta_surface_show_text_glyphs (void *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; @@ -471,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; } @@ -479,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; } @@ -487,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; } @@ -537,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, @@ -567,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; @@ -930,7 +930,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; } diff --git a/src/cairo-misc.c b/src/cairo-misc.c index c4876031..6f707a66 100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -714,14 +714,19 @@ _cairo_intern_string (const char **str_inout, int len) tmpl.string = (char *) str; CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex); - if (_cairo_intern_string_ht == NULL) + 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 (istring != NULL) { + if (likely (istring != NULL)) { istring->hash_entry.hash = tmpl.hash_entry.hash; istring->len = tmpl.len; istring->string = (char *) (istring + 1); @@ -730,17 +735,20 @@ _cairo_intern_string (const char **str_inout, int len) status = _cairo_hash_table_insert (_cairo_intern_string_ht, &istring->hash_entry); - if (unlikely (status)) + if (unlikely (status)) { free (istring); - } else + goto BAIL; + } + } else { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } } - CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); - - if (likely (status == CAIRO_STATUS_SUCCESS)) - *str_inout = istring->string; + *str_inout = istring->string; + BAIL: + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); return status; } diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c index 780bd50c..71154339 100644 --- a/src/cairo-output-stream.c +++ b/src/cairo-output-stream.c @@ -147,7 +147,7 @@ _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; } @@ -173,7 +173,7 @@ _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; } @@ -598,7 +598,7 @@ _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; } @@ -632,7 +632,7 @@ _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; @@ -676,7 +676,7 @@ _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; } @@ -703,7 +703,7 @@ _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, *length_out = _cairo_array_num_elements (&stream->array); *data_out = malloc (*length_out); - if (*data_out == NULL) { + if (unlikely (*data_out == NULL)) { status = _cairo_output_stream_destroy (abstract_stream); assert (status == CAIRO_STATUS_SUCCESS); return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -753,7 +753,7 @@ _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; } diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index 70b728ea..2b58e499 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; } diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 04d547ca..2f365624 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); } @@ -557,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); diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index f2b9e7ae..8c3064ea 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -1254,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, @@ -1262,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); } diff --git a/src/cairo-path.c b/src/cairo-path.c index 855b85fe..84dfc0c4 100644 --- a/src/cairo-path.c +++ b/src/cairo-path.c @@ -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; diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 56fa28a5..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); @@ -272,7 +272,7 @@ _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); @@ -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; } @@ -846,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; @@ -1255,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); } @@ -1340,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)) diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c index 9d5bcba1..ea5c5148 100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -301,7 +301,7 @@ _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; } @@ -569,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)); @@ -585,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)); } diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 9926e6ff..b85a6c82 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -249,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)); @@ -817,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; } @@ -1461,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; } @@ -1557,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; } @@ -2333,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]; @@ -3857,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); } @@ -4171,7 +4171,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, 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; @@ -4227,7 +4227,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, 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; @@ -4740,7 +4740,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, 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; @@ -4823,7 +4823,7 @@ _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; @@ -4902,7 +4902,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, 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; @@ -5000,7 +5000,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, 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; @@ -5190,7 +5190,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, 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; @@ -5203,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); } @@ -5213,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); } @@ -5223,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); } diff --git a/src/cairo-pen.c b/src/cairo-pen.c index 21ed8e35..4158f175 100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c @@ -65,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; @@ -112,7 +112,7 @@ _cairo_pen_init_copy (cairo_pen_t *pen, const 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); } @@ -139,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, @@ -148,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); } diff --git a/src/cairo-png.c b/src/cairo-png.c index 69df0f3e..301a8921 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -169,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; } @@ -180,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; } @@ -517,13 +517,13 @@ read_png (struct png_read_closure_t *png_closure) &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; } @@ -620,13 +620,13 @@ read_png (struct png_read_closure_t *png_closure) } 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; } diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index 95cadc9c..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; } diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 43219e5b..9d2a7c5c 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -705,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; } @@ -734,7 +734,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, 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; } @@ -1201,7 +1201,7 @@ 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; } @@ -1733,7 +1733,7 @@ _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; } @@ -1760,7 +1760,7 @@ _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; } @@ -1940,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; } @@ -1989,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; } @@ -2749,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]; diff --git a/src/cairo-region.c b/src/cairo-region.c index 146ae60b..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); } diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index a1b4c22c..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); } @@ -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); @@ -489,7 +489,7 @@ _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, @@ -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; } @@ -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; @@ -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); @@ -985,11 +985,11 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset 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; } @@ -997,7 +997,7 @@ _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; } @@ -1037,7 +1037,7 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset 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; } diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 76572a54..ca86f512 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -321,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; @@ -360,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; } @@ -429,7 +429,7 @@ _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t 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... */ @@ -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); @@ -797,7 +797,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, 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, @@ -935,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; @@ -1642,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; } @@ -1652,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; } @@ -1864,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 @@ -2157,7 +2156,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, 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; } @@ -2361,7 +2360,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, * 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; } diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index fc3164d7..77a9e5f5 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -186,7 +186,7 @@ _bitmap_next_id (struct _bitmap *b, } while (b != NULL); bb = malloc (sizeof (struct _bitmap)); - if (bb == NULL) + if (unlikely (bb == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); *prev = bb; @@ -852,7 +852,7 @@ _write_image_surface (cairo_output_stream_t *output, #else if (stride > ARRAY_LENGTH (row_stack)) { rowdata = malloc (stride); - if (rowdata == NULL) + if (unlikely (rowdata == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } else rowdata = row_stack; @@ -1832,7 +1832,7 @@ _emit_type42_font (cairo_script_surface_t *surface, return status; buf = malloc (size); - if (buf == NULL) + if (unlikely (buf == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL); @@ -1882,7 +1882,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, cairo_status_t status; font_private = malloc (sizeof (cairo_script_surface_font_private_t)); - if (font_private == NULL) + if (unlikely (font_private == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font_private->ctx = surface->ctx; @@ -2466,7 +2466,7 @@ _cairo_script_vmcontext_create (cairo_output_stream_t *stream) cairo_script_vmcontext_t *ctx; ctx = malloc (sizeof (cairo_script_vmcontext_t)); - if (ctx == NULL) + if (unlikely (ctx == NULL)) return NULL; memset (ctx, 0, sizeof (cairo_script_vmcontext_t)); @@ -2500,11 +2500,11 @@ _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, { cairo_script_surface_t *surface; - if (ctx == NULL) + 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 (surface == NULL) + 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, diff --git a/src/cairo-sdl-surface.c b/src/cairo-sdl-surface.c index 800ad83a..d98566d5 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, diff --git a/src/cairo-skiplist.c b/src/cairo-skiplist.c index 02e15565..d03a6bfc 100644 --- a/src/cairo-skiplist.c +++ b/src/cairo-skiplist.c @@ -183,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; } 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 bb80538f..8e6e2687 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -1183,7 +1183,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; } diff --git a/src/cairo-surface.c b/src/cairo-surface.c index a6c97f23..dff8d9f0 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -237,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) { @@ -677,7 +677,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, if (data != NULL) { mime_data = malloc (sizeof (cairo_mime_data_t)); - if (mime_data == NULL) + 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); diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 35e256fd..8b66662d 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -347,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, @@ -482,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); @@ -496,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; @@ -1268,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); } @@ -1449,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++) { @@ -2458,12 +2458,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; } @@ -2607,7 +2607,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-traps.c b/src/cairo-traps.c index a8717029..0afdce23 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; } @@ -635,7 +635,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); } diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c index b3a48151..4662eaa3 100644 --- a/src/cairo-truetype-subset.c +++ b/src/cairo-truetype-subset.c @@ -173,8 +173,8 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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, @@ -185,7 +185,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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; } @@ -202,13 +202,13 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, 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,7 +270,7 @@ _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; } @@ -577,14 +577,14 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, (unsigned char*) &header, &size); 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, @@ -1098,7 +1098,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, goto fail1; truetype_subset->base_font = strdup (font->base.base_font); - if (truetype_subset->base_font == NULL) { + if (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; } @@ -1209,7 +1209,7 @@ _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, @@ -1306,7 +1306,7 @@ _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font, 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, diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c index d54215de..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); } @@ -722,13 +721,13 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset, 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; } @@ -822,7 +821,7 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset, _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; } diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index a62a2613..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; @@ -573,7 +573,7 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f } 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); } @@ -838,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 *) @@ -1210,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; } @@ -1325,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) @@ -1349,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 7106040f..ebc78dd2 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, diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index 5e2077f3..6670b536 100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -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, diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index 2823e5dc..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; diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 1878f8e7..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 */ diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 75d4de3f..0e915132 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -147,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; @@ -910,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); } } @@ -990,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; @@ -1964,7 +1963,7 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, 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); } @@ -2225,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; } @@ -2317,7 +2316,7 @@ _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); @@ -2574,7 +2573,7 @@ _cairo_xlib_surface_create_internal (Display *dpy, } 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)); @@ -3168,7 +3167,7 @@ _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; @@ -3297,7 +3296,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 */ } @@ -3579,7 +3578,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; } @@ -3723,7 +3722,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); } 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.c b/src/cairo.c index 924f7caa..75674f98 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; } @@ -2529,7 +2529,7 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status) return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; list = malloc (sizeof (cairo_rectangle_list_t)); - if (list == NULL) { + if (unlikely (list == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; } diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c index 883941df..d20e7c94 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)); } diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c index 71700bdd..6ac1803e 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; } diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c index cfb87f33..58d5b0a7 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)); } -- cgit v1.2.3 From 0d757a793d7fe2860c6a522124a123864fc97f0a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 29 Nov 2008 10:36:34 +0000 Subject: [png] Fix leak of original png data on error path. The error path was missing a _cairo_output_stream_destroy() to cleanup a copy of the incoming PNG data. --- src/cairo-png.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cairo-png.c b/src/cairo-png.c index 301a8921..fd16c4dc 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -512,6 +512,8 @@ read_png (struct png_read_closure_t *png_closure) 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, @@ -528,7 +530,6 @@ read_png (struct png_read_closure_t *png_closure) goto BAIL; } - png_closure->png_data = _cairo_memory_stream_create (); png_set_read_fn (png, png_closure, stream_read_func); status = CAIRO_STATUS_SUCCESS; @@ -659,6 +660,7 @@ read_png (struct png_read_closure_t *png_closure) 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, @@ -674,12 +676,17 @@ read_png (struct png_read_closure_t *png_closure) } 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; + + status_ignored = _cairo_output_stream_destroy (png_closure->png_data); + } return surface; } -- cgit v1.2.3 From 1659db2c1f4cc72e51fb43d119822ec7aaa77ac0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 29 Nov 2008 10:37:58 +0000 Subject: [test] Fix surface leak from device-offset-positive. A forgotten cairo_surface_destroy() caused the similar surface to be leaked during the test. --- test/device-offset-positive.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/device-offset-positive.c b/test/device-offset-positive.c index 4ea9469d..5afe9730 100644 --- a/test/device-offset-positive.c +++ b/test/device-offset-positive.c @@ -67,6 +67,7 @@ draw (cairo_t *cr, int width, int height) cairo_destroy (cr2); cairo_surface_set_device_offset (surface, + SIZE / 2, + SIZE / 2); cairo_set_source_surface (cr, surface, SIZE / 2, SIZE / 2); + cairo_surface_destroy (surface); cairo_paint (cr); -- cgit v1.2.3 From 7247017cf5e6b497a5836d9081ee153d27c6b15e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 29 Nov 2008 11:47:25 +0000 Subject: Fix up a couple of likely(malloc==NULL) Adrian Johnson spotted that I marked a few malloc failures as likely, whoops. --- src/cairo-cff-subset.c | 4 ++-- src/cairo-clip.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index d1e5a6dd..75e1ab51 100644 --- a/src/cairo-cff-subset.c +++ b/src/cairo-cff-subset.c @@ -2233,7 +2233,7 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, } cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); - if (likely (cff_subset->widths == NULL)) { + if (unlikely (cff_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -2248,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 (likely (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 35082f94..4303b605 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -298,7 +298,7 @@ _cairo_clip_intersect_path (cairo_clip_t *clip, return CAIRO_INT_STATUS_UNSUPPORTED; clip_path = malloc (sizeof (cairo_clip_path_t)); - if (likely (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); -- cgit v1.2.3 From 51a75ad932af4a3c3da96ef98de79328afa200c3 Mon Sep 17 00:00:00 2001 From: Luo Jinghua Date: Sun, 30 Nov 2008 20:42:49 +0800 Subject: glitz: Replace specified color with an opaque one if dst surface don't have an alpha channel. Otherwise if underlying glitz drawable has an alpha channel, glitz_set_rectangles will set its alpha channel to specified value instead of opaque one and effects following composite operations since glitz draws to attached drawable then copies its content to the dst surface. With this commit, three test cases such as operator, operator-alpha and unbounded-operator passes now. --- src/cairo-glitz-surface.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index d4eb0681..589e14ff 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -999,23 +999,29 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, } 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; + /* + * 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_rects, n_rects); } break; - case CAIRO_OPERATOR_CLEAR: { - static const glitz_color_t glitz_color = { 0, 0, 0, 0 }; - - glitz_set_rectangles (dst->surface, &glitz_color, - glitz_rects, n_rects); - } break; case CAIRO_OPERATOR_SATURATE: return CAIRO_INT_STATUS_UNSUPPORTED; case CAIRO_OPERATOR_OVER: -- cgit v1.2.3 From aff32019a70600fec5040a5a73c4f0b688826064 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 30 Nov 2008 23:28:59 -0500 Subject: [Makefile.am] Use top_srcdir instead of srcdir Doesn't make much difference here, but makes our intention clear. --- build/Makefile.am.changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Makefile.am.changelog b/build/Makefile.am.changelog index b9fbdcf3..888f4e79 100644 --- a/build/Makefile.am.changelog +++ b/build/Makefile.am.changelog @@ -71,7 +71,7 @@ $(srcdir)/ChangeLog.cache-% $(srcdir)/ChangeLog.pre-%: test "x$$from" = xinitial || from=$$from.0; \ spec=$$from..$$to; \ fi; \ - $(srcdir)/build/missing --run git-log --stat "$$spec") > $@.tmp \ + $(top_srcdir)/build/missing --run git-log --stat "$$spec") > $@.tmp \ && mv -f $@.tmp $@ \ || ($(RM) $@.tmp; \ echo Failed to generate $@, your $@ may be outdated >&2); \ -- cgit v1.2.3 From 540de34453d16092acd2978b513831a02f01f59f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Oct 2008 12:53:29 +0000 Subject: [matrix] Optimise invert for simple scaling|translation matrices. Peter Hercek reported, and provided a very useful test case for, a bug that caused his applications to crash with Cairo detecting an non-invertible pattern matrix and thus asserting the impossible happened. Bisecting revealed that the bug first appeared with 3c18d95 and disappeared with 0d0c6a1. Since neither of these explain the crash, further investigation revealed a compiler bug (gcc 4.3.3 20081130, earlier versions have different bugs!) that caused the matrix inversion to be invalid iff _cairo_matrix_scalar_multiply() was inlined (i.e. -O0, or an explicit noinline atttribute on that function prevented the bug, as did -msse.) So we apply this workaround to hide the bug in the stable series... The matrix is quite often just a simple scale and translate (or even identity!). For this class of matrix, we can skip the full adjoint rearrangement and determinant calculation and just compute the inverse directly. (cherry picked from commit 0d0c6a199c5b631299c72dce80d66ac0f4936a64) --- src/cairo-matrix.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index ca183230..6a29aecc 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -485,9 +485,33 @@ _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix) cairo_status_t cairo_matrix_invert (cairo_matrix_t *matrix) { - /* inv (A) = 1/det (A) * adj (A) */ double det; + /* Simple scaling|translation matrices are quite common... */ + if (matrix->xy == 0. && matrix->yx == 0.) { + matrix->x0 = -matrix->x0; + matrix->y0 = -matrix->y0; + + if (matrix->xx != 1.) { + if (matrix->xx == 0.) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + matrix->xx = 1. / matrix->xx; + matrix->x0 *= matrix->xx; + } + + if (matrix->yy != 1.) { + if (matrix->yy == 0.) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + matrix->yy = 1. / matrix->yy; + matrix->y0 *= matrix->yy; + } + + return CAIRO_STATUS_SUCCESS; + } + + /* inv (A) = 1/det (A) * adj (A) */ det = _cairo_matrix_compute_determinant (matrix); if (! ISFINITE (det)) -- cgit v1.2.3 From 08b486c9aa1d6ad01f1b17a16dcb4d695e8cbf7d Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Thu, 4 Dec 2008 17:53:06 -0500 Subject: [win32] Use MOD instead of the '%' operator Repeat should be handled using MOD instead of '%' so that negative numbers are handled as expected. E.g. -1 mod 600 = 599, not 495 as the '%' operator gives. This was causing https://bugzilla.mozilla.org/show_bug.cgi?id=466258 Patch from Robert O'Callahan --- src/cairo-win32-surface.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 863f9d52..bc665807 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; -- cgit v1.2.3 From 8ec58113df417e1ec1d331ab65267c34e6d32096 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 12 Sep 2008 17:32:40 +0300 Subject: [perf] Explicitly test rendering a path with lots of intersections. We don't have one just for this purpose. The only other path with many intersections that gets actually rendered is zrusin-another, but that might be sped up in the future (say by identifying collinearities up front or something like that.) --- perf/Makefile.am | 3 +- perf/cairo-perf.c | 1 + perf/cairo-perf.h | 1 + perf/intersections.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 perf/intersections.c diff --git a/perf/Makefile.am b/perf/Makefile.am index ae39dbc1..b85d7328 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -43,7 +43,8 @@ cairo_perf_SOURCES = \ zrusin-another.h \ long-dashed-lines.c \ dragon.c \ - pythagoras-tree.c + pythagoras-tree.c \ + intersections.c if CAIRO_HAS_WIN32_SURFACE cairo_perf_SOURCES += cairo-perf-win32.c diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c index c96e6c23..f419f05c 100644 --- a/perf/cairo-perf.c +++ b/perf/cairo-perf.c @@ -465,5 +465,6 @@ const cairo_perf_case_t perf_cases[] = { { twin, 800, 800}, { dragon, 1024, 1024 }, { pythagoras_tree, 768, 768 }, + { intersections, 512, 512 }, { NULL } }; diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h index d18be033..91e38dee 100644 --- a/perf/cairo-perf.h +++ b/perf/cairo-perf.h @@ -175,5 +175,6 @@ CAIRO_PERF_DECL (composite_checker); CAIRO_PERF_DECL (twin); CAIRO_PERF_DECL (dragon); CAIRO_PERF_DECL (pythagoras_tree); +CAIRO_PERF_DECL (intersections); #endif diff --git a/perf/intersections.c b/perf/intersections.c new file mode 100644 index 00000000..5e410366 --- /dev/null +++ b/perf/intersections.c @@ -0,0 +1,97 @@ +/* -*- 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 "cairo-perf.h" + +#define NUM_SEGMENTS 256 + +static unsigned state; +static double +uniform_random (double minval, double maxval) +{ + static unsigned const poly = 0x9a795537U; + unsigned n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_perf_ticks_t +draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule, int width, int height) +{ + int i; + double x[NUM_SEGMENTS]; + double y[NUM_SEGMENTS]; + + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + for (i = 0; i < NUM_SEGMENTS; i++) { + x[i] = uniform_random (0, width); + y[i] = uniform_random (0, height); + } + + state = 0x12345678; + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, fill_rule); + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_perf_timer_start (); { + + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) { + cairo_line_to (cr, x[i], y[i]); + } + cairo_close_path (cr); + + cairo_fill (cr); + } + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_perf_ticks_t +random_eo (cairo_t *cr, int width, int height) +{ + return draw_random (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height); +} + +static cairo_perf_ticks_t +random_nz (cairo_t *cr, int width, int height) +{ + return draw_random (cr, CAIRO_FILL_RULE_WINDING, width, height); +} + +void +intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "intersections-nz-fill", random_nz); + cairo_perf_run (perf, "intersections-eo-fill", random_eo); +} -- cgit v1.2.3 From afba0c312958852586b846ec615cff1bd3e5cde7 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 12 Sep 2008 17:41:45 +0300 Subject: [perf] Add perf tests to hit rectilinear code paths. These tests look at the differences in code paths hit by filling paths that are rectilinear (or not) and pixel aligned (or not) with the even-odd and non-zero fill rules. The paths are not simple, so they don't hit the special case quad/triangle tessellator. --- perf/Makefile.am | 3 +- perf/cairo-perf.c | 1 + perf/cairo-perf.h | 1 + perf/spiral.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 perf/spiral.c diff --git a/perf/Makefile.am b/perf/Makefile.am index b85d7328..5dcc0ab3 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -44,7 +44,8 @@ cairo_perf_SOURCES = \ long-dashed-lines.c \ dragon.c \ pythagoras-tree.c \ - intersections.c + intersections.c \ + spiral.c if CAIRO_HAS_WIN32_SURFACE cairo_perf_SOURCES += cairo-perf-win32.c diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c index f419f05c..6bb48f13 100644 --- a/perf/cairo-perf.c +++ b/perf/cairo-perf.c @@ -466,5 +466,6 @@ const cairo_perf_case_t perf_cases[] = { { dragon, 1024, 1024 }, { pythagoras_tree, 768, 768 }, { intersections, 512, 512 }, + { spiral, 512, 512 }, { NULL } }; diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h index 91e38dee..3affcb82 100644 --- a/perf/cairo-perf.h +++ b/perf/cairo-perf.h @@ -176,5 +176,6 @@ CAIRO_PERF_DECL (twin); CAIRO_PERF_DECL (dragon); CAIRO_PERF_DECL (pythagoras_tree); CAIRO_PERF_DECL (intersections); +CAIRO_PERF_DECL (spiral); #endif diff --git a/perf/spiral.c b/perf/spiral.c new file mode 100644 index 00000000..f26d0a2b --- /dev/null +++ b/perf/spiral.c @@ -0,0 +1,200 @@ +/* -*- 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 +#include "cairo-perf.h" + +#define MAX_SEGMENTS 2560 + +typedef enum { + PIXALIGN, /* pixel aligned path */ + NONALIGN /* unaligned path. */ +} align_t; + +typedef enum { + RECTCLOSE, /* keeps the path rectilinear */ + DIAGCLOSE /* forces a diagonal */ +} close_t; + +static cairo_perf_ticks_t +draw_spiral (cairo_t *cr, + cairo_fill_rule_t fill_rule, + align_t align, + close_t close, + int width, int height) +{ + int i; + int n=0; + double x[MAX_SEGMENTS]; + double y[MAX_SEGMENTS]; + int step = 3; + int side = width < height ? width : height; + + assert(5*(side/step/2+1)+2 < MAX_SEGMENTS); + +#define L(x_,y_) (x[n] = (x_), y[n] = (y_), n++) +#define M(x_,y_) L(x_,y_) +#define v(t) L(x[n-1], y[n-1] + (t)) +#define h(t) L(x[n-1] + (t), y[n-1]) + + switch (align) { + case PIXALIGN: M(0,0); break; + case NONALIGN: M(0.1415926, 0.7182818); break; + } + + while (side >= step && side >= 0) { + v(side); + h(side); + v(-side); + h(-side+step); + v(step); + side -= 2*step; + } + + switch (close) { + case RECTCLOSE: L(x[n-1],y[0]); break; + case DIAGCLOSE: L(x[0],y[0]); break; + } + + assert(n < MAX_SEGMENTS); + + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, fill_rule); + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_perf_timer_start (); { + + cairo_move_to (cr, x[0], y[0]); + for (i = 1; i < n; i++) { + cairo_line_to (cr, x[i], y[i]); + } + cairo_close_path (cr); + + cairo_fill (cr); + } + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_perf_ticks_t +draw_spiral_eo_pa_re (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + PIXALIGN, + RECTCLOSE, + width, height); +} + +static cairo_perf_ticks_t +draw_spiral_nz_pa_re (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + PIXALIGN, + RECTCLOSE, + width, height); +} + +static cairo_perf_ticks_t +draw_spiral_eo_na_re (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + NONALIGN, + RECTCLOSE, + width, height); +} + +static cairo_perf_ticks_t +draw_spiral_nz_na_re (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + NONALIGN, + RECTCLOSE, + width, height); +} + +static cairo_perf_ticks_t +draw_spiral_eo_pa_di (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + PIXALIGN, + DIAGCLOSE, + width, height); +} + +static cairo_perf_ticks_t +draw_spiral_nz_pa_di (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + PIXALIGN, + DIAGCLOSE, + width, height); +} + +static cairo_perf_ticks_t +draw_spiral_eo_na_di (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + NONALIGN, + DIAGCLOSE, + width, height); +} + +static cairo_perf_ticks_t +draw_spiral_nz_na_di (cairo_t *cr, int width, int height) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + NONALIGN, + DIAGCLOSE, + width, height); +} + +void +spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "spiral-diag-nonalign-evenodd-fill", draw_spiral_eo_na_di); + cairo_perf_run (perf, "spiral-diag-nonalign-nonzero-fill", draw_spiral_nz_na_di); + cairo_perf_run (perf, "spiral-diag-pixalign-evenodd-fill", draw_spiral_eo_pa_di); + cairo_perf_run (perf, "spiral-diag-pixalign-nonzero-fill", draw_spiral_nz_pa_di); + cairo_perf_run (perf, "spiral-rect-nonalign-evenodd-fill", draw_spiral_eo_na_re); + cairo_perf_run (perf, "spiral-rect-nonalign-nonzero-fill", draw_spiral_nz_na_re); + cairo_perf_run (perf, "spiral-rect-pixalign-evenodd-fill", draw_spiral_eo_pa_re); + cairo_perf_run (perf, "spiral-rect-pixalign-nonzero-fill", draw_spiral_nz_pa_re); +} -- cgit v1.2.3 From 0c0f4862c52d68776024f125b003ade455044b27 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 6 Dec 2008 13:32:37 +0200 Subject: [perf-diff] Fix cairo-perf-diff for git 1.6 Since git 1.6 the plumbing commands aren't installed in the user's path by default. This patch fixes cairo-perf-diff to find the git-sh-setup command from git's lib dir. --- perf/cairo-perf-diff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perf/cairo-perf-diff b/perf/cairo-perf-diff index 50cd1f2c..718cdc57 100755 --- a/perf/cairo-perf-diff +++ b/perf/cairo-perf-diff @@ -89,7 +89,7 @@ fi git_setup() { SUBDIRECTORY_OK='Yes' - . git-sh-setup + . "$(git --exec-path)/git-sh-setup" CAIRO_DIR=`dirname $GIT_DIR` if [ "$CAIRO_DIR" = "." ]; then CAIRO_DIR=`pwd` -- cgit v1.2.3 From 6acb8223930081f70b422ef93a49ea645c2cc12d Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 12 Sep 2008 19:32:12 +0300 Subject: [path-fixed] Avoid extra indirection when iterating already flat paths. Perform a plain iteration rather than a flattening one if the path knows it doesn't have any curves. --- src/cairo-path-fixed.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 2f365624..d6a3d7f2 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -930,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; -- cgit v1.2.3 From a370d077bc697588b6dac2556afa0b95ff83a77d Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 25 Jul 2008 16:35:14 +0300 Subject: [path-fixed] New _cairo_path_fixed_is_region(). We want to hit the current fast paths for rendering axis aligned rectilinear paths rather than spans, and for that we need to be able to identify regional paths. --- src/cairo-path-fixed.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/cairoint.h | 3 ++ 2 files changed, 99 insertions(+) diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index d6a3d7f2..dd25bb88 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -1179,3 +1179,99 @@ _cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter) 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/cairoint.h b/src/cairoint.h index 34ea874a..692c36ab 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1536,6 +1536,9 @@ 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, -- cgit v1.2.3 From 4b227143b3daab75148cd54c9e7580d509864e0d Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Thu, 31 Jul 2008 01:54:53 +0300 Subject: [cairo-spans] Introduce a type to track which pixels combine in a compositing op. A cairo_composite_rectangles_t contains the coordinates of rectangular windows into each of the source pattern, mask, clip and destination surface containing the pixels that will combine in a compositing operation. The idea is to have a uniform way to represent all the translations involved rather than overloading parameters like src_x/y, dst_x/y, etc., sometimes with different incompatible meanings across functions. --- src/cairo-rectangle.c | 21 +++++++++++++++++++++ src/cairo-types-private.h | 24 ++++++++++++++++++++++++ src/cairoint.h | 7 +++++++ 3 files changed, 52 insertions(+) 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-types-private.h b/src/cairo-types-private.h index 6f1354d6..d8d5a2c0 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -252,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 diff --git a/src/cairoint.h b/src/cairoint.h index 692c36ab..4246ed98 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -263,6 +263,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 -- cgit v1.2.3 From 948c3526dcdbc440395fff4ce9bf4b7553930d92 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 24 Oct 2008 17:37:30 +0300 Subject: [cairo-spans] New abstract types for scan converting polygons. A cairo_span_renderer_t implementation can be provided by a surface if it wants to render paths as horizontal spans of the alpha component of a mask. Its job is to composite a source pattern to the destination surface when given spans of alpha coverage for a row while taking care of backend specific clipping. A cairo_scan_converter_t takes edges of a flattened path and generates spans for a span renderer to render. --- src/Makefile.sources | 2 + src/cairo-spans-private.h | 124 ++++++++++++++++++++++++ src/cairo-spans.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++ src/cairoint.h | 1 + 4 files changed, 369 insertions(+) create mode 100644 src/cairo-spans-private.h create mode 100644 src/cairo-spans.c diff --git a/src/Makefile.sources b/src/Makefile.sources index 5d643dcb..98116505 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -81,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 \ @@ -132,6 +133,7 @@ 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 \ diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h new file mode 100644 index 00000000..ba10d5b2 --- /dev/null +++ b/src/cairo-spans-private.h @@ -0,0 +1,124 @@ +/* -*- 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; +}; + +/* 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); + +#endif /* CAIRO_SPANS_PRIVATE_H */ diff --git a/src/cairo-spans.c b/src/cairo-spans.c new file mode 100644 index 00000000..9cf351bd --- /dev/null +++ b/src/cairo-spans.c @@ -0,0 +1,242 @@ +/* -*- 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" + +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/cairoint.h b/src/cairoint.h index 4246ed98..6b26e293 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, -- cgit v1.2.3 From 4a9b274eebe674bbc5c66dc3e33256723cdf9829 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 11 Jul 2008 00:59:47 +0300 Subject: [cairo-spans] Add a check/create_span_renderer backend methods. A surface will have the chance to use span rendering at cairo_fill() time by creating a renderer for a specific combination of pattern/dst/op before the path is scan converted. The protocol is to first call check_span_renderer() to see if the surface wants to render with spans and then later call create_span_renderer() to create the renderer for real once the extents of the path are known. No backends have an implementation yet. --- src/cairo-analysis-surface.c | 4 +++ src/cairo-beos-surface.cpp | 2 ++ src/cairo-directfb-surface.c | 2 ++ src/cairo-glitz-surface.c | 2 ++ src/cairo-image-surface.c | 2 ++ src/cairo-meta-surface.c | 2 ++ src/cairo-os2-surface.c | 2 ++ src/cairo-paginated-surface.c | 2 ++ src/cairo-pdf-surface.c | 2 ++ src/cairo-ps-surface.c | 2 ++ src/cairo-quartz-image-surface.c | 2 ++ src/cairo-quartz-surface.c | 2 ++ src/cairo-script-surface.c | 2 ++ src/cairo-sdl-surface.c | 2 ++ src/cairo-surface.c | 53 ++++++++++++++++++++++++++++++++++++++ src/cairo-svg-surface.c | 2 ++ src/cairo-type3-glyph-surface.c | 2 ++ src/cairo-win32-printing-surface.c | 2 ++ src/cairo-win32-surface.c | 2 ++ src/cairo-xcb-surface.c | 2 ++ src/cairo-xlib-surface.c | 2 ++ src/cairoint.h | 30 +++++++++++++++++++++ src/test-fallback-surface.c | 2 ++ src/test-meta-surface.c | 2 ++ src/test-paginated-surface.c | 2 ++ 25 files changed, 131 insertions(+) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index a19ff10c..50005c21 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -746,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 */ @@ -961,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 */ 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-directfb-surface.c b/src/cairo-directfb-surface.c index cab7104c..71c46755 100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -1815,6 +1815,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-glitz-surface.c b/src/cairo-glitz-surface.c index 589e14ff..f049f401 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -2293,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, diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 2bf45430..ef5e238d 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -1303,6 +1303,8 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { _cairo_image_surface_composite, _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_image_surface_set_clip_region, diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c index e69df21c..0f6e6324 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -647,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 */ diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c index e4cef052..02840e33 100644 --- a/src/cairo-os2-surface.c +++ b/src/cairo-os2-surface.c @@ -1326,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-paginated-surface.c b/src/cairo-paginated-surface.c index 2b58e499..ce4e4def 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -678,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-pdf-surface.c b/src/cairo-pdf-surface.c index b85a6c82..5862c4b5 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -5308,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-ps-surface.c b/src/cairo-ps-surface.c index 9d2a7c5c..a13be1d8 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -3503,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 19160b4b..9f6b2451 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -2404,6 +2404,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-script-surface.c b/src/cairo-script-surface.c index 77a9e5f5..cf2809f5 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -2423,6 +2423,8 @@ _cairo_script_surface_backend = { 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 */ diff --git a/src/cairo-sdl-surface.c b/src/cairo-sdl-surface.c index d98566d5..1f97fb47 100644 --- a/src/cairo-sdl-surface.c +++ b/src/cairo-sdl-surface.c @@ -357,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-surface.c b/src/cairo-surface.c index dff8d9f0..077af5b4 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -1953,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 diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 8b66662d..cfd9a2d5 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -2422,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 */ diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c index ebc78dd2..b3a48313 100644 --- a/src/cairo-type3-glyph-surface.c +++ b/src/cairo-type3-glyph-surface.c @@ -315,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 */ diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 41330198..94927aeb 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -1752,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-surface.c b/src/cairo-win32-surface.c index bc665807..03a8f61a 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -1982,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 999f7d54..6f246f80 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -1684,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, diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 0e915132..68d81922 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -2446,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, diff --git a/src/cairoint.h b/src/cairoint.h index 6b26e293..cfc850e8 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -634,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); @@ -1863,6 +1877,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, diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c index d20e7c94..8acd91ee 100644 --- a/src/test-fallback-surface.c +++ b/src/test-fallback-surface.c @@ -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 6ac1803e..42bf6b0c 100644 --- a/src/test-meta-surface.c +++ b/src/test-meta-surface.c @@ -313,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 58d5b0a7..4c566470 100644 --- a/src/test-paginated-surface.c +++ b/src/test-paginated-surface.c @@ -298,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, -- cgit v1.2.3 From 2078e5b20fdff76ada6e13b29b2775b7dcd35439 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Thu, 31 Jul 2008 01:58:08 +0300 Subject: [cairo-spans] New _cairo_path_fixed_fill_using_spans(). Adds a helper function for backends to use for filling a path using spans. --- src/cairo-spans-private.h | 10 ++++ src/cairo-spans.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h index ba10d5b2..e86d3d47 100644 --- a/src/cairo-spans-private.h +++ b/src/cairo-spans-private.h @@ -121,4 +121,14 @@ 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 index 9cf351bd..4411abbc 100644 --- a/src/cairo-spans.c +++ b/src/cairo-spans.c @@ -26,6 +26,151 @@ */ #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) +{ + /* Until we get a scan converter implementation we're going to + * fail. */ + ASSERT_NOT_REACHED; + return _cairo_scan_converter_create_in_error ( + CAIRO_INT_STATUS_UNSUPPORTED); +} + +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) { -- cgit v1.2.3 From 7994fc06ad66e31fcbc16f6e8cd9ad226022ec8c Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Thu, 28 Aug 2008 22:16:07 +0300 Subject: [cairo-spans] New cairo_tor_scan_converter_t. Imports a new polygon scan converter implementation from the repository at http://cgit.freedesktop.org/~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 in this implementation is cheaply choosing per-scan line between doing fully analytical coverage computation for an entire row at a time vs. using a supersampling approach. --- src/Makefile.sources | 1 + src/cairo-spans-private.h | 10 + src/cairo-spans.c | 18 +- src/cairo-tor-scan-converter.c | 2003 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 2027 insertions(+), 5 deletions(-) create mode 100644 src/cairo-tor-scan-converter.c diff --git a/src/Makefile.sources b/src/Makefile.sources index 98116505..5f387f43 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -138,6 +138,7 @@ cairo_sources = \ 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 \ diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h index e86d3d47..c285f949 100644 --- a/src/cairo-spans-private.h +++ b/src/cairo-spans-private.h @@ -96,6 +96,16 @@ struct _cairo_scan_converter { 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 * diff --git a/src/cairo-spans.c b/src/cairo-spans.c index 4411abbc..e441143b 100644 --- a/src/cairo-spans.c +++ b/src/cairo-spans.c @@ -128,11 +128,19 @@ _create_scan_converter (cairo_fill_rule_t fill_rule, cairo_antialias_t antialias, const cairo_composite_rectangles_t *rects) { - /* Until we get a scan converter implementation we're going to - * fail. */ - ASSERT_NOT_REACHED; - return _cairo_scan_converter_create_in_error ( - CAIRO_INT_STATUS_UNSUPPORTED); + 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 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 +#include +#include +#include + +/*------------------------------------------------------------------------- + * 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< +#include +#include + +/* 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; iy_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); +} -- cgit v1.2.3 From 85b81a3e59401e2fc68209634f7622694e7d30e1 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 11 Jul 2008 13:10:20 +0300 Subject: [cairo-spans] Implement a span renderer for cairo_image_surface_t. This implementation first produces an A8 alpha mask and then pixman_image_composites the result to the destination with the source. Clipping is handled by pixman when it is region clipping or by cairo-surface-fallback when it is something more complex. --- src/cairo-image-surface.c | 273 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 233 insertions(+), 40 deletions(-) diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index ef5e238d..f484466a 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -1078,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, @@ -1095,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) @@ -1165,40 +1171,19 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, 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 (unlikely (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 (unlikely (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, @@ -1208,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); @@ -1228,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) @@ -1303,8 +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, - NULL, /* create_span_renderer */ - NULL, /* check_span_renderer */ + _cairo_image_surface_create_span_renderer, + _cairo_image_surface_check_span_renderer, NULL, /* copy_page */ NULL, /* show_page */ _cairo_image_surface_set_clip_region, -- cgit v1.2.3 From 18634c37026a2d6147443cb6d991576f62b07e6d Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Thu, 24 Jul 2008 20:47:14 +0300 Subject: [cairo-spans] Hook up filling paths with spans to cairo-surface-fallback.c. This speeds up the mask generation step in cairo_fill() for the image surface by up to 10x in especially favourable cases. image-rgba twin-800 7757.80 0.20% -> 749.41 0.29%: 10.36x speedup image-rgba spiral-diag-pixalign-nonzero-fill-512 15.16 0.44% -> 3.45 8.80%: 5.54x speedup More typical simple non-rectilinear geometries are sped up by 30-50%. This patch does not affect any stroking operations or any fill operations of pixel aligned rectilinear geometries; those are still rendered using trapezoids. --- src/cairo-surface-fallback.c | 86 ++++++++++++++++++++- test/clip-fill-rule.test-fallback.rgb24.ref.png | Bin 0 -> 361 bytes test/clip-operator.pdf.argb32.ref.png | Bin 12125 -> 11600 bytes test/clip-operator.pdf.rgb24.ref.png | Bin 7367 -> 6882 bytes test/clip-operator.ps2.rgb24.ref.png | Bin 3624 -> 3736 bytes test/clip-operator.ps3.argb32.ref.png | Bin 0 -> 7574 bytes test/clip-operator.ps3.rgb24.ref.png | Bin 3624 -> 3736 bytes test/clip-operator.ref.png | Bin 8271 -> 8247 bytes test/clip-operator.rgb24.ref.png | Bin 3258 -> 3279 bytes test/clip-operator.test-fallback.argb32.ref.png | Bin 0 -> 8252 bytes test/clip-operator.test-fallback.rgb24.ref.png | Bin 0 -> 3241 bytes test/clip-operator.xlib-fallback.rgb24.ref.png | Bin 0 -> 3254 bytes test/clip-operator.xlib.ref.png | Bin 0 -> 8271 bytes test/clip-operator.xlib.rgb24.ref.png | Bin 0 -> 3258 bytes test/clip-twice.pdf.argb32.ref.png | Bin 0 -> 1458 bytes test/clipped-group.pdf.argb32.ref.png | Bin 0 -> 298 bytes test/clipped-group.pdf.rgb24.ref.png | Bin 0 -> 298 bytes test/degenerate-arc.ref.png | Bin 616 -> 544 bytes test/degenerate-arc.test-fallback.argb32.ref.png | Bin 0 -> 547 bytes test/degenerate-arc.test-fallback.rgb24.ref.png | Bin 0 -> 547 bytes test/degenerate-arc.xlib.ref.png | Bin 0 -> 616 bytes test/fill-alpha-pattern.pdf.argb32.ref.png | Bin 3887 -> 3750 bytes test/fill-alpha-pattern.pdf.rgb24.ref.png | Bin 3840 -> 3758 bytes test/fill-alpha-pattern.ps3.argb32.ref.png | Bin 0 -> 4070 bytes test/fill-alpha-pattern.ps3.rgb24.ref.png | Bin 0 -> 4473 bytes test/fill-alpha-pattern.ref.png | Bin 3653 -> 3374 bytes ...fill-alpha-pattern.test-fallback.argb32.ref.png | Bin 0 -> 3379 bytes .../fill-alpha-pattern.test-fallback.rgb24.ref.png | Bin 0 -> 3379 bytes test/fill-alpha-pattern.xlib.ref.png | Bin 0 -> 3653 bytes test/fill-alpha.ref.png | Bin 2989 -> 2728 bytes test/fill-alpha.test-fallback.argb32.ref.png | Bin 0 -> 2824 bytes test/fill-alpha.test-fallback.rgb24.ref.png | Bin 0 -> 2824 bytes test/fill-alpha.xlib.ref.png | Bin 0 -> 2989 bytes test/fill-degenerate-sort-order.ref.png | Bin 2397 -> 2406 bytes test/fill-degenerate-sort-order.rgb24.ref.png | Bin 2060 -> 2052 bytes ...enerate-sort-order.test-fallback.argb32.ref.png | Bin 0 -> 2378 bytes ...generate-sort-order.test-fallback.rgb24.ref.png | Bin 0 -> 2041 bytes test/fill-degenerate-sort-order.xlib.ref.png | Bin 0 -> 2397 bytes test/fill-degenerate-sort-order.xlib.rgb24.ref.png | Bin 0 -> 2060 bytes test/fill-missed-stop.pdf.argb32.ref.png | Bin 0 -> 452 bytes test/fill-rule.ref.png | Bin 1979 -> 2061 bytes test/fill-rule.rgb24.ref.png | Bin 1722 -> 1780 bytes test/fill-rule.test-fallback.argb32.ref.png | Bin 0 -> 1979 bytes test/fill-rule.test-fallback.rgb24.ref.png | Bin 0 -> 1703 bytes test/fill-rule.xlib.ref.png | Bin 0 -> 1979 bytes test/fill-rule.xlib.rgb24.ref.png | Bin 0 -> 1722 bytes test/finer-grained-fallbacks.ps2.argb32.ref.png | Bin 0 -> 1173 bytes test/finer-grained-fallbacks.ps2.rgb24.ref.png | Bin 1096 -> 1154 bytes test/finer-grained-fallbacks.ps3.argb32.ref.png | Bin 0 -> 1173 bytes test/finer-grained-fallbacks.ps3.rgb24.ref.png | Bin 1096 -> 1154 bytes test/finer-grained-fallbacks.ref.png | Bin 1111 -> 1069 bytes test/finer-grained-fallbacks.rgb24.ref.png | Bin 1114 -> 839 bytes ...-grained-fallbacks.test-fallback.argb32.ref.png | Bin 0 -> 1111 bytes ...r-grained-fallbacks.test-fallback.rgb24.ref.png | Bin 0 -> 854 bytes test/finer-grained-fallbacks.xlib.ref.png | Bin 0 -> 1111 bytes test/finer-grained-fallbacks.xlib.rgb24.ref.png | Bin 0 -> 1114 bytes test/font-matrix-translation.svg11.argb32.ref.png | Bin 0 -> 857 bytes test/font-matrix-translation.svg11.rgb24.ref.png | Bin 0 -> 857 bytes test/font-matrix-translation.svg12.argb32.ref.png | Bin 0 -> 857 bytes test/font-matrix-translation.svg12.rgb24.ref.png | Bin 0 -> 857 bytes test/ft-show-glyphs-table.svg11.argb32.ref.png | Bin 0 -> 9953 bytes test/ft-show-glyphs-table.svg11.rgb24.ref.png | Bin 0 -> 9953 bytes test/ft-show-glyphs-table.svg12.argb32.ref.png | Bin 0 -> 9953 bytes test/ft-show-glyphs-table.svg12.rgb24.ref.png | Bin 0 -> 9953 bytes ...t-text-vertical-layout-type1.pdf.argb32.ref.png | Bin 0 -> 3632 bytes ...ft-text-vertical-layout-type1.pdf.rgb24.ref.png | Bin 0 -> 3632 bytes test/ft-text-vertical-layout-type1.ref.png | Bin 3980 -> 3643 bytes ...text-vertical-layout-type1.svg11.argb32.ref.png | Bin 0 -> 3614 bytes ...-text-vertical-layout-type1.svg11.rgb24.ref.png | Bin 0 -> 3614 bytes ...text-vertical-layout-type1.svg12.argb32.ref.png | Bin 0 -> 3614 bytes ...-text-vertical-layout-type1.svg12.rgb24.ref.png | Bin 0 -> 3614 bytes ...tical-layout-type1.test-fallback.argb32.ref.png | Bin 0 -> 3639 bytes ...rtical-layout-type1.test-fallback.rgb24.ref.png | Bin 0 -> 3639 bytes test/ft-text-vertical-layout-type1.xlib.ref.png | Bin 0 -> 3980 bytes ...t-text-vertical-layout-type3.pdf.argb32.ref.png | Bin 0 -> 3642 bytes ...ft-text-vertical-layout-type3.pdf.rgb24.ref.png | Bin 0 -> 3642 bytes test/ft-text-vertical-layout-type3.ref.png | Bin 3934 -> 3609 bytes ...text-vertical-layout-type3.svg11.argb32.ref.png | Bin 0 -> 3640 bytes ...-text-vertical-layout-type3.svg11.rgb24.ref.png | Bin 0 -> 3640 bytes ...text-vertical-layout-type3.svg12.argb32.ref.png | Bin 0 -> 3640 bytes ...-text-vertical-layout-type3.svg12.rgb24.ref.png | Bin 0 -> 3640 bytes ...tical-layout-type3.test-fallback.argb32.ref.png | Bin 0 -> 3605 bytes ...rtical-layout-type3.test-fallback.rgb24.ref.png | Bin 0 -> 3605 bytes test/ft-text-vertical-layout-type3.xlib.ref.png | Bin 0 -> 3934 bytes test/huge-pattern.pdf.argb32.ref.png | Bin 0 -> 2430 bytes test/linear-gradient.pdf.argb32.ref.png | Bin 0 -> 1118 bytes test/linear-gradient.pdf.rgb24.ref.png | Bin 0 -> 1118 bytes test/linear-gradient.ref.png | Bin 1021 -> 983 bytes test/linear-gradient.svg11.argb32.ref.png | Bin 0 -> 988 bytes test/linear-gradient.svg11.rgb24.ref.png | Bin 0 -> 988 bytes test/linear-gradient.svg12.argb32.ref.png | Bin 0 -> 988 bytes test/linear-gradient.svg12.rgb24.ref.png | Bin 0 -> 988 bytes test/linear-gradient.test-fallback.argb32.ref.png | Bin 0 -> 923 bytes test/linear-gradient.test-fallback.rgb24.ref.png | Bin 0 -> 923 bytes test/linear-gradient.xlib.ref.png | Bin 0 -> 1021 bytes test/mask-alpha.ref.png | Bin 640 -> 643 bytes test/mask-alpha.svg11.argb32.ref.png | Bin 615 -> 642 bytes test/mask-alpha.svg11.rgb24.ref.png | Bin 0 -> 592 bytes test/mask-alpha.svg12.argb32.ref.png | Bin 615 -> 642 bytes test/mask-alpha.svg12.rgb24.ref.png | Bin 0 -> 592 bytes test/mask-alpha.test-fallback.argb32.ref.png | Bin 0 -> 627 bytes test/mask-alpha.xlib.ref.png | Bin 0 -> 640 bytes test/mask-alpha.xlib.rgb24.ref.png | Bin 0 -> 599 bytes test/mask.pdf.argb32.ref.png | Bin 8881 -> 9956 bytes test/mask.pdf.rgb24.ref.png | Bin 8267 -> 8735 bytes test/mask.ref.png | Bin 8476 -> 8571 bytes test/mask.rgb24.ref.png | Bin 7041 -> 7216 bytes test/mask.svg11.argb32.ref.png | Bin 8527 -> 8625 bytes test/mask.svg11.rgb24.ref.png | Bin 7935 -> 7203 bytes test/mask.svg12.argb32.ref.png | Bin 8527 -> 8625 bytes test/mask.svg12.rgb24.ref.png | Bin 7935 -> 7203 bytes test/mask.test-fallback.argb32.ref.png | Bin 0 -> 8457 bytes test/mask.test-fallback.rgb24.ref.png | Bin 0 -> 7058 bytes test/mask.xlib-fallback.rgb24.ref.png | Bin 0 -> 7216 bytes test/mask.xlib.ref.png | Bin 0 -> 8476 bytes test/mask.xlib.rgb24.ref.png | Bin 0 -> 7041 bytes test/meta-surface-pattern.pdf.argb32.ref.png | Bin 0 -> 4017 bytes test/meta-surface-pattern.pdf.rgb24.ref.png | Bin 4009 -> 3910 bytes test/meta-surface-pattern.svg11.argb32.ref.png | Bin 3924 -> 3928 bytes test/meta-surface-pattern.svg11.rgb24.ref.png | Bin 4593 -> 3914 bytes test/meta-surface-pattern.svg12.argb32.ref.png | Bin 3924 -> 3928 bytes test/meta-surface-pattern.svg12.rgb24.ref.png | Bin 4593 -> 3914 bytes test/operator-clear.pdf.argb32.ref.png | Bin 1614 -> 1607 bytes test/operator-clear.ps2.argb32.ref.png | Bin 0 -> 1156 bytes test/operator-clear.ps3.argb32.ref.png | Bin 0 -> 1156 bytes test/operator-source.pdf.argb32.ref.png | Bin 5149 -> 5112 bytes test/operator-source.pdf.rgb24.ref.png | Bin 4354 -> 4186 bytes test/operator-source.ref.png | Bin 4420 -> 4425 bytes test/operator-source.rgb24.ref.png | Bin 3201 -> 3231 bytes test/operator-source.test-fallback.argb32.ref.png | Bin 0 -> 4401 bytes test/operator-source.test-fallback.rgb24.ref.png | Bin 0 -> 3200 bytes test/operator-source.xlib-fallback.rgb24.ref.png | Bin 0 -> 3193 bytes test/operator-source.xlib.ref.png | Bin 0 -> 4420 bytes test/operator-source.xlib.rgb24.ref.png | Bin 0 -> 3201 bytes test/over-above-source.ps2.argb32.ref.png | Bin 636 -> 558 bytes test/over-above-source.ps3.argb32.ref.png | Bin 636 -> 558 bytes test/over-above-source.ref.png | Bin 538 -> 560 bytes test/over-above-source.rgb24.ref.png | Bin 461 -> 466 bytes .../over-above-source.test-fallback.argb32.ref.png | Bin 0 -> 533 bytes test/over-above-source.test-fallback.rgb24.ref.png | Bin 0 -> 450 bytes test/over-above-source.xlib.ref.png | Bin 0 -> 538 bytes test/over-above-source.xlib.rgb24.ref.png | Bin 0 -> 461 bytes test/over-around-source.pdf.argb32.ref.png | Bin 0 -> 585 bytes test/over-around-source.ps2.argb32.ref.png | Bin 632 -> 522 bytes test/over-around-source.ps3.argb32.ref.png | Bin 632 -> 522 bytes test/over-around-source.ref.png | Bin 614 -> 645 bytes ...over-around-source.test-fallback.argb32.ref.png | Bin 0 -> 610 bytes test/over-around-source.xlib.ref.png | Bin 0 -> 614 bytes test/over-around-source.xlib.rgb24.ref.png | Bin 0 -> 503 bytes test/over-below-source.pdf.argb32.ref.png | Bin 0 -> 464 bytes test/over-between-source.ps2.argb32.ref.png | Bin 678 -> 551 bytes test/over-between-source.ps3.argb32.ref.png | Bin 678 -> 551 bytes test/over-between-source.ref.png | Bin 575 -> 612 bytes ...ver-between-source.test-fallback.argb32.ref.png | Bin 0 -> 578 bytes test/over-between-source.xlib.ref.png | Bin 0 -> 575 bytes test/over-between-source.xlib.rgb24.ref.png | Bin 0 -> 473 bytes test/push-group.pdf.argb32.ref.png | Bin 0 -> 2722 bytes test/push-group.pdf.rgb24.ref.png | Bin 2714 -> 2740 bytes test/push-group.ref.png | Bin 3126 -> 3060 bytes test/push-group.rgb24.ref.png | Bin 2961 -> 2912 bytes test/push-group.svg11.argb32.ref.png | Bin 2935 -> 3034 bytes test/push-group.svg12.argb32.ref.png | Bin 2935 -> 3034 bytes test/push-group.test-fallback.argb32.ref.png | Bin 0 -> 3107 bytes test/push-group.test-fallback.rgb24.ref.png | Bin 0 -> 2942 bytes test/push-group.xlib-fallback.rgb24.ref.png | Bin 0 -> 2912 bytes test/push-group.xlib.ref.png | Bin 0 -> 3126 bytes test/push-group.xlib.rgb24.ref.png | Bin 0 -> 2961 bytes test/radial-gradient.pdf.argb32.ref.png | Bin 0 -> 79601 bytes test/radial-gradient.pdf.rgb24.ref.png | Bin 0 -> 79601 bytes test/random-intersections.ref.png | Bin 148722 -> 133462 bytes ...ndom-intersections.test-fallback.argb32.ref.png | Bin 0 -> 132312 bytes ...andom-intersections.test-fallback.rgb24.ref.png | Bin 0 -> 132312 bytes test/random-intersections.xlib.ref.png | Bin 0 -> 148722 bytes test/smask-fill.pdf.argb32.ref.png | Bin 0 -> 1909 bytes test/smask-fill.pdf.rgb24.ref.png | Bin 0 -> 1909 bytes test/smask-fill.ref.png | Bin 1223 -> 1156 bytes test/smask-fill.svg11.argb32.ref.png | Bin 0 -> 1128 bytes test/smask-fill.svg11.rgb24.ref.png | Bin 0 -> 1128 bytes test/smask-fill.svg12.argb32.ref.png | Bin 0 -> 1128 bytes test/smask-fill.svg12.rgb24.ref.png | Bin 0 -> 1128 bytes test/smask-fill.test-fallback.argb32.ref.png | Bin 0 -> 1148 bytes test/smask-fill.test-fallback.rgb24.ref.png | Bin 0 -> 1148 bytes test/smask-fill.xlib-fallback.ref.png | Bin 0 -> 1156 bytes test/smask-fill.xlib.ref.png | Bin 0 -> 1223 bytes test/smask-image-mask.pdf.argb32.ref.png | Bin 0 -> 1651 bytes test/smask-image-mask.pdf.rgb24.ref.png | Bin 0 -> 1651 bytes test/smask-mask.pdf.argb32.ref.png | Bin 0 -> 4398 bytes test/smask-mask.pdf.rgb24.ref.png | Bin 0 -> 4398 bytes test/smask-paint.pdf.argb32.ref.png | Bin 0 -> 4496 bytes test/smask-paint.pdf.rgb24.ref.png | Bin 0 -> 4496 bytes test/smask-stroke.pdf.argb32.ref.png | Bin 0 -> 1417 bytes test/smask-stroke.pdf.rgb24.ref.png | Bin 0 -> 1417 bytes test/smask-text.svg11.argb32.ref.png | Bin 0 -> 1791 bytes test/smask-text.svg11.rgb24.ref.png | Bin 0 -> 1791 bytes test/smask-text.svg12.argb32.ref.png | Bin 0 -> 1791 bytes test/smask-text.svg12.rgb24.ref.png | Bin 0 -> 1791 bytes test/smask.pdf.argb32.ref.png | Bin 0 -> 4496 bytes test/smask.pdf.rgb24.ref.png | Bin 0 -> 4496 bytes test/text-pattern.pdf.argb32.ref.png | Bin 1823 -> 2151 bytes test/text-pattern.svg11.argb32.ref.png | Bin 1733 -> 1743 bytes test/text-pattern.svg12.argb32.ref.png | Bin 1733 -> 1743 bytes test/text-rotate.svg11.argb32.ref.png | Bin 0 -> 16942 bytes test/text-rotate.svg11.rgb24.ref.png | Bin 0 -> 16942 bytes test/text-rotate.svg12.argb32.ref.png | Bin 0 -> 16942 bytes test/text-rotate.svg12.rgb24.ref.png | Bin 0 -> 16942 bytes test/text-transform.svg11.argb32.ref.png | Bin 0 -> 5677 bytes test/text-transform.svg11.rgb24.ref.png | Bin 0 -> 5677 bytes test/text-transform.svg12.argb32.ref.png | Bin 0 -> 5677 bytes test/text-transform.svg12.rgb24.ref.png | Bin 0 -> 5677 bytes test/trap-clip.pdf.argb32.ref.png | Bin 5809 -> 6720 bytes test/trap-clip.pdf.rgb24.ref.png | Bin 5768 -> 6642 bytes test/trap-clip.ps2.argb32.ref.png | Bin 5690 -> 4849 bytes test/trap-clip.ref.png | Bin 5772 -> 5865 bytes test/trap-clip.rgb24.ref.png | Bin 5365 -> 5457 bytes test/trap-clip.test-fallback.argb32.ref.png | Bin 0 -> 5753 bytes test/trap-clip.test-fallback.rgb24.ref.png | Bin 0 -> 5379 bytes test/trap-clip.xlib.ref.png | Bin 0 -> 5772 bytes test/trap-clip.xlib.rgb24.ref.png | Bin 0 -> 5365 bytes test/twin.svg11.argb32.ref.png | Bin 0 -> 1797 bytes test/twin.svg11.rgb24.ref.png | Bin 0 -> 1797 bytes test/twin.svg12.argb32.ref.png | Bin 0 -> 1797 bytes test/twin.svg12.rgb24.ref.png | Bin 0 -> 1797 bytes test/unbounded-operator.pdf.argb32.ref.png | Bin 0 -> 2713 bytes test/unbounded-operator.ps2.argb32.ref.png | Bin 0 -> 2713 bytes test/unbounded-operator.ps3.argb32.ref.png | Bin 0 -> 2713 bytes test/unbounded-operator.rgb24.ref.png | Bin 1315 -> 1341 bytes .../unbounded-operator.test-fallback.rgb24.ref.png | Bin 0 -> 1306 bytes test/unbounded-operator.xlib.rgb24.ref.png | Bin 0 -> 1315 bytes test/user-font-proxy.pdf.argb32.ref.png | Bin 0 -> 16937 bytes test/user-font-proxy.pdf.rgb24.ref.png | Bin 0 -> 16937 bytes test/user-font-proxy.ref.png | Bin 18121 -> 16937 bytes test/user-font-proxy.svg11.argb32.ref.png | Bin 0 -> 16836 bytes test/user-font-proxy.svg11.rgb24.ref.png | Bin 0 -> 16836 bytes test/user-font-proxy.svg12.argb32.ref.png | Bin 0 -> 16836 bytes test/user-font-proxy.svg12.rgb24.ref.png | Bin 0 -> 16836 bytes test/user-font-proxy.test-fallback.argb32.ref.png | Bin 0 -> 16835 bytes test/user-font-proxy.test-fallback.rgb24.ref.png | Bin 0 -> 16835 bytes test/user-font-proxy.xlib.ref.png | Bin 0 -> 18121 bytes test/user-font.ref.png | Bin 6183 -> 6082 bytes test/user-font.svg11.argb32.ref.png | Bin 0 -> 6411 bytes test/user-font.svg11.rgb24.ref.png | Bin 0 -> 6411 bytes test/user-font.svg12.argb32.ref.png | Bin 0 -> 6411 bytes test/user-font.svg12.rgb24.ref.png | Bin 0 -> 6411 bytes test/user-font.test-fallback.argb32.ref.png | Bin 0 -> 5601 bytes test/user-font.test-fallback.rgb24.ref.png | Bin 0 -> 5601 bytes test/user-font.xlib.ref.png | Bin 0 -> 6183 bytes 246 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 test/clip-fill-rule.test-fallback.rgb24.ref.png create mode 100644 test/clip-operator.ps3.argb32.ref.png create mode 100644 test/clip-operator.test-fallback.argb32.ref.png create mode 100644 test/clip-operator.test-fallback.rgb24.ref.png create mode 100644 test/clip-operator.xlib-fallback.rgb24.ref.png create mode 100644 test/clip-operator.xlib.ref.png create mode 100644 test/clip-operator.xlib.rgb24.ref.png create mode 100644 test/clip-twice.pdf.argb32.ref.png create mode 100644 test/clipped-group.pdf.argb32.ref.png create mode 100644 test/clipped-group.pdf.rgb24.ref.png create mode 100644 test/degenerate-arc.test-fallback.argb32.ref.png create mode 100644 test/degenerate-arc.test-fallback.rgb24.ref.png create mode 100644 test/degenerate-arc.xlib.ref.png create mode 100644 test/fill-alpha-pattern.ps3.argb32.ref.png create mode 100644 test/fill-alpha-pattern.ps3.rgb24.ref.png create mode 100644 test/fill-alpha-pattern.test-fallback.argb32.ref.png create mode 100644 test/fill-alpha-pattern.test-fallback.rgb24.ref.png create mode 100644 test/fill-alpha-pattern.xlib.ref.png create mode 100644 test/fill-alpha.test-fallback.argb32.ref.png create mode 100644 test/fill-alpha.test-fallback.rgb24.ref.png create mode 100644 test/fill-alpha.xlib.ref.png create mode 100644 test/fill-degenerate-sort-order.test-fallback.argb32.ref.png create mode 100644 test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png create mode 100644 test/fill-degenerate-sort-order.xlib.ref.png create mode 100644 test/fill-degenerate-sort-order.xlib.rgb24.ref.png create mode 100644 test/fill-missed-stop.pdf.argb32.ref.png create mode 100644 test/fill-rule.test-fallback.argb32.ref.png create mode 100644 test/fill-rule.test-fallback.rgb24.ref.png create mode 100644 test/fill-rule.xlib.ref.png create mode 100644 test/fill-rule.xlib.rgb24.ref.png create mode 100644 test/finer-grained-fallbacks.ps2.argb32.ref.png create mode 100644 test/finer-grained-fallbacks.ps3.argb32.ref.png create mode 100644 test/finer-grained-fallbacks.test-fallback.argb32.ref.png create mode 100644 test/finer-grained-fallbacks.test-fallback.rgb24.ref.png create mode 100644 test/finer-grained-fallbacks.xlib.ref.png create mode 100644 test/finer-grained-fallbacks.xlib.rgb24.ref.png create mode 100644 test/font-matrix-translation.svg11.argb32.ref.png create mode 100644 test/font-matrix-translation.svg11.rgb24.ref.png create mode 100644 test/font-matrix-translation.svg12.argb32.ref.png create mode 100644 test/font-matrix-translation.svg12.rgb24.ref.png create mode 100644 test/ft-show-glyphs-table.svg11.argb32.ref.png create mode 100644 test/ft-show-glyphs-table.svg11.rgb24.ref.png create mode 100644 test/ft-show-glyphs-table.svg12.argb32.ref.png create mode 100644 test/ft-show-glyphs-table.svg12.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type1.pdf.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type1.svg11.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type1.svg12.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type1.xlib.ref.png create mode 100644 test/ft-text-vertical-layout-type3.pdf.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type3.svg11.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type3.svg12.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png create mode 100644 test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png create mode 100644 test/ft-text-vertical-layout-type3.xlib.ref.png create mode 100644 test/huge-pattern.pdf.argb32.ref.png create mode 100644 test/linear-gradient.pdf.argb32.ref.png create mode 100644 test/linear-gradient.pdf.rgb24.ref.png create mode 100644 test/linear-gradient.svg11.argb32.ref.png create mode 100644 test/linear-gradient.svg11.rgb24.ref.png create mode 100644 test/linear-gradient.svg12.argb32.ref.png create mode 100644 test/linear-gradient.svg12.rgb24.ref.png create mode 100644 test/linear-gradient.test-fallback.argb32.ref.png create mode 100644 test/linear-gradient.test-fallback.rgb24.ref.png create mode 100644 test/linear-gradient.xlib.ref.png create mode 100644 test/mask-alpha.svg11.rgb24.ref.png create mode 100644 test/mask-alpha.svg12.rgb24.ref.png create mode 100644 test/mask-alpha.test-fallback.argb32.ref.png create mode 100644 test/mask-alpha.xlib.ref.png create mode 100644 test/mask-alpha.xlib.rgb24.ref.png create mode 100644 test/mask.test-fallback.argb32.ref.png create mode 100644 test/mask.test-fallback.rgb24.ref.png create mode 100644 test/mask.xlib-fallback.rgb24.ref.png create mode 100644 test/mask.xlib.ref.png create mode 100644 test/mask.xlib.rgb24.ref.png create mode 100644 test/meta-surface-pattern.pdf.argb32.ref.png create mode 100644 test/operator-clear.ps2.argb32.ref.png create mode 100644 test/operator-clear.ps3.argb32.ref.png create mode 100644 test/operator-source.test-fallback.argb32.ref.png create mode 100644 test/operator-source.test-fallback.rgb24.ref.png create mode 100644 test/operator-source.xlib-fallback.rgb24.ref.png create mode 100644 test/operator-source.xlib.ref.png create mode 100644 test/operator-source.xlib.rgb24.ref.png create mode 100644 test/over-above-source.test-fallback.argb32.ref.png create mode 100644 test/over-above-source.test-fallback.rgb24.ref.png create mode 100644 test/over-above-source.xlib.ref.png create mode 100644 test/over-above-source.xlib.rgb24.ref.png create mode 100644 test/over-around-source.pdf.argb32.ref.png create mode 100644 test/over-around-source.test-fallback.argb32.ref.png create mode 100644 test/over-around-source.xlib.ref.png create mode 100644 test/over-around-source.xlib.rgb24.ref.png create mode 100644 test/over-below-source.pdf.argb32.ref.png create mode 100644 test/over-between-source.test-fallback.argb32.ref.png create mode 100644 test/over-between-source.xlib.ref.png create mode 100644 test/over-between-source.xlib.rgb24.ref.png create mode 100644 test/push-group.pdf.argb32.ref.png create mode 100644 test/push-group.test-fallback.argb32.ref.png create mode 100644 test/push-group.test-fallback.rgb24.ref.png create mode 100644 test/push-group.xlib-fallback.rgb24.ref.png create mode 100644 test/push-group.xlib.ref.png create mode 100644 test/push-group.xlib.rgb24.ref.png create mode 100644 test/radial-gradient.pdf.argb32.ref.png create mode 100644 test/radial-gradient.pdf.rgb24.ref.png create mode 100644 test/random-intersections.test-fallback.argb32.ref.png create mode 100644 test/random-intersections.test-fallback.rgb24.ref.png create mode 100644 test/random-intersections.xlib.ref.png create mode 100644 test/smask-fill.pdf.argb32.ref.png create mode 100644 test/smask-fill.pdf.rgb24.ref.png create mode 100644 test/smask-fill.svg11.argb32.ref.png create mode 100644 test/smask-fill.svg11.rgb24.ref.png create mode 100644 test/smask-fill.svg12.argb32.ref.png create mode 100644 test/smask-fill.svg12.rgb24.ref.png create mode 100644 test/smask-fill.test-fallback.argb32.ref.png create mode 100644 test/smask-fill.test-fallback.rgb24.ref.png create mode 100644 test/smask-fill.xlib-fallback.ref.png create mode 100644 test/smask-fill.xlib.ref.png create mode 100644 test/smask-image-mask.pdf.argb32.ref.png create mode 100644 test/smask-image-mask.pdf.rgb24.ref.png create mode 100644 test/smask-mask.pdf.argb32.ref.png create mode 100644 test/smask-mask.pdf.rgb24.ref.png create mode 100644 test/smask-paint.pdf.argb32.ref.png create mode 100644 test/smask-paint.pdf.rgb24.ref.png create mode 100644 test/smask-stroke.pdf.argb32.ref.png create mode 100644 test/smask-stroke.pdf.rgb24.ref.png create mode 100644 test/smask-text.svg11.argb32.ref.png create mode 100644 test/smask-text.svg11.rgb24.ref.png create mode 100644 test/smask-text.svg12.argb32.ref.png create mode 100644 test/smask-text.svg12.rgb24.ref.png create mode 100644 test/smask.pdf.argb32.ref.png create mode 100644 test/smask.pdf.rgb24.ref.png create mode 100644 test/text-rotate.svg11.argb32.ref.png create mode 100644 test/text-rotate.svg11.rgb24.ref.png create mode 100644 test/text-rotate.svg12.argb32.ref.png create mode 100644 test/text-rotate.svg12.rgb24.ref.png create mode 100644 test/text-transform.svg11.argb32.ref.png create mode 100644 test/text-transform.svg11.rgb24.ref.png create mode 100644 test/text-transform.svg12.argb32.ref.png create mode 100644 test/text-transform.svg12.rgb24.ref.png create mode 100644 test/trap-clip.test-fallback.argb32.ref.png create mode 100644 test/trap-clip.test-fallback.rgb24.ref.png create mode 100644 test/trap-clip.xlib.ref.png create mode 100644 test/trap-clip.xlib.rgb24.ref.png create mode 100644 test/twin.svg11.argb32.ref.png create mode 100644 test/twin.svg11.rgb24.ref.png create mode 100644 test/twin.svg12.argb32.ref.png create mode 100644 test/twin.svg12.rgb24.ref.png create mode 100644 test/unbounded-operator.pdf.argb32.ref.png create mode 100644 test/unbounded-operator.ps2.argb32.ref.png create mode 100644 test/unbounded-operator.ps3.argb32.ref.png create mode 100644 test/unbounded-operator.test-fallback.rgb24.ref.png create mode 100644 test/unbounded-operator.xlib.rgb24.ref.png create mode 100644 test/user-font-proxy.pdf.argb32.ref.png create mode 100644 test/user-font-proxy.pdf.rgb24.ref.png create mode 100644 test/user-font-proxy.svg11.argb32.ref.png create mode 100644 test/user-font-proxy.svg11.rgb24.ref.png create mode 100644 test/user-font-proxy.svg12.argb32.ref.png create mode 100644 test/user-font-proxy.svg12.rgb24.ref.png create mode 100644 test/user-font-proxy.test-fallback.argb32.ref.png create mode 100644 test/user-font-proxy.test-fallback.rgb24.ref.png create mode 100644 test/user-font-proxy.xlib.ref.png create mode 100644 test/user-font.svg11.argb32.ref.png create mode 100644 test/user-font.svg11.rgb24.ref.png create mode 100644 test/user-font.svg12.argb32.ref.png create mode 100644 test/user-font.svg12.rgb24.ref.png create mode 100644 test/user-font.test-fallback.argb32.ref.png create mode 100644 test/user-font.test-fallback.rgb24.ref.png create mode 100644 test/user-font.xlib.ref.png diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index 8e6e2687..88975e9a 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -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, @@ -886,8 +933,45 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, 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); diff --git a/test/clip-fill-rule.test-fallback.rgb24.ref.png b/test/clip-fill-rule.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..d21472dc Binary files /dev/null and b/test/clip-fill-rule.test-fallback.rgb24.ref.png differ diff --git a/test/clip-operator.pdf.argb32.ref.png b/test/clip-operator.pdf.argb32.ref.png index b3ee1437..4bf79c4c 100644 Binary files a/test/clip-operator.pdf.argb32.ref.png and b/test/clip-operator.pdf.argb32.ref.png differ diff --git a/test/clip-operator.pdf.rgb24.ref.png b/test/clip-operator.pdf.rgb24.ref.png index b420f385..6590dd88 100644 Binary files a/test/clip-operator.pdf.rgb24.ref.png and b/test/clip-operator.pdf.rgb24.ref.png differ diff --git a/test/clip-operator.ps2.rgb24.ref.png b/test/clip-operator.ps2.rgb24.ref.png index 6ed9fc45..52452993 100644 Binary files a/test/clip-operator.ps2.rgb24.ref.png and b/test/clip-operator.ps2.rgb24.ref.png differ diff --git a/test/clip-operator.ps3.argb32.ref.png b/test/clip-operator.ps3.argb32.ref.png new file mode 100644 index 00000000..638831ce Binary files /dev/null and b/test/clip-operator.ps3.argb32.ref.png differ diff --git a/test/clip-operator.ps3.rgb24.ref.png b/test/clip-operator.ps3.rgb24.ref.png index 6ed9fc45..52452993 100644 Binary files a/test/clip-operator.ps3.rgb24.ref.png and b/test/clip-operator.ps3.rgb24.ref.png differ diff --git a/test/clip-operator.ref.png b/test/clip-operator.ref.png index 4ea1842e..22e080a2 100644 Binary files a/test/clip-operator.ref.png and b/test/clip-operator.ref.png differ diff --git a/test/clip-operator.rgb24.ref.png b/test/clip-operator.rgb24.ref.png index 7ab964c3..0a4d4c09 100644 Binary files a/test/clip-operator.rgb24.ref.png and b/test/clip-operator.rgb24.ref.png differ diff --git a/test/clip-operator.test-fallback.argb32.ref.png b/test/clip-operator.test-fallback.argb32.ref.png new file mode 100644 index 00000000..f53e4921 Binary files /dev/null and b/test/clip-operator.test-fallback.argb32.ref.png differ diff --git a/test/clip-operator.test-fallback.rgb24.ref.png b/test/clip-operator.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..7579ae69 Binary files /dev/null and b/test/clip-operator.test-fallback.rgb24.ref.png differ diff --git a/test/clip-operator.xlib-fallback.rgb24.ref.png b/test/clip-operator.xlib-fallback.rgb24.ref.png new file mode 100644 index 00000000..4a05f7ba Binary files /dev/null and b/test/clip-operator.xlib-fallback.rgb24.ref.png differ diff --git a/test/clip-operator.xlib.ref.png b/test/clip-operator.xlib.ref.png new file mode 100644 index 00000000..4ea1842e Binary files /dev/null and b/test/clip-operator.xlib.ref.png differ diff --git a/test/clip-operator.xlib.rgb24.ref.png b/test/clip-operator.xlib.rgb24.ref.png new file mode 100644 index 00000000..7ab964c3 Binary files /dev/null and b/test/clip-operator.xlib.rgb24.ref.png differ diff --git a/test/clip-twice.pdf.argb32.ref.png b/test/clip-twice.pdf.argb32.ref.png new file mode 100644 index 00000000..589dfc97 Binary files /dev/null and b/test/clip-twice.pdf.argb32.ref.png differ diff --git a/test/clipped-group.pdf.argb32.ref.png b/test/clipped-group.pdf.argb32.ref.png new file mode 100644 index 00000000..b9975e12 Binary files /dev/null and b/test/clipped-group.pdf.argb32.ref.png differ diff --git a/test/clipped-group.pdf.rgb24.ref.png b/test/clipped-group.pdf.rgb24.ref.png new file mode 100644 index 00000000..b9975e12 Binary files /dev/null and b/test/clipped-group.pdf.rgb24.ref.png differ diff --git a/test/degenerate-arc.ref.png b/test/degenerate-arc.ref.png index 5112d7f9..1d131b22 100644 Binary files a/test/degenerate-arc.ref.png and b/test/degenerate-arc.ref.png differ diff --git a/test/degenerate-arc.test-fallback.argb32.ref.png b/test/degenerate-arc.test-fallback.argb32.ref.png new file mode 100644 index 00000000..73d41afa Binary files /dev/null and b/test/degenerate-arc.test-fallback.argb32.ref.png differ diff --git a/test/degenerate-arc.test-fallback.rgb24.ref.png b/test/degenerate-arc.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..73d41afa Binary files /dev/null and b/test/degenerate-arc.test-fallback.rgb24.ref.png differ diff --git a/test/degenerate-arc.xlib.ref.png b/test/degenerate-arc.xlib.ref.png new file mode 100644 index 00000000..5112d7f9 Binary files /dev/null and b/test/degenerate-arc.xlib.ref.png differ diff --git a/test/fill-alpha-pattern.pdf.argb32.ref.png b/test/fill-alpha-pattern.pdf.argb32.ref.png index d786c86a..d7a7ebe5 100644 Binary files a/test/fill-alpha-pattern.pdf.argb32.ref.png and b/test/fill-alpha-pattern.pdf.argb32.ref.png differ diff --git a/test/fill-alpha-pattern.pdf.rgb24.ref.png b/test/fill-alpha-pattern.pdf.rgb24.ref.png index 75e580fb..ef9049e2 100644 Binary files a/test/fill-alpha-pattern.pdf.rgb24.ref.png and b/test/fill-alpha-pattern.pdf.rgb24.ref.png differ diff --git a/test/fill-alpha-pattern.ps3.argb32.ref.png b/test/fill-alpha-pattern.ps3.argb32.ref.png new file mode 100644 index 00000000..b16731af Binary files /dev/null and b/test/fill-alpha-pattern.ps3.argb32.ref.png differ diff --git a/test/fill-alpha-pattern.ps3.rgb24.ref.png b/test/fill-alpha-pattern.ps3.rgb24.ref.png new file mode 100644 index 00000000..d0193545 Binary files /dev/null and b/test/fill-alpha-pattern.ps3.rgb24.ref.png differ diff --git a/test/fill-alpha-pattern.ref.png b/test/fill-alpha-pattern.ref.png index 0031c04c..9ab39a7d 100644 Binary files a/test/fill-alpha-pattern.ref.png and b/test/fill-alpha-pattern.ref.png differ diff --git a/test/fill-alpha-pattern.test-fallback.argb32.ref.png b/test/fill-alpha-pattern.test-fallback.argb32.ref.png new file mode 100644 index 00000000..4dafb835 Binary files /dev/null and b/test/fill-alpha-pattern.test-fallback.argb32.ref.png differ diff --git a/test/fill-alpha-pattern.test-fallback.rgb24.ref.png b/test/fill-alpha-pattern.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..4dafb835 Binary files /dev/null and b/test/fill-alpha-pattern.test-fallback.rgb24.ref.png differ diff --git a/test/fill-alpha-pattern.xlib.ref.png b/test/fill-alpha-pattern.xlib.ref.png new file mode 100644 index 00000000..0031c04c Binary files /dev/null and b/test/fill-alpha-pattern.xlib.ref.png differ diff --git a/test/fill-alpha.ref.png b/test/fill-alpha.ref.png index 61aaac29..b50a456d 100644 Binary files a/test/fill-alpha.ref.png and b/test/fill-alpha.ref.png differ diff --git a/test/fill-alpha.test-fallback.argb32.ref.png b/test/fill-alpha.test-fallback.argb32.ref.png new file mode 100644 index 00000000..85df9198 Binary files /dev/null and b/test/fill-alpha.test-fallback.argb32.ref.png differ diff --git a/test/fill-alpha.test-fallback.rgb24.ref.png b/test/fill-alpha.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..85df9198 Binary files /dev/null and b/test/fill-alpha.test-fallback.rgb24.ref.png differ diff --git a/test/fill-alpha.xlib.ref.png b/test/fill-alpha.xlib.ref.png new file mode 100644 index 00000000..61aaac29 Binary files /dev/null and b/test/fill-alpha.xlib.ref.png differ diff --git a/test/fill-degenerate-sort-order.ref.png b/test/fill-degenerate-sort-order.ref.png index 8278d76e..3a95c257 100644 Binary files a/test/fill-degenerate-sort-order.ref.png and b/test/fill-degenerate-sort-order.ref.png differ diff --git a/test/fill-degenerate-sort-order.rgb24.ref.png b/test/fill-degenerate-sort-order.rgb24.ref.png index 6c76eaf4..377c7087 100644 Binary files a/test/fill-degenerate-sort-order.rgb24.ref.png and b/test/fill-degenerate-sort-order.rgb24.ref.png differ diff --git a/test/fill-degenerate-sort-order.test-fallback.argb32.ref.png b/test/fill-degenerate-sort-order.test-fallback.argb32.ref.png new file mode 100644 index 00000000..8cf567dd Binary files /dev/null and b/test/fill-degenerate-sort-order.test-fallback.argb32.ref.png differ diff --git a/test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png b/test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..da5aa50a Binary files /dev/null and b/test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png differ diff --git a/test/fill-degenerate-sort-order.xlib.ref.png b/test/fill-degenerate-sort-order.xlib.ref.png new file mode 100644 index 00000000..8278d76e Binary files /dev/null and b/test/fill-degenerate-sort-order.xlib.ref.png differ diff --git a/test/fill-degenerate-sort-order.xlib.rgb24.ref.png b/test/fill-degenerate-sort-order.xlib.rgb24.ref.png new file mode 100644 index 00000000..6c76eaf4 Binary files /dev/null and b/test/fill-degenerate-sort-order.xlib.rgb24.ref.png differ diff --git a/test/fill-missed-stop.pdf.argb32.ref.png b/test/fill-missed-stop.pdf.argb32.ref.png new file mode 100644 index 00000000..7d56e3e8 Binary files /dev/null and b/test/fill-missed-stop.pdf.argb32.ref.png differ diff --git a/test/fill-rule.ref.png b/test/fill-rule.ref.png index e2e10d4a..6e19b621 100644 Binary files a/test/fill-rule.ref.png and b/test/fill-rule.ref.png differ diff --git a/test/fill-rule.rgb24.ref.png b/test/fill-rule.rgb24.ref.png index 68d2b9b8..bdfc12f4 100644 Binary files a/test/fill-rule.rgb24.ref.png and b/test/fill-rule.rgb24.ref.png differ diff --git a/test/fill-rule.test-fallback.argb32.ref.png b/test/fill-rule.test-fallback.argb32.ref.png new file mode 100644 index 00000000..e2e10d4a Binary files /dev/null and b/test/fill-rule.test-fallback.argb32.ref.png differ diff --git a/test/fill-rule.test-fallback.rgb24.ref.png b/test/fill-rule.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..49fb39c7 Binary files /dev/null and b/test/fill-rule.test-fallback.rgb24.ref.png differ diff --git a/test/fill-rule.xlib.ref.png b/test/fill-rule.xlib.ref.png new file mode 100644 index 00000000..e2e10d4a Binary files /dev/null and b/test/fill-rule.xlib.ref.png differ diff --git a/test/fill-rule.xlib.rgb24.ref.png b/test/fill-rule.xlib.rgb24.ref.png new file mode 100644 index 00000000..68d2b9b8 Binary files /dev/null and b/test/fill-rule.xlib.rgb24.ref.png differ diff --git a/test/finer-grained-fallbacks.ps2.argb32.ref.png b/test/finer-grained-fallbacks.ps2.argb32.ref.png new file mode 100644 index 00000000..92cd9517 Binary files /dev/null and b/test/finer-grained-fallbacks.ps2.argb32.ref.png differ diff --git a/test/finer-grained-fallbacks.ps2.rgb24.ref.png b/test/finer-grained-fallbacks.ps2.rgb24.ref.png index de482860..688c3e06 100644 Binary files a/test/finer-grained-fallbacks.ps2.rgb24.ref.png and b/test/finer-grained-fallbacks.ps2.rgb24.ref.png differ diff --git a/test/finer-grained-fallbacks.ps3.argb32.ref.png b/test/finer-grained-fallbacks.ps3.argb32.ref.png new file mode 100644 index 00000000..92cd9517 Binary files /dev/null and b/test/finer-grained-fallbacks.ps3.argb32.ref.png differ diff --git a/test/finer-grained-fallbacks.ps3.rgb24.ref.png b/test/finer-grained-fallbacks.ps3.rgb24.ref.png index de482860..688c3e06 100644 Binary files a/test/finer-grained-fallbacks.ps3.rgb24.ref.png and b/test/finer-grained-fallbacks.ps3.rgb24.ref.png differ diff --git a/test/finer-grained-fallbacks.ref.png b/test/finer-grained-fallbacks.ref.png index c7eb113d..5b1e532b 100644 Binary files a/test/finer-grained-fallbacks.ref.png and b/test/finer-grained-fallbacks.ref.png differ diff --git a/test/finer-grained-fallbacks.rgb24.ref.png b/test/finer-grained-fallbacks.rgb24.ref.png index 3b8e9c38..d3997fe1 100644 Binary files a/test/finer-grained-fallbacks.rgb24.ref.png and b/test/finer-grained-fallbacks.rgb24.ref.png differ diff --git a/test/finer-grained-fallbacks.test-fallback.argb32.ref.png b/test/finer-grained-fallbacks.test-fallback.argb32.ref.png new file mode 100644 index 00000000..c7eb113d Binary files /dev/null and b/test/finer-grained-fallbacks.test-fallback.argb32.ref.png differ diff --git a/test/finer-grained-fallbacks.test-fallback.rgb24.ref.png b/test/finer-grained-fallbacks.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..ff75c6dd Binary files /dev/null and b/test/finer-grained-fallbacks.test-fallback.rgb24.ref.png differ diff --git a/test/finer-grained-fallbacks.xlib.ref.png b/test/finer-grained-fallbacks.xlib.ref.png new file mode 100644 index 00000000..c7eb113d Binary files /dev/null and b/test/finer-grained-fallbacks.xlib.ref.png differ diff --git a/test/finer-grained-fallbacks.xlib.rgb24.ref.png b/test/finer-grained-fallbacks.xlib.rgb24.ref.png new file mode 100644 index 00000000..3b8e9c38 Binary files /dev/null and b/test/finer-grained-fallbacks.xlib.rgb24.ref.png differ diff --git a/test/font-matrix-translation.svg11.argb32.ref.png b/test/font-matrix-translation.svg11.argb32.ref.png new file mode 100644 index 00000000..441f6e3b Binary files /dev/null and b/test/font-matrix-translation.svg11.argb32.ref.png differ diff --git a/test/font-matrix-translation.svg11.rgb24.ref.png b/test/font-matrix-translation.svg11.rgb24.ref.png new file mode 100644 index 00000000..441f6e3b Binary files /dev/null and b/test/font-matrix-translation.svg11.rgb24.ref.png differ diff --git a/test/font-matrix-translation.svg12.argb32.ref.png b/test/font-matrix-translation.svg12.argb32.ref.png new file mode 100644 index 00000000..441f6e3b Binary files /dev/null and b/test/font-matrix-translation.svg12.argb32.ref.png differ diff --git a/test/font-matrix-translation.svg12.rgb24.ref.png b/test/font-matrix-translation.svg12.rgb24.ref.png new file mode 100644 index 00000000..441f6e3b Binary files /dev/null and b/test/font-matrix-translation.svg12.rgb24.ref.png differ diff --git a/test/ft-show-glyphs-table.svg11.argb32.ref.png b/test/ft-show-glyphs-table.svg11.argb32.ref.png new file mode 100644 index 00000000..0c6e1c0b Binary files /dev/null and b/test/ft-show-glyphs-table.svg11.argb32.ref.png differ diff --git a/test/ft-show-glyphs-table.svg11.rgb24.ref.png b/test/ft-show-glyphs-table.svg11.rgb24.ref.png new file mode 100644 index 00000000..0c6e1c0b Binary files /dev/null and b/test/ft-show-glyphs-table.svg11.rgb24.ref.png differ diff --git a/test/ft-show-glyphs-table.svg12.argb32.ref.png b/test/ft-show-glyphs-table.svg12.argb32.ref.png new file mode 100644 index 00000000..0c6e1c0b Binary files /dev/null and b/test/ft-show-glyphs-table.svg12.argb32.ref.png differ diff --git a/test/ft-show-glyphs-table.svg12.rgb24.ref.png b/test/ft-show-glyphs-table.svg12.rgb24.ref.png new file mode 100644 index 00000000..0c6e1c0b Binary files /dev/null and b/test/ft-show-glyphs-table.svg12.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png new file mode 100644 index 00000000..242c3be5 Binary files /dev/null and b/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png new file mode 100644 index 00000000..242c3be5 Binary files /dev/null and b/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.ref.png b/test/ft-text-vertical-layout-type1.ref.png index 2b74aa60..1accc0b3 100644 Binary files a/test/ft-text-vertical-layout-type1.ref.png and b/test/ft-text-vertical-layout-type1.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.svg11.argb32.ref.png b/test/ft-text-vertical-layout-type1.svg11.argb32.ref.png new file mode 100644 index 00000000..2de3f5be Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg11.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png b/test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png new file mode 100644 index 00000000..2de3f5be Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.svg12.argb32.ref.png b/test/ft-text-vertical-layout-type1.svg12.argb32.ref.png new file mode 100644 index 00000000..2de3f5be Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg12.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png b/test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png new file mode 100644 index 00000000..2de3f5be Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png b/test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png new file mode 100644 index 00000000..9eba6bb0 Binary files /dev/null and b/test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png b/test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..9eba6bb0 Binary files /dev/null and b/test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type1.xlib.ref.png b/test/ft-text-vertical-layout-type1.xlib.ref.png new file mode 100644 index 00000000..2b74aa60 Binary files /dev/null and b/test/ft-text-vertical-layout-type1.xlib.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png new file mode 100644 index 00000000..f232b9a5 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png new file mode 100644 index 00000000..f232b9a5 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.ref.png b/test/ft-text-vertical-layout-type3.ref.png index 8ec2ebec..6b59c56a 100644 Binary files a/test/ft-text-vertical-layout-type3.ref.png and b/test/ft-text-vertical-layout-type3.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.svg11.argb32.ref.png b/test/ft-text-vertical-layout-type3.svg11.argb32.ref.png new file mode 100644 index 00000000..cfe92681 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg11.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png b/test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png new file mode 100644 index 00000000..cfe92681 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.svg12.argb32.ref.png b/test/ft-text-vertical-layout-type3.svg12.argb32.ref.png new file mode 100644 index 00000000..cfe92681 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg12.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png b/test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png new file mode 100644 index 00000000..cfe92681 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png b/test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png new file mode 100644 index 00000000..e57c0831 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png b/test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..e57c0831 Binary files /dev/null and b/test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png differ diff --git a/test/ft-text-vertical-layout-type3.xlib.ref.png b/test/ft-text-vertical-layout-type3.xlib.ref.png new file mode 100644 index 00000000..8ec2ebec Binary files /dev/null and b/test/ft-text-vertical-layout-type3.xlib.ref.png differ diff --git a/test/huge-pattern.pdf.argb32.ref.png b/test/huge-pattern.pdf.argb32.ref.png new file mode 100644 index 00000000..005d4a65 Binary files /dev/null and b/test/huge-pattern.pdf.argb32.ref.png differ diff --git a/test/linear-gradient.pdf.argb32.ref.png b/test/linear-gradient.pdf.argb32.ref.png new file mode 100644 index 00000000..bddb681c Binary files /dev/null and b/test/linear-gradient.pdf.argb32.ref.png differ diff --git a/test/linear-gradient.pdf.rgb24.ref.png b/test/linear-gradient.pdf.rgb24.ref.png new file mode 100644 index 00000000..bddb681c Binary files /dev/null and b/test/linear-gradient.pdf.rgb24.ref.png differ diff --git a/test/linear-gradient.ref.png b/test/linear-gradient.ref.png index cb8f9089..ee238e6a 100644 Binary files a/test/linear-gradient.ref.png and b/test/linear-gradient.ref.png differ diff --git a/test/linear-gradient.svg11.argb32.ref.png b/test/linear-gradient.svg11.argb32.ref.png new file mode 100644 index 00000000..ea0e7238 Binary files /dev/null and b/test/linear-gradient.svg11.argb32.ref.png differ diff --git a/test/linear-gradient.svg11.rgb24.ref.png b/test/linear-gradient.svg11.rgb24.ref.png new file mode 100644 index 00000000..ea0e7238 Binary files /dev/null and b/test/linear-gradient.svg11.rgb24.ref.png differ diff --git a/test/linear-gradient.svg12.argb32.ref.png b/test/linear-gradient.svg12.argb32.ref.png new file mode 100644 index 00000000..ea0e7238 Binary files /dev/null and b/test/linear-gradient.svg12.argb32.ref.png differ diff --git a/test/linear-gradient.svg12.rgb24.ref.png b/test/linear-gradient.svg12.rgb24.ref.png new file mode 100644 index 00000000..ea0e7238 Binary files /dev/null and b/test/linear-gradient.svg12.rgb24.ref.png differ diff --git a/test/linear-gradient.test-fallback.argb32.ref.png b/test/linear-gradient.test-fallback.argb32.ref.png new file mode 100644 index 00000000..8202880e Binary files /dev/null and b/test/linear-gradient.test-fallback.argb32.ref.png differ diff --git a/test/linear-gradient.test-fallback.rgb24.ref.png b/test/linear-gradient.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..8202880e Binary files /dev/null and b/test/linear-gradient.test-fallback.rgb24.ref.png differ diff --git a/test/linear-gradient.xlib.ref.png b/test/linear-gradient.xlib.ref.png new file mode 100644 index 00000000..cb8f9089 Binary files /dev/null and b/test/linear-gradient.xlib.ref.png differ diff --git a/test/mask-alpha.ref.png b/test/mask-alpha.ref.png index 715a959e..d100da46 100644 Binary files a/test/mask-alpha.ref.png and b/test/mask-alpha.ref.png differ diff --git a/test/mask-alpha.svg11.argb32.ref.png b/test/mask-alpha.svg11.argb32.ref.png index 3e56aa34..fa9e82d1 100644 Binary files a/test/mask-alpha.svg11.argb32.ref.png and b/test/mask-alpha.svg11.argb32.ref.png differ diff --git a/test/mask-alpha.svg11.rgb24.ref.png b/test/mask-alpha.svg11.rgb24.ref.png new file mode 100644 index 00000000..167eab48 Binary files /dev/null and b/test/mask-alpha.svg11.rgb24.ref.png differ diff --git a/test/mask-alpha.svg12.argb32.ref.png b/test/mask-alpha.svg12.argb32.ref.png index 3e56aa34..fa9e82d1 100644 Binary files a/test/mask-alpha.svg12.argb32.ref.png and b/test/mask-alpha.svg12.argb32.ref.png differ diff --git a/test/mask-alpha.svg12.rgb24.ref.png b/test/mask-alpha.svg12.rgb24.ref.png new file mode 100644 index 00000000..167eab48 Binary files /dev/null and b/test/mask-alpha.svg12.rgb24.ref.png differ diff --git a/test/mask-alpha.test-fallback.argb32.ref.png b/test/mask-alpha.test-fallback.argb32.ref.png new file mode 100644 index 00000000..a0b9017e Binary files /dev/null and b/test/mask-alpha.test-fallback.argb32.ref.png differ diff --git a/test/mask-alpha.xlib.ref.png b/test/mask-alpha.xlib.ref.png new file mode 100644 index 00000000..715a959e Binary files /dev/null and b/test/mask-alpha.xlib.ref.png differ diff --git a/test/mask-alpha.xlib.rgb24.ref.png b/test/mask-alpha.xlib.rgb24.ref.png new file mode 100644 index 00000000..aa2010f3 Binary files /dev/null and b/test/mask-alpha.xlib.rgb24.ref.png differ diff --git a/test/mask.pdf.argb32.ref.png b/test/mask.pdf.argb32.ref.png index 4570bff1..d1cc8ff7 100644 Binary files a/test/mask.pdf.argb32.ref.png and b/test/mask.pdf.argb32.ref.png differ diff --git a/test/mask.pdf.rgb24.ref.png b/test/mask.pdf.rgb24.ref.png index 1231965d..a3d3845c 100644 Binary files a/test/mask.pdf.rgb24.ref.png and b/test/mask.pdf.rgb24.ref.png differ diff --git a/test/mask.ref.png b/test/mask.ref.png index 549c130c..f5d30c53 100644 Binary files a/test/mask.ref.png and b/test/mask.ref.png differ diff --git a/test/mask.rgb24.ref.png b/test/mask.rgb24.ref.png index 70323672..34400504 100644 Binary files a/test/mask.rgb24.ref.png and b/test/mask.rgb24.ref.png differ diff --git a/test/mask.svg11.argb32.ref.png b/test/mask.svg11.argb32.ref.png index c5828591..e48e47bf 100644 Binary files a/test/mask.svg11.argb32.ref.png and b/test/mask.svg11.argb32.ref.png differ diff --git a/test/mask.svg11.rgb24.ref.png b/test/mask.svg11.rgb24.ref.png index 79957237..94e38009 100644 Binary files a/test/mask.svg11.rgb24.ref.png and b/test/mask.svg11.rgb24.ref.png differ diff --git a/test/mask.svg12.argb32.ref.png b/test/mask.svg12.argb32.ref.png index c5828591..e48e47bf 100644 Binary files a/test/mask.svg12.argb32.ref.png and b/test/mask.svg12.argb32.ref.png differ diff --git a/test/mask.svg12.rgb24.ref.png b/test/mask.svg12.rgb24.ref.png index 79957237..94e38009 100644 Binary files a/test/mask.svg12.rgb24.ref.png and b/test/mask.svg12.rgb24.ref.png differ diff --git a/test/mask.test-fallback.argb32.ref.png b/test/mask.test-fallback.argb32.ref.png new file mode 100644 index 00000000..bba0f9f3 Binary files /dev/null and b/test/mask.test-fallback.argb32.ref.png differ diff --git a/test/mask.test-fallback.rgb24.ref.png b/test/mask.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..49a5b364 Binary files /dev/null and b/test/mask.test-fallback.rgb24.ref.png differ diff --git a/test/mask.xlib-fallback.rgb24.ref.png b/test/mask.xlib-fallback.rgb24.ref.png new file mode 100644 index 00000000..34400504 Binary files /dev/null and b/test/mask.xlib-fallback.rgb24.ref.png differ diff --git a/test/mask.xlib.ref.png b/test/mask.xlib.ref.png new file mode 100644 index 00000000..549c130c Binary files /dev/null and b/test/mask.xlib.ref.png differ diff --git a/test/mask.xlib.rgb24.ref.png b/test/mask.xlib.rgb24.ref.png new file mode 100644 index 00000000..70323672 Binary files /dev/null and b/test/mask.xlib.rgb24.ref.png differ diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png new file mode 100644 index 00000000..a842b6fa Binary files /dev/null and b/test/meta-surface-pattern.pdf.argb32.ref.png differ diff --git a/test/meta-surface-pattern.pdf.rgb24.ref.png b/test/meta-surface-pattern.pdf.rgb24.ref.png index 680f0f50..6555a265 100644 Binary files a/test/meta-surface-pattern.pdf.rgb24.ref.png and b/test/meta-surface-pattern.pdf.rgb24.ref.png differ diff --git a/test/meta-surface-pattern.svg11.argb32.ref.png b/test/meta-surface-pattern.svg11.argb32.ref.png index 6250f26c..3a6836dc 100644 Binary files a/test/meta-surface-pattern.svg11.argb32.ref.png and b/test/meta-surface-pattern.svg11.argb32.ref.png differ diff --git a/test/meta-surface-pattern.svg11.rgb24.ref.png b/test/meta-surface-pattern.svg11.rgb24.ref.png index feda67da..dea9b9b5 100644 Binary files a/test/meta-surface-pattern.svg11.rgb24.ref.png and b/test/meta-surface-pattern.svg11.rgb24.ref.png differ diff --git a/test/meta-surface-pattern.svg12.argb32.ref.png b/test/meta-surface-pattern.svg12.argb32.ref.png index 6250f26c..3a6836dc 100644 Binary files a/test/meta-surface-pattern.svg12.argb32.ref.png and b/test/meta-surface-pattern.svg12.argb32.ref.png differ diff --git a/test/meta-surface-pattern.svg12.rgb24.ref.png b/test/meta-surface-pattern.svg12.rgb24.ref.png index feda67da..dea9b9b5 100644 Binary files a/test/meta-surface-pattern.svg12.rgb24.ref.png and b/test/meta-surface-pattern.svg12.rgb24.ref.png differ diff --git a/test/operator-clear.pdf.argb32.ref.png b/test/operator-clear.pdf.argb32.ref.png index 06fc51e3..258c61c9 100644 Binary files a/test/operator-clear.pdf.argb32.ref.png and b/test/operator-clear.pdf.argb32.ref.png differ diff --git a/test/operator-clear.ps2.argb32.ref.png b/test/operator-clear.ps2.argb32.ref.png new file mode 100644 index 00000000..92b41111 Binary files /dev/null and b/test/operator-clear.ps2.argb32.ref.png differ diff --git a/test/operator-clear.ps3.argb32.ref.png b/test/operator-clear.ps3.argb32.ref.png new file mode 100644 index 00000000..92b41111 Binary files /dev/null and b/test/operator-clear.ps3.argb32.ref.png differ diff --git a/test/operator-source.pdf.argb32.ref.png b/test/operator-source.pdf.argb32.ref.png index f110ff2a..f42d5af4 100644 Binary files a/test/operator-source.pdf.argb32.ref.png and b/test/operator-source.pdf.argb32.ref.png differ diff --git a/test/operator-source.pdf.rgb24.ref.png b/test/operator-source.pdf.rgb24.ref.png index c6b71705..8269bc10 100644 Binary files a/test/operator-source.pdf.rgb24.ref.png and b/test/operator-source.pdf.rgb24.ref.png differ diff --git a/test/operator-source.ref.png b/test/operator-source.ref.png index 8e2f5e61..006bf950 100644 Binary files a/test/operator-source.ref.png and b/test/operator-source.ref.png differ diff --git a/test/operator-source.rgb24.ref.png b/test/operator-source.rgb24.ref.png index a762d60a..013d8a42 100644 Binary files a/test/operator-source.rgb24.ref.png and b/test/operator-source.rgb24.ref.png differ diff --git a/test/operator-source.test-fallback.argb32.ref.png b/test/operator-source.test-fallback.argb32.ref.png new file mode 100644 index 00000000..8aac39d1 Binary files /dev/null and b/test/operator-source.test-fallback.argb32.ref.png differ diff --git a/test/operator-source.test-fallback.rgb24.ref.png b/test/operator-source.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..ad37a60b Binary files /dev/null and b/test/operator-source.test-fallback.rgb24.ref.png differ diff --git a/test/operator-source.xlib-fallback.rgb24.ref.png b/test/operator-source.xlib-fallback.rgb24.ref.png new file mode 100644 index 00000000..fe0d3c61 Binary files /dev/null and b/test/operator-source.xlib-fallback.rgb24.ref.png differ diff --git a/test/operator-source.xlib.ref.png b/test/operator-source.xlib.ref.png new file mode 100644 index 00000000..8e2f5e61 Binary files /dev/null and b/test/operator-source.xlib.ref.png differ diff --git a/test/operator-source.xlib.rgb24.ref.png b/test/operator-source.xlib.rgb24.ref.png new file mode 100644 index 00000000..a762d60a Binary files /dev/null and b/test/operator-source.xlib.rgb24.ref.png differ diff --git a/test/over-above-source.ps2.argb32.ref.png b/test/over-above-source.ps2.argb32.ref.png index 886faad4..7c90d086 100644 Binary files a/test/over-above-source.ps2.argb32.ref.png and b/test/over-above-source.ps2.argb32.ref.png differ diff --git a/test/over-above-source.ps3.argb32.ref.png b/test/over-above-source.ps3.argb32.ref.png index 886faad4..7c90d086 100644 Binary files a/test/over-above-source.ps3.argb32.ref.png and b/test/over-above-source.ps3.argb32.ref.png differ diff --git a/test/over-above-source.ref.png b/test/over-above-source.ref.png index f3a49f61..c45fcbde 100644 Binary files a/test/over-above-source.ref.png and b/test/over-above-source.ref.png differ diff --git a/test/over-above-source.rgb24.ref.png b/test/over-above-source.rgb24.ref.png index 68c7d982..84fc880c 100644 Binary files a/test/over-above-source.rgb24.ref.png and b/test/over-above-source.rgb24.ref.png differ diff --git a/test/over-above-source.test-fallback.argb32.ref.png b/test/over-above-source.test-fallback.argb32.ref.png new file mode 100644 index 00000000..8a0183a6 Binary files /dev/null and b/test/over-above-source.test-fallback.argb32.ref.png differ diff --git a/test/over-above-source.test-fallback.rgb24.ref.png b/test/over-above-source.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..85c19971 Binary files /dev/null and b/test/over-above-source.test-fallback.rgb24.ref.png differ diff --git a/test/over-above-source.xlib.ref.png b/test/over-above-source.xlib.ref.png new file mode 100644 index 00000000..f3a49f61 Binary files /dev/null and b/test/over-above-source.xlib.ref.png differ diff --git a/test/over-above-source.xlib.rgb24.ref.png b/test/over-above-source.xlib.rgb24.ref.png new file mode 100644 index 00000000..68c7d982 Binary files /dev/null and b/test/over-above-source.xlib.rgb24.ref.png differ diff --git a/test/over-around-source.pdf.argb32.ref.png b/test/over-around-source.pdf.argb32.ref.png new file mode 100644 index 00000000..02af76a9 Binary files /dev/null and b/test/over-around-source.pdf.argb32.ref.png differ diff --git a/test/over-around-source.ps2.argb32.ref.png b/test/over-around-source.ps2.argb32.ref.png index ea6de696..647420ad 100644 Binary files a/test/over-around-source.ps2.argb32.ref.png and b/test/over-around-source.ps2.argb32.ref.png differ diff --git a/test/over-around-source.ps3.argb32.ref.png b/test/over-around-source.ps3.argb32.ref.png index ea6de696..647420ad 100644 Binary files a/test/over-around-source.ps3.argb32.ref.png and b/test/over-around-source.ps3.argb32.ref.png differ diff --git a/test/over-around-source.ref.png b/test/over-around-source.ref.png index ccae9514..abaeb4e4 100644 Binary files a/test/over-around-source.ref.png and b/test/over-around-source.ref.png differ diff --git a/test/over-around-source.test-fallback.argb32.ref.png b/test/over-around-source.test-fallback.argb32.ref.png new file mode 100644 index 00000000..fca75056 Binary files /dev/null and b/test/over-around-source.test-fallback.argb32.ref.png differ diff --git a/test/over-around-source.xlib.ref.png b/test/over-around-source.xlib.ref.png new file mode 100644 index 00000000..ccae9514 Binary files /dev/null and b/test/over-around-source.xlib.ref.png differ diff --git a/test/over-around-source.xlib.rgb24.ref.png b/test/over-around-source.xlib.rgb24.ref.png new file mode 100644 index 00000000..943a28e3 Binary files /dev/null and b/test/over-around-source.xlib.rgb24.ref.png differ diff --git a/test/over-below-source.pdf.argb32.ref.png b/test/over-below-source.pdf.argb32.ref.png new file mode 100644 index 00000000..b9c4fe28 Binary files /dev/null and b/test/over-below-source.pdf.argb32.ref.png differ diff --git a/test/over-between-source.ps2.argb32.ref.png b/test/over-between-source.ps2.argb32.ref.png index 43e9424b..dd95940a 100644 Binary files a/test/over-between-source.ps2.argb32.ref.png and b/test/over-between-source.ps2.argb32.ref.png differ diff --git a/test/over-between-source.ps3.argb32.ref.png b/test/over-between-source.ps3.argb32.ref.png index 43e9424b..dd95940a 100644 Binary files a/test/over-between-source.ps3.argb32.ref.png and b/test/over-between-source.ps3.argb32.ref.png differ diff --git a/test/over-between-source.ref.png b/test/over-between-source.ref.png index 79ea75e9..0c3986fc 100644 Binary files a/test/over-between-source.ref.png and b/test/over-between-source.ref.png differ diff --git a/test/over-between-source.test-fallback.argb32.ref.png b/test/over-between-source.test-fallback.argb32.ref.png new file mode 100644 index 00000000..a8fe66a3 Binary files /dev/null and b/test/over-between-source.test-fallback.argb32.ref.png differ diff --git a/test/over-between-source.xlib.ref.png b/test/over-between-source.xlib.ref.png new file mode 100644 index 00000000..79ea75e9 Binary files /dev/null and b/test/over-between-source.xlib.ref.png differ diff --git a/test/over-between-source.xlib.rgb24.ref.png b/test/over-between-source.xlib.rgb24.ref.png new file mode 100644 index 00000000..602f2d26 Binary files /dev/null and b/test/over-between-source.xlib.rgb24.ref.png differ diff --git a/test/push-group.pdf.argb32.ref.png b/test/push-group.pdf.argb32.ref.png new file mode 100644 index 00000000..9cb59c94 Binary files /dev/null and b/test/push-group.pdf.argb32.ref.png differ diff --git a/test/push-group.pdf.rgb24.ref.png b/test/push-group.pdf.rgb24.ref.png index 7e84ec83..34d7f74e 100644 Binary files a/test/push-group.pdf.rgb24.ref.png and b/test/push-group.pdf.rgb24.ref.png differ diff --git a/test/push-group.ref.png b/test/push-group.ref.png index 84bc184d..e4ae291f 100644 Binary files a/test/push-group.ref.png and b/test/push-group.ref.png differ diff --git a/test/push-group.rgb24.ref.png b/test/push-group.rgb24.ref.png index cababd95..3a951827 100644 Binary files a/test/push-group.rgb24.ref.png and b/test/push-group.rgb24.ref.png differ diff --git a/test/push-group.svg11.argb32.ref.png b/test/push-group.svg11.argb32.ref.png index 34f06bf7..d6958798 100644 Binary files a/test/push-group.svg11.argb32.ref.png and b/test/push-group.svg11.argb32.ref.png differ diff --git a/test/push-group.svg12.argb32.ref.png b/test/push-group.svg12.argb32.ref.png index 34f06bf7..d6958798 100644 Binary files a/test/push-group.svg12.argb32.ref.png and b/test/push-group.svg12.argb32.ref.png differ diff --git a/test/push-group.test-fallback.argb32.ref.png b/test/push-group.test-fallback.argb32.ref.png new file mode 100644 index 00000000..7c5905a6 Binary files /dev/null and b/test/push-group.test-fallback.argb32.ref.png differ diff --git a/test/push-group.test-fallback.rgb24.ref.png b/test/push-group.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..4586d5c5 Binary files /dev/null and b/test/push-group.test-fallback.rgb24.ref.png differ diff --git a/test/push-group.xlib-fallback.rgb24.ref.png b/test/push-group.xlib-fallback.rgb24.ref.png new file mode 100644 index 00000000..3a951827 Binary files /dev/null and b/test/push-group.xlib-fallback.rgb24.ref.png differ diff --git a/test/push-group.xlib.ref.png b/test/push-group.xlib.ref.png new file mode 100644 index 00000000..84bc184d Binary files /dev/null and b/test/push-group.xlib.ref.png differ diff --git a/test/push-group.xlib.rgb24.ref.png b/test/push-group.xlib.rgb24.ref.png new file mode 100644 index 00000000..cababd95 Binary files /dev/null and b/test/push-group.xlib.rgb24.ref.png differ diff --git a/test/radial-gradient.pdf.argb32.ref.png b/test/radial-gradient.pdf.argb32.ref.png new file mode 100644 index 00000000..6cee5d12 Binary files /dev/null and b/test/radial-gradient.pdf.argb32.ref.png differ diff --git a/test/radial-gradient.pdf.rgb24.ref.png b/test/radial-gradient.pdf.rgb24.ref.png new file mode 100644 index 00000000..6cee5d12 Binary files /dev/null and b/test/radial-gradient.pdf.rgb24.ref.png differ diff --git a/test/random-intersections.ref.png b/test/random-intersections.ref.png index 3188edef..ace75a24 100644 Binary files a/test/random-intersections.ref.png and b/test/random-intersections.ref.png differ diff --git a/test/random-intersections.test-fallback.argb32.ref.png b/test/random-intersections.test-fallback.argb32.ref.png new file mode 100644 index 00000000..a35364d8 Binary files /dev/null and b/test/random-intersections.test-fallback.argb32.ref.png differ diff --git a/test/random-intersections.test-fallback.rgb24.ref.png b/test/random-intersections.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..a35364d8 Binary files /dev/null and b/test/random-intersections.test-fallback.rgb24.ref.png differ diff --git a/test/random-intersections.xlib.ref.png b/test/random-intersections.xlib.ref.png new file mode 100644 index 00000000..3188edef Binary files /dev/null and b/test/random-intersections.xlib.ref.png differ diff --git a/test/smask-fill.pdf.argb32.ref.png b/test/smask-fill.pdf.argb32.ref.png new file mode 100644 index 00000000..51d34d43 Binary files /dev/null and b/test/smask-fill.pdf.argb32.ref.png differ diff --git a/test/smask-fill.pdf.rgb24.ref.png b/test/smask-fill.pdf.rgb24.ref.png new file mode 100644 index 00000000..51d34d43 Binary files /dev/null and b/test/smask-fill.pdf.rgb24.ref.png differ diff --git a/test/smask-fill.ref.png b/test/smask-fill.ref.png index c778a791..28ab7338 100644 Binary files a/test/smask-fill.ref.png and b/test/smask-fill.ref.png differ diff --git a/test/smask-fill.svg11.argb32.ref.png b/test/smask-fill.svg11.argb32.ref.png new file mode 100644 index 00000000..57ae76e6 Binary files /dev/null and b/test/smask-fill.svg11.argb32.ref.png differ diff --git a/test/smask-fill.svg11.rgb24.ref.png b/test/smask-fill.svg11.rgb24.ref.png new file mode 100644 index 00000000..57ae76e6 Binary files /dev/null and b/test/smask-fill.svg11.rgb24.ref.png differ diff --git a/test/smask-fill.svg12.argb32.ref.png b/test/smask-fill.svg12.argb32.ref.png new file mode 100644 index 00000000..57ae76e6 Binary files /dev/null and b/test/smask-fill.svg12.argb32.ref.png differ diff --git a/test/smask-fill.svg12.rgb24.ref.png b/test/smask-fill.svg12.rgb24.ref.png new file mode 100644 index 00000000..57ae76e6 Binary files /dev/null and b/test/smask-fill.svg12.rgb24.ref.png differ diff --git a/test/smask-fill.test-fallback.argb32.ref.png b/test/smask-fill.test-fallback.argb32.ref.png new file mode 100644 index 00000000..3d375bba Binary files /dev/null and b/test/smask-fill.test-fallback.argb32.ref.png differ diff --git a/test/smask-fill.test-fallback.rgb24.ref.png b/test/smask-fill.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..3d375bba Binary files /dev/null and b/test/smask-fill.test-fallback.rgb24.ref.png differ diff --git a/test/smask-fill.xlib-fallback.ref.png b/test/smask-fill.xlib-fallback.ref.png new file mode 100644 index 00000000..28ab7338 Binary files /dev/null and b/test/smask-fill.xlib-fallback.ref.png differ diff --git a/test/smask-fill.xlib.ref.png b/test/smask-fill.xlib.ref.png new file mode 100644 index 00000000..c778a791 Binary files /dev/null and b/test/smask-fill.xlib.ref.png differ diff --git a/test/smask-image-mask.pdf.argb32.ref.png b/test/smask-image-mask.pdf.argb32.ref.png new file mode 100644 index 00000000..19a20f48 Binary files /dev/null and b/test/smask-image-mask.pdf.argb32.ref.png differ diff --git a/test/smask-image-mask.pdf.rgb24.ref.png b/test/smask-image-mask.pdf.rgb24.ref.png new file mode 100644 index 00000000..19a20f48 Binary files /dev/null and b/test/smask-image-mask.pdf.rgb24.ref.png differ diff --git a/test/smask-mask.pdf.argb32.ref.png b/test/smask-mask.pdf.argb32.ref.png new file mode 100644 index 00000000..0dc2135d Binary files /dev/null and b/test/smask-mask.pdf.argb32.ref.png differ diff --git a/test/smask-mask.pdf.rgb24.ref.png b/test/smask-mask.pdf.rgb24.ref.png new file mode 100644 index 00000000..0dc2135d Binary files /dev/null and b/test/smask-mask.pdf.rgb24.ref.png differ diff --git a/test/smask-paint.pdf.argb32.ref.png b/test/smask-paint.pdf.argb32.ref.png new file mode 100644 index 00000000..c6b1731f Binary files /dev/null and b/test/smask-paint.pdf.argb32.ref.png differ diff --git a/test/smask-paint.pdf.rgb24.ref.png b/test/smask-paint.pdf.rgb24.ref.png new file mode 100644 index 00000000..c6b1731f Binary files /dev/null and b/test/smask-paint.pdf.rgb24.ref.png differ diff --git a/test/smask-stroke.pdf.argb32.ref.png b/test/smask-stroke.pdf.argb32.ref.png new file mode 100644 index 00000000..41321f23 Binary files /dev/null and b/test/smask-stroke.pdf.argb32.ref.png differ diff --git a/test/smask-stroke.pdf.rgb24.ref.png b/test/smask-stroke.pdf.rgb24.ref.png new file mode 100644 index 00000000..41321f23 Binary files /dev/null and b/test/smask-stroke.pdf.rgb24.ref.png differ diff --git a/test/smask-text.svg11.argb32.ref.png b/test/smask-text.svg11.argb32.ref.png new file mode 100644 index 00000000..5034526a Binary files /dev/null and b/test/smask-text.svg11.argb32.ref.png differ diff --git a/test/smask-text.svg11.rgb24.ref.png b/test/smask-text.svg11.rgb24.ref.png new file mode 100644 index 00000000..5034526a Binary files /dev/null and b/test/smask-text.svg11.rgb24.ref.png differ diff --git a/test/smask-text.svg12.argb32.ref.png b/test/smask-text.svg12.argb32.ref.png new file mode 100644 index 00000000..5034526a Binary files /dev/null and b/test/smask-text.svg12.argb32.ref.png differ diff --git a/test/smask-text.svg12.rgb24.ref.png b/test/smask-text.svg12.rgb24.ref.png new file mode 100644 index 00000000..5034526a Binary files /dev/null and b/test/smask-text.svg12.rgb24.ref.png differ diff --git a/test/smask.pdf.argb32.ref.png b/test/smask.pdf.argb32.ref.png new file mode 100644 index 00000000..c6b1731f Binary files /dev/null and b/test/smask.pdf.argb32.ref.png differ diff --git a/test/smask.pdf.rgb24.ref.png b/test/smask.pdf.rgb24.ref.png new file mode 100644 index 00000000..c6b1731f Binary files /dev/null and b/test/smask.pdf.rgb24.ref.png differ diff --git a/test/text-pattern.pdf.argb32.ref.png b/test/text-pattern.pdf.argb32.ref.png index 2a70deb0..dfaed39f 100644 Binary files a/test/text-pattern.pdf.argb32.ref.png and b/test/text-pattern.pdf.argb32.ref.png differ diff --git a/test/text-pattern.svg11.argb32.ref.png b/test/text-pattern.svg11.argb32.ref.png index 97d7534c..47ee89c2 100644 Binary files a/test/text-pattern.svg11.argb32.ref.png and b/test/text-pattern.svg11.argb32.ref.png differ diff --git a/test/text-pattern.svg12.argb32.ref.png b/test/text-pattern.svg12.argb32.ref.png index 97d7534c..47ee89c2 100644 Binary files a/test/text-pattern.svg12.argb32.ref.png and b/test/text-pattern.svg12.argb32.ref.png differ diff --git a/test/text-rotate.svg11.argb32.ref.png b/test/text-rotate.svg11.argb32.ref.png new file mode 100644 index 00000000..4864046f Binary files /dev/null and b/test/text-rotate.svg11.argb32.ref.png differ diff --git a/test/text-rotate.svg11.rgb24.ref.png b/test/text-rotate.svg11.rgb24.ref.png new file mode 100644 index 00000000..4864046f Binary files /dev/null and b/test/text-rotate.svg11.rgb24.ref.png differ diff --git a/test/text-rotate.svg12.argb32.ref.png b/test/text-rotate.svg12.argb32.ref.png new file mode 100644 index 00000000..4864046f Binary files /dev/null and b/test/text-rotate.svg12.argb32.ref.png differ diff --git a/test/text-rotate.svg12.rgb24.ref.png b/test/text-rotate.svg12.rgb24.ref.png new file mode 100644 index 00000000..4864046f Binary files /dev/null and b/test/text-rotate.svg12.rgb24.ref.png differ diff --git a/test/text-transform.svg11.argb32.ref.png b/test/text-transform.svg11.argb32.ref.png new file mode 100644 index 00000000..0c4e57cc Binary files /dev/null and b/test/text-transform.svg11.argb32.ref.png differ diff --git a/test/text-transform.svg11.rgb24.ref.png b/test/text-transform.svg11.rgb24.ref.png new file mode 100644 index 00000000..0c4e57cc Binary files /dev/null and b/test/text-transform.svg11.rgb24.ref.png differ diff --git a/test/text-transform.svg12.argb32.ref.png b/test/text-transform.svg12.argb32.ref.png new file mode 100644 index 00000000..0c4e57cc Binary files /dev/null and b/test/text-transform.svg12.argb32.ref.png differ diff --git a/test/text-transform.svg12.rgb24.ref.png b/test/text-transform.svg12.rgb24.ref.png new file mode 100644 index 00000000..0c4e57cc Binary files /dev/null and b/test/text-transform.svg12.rgb24.ref.png differ diff --git a/test/trap-clip.pdf.argb32.ref.png b/test/trap-clip.pdf.argb32.ref.png index c3ee9971..15010164 100644 Binary files a/test/trap-clip.pdf.argb32.ref.png and b/test/trap-clip.pdf.argb32.ref.png differ diff --git a/test/trap-clip.pdf.rgb24.ref.png b/test/trap-clip.pdf.rgb24.ref.png index f787011c..90b476b5 100644 Binary files a/test/trap-clip.pdf.rgb24.ref.png and b/test/trap-clip.pdf.rgb24.ref.png differ diff --git a/test/trap-clip.ps2.argb32.ref.png b/test/trap-clip.ps2.argb32.ref.png index 37121cde..957b9382 100644 Binary files a/test/trap-clip.ps2.argb32.ref.png and b/test/trap-clip.ps2.argb32.ref.png differ diff --git a/test/trap-clip.ref.png b/test/trap-clip.ref.png index 2cbbdb76..dee57e7b 100644 Binary files a/test/trap-clip.ref.png and b/test/trap-clip.ref.png differ diff --git a/test/trap-clip.rgb24.ref.png b/test/trap-clip.rgb24.ref.png index 15068aa5..e61992ff 100644 Binary files a/test/trap-clip.rgb24.ref.png and b/test/trap-clip.rgb24.ref.png differ diff --git a/test/trap-clip.test-fallback.argb32.ref.png b/test/trap-clip.test-fallback.argb32.ref.png new file mode 100644 index 00000000..319d8356 Binary files /dev/null and b/test/trap-clip.test-fallback.argb32.ref.png differ diff --git a/test/trap-clip.test-fallback.rgb24.ref.png b/test/trap-clip.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..7ac5789b Binary files /dev/null and b/test/trap-clip.test-fallback.rgb24.ref.png differ diff --git a/test/trap-clip.xlib.ref.png b/test/trap-clip.xlib.ref.png new file mode 100644 index 00000000..2cbbdb76 Binary files /dev/null and b/test/trap-clip.xlib.ref.png differ diff --git a/test/trap-clip.xlib.rgb24.ref.png b/test/trap-clip.xlib.rgb24.ref.png new file mode 100644 index 00000000..15068aa5 Binary files /dev/null and b/test/trap-clip.xlib.rgb24.ref.png differ diff --git a/test/twin.svg11.argb32.ref.png b/test/twin.svg11.argb32.ref.png new file mode 100644 index 00000000..0818c67c Binary files /dev/null and b/test/twin.svg11.argb32.ref.png differ diff --git a/test/twin.svg11.rgb24.ref.png b/test/twin.svg11.rgb24.ref.png new file mode 100644 index 00000000..0818c67c Binary files /dev/null and b/test/twin.svg11.rgb24.ref.png differ diff --git a/test/twin.svg12.argb32.ref.png b/test/twin.svg12.argb32.ref.png new file mode 100644 index 00000000..0818c67c Binary files /dev/null and b/test/twin.svg12.argb32.ref.png differ diff --git a/test/twin.svg12.rgb24.ref.png b/test/twin.svg12.rgb24.ref.png new file mode 100644 index 00000000..0818c67c Binary files /dev/null and b/test/twin.svg12.rgb24.ref.png differ diff --git a/test/unbounded-operator.pdf.argb32.ref.png b/test/unbounded-operator.pdf.argb32.ref.png new file mode 100644 index 00000000..4aa476de Binary files /dev/null and b/test/unbounded-operator.pdf.argb32.ref.png differ diff --git a/test/unbounded-operator.ps2.argb32.ref.png b/test/unbounded-operator.ps2.argb32.ref.png new file mode 100644 index 00000000..4aa476de Binary files /dev/null and b/test/unbounded-operator.ps2.argb32.ref.png differ diff --git a/test/unbounded-operator.ps3.argb32.ref.png b/test/unbounded-operator.ps3.argb32.ref.png new file mode 100644 index 00000000..4aa476de Binary files /dev/null and b/test/unbounded-operator.ps3.argb32.ref.png differ diff --git a/test/unbounded-operator.rgb24.ref.png b/test/unbounded-operator.rgb24.ref.png index b2f1a84d..ad3225d0 100644 Binary files a/test/unbounded-operator.rgb24.ref.png and b/test/unbounded-operator.rgb24.ref.png differ diff --git a/test/unbounded-operator.test-fallback.rgb24.ref.png b/test/unbounded-operator.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..07c7ecff Binary files /dev/null and b/test/unbounded-operator.test-fallback.rgb24.ref.png differ diff --git a/test/unbounded-operator.xlib.rgb24.ref.png b/test/unbounded-operator.xlib.rgb24.ref.png new file mode 100644 index 00000000..b2f1a84d Binary files /dev/null and b/test/unbounded-operator.xlib.rgb24.ref.png differ diff --git a/test/user-font-proxy.pdf.argb32.ref.png b/test/user-font-proxy.pdf.argb32.ref.png new file mode 100644 index 00000000..cffa9edb Binary files /dev/null and b/test/user-font-proxy.pdf.argb32.ref.png differ diff --git a/test/user-font-proxy.pdf.rgb24.ref.png b/test/user-font-proxy.pdf.rgb24.ref.png new file mode 100644 index 00000000..cffa9edb Binary files /dev/null and b/test/user-font-proxy.pdf.rgb24.ref.png differ diff --git a/test/user-font-proxy.ref.png b/test/user-font-proxy.ref.png index ebd97198..cffa9edb 100644 Binary files a/test/user-font-proxy.ref.png and b/test/user-font-proxy.ref.png differ diff --git a/test/user-font-proxy.svg11.argb32.ref.png b/test/user-font-proxy.svg11.argb32.ref.png new file mode 100644 index 00000000..d2a7812b Binary files /dev/null and b/test/user-font-proxy.svg11.argb32.ref.png differ diff --git a/test/user-font-proxy.svg11.rgb24.ref.png b/test/user-font-proxy.svg11.rgb24.ref.png new file mode 100644 index 00000000..d2a7812b Binary files /dev/null and b/test/user-font-proxy.svg11.rgb24.ref.png differ diff --git a/test/user-font-proxy.svg12.argb32.ref.png b/test/user-font-proxy.svg12.argb32.ref.png new file mode 100644 index 00000000..d2a7812b Binary files /dev/null and b/test/user-font-proxy.svg12.argb32.ref.png differ diff --git a/test/user-font-proxy.svg12.rgb24.ref.png b/test/user-font-proxy.svg12.rgb24.ref.png new file mode 100644 index 00000000..d2a7812b Binary files /dev/null and b/test/user-font-proxy.svg12.rgb24.ref.png differ diff --git a/test/user-font-proxy.test-fallback.argb32.ref.png b/test/user-font-proxy.test-fallback.argb32.ref.png new file mode 100644 index 00000000..9cccf312 Binary files /dev/null and b/test/user-font-proxy.test-fallback.argb32.ref.png differ diff --git a/test/user-font-proxy.test-fallback.rgb24.ref.png b/test/user-font-proxy.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..9cccf312 Binary files /dev/null and b/test/user-font-proxy.test-fallback.rgb24.ref.png differ diff --git a/test/user-font-proxy.xlib.ref.png b/test/user-font-proxy.xlib.ref.png new file mode 100644 index 00000000..ebd97198 Binary files /dev/null and b/test/user-font-proxy.xlib.ref.png differ diff --git a/test/user-font.ref.png b/test/user-font.ref.png index abc31171..753fc7bc 100644 Binary files a/test/user-font.ref.png and b/test/user-font.ref.png differ diff --git a/test/user-font.svg11.argb32.ref.png b/test/user-font.svg11.argb32.ref.png new file mode 100644 index 00000000..3dc77ae4 Binary files /dev/null and b/test/user-font.svg11.argb32.ref.png differ diff --git a/test/user-font.svg11.rgb24.ref.png b/test/user-font.svg11.rgb24.ref.png new file mode 100644 index 00000000..3dc77ae4 Binary files /dev/null and b/test/user-font.svg11.rgb24.ref.png differ diff --git a/test/user-font.svg12.argb32.ref.png b/test/user-font.svg12.argb32.ref.png new file mode 100644 index 00000000..3dc77ae4 Binary files /dev/null and b/test/user-font.svg12.argb32.ref.png differ diff --git a/test/user-font.svg12.rgb24.ref.png b/test/user-font.svg12.rgb24.ref.png new file mode 100644 index 00000000..3dc77ae4 Binary files /dev/null and b/test/user-font.svg12.rgb24.ref.png differ diff --git a/test/user-font.test-fallback.argb32.ref.png b/test/user-font.test-fallback.argb32.ref.png new file mode 100644 index 00000000..3080c694 Binary files /dev/null and b/test/user-font.test-fallback.argb32.ref.png differ diff --git a/test/user-font.test-fallback.rgb24.ref.png b/test/user-font.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..3080c694 Binary files /dev/null and b/test/user-font.test-fallback.rgb24.ref.png differ diff --git a/test/user-font.xlib.ref.png b/test/user-font.xlib.ref.png new file mode 100644 index 00000000..abc31171 Binary files /dev/null and b/test/user-font.xlib.ref.png differ -- cgit v1.2.3 From 5e06085b483dcaaa7b1b29b13cd2813c7e51e02a Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Fri, 1 Aug 2008 23:28:15 +0300 Subject: [cairo-spans] Render clip mask surfaces with spans if we can. Generating surface masks for clipping can also benefit from span rendering sometimes. --- src/cairo-clip.c | 140 +++++++++++++++++++++ test/clip-fill-rule.pdf.argb32.ref.png | Bin 0 -> 509 bytes test/clip-fill-rule.rgb24.ref.png | Bin 380 -> 390 bytes test/clip-fill-rule.test-paginated.rgb24.ref.png | Bin 0 -> 361 bytes test/clip-fill-rule.xlib.rgb24.ref.png | Bin 0 -> 380 bytes test/clip-nesting.pdf.argb32.ref.png | Bin 0 -> 850 bytes test/clip-nesting.rgb24.ref.png | Bin 955 -> 963 bytes test/clip-nesting.test-fallback.rgb24.ref.png | Bin 0 -> 936 bytes test/clip-nesting.test-paginated.rgb24.ref.png | Bin 0 -> 936 bytes test/clip-nesting.xlib.rgb24.ref.png | Bin 0 -> 955 bytes test/clip-operator.pdf.argb32.ref.png | Bin 11600 -> 11604 bytes test/clip-operator.ps3.argb32.ref.png | Bin 7574 -> 7576 bytes test/clip-operator.ref.png | Bin 8247 -> 8210 bytes test/clip-operator.test-paginated.argb32.ref.png | Bin 0 -> 8247 bytes test/clip-twice.pdf.argb32.ref.png | Bin 1458 -> 1498 bytes test/clip-twice.ref.png | Bin 1362 -> 1342 bytes test/clip-twice.rgb24.ref.png | Bin 1198 -> 1203 bytes test/clip-twice.test-fallback.argb32.ref.png | Bin 0 -> 1343 bytes test/clip-twice.test-fallback.rgb24.ref.png | Bin 0 -> 1179 bytes test/clip-twice.test-paginated.argb32.ref.png | Bin 0 -> 1361 bytes test/clip-twice.test-paginated.rgb24.ref.png | Bin 0 -> 1199 bytes test/clip-twice.xlib.ref.png | Bin 0 -> 1362 bytes test/clip-twice.xlib.rgb24.ref.png | Bin 0 -> 1198 bytes test/device-offset-fractional.pdf.argb32.ref.png | Bin 0 -> 275 bytes test/device-offset-fractional.pdf.rgb24.ref.png | Bin 0 -> 275 bytes test/filter-nearest-offset.pdf.argb32.ref.png | Bin 0 -> 4295 bytes test/filter-nearest-offset.pdf.rgb24.ref.png | Bin 0 -> 4295 bytes test/filter-nearest-transformed.pdf.argb32.ref.png | Bin 0 -> 488 bytes test/filter-nearest-transformed.pdf.rgb24.ref.png | Bin 0 -> 488 bytes test/linear-gradient.pdf.argb32.ref.png | Bin 1118 -> 1112 bytes test/linear-gradient.pdf.rgb24.ref.png | Bin 1118 -> 1112 bytes test/mask.pdf.argb32.ref.png | Bin 9956 -> 9903 bytes test/mask.ref.png | Bin 8571 -> 8581 bytes test/mask.svg11.argb32.ref.png | Bin 8625 -> 8682 bytes test/mask.svg12.argb32.ref.png | Bin 8625 -> 8682 bytes test/meta-surface-pattern.pdf.argb32.ref.png | Bin 4017 -> 4011 bytes test/meta-surface-pattern.svg11.argb32.ref.png | Bin 3928 -> 3924 bytes test/meta-surface-pattern.svg12.argb32.ref.png | Bin 3928 -> 3924 bytes test/rotate-image-surface-paint.pdf.argb32.ref.png | Bin 209 -> 215 bytes test/rotate-image-surface-paint.pdf.rgb24.ref.png | Bin 207 -> 215 bytes test/surface-pattern-scale-down.pdf.argb32.ref.png | Bin 2386 -> 1532 bytes test/surface-pattern-scale-down.pdf.rgb24.ref.png | Bin 2386 -> 1532 bytes test/surface-pattern-scale-up.pdf.argb32.ref.png | Bin 4247 -> 3834 bytes test/surface-pattern-scale-up.pdf.rgb24.ref.png | Bin 4247 -> 3834 bytes test/surface-pattern.pdf.argb32.ref.png | Bin 0 -> 14808 bytes test/surface-pattern.pdf.rgb24.ref.png | Bin 0 -> 14808 bytes test/trap-clip.pdf.rgb24.ref.png | Bin 6642 -> 6621 bytes test/trap-clip.ref.png | Bin 5865 -> 5829 bytes test/trap-clip.test-paginated.argb32.ref.png | Bin 0 -> 5865 bytes 49 files changed, 140 insertions(+) create mode 100644 test/clip-fill-rule.pdf.argb32.ref.png create mode 100644 test/clip-fill-rule.test-paginated.rgb24.ref.png create mode 100644 test/clip-fill-rule.xlib.rgb24.ref.png create mode 100644 test/clip-nesting.pdf.argb32.ref.png create mode 100644 test/clip-nesting.test-fallback.rgb24.ref.png create mode 100644 test/clip-nesting.test-paginated.rgb24.ref.png create mode 100644 test/clip-nesting.xlib.rgb24.ref.png create mode 100644 test/clip-operator.test-paginated.argb32.ref.png create mode 100644 test/clip-twice.test-fallback.argb32.ref.png create mode 100644 test/clip-twice.test-fallback.rgb24.ref.png create mode 100644 test/clip-twice.test-paginated.argb32.ref.png create mode 100644 test/clip-twice.test-paginated.rgb24.ref.png create mode 100644 test/clip-twice.xlib.ref.png create mode 100644 test/clip-twice.xlib.rgb24.ref.png create mode 100644 test/device-offset-fractional.pdf.argb32.ref.png create mode 100644 test/device-offset-fractional.pdf.rgb24.ref.png create mode 100644 test/filter-nearest-offset.pdf.argb32.ref.png create mode 100644 test/filter-nearest-offset.pdf.rgb24.ref.png create mode 100644 test/filter-nearest-transformed.pdf.argb32.ref.png create mode 100644 test/filter-nearest-transformed.pdf.rgb24.ref.png create mode 100644 test/surface-pattern.pdf.argb32.ref.png create mode 100644 test/surface-pattern.pdf.rgb24.ref.png create mode 100644 test/trap-clip.test-paginated.argb32.ref.png diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 4303b605..cd423a44 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -534,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, @@ -545,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; @@ -564,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 diff --git a/test/clip-fill-rule.pdf.argb32.ref.png b/test/clip-fill-rule.pdf.argb32.ref.png new file mode 100644 index 00000000..0d9938e7 Binary files /dev/null and b/test/clip-fill-rule.pdf.argb32.ref.png differ diff --git a/test/clip-fill-rule.rgb24.ref.png b/test/clip-fill-rule.rgb24.ref.png index a969e367..050bd666 100644 Binary files a/test/clip-fill-rule.rgb24.ref.png and b/test/clip-fill-rule.rgb24.ref.png differ diff --git a/test/clip-fill-rule.test-paginated.rgb24.ref.png b/test/clip-fill-rule.test-paginated.rgb24.ref.png new file mode 100644 index 00000000..d21472dc Binary files /dev/null and b/test/clip-fill-rule.test-paginated.rgb24.ref.png differ diff --git a/test/clip-fill-rule.xlib.rgb24.ref.png b/test/clip-fill-rule.xlib.rgb24.ref.png new file mode 100644 index 00000000..a969e367 Binary files /dev/null and b/test/clip-fill-rule.xlib.rgb24.ref.png differ diff --git a/test/clip-nesting.pdf.argb32.ref.png b/test/clip-nesting.pdf.argb32.ref.png new file mode 100644 index 00000000..78ae6e08 Binary files /dev/null and b/test/clip-nesting.pdf.argb32.ref.png differ diff --git a/test/clip-nesting.rgb24.ref.png b/test/clip-nesting.rgb24.ref.png index e2488f34..a014763d 100644 Binary files a/test/clip-nesting.rgb24.ref.png and b/test/clip-nesting.rgb24.ref.png differ diff --git a/test/clip-nesting.test-fallback.rgb24.ref.png b/test/clip-nesting.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..d087ab6c Binary files /dev/null and b/test/clip-nesting.test-fallback.rgb24.ref.png differ diff --git a/test/clip-nesting.test-paginated.rgb24.ref.png b/test/clip-nesting.test-paginated.rgb24.ref.png new file mode 100644 index 00000000..d087ab6c Binary files /dev/null and b/test/clip-nesting.test-paginated.rgb24.ref.png differ diff --git a/test/clip-nesting.xlib.rgb24.ref.png b/test/clip-nesting.xlib.rgb24.ref.png new file mode 100644 index 00000000..e2488f34 Binary files /dev/null and b/test/clip-nesting.xlib.rgb24.ref.png differ diff --git a/test/clip-operator.pdf.argb32.ref.png b/test/clip-operator.pdf.argb32.ref.png index 4bf79c4c..e2fdc8d1 100644 Binary files a/test/clip-operator.pdf.argb32.ref.png and b/test/clip-operator.pdf.argb32.ref.png differ diff --git a/test/clip-operator.ps3.argb32.ref.png b/test/clip-operator.ps3.argb32.ref.png index 638831ce..cd207d92 100644 Binary files a/test/clip-operator.ps3.argb32.ref.png and b/test/clip-operator.ps3.argb32.ref.png differ diff --git a/test/clip-operator.ref.png b/test/clip-operator.ref.png index 22e080a2..3a685f5e 100644 Binary files a/test/clip-operator.ref.png and b/test/clip-operator.ref.png differ diff --git a/test/clip-operator.test-paginated.argb32.ref.png b/test/clip-operator.test-paginated.argb32.ref.png new file mode 100644 index 00000000..22e080a2 Binary files /dev/null and b/test/clip-operator.test-paginated.argb32.ref.png differ diff --git a/test/clip-twice.pdf.argb32.ref.png b/test/clip-twice.pdf.argb32.ref.png index 589dfc97..2a7541fe 100644 Binary files a/test/clip-twice.pdf.argb32.ref.png and b/test/clip-twice.pdf.argb32.ref.png differ diff --git a/test/clip-twice.ref.png b/test/clip-twice.ref.png index 8dc86f30..4aafc9ac 100644 Binary files a/test/clip-twice.ref.png and b/test/clip-twice.ref.png differ diff --git a/test/clip-twice.rgb24.ref.png b/test/clip-twice.rgb24.ref.png index 3f1c013b..25c44ef7 100644 Binary files a/test/clip-twice.rgb24.ref.png and b/test/clip-twice.rgb24.ref.png differ diff --git a/test/clip-twice.test-fallback.argb32.ref.png b/test/clip-twice.test-fallback.argb32.ref.png new file mode 100644 index 00000000..ba621807 Binary files /dev/null and b/test/clip-twice.test-fallback.argb32.ref.png differ diff --git a/test/clip-twice.test-fallback.rgb24.ref.png b/test/clip-twice.test-fallback.rgb24.ref.png new file mode 100644 index 00000000..9cbdc4d4 Binary files /dev/null and b/test/clip-twice.test-fallback.rgb24.ref.png differ diff --git a/test/clip-twice.test-paginated.argb32.ref.png b/test/clip-twice.test-paginated.argb32.ref.png new file mode 100644 index 00000000..ffd59aaf Binary files /dev/null and b/test/clip-twice.test-paginated.argb32.ref.png differ diff --git a/test/clip-twice.test-paginated.rgb24.ref.png b/test/clip-twice.test-paginated.rgb24.ref.png new file mode 100644 index 00000000..e3d0ae49 Binary files /dev/null and b/test/clip-twice.test-paginated.rgb24.ref.png differ diff --git a/test/clip-twice.xlib.ref.png b/test/clip-twice.xlib.ref.png new file mode 100644 index 00000000..8dc86f30 Binary files /dev/null and b/test/clip-twice.xlib.ref.png differ diff --git a/test/clip-twice.xlib.rgb24.ref.png b/test/clip-twice.xlib.rgb24.ref.png new file mode 100644 index 00000000..3f1c013b Binary files /dev/null and b/test/clip-twice.xlib.rgb24.ref.png differ diff --git a/test/device-offset-fractional.pdf.argb32.ref.png b/test/device-offset-fractional.pdf.argb32.ref.png new file mode 100644 index 00000000..c076932c Binary files /dev/null and b/test/device-offset-fractional.pdf.argb32.ref.png differ diff --git a/test/device-offset-fractional.pdf.rgb24.ref.png b/test/device-offset-fractional.pdf.rgb24.ref.png new file mode 100644 index 00000000..c076932c Binary files /dev/null and b/test/device-offset-fractional.pdf.rgb24.ref.png differ diff --git a/test/filter-nearest-offset.pdf.argb32.ref.png b/test/filter-nearest-offset.pdf.argb32.ref.png new file mode 100644 index 00000000..3475cb6e Binary files /dev/null and b/test/filter-nearest-offset.pdf.argb32.ref.png differ diff --git a/test/filter-nearest-offset.pdf.rgb24.ref.png b/test/filter-nearest-offset.pdf.rgb24.ref.png new file mode 100644 index 00000000..3475cb6e Binary files /dev/null and b/test/filter-nearest-offset.pdf.rgb24.ref.png differ diff --git a/test/filter-nearest-transformed.pdf.argb32.ref.png b/test/filter-nearest-transformed.pdf.argb32.ref.png new file mode 100644 index 00000000..40169593 Binary files /dev/null and b/test/filter-nearest-transformed.pdf.argb32.ref.png differ diff --git a/test/filter-nearest-transformed.pdf.rgb24.ref.png b/test/filter-nearest-transformed.pdf.rgb24.ref.png new file mode 100644 index 00000000..40169593 Binary files /dev/null and b/test/filter-nearest-transformed.pdf.rgb24.ref.png differ diff --git a/test/linear-gradient.pdf.argb32.ref.png b/test/linear-gradient.pdf.argb32.ref.png index bddb681c..f820c374 100644 Binary files a/test/linear-gradient.pdf.argb32.ref.png and b/test/linear-gradient.pdf.argb32.ref.png differ diff --git a/test/linear-gradient.pdf.rgb24.ref.png b/test/linear-gradient.pdf.rgb24.ref.png index bddb681c..f820c374 100644 Binary files a/test/linear-gradient.pdf.rgb24.ref.png and b/test/linear-gradient.pdf.rgb24.ref.png differ diff --git a/test/mask.pdf.argb32.ref.png b/test/mask.pdf.argb32.ref.png index d1cc8ff7..8bd8f140 100644 Binary files a/test/mask.pdf.argb32.ref.png and b/test/mask.pdf.argb32.ref.png differ diff --git a/test/mask.ref.png b/test/mask.ref.png index f5d30c53..2c2fa117 100644 Binary files a/test/mask.ref.png and b/test/mask.ref.png differ diff --git a/test/mask.svg11.argb32.ref.png b/test/mask.svg11.argb32.ref.png index e48e47bf..3ce4d53f 100644 Binary files a/test/mask.svg11.argb32.ref.png and b/test/mask.svg11.argb32.ref.png differ diff --git a/test/mask.svg12.argb32.ref.png b/test/mask.svg12.argb32.ref.png index e48e47bf..3ce4d53f 100644 Binary files a/test/mask.svg12.argb32.ref.png and b/test/mask.svg12.argb32.ref.png differ diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png index a842b6fa..2ee9b7da 100644 Binary files a/test/meta-surface-pattern.pdf.argb32.ref.png and b/test/meta-surface-pattern.pdf.argb32.ref.png differ diff --git a/test/meta-surface-pattern.svg11.argb32.ref.png b/test/meta-surface-pattern.svg11.argb32.ref.png index 3a6836dc..99695748 100644 Binary files a/test/meta-surface-pattern.svg11.argb32.ref.png and b/test/meta-surface-pattern.svg11.argb32.ref.png differ diff --git a/test/meta-surface-pattern.svg12.argb32.ref.png b/test/meta-surface-pattern.svg12.argb32.ref.png index 3a6836dc..99695748 100644 Binary files a/test/meta-surface-pattern.svg12.argb32.ref.png and b/test/meta-surface-pattern.svg12.argb32.ref.png differ diff --git a/test/rotate-image-surface-paint.pdf.argb32.ref.png b/test/rotate-image-surface-paint.pdf.argb32.ref.png index c12ae8fd..93fab525 100644 Binary files a/test/rotate-image-surface-paint.pdf.argb32.ref.png and b/test/rotate-image-surface-paint.pdf.argb32.ref.png differ diff --git a/test/rotate-image-surface-paint.pdf.rgb24.ref.png b/test/rotate-image-surface-paint.pdf.rgb24.ref.png index 5cd7bf61..93fab525 100644 Binary files a/test/rotate-image-surface-paint.pdf.rgb24.ref.png and b/test/rotate-image-surface-paint.pdf.rgb24.ref.png differ diff --git a/test/surface-pattern-scale-down.pdf.argb32.ref.png b/test/surface-pattern-scale-down.pdf.argb32.ref.png index c29d804c..dc4b3a31 100644 Binary files a/test/surface-pattern-scale-down.pdf.argb32.ref.png and b/test/surface-pattern-scale-down.pdf.argb32.ref.png differ diff --git a/test/surface-pattern-scale-down.pdf.rgb24.ref.png b/test/surface-pattern-scale-down.pdf.rgb24.ref.png index c29d804c..dc4b3a31 100644 Binary files a/test/surface-pattern-scale-down.pdf.rgb24.ref.png and b/test/surface-pattern-scale-down.pdf.rgb24.ref.png differ diff --git a/test/surface-pattern-scale-up.pdf.argb32.ref.png b/test/surface-pattern-scale-up.pdf.argb32.ref.png index 6f3a53c5..c0a2896a 100644 Binary files a/test/surface-pattern-scale-up.pdf.argb32.ref.png and b/test/surface-pattern-scale-up.pdf.argb32.ref.png differ diff --git a/test/surface-pattern-scale-up.pdf.rgb24.ref.png b/test/surface-pattern-scale-up.pdf.rgb24.ref.png index 6f3a53c5..c0a2896a 100644 Binary files a/test/surface-pattern-scale-up.pdf.rgb24.ref.png and b/test/surface-pattern-scale-up.pdf.rgb24.ref.png differ diff --git a/test/surface-pattern.pdf.argb32.ref.png b/test/surface-pattern.pdf.argb32.ref.png new file mode 100644 index 00000000..70a44767 Binary files /dev/null and b/test/surface-pattern.pdf.argb32.ref.png differ diff --git a/test/surface-pattern.pdf.rgb24.ref.png b/test/surface-pattern.pdf.rgb24.ref.png new file mode 100644 index 00000000..70a44767 Binary files /dev/null and b/test/surface-pattern.pdf.rgb24.ref.png differ diff --git a/test/trap-clip.pdf.rgb24.ref.png b/test/trap-clip.pdf.rgb24.ref.png index 90b476b5..06163675 100644 Binary files a/test/trap-clip.pdf.rgb24.ref.png and b/test/trap-clip.pdf.rgb24.ref.png differ diff --git a/test/trap-clip.ref.png b/test/trap-clip.ref.png index dee57e7b..e8c26d32 100644 Binary files a/test/trap-clip.ref.png and b/test/trap-clip.ref.png differ diff --git a/test/trap-clip.test-paginated.argb32.ref.png b/test/trap-clip.test-paginated.argb32.ref.png new file mode 100644 index 00000000..dee57e7b Binary files /dev/null and b/test/trap-clip.test-paginated.argb32.ref.png differ -- cgit v1.2.3 From 673640a3b3931995897b01d49c5dd8d82b50dac2 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Thu, 4 Dec 2008 17:53:06 -0500 Subject: [win32] Use MOD instead of the '%' operator Repeat should be handled using MOD instead of '%' so that negative numbers are handled as expected. E.g. -1 mod 600 = 599, not 495 as the '%' operator gives. This was causing https://bugzilla.mozilla.org/show_bug.cgi?id=466258 Patch from Robert O'Callahan --- src/cairo-win32-surface.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 5787e261..43276217 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, 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; -- cgit v1.2.3 From 5f60e2e00455f2894c7ce3805a029c806f21514a Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 9 Dec 2008 11:41:10 -0500 Subject: Reorganize the (set|get)_antialias prototypes Move _cairo_gstate_set_antialias() and _cairo_gstate_get_antialias() into the gstate section of cairoint.h --- src/cairoint.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cairoint.h b/src/cairoint.h index cfc850e8..c8b1f583 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1312,6 +1312,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; @@ -2481,13 +2488,6 @@ _cairo_pattern_equal (const cairo_pattern_t *a, cairo_private void _cairo_pattern_reset_static_data (void); -cairo_private cairo_status_t -_cairo_gstate_set_antialias (cairo_gstate_t *gstate, - cairo_antialias_t antialias); - -cairo_private cairo_antialias_t -_cairo_gstate_get_antialias (cairo_gstate_t *gstate); - /* cairo-region.c */ #include "cairo-region-private.h" -- cgit v1.2.3 From db4c427e8460b0e326691bd6d3784178a713eb33 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 9 Dec 2008 12:03:11 -0500 Subject: [quartz] Change some pattern casts to access to the base class Avoiding casts gives us some more type safety. --- src/cairo-quartz-surface.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 9f6b2451..17fabe02 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -1072,7 +1072,7 @@ static cairo_quartz_action_t _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface, cairo_linear_pattern_t *lpat) { - cairo_pattern_t *abspat = (cairo_pattern_t *) lpat; + cairo_pattern_t *abspat = &lpat->base.base; cairo_matrix_t mat; CGPoint start, end; CGFunctionRef gradFunc; @@ -1099,10 +1099,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); } @@ -1121,7 +1121,7 @@ static cairo_quartz_action_t _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface, cairo_radial_pattern_t *rpat) { - cairo_pattern_t *abspat = (cairo_pattern_t *)rpat; + cairo_pattern_t *abspat = &rpat->base.base; cairo_matrix_t mat; CGPoint start, end; CGFunctionRef gradFunc; @@ -1142,7 +1142,7 @@ _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); @@ -1156,7 +1156,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, -- cgit v1.2.3 From d93bf10edc7e432349524221a3d1b0f0b2ec8090 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Wed, 10 Dec 2008 17:02:55 -0500 Subject: [quartz] Create a copy of the pattern so that the reference counts are balanced The pattern could be stack allocated so we can't take a reference to it; instead make a copy. Based on a patch by Paolo Bonzini. --- src/cairo-quartz-surface.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 41fde0be..163c9fba 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -682,13 +682,19 @@ ComputeGradientValue (void *info, const float *in, float *out) static CGFunctionRef CreateGradientFunction (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 (gpat, + 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, @@ -702,6 +708,7 @@ CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface, 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 (gpat, + 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, -- cgit v1.2.3 From f7b3f1b7d70a271575d3bb233b7ee51a21861c05 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Wed, 10 Dec 2008 17:54:59 -0500 Subject: [quartz] Propagate const patterns through the casts As part of this avoid using cairo_pattern_get_matrix() because it requires a 'cairo_pattern_t *' instead of 'const cairo_pattern *' Also, make a copy of the pattern before pasing it in to cairo_set_source() --- src/cairo-quartz-surface.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 17fabe02..9dc5eaae 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -680,7 +680,7 @@ ComputeGradientValue (void *info, const float *in, float *out) } static CGFunctionRef -CreateGradientFunction (cairo_gradient_pattern_t *gpat) +CreateGradientFunction (const cairo_gradient_pattern_t *gpat) { 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 }; @@ -698,7 +698,7 @@ 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) { @@ -1013,7 +1013,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 +1022,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 +1051,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 +1077,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 = &lpat->base.base; + const cairo_pattern_t *abspat = &lpat->base.base; cairo_matrix_t mat; CGPoint start, end; CGFunctionRef gradFunc; @@ -1085,7 +1092,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); @@ -1119,9 +1126,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 = &rpat->base.base; + const cairo_pattern_t *abspat = &rpat->base.base; cairo_matrix_t mat; CGPoint start, end; CGFunctionRef gradFunc; @@ -1145,7 +1152,7 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface, 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); @@ -1199,13 +1206,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 +1220,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; @@ -2259,7 +2266,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 = NULL; + cairo_pattern_t *mask_copy; cairo_int_status_t status; /* Render the gradient to a surface */ @@ -2271,13 +2278,13 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface, /* 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); cairo_destroy (gradient_surf_cr); - cairo_pattern_destroy (mask_copy); if (status) goto BAIL; -- cgit v1.2.3 From 2f1b581f54713c899f3b03af1e0ac8c38c36c385 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Thu, 11 Dec 2008 10:34:37 -0500 Subject: [quartz] Create a copy instead of increasing the reference The pattern could be stack allocated so we can't take a reference to it. Some testing of quartz shows that it doesn't deal with malloc failure particularily well. In the best case CGFunctionCreate returns NULL, in the worst case it just crashes. Quartz does seem to be able to handle a NULL CGFunctionRef, so returning NULL if we fail to copy the pattern avoids complicating the code to deal with propagating the failure and shouldn't cause any additional crashes. Based on a patch by Paolo Bonzini. --- src/cairo-quartz-surface.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 9dc5eaae..34661853 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -682,13 +682,19 @@ ComputeGradientValue (void *info, const float *in, float *out) static CGFunctionRef 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_reference (&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, @@ -702,6 +708,7 @@ CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface, 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_reference (&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, -- cgit v1.2.3