diff --git a/boilerplate/Makefile.am b/boilerplate/Makefile.am index 3d8339fb0..c8b5d41b6 100644 --- a/boilerplate/Makefile.am +++ b/boilerplate/Makefile.am @@ -48,8 +48,13 @@ endif libcairoboilerplate_la_LIBADD += $(CAIROBOILERPLATE_LIBS) +# we need to workaround the introduction of CC_FOR_BUILD with older builds make-cairo-boilerplate-constructors$(EXEEXT): make-cairo-boilerplate-constructors.c - $(CC_FOR_BUILD) $^ -o $@ + if test -n "$(CC_FOR_BUILD)"; then \ + $(CC_FOR_BUILD) $^ -o $@; \ + else \ + $(CC) $^ -o $@; \ + fi cairo-boilerplate-constructors.c: Makefile $(enabled_cairo_boilerplate_sources) make-cairo-boilerplate-constructors$(EXEEXT) echo '(cd $(srcdir) && $(top_builddir)/boilerplate/make-cairo-boilerplate-constructors$(EXEEXT) $(enabled_cairo_boilerplate_sources)) > $@' diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c index e941d46ff..838038af8 100644 --- a/boilerplate/cairo-boilerplate-pdf.c +++ b/boilerplate/cairo-boilerplate-pdf.c @@ -30,6 +30,10 @@ #include #include +#if ! CAIRO_HAS_META_SURFACE +#define CAIRO_SURFACE_TYPE_META CAIRO_INTERNAL_SURFACE_TYPE_META +#endif + static const cairo_user_data_key_t pdf_closure_key; typedef struct _pdf_target_closure diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c index 40148ddeb..8619e47f8 100644 --- a/boilerplate/cairo-boilerplate-ps.c +++ b/boilerplate/cairo-boilerplate-ps.c @@ -31,6 +31,10 @@ #include #include +#if ! CAIRO_HAS_META_SURFACE +#define CAIRO_SURFACE_TYPE_META CAIRO_INTERNAL_SURFACE_TYPE_META +#endif + static const cairo_user_data_key_t ps_closure_key; typedef struct _ps_target_closure { diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c index 45e085ce9..56296f46f 100644 --- a/boilerplate/cairo-boilerplate-svg.c +++ b/boilerplate/cairo-boilerplate-svg.c @@ -35,6 +35,10 @@ #include #endif +#if ! CAIRO_HAS_META_SURFACE +#define CAIRO_SURFACE_TYPE_META CAIRO_INTERNAL_SURFACE_TYPE_META +#endif + static const cairo_user_data_key_t svg_closure_key; typedef struct _svg_target_closure { diff --git a/boilerplate/cairo-boilerplate-test-surfaces.c b/boilerplate/cairo-boilerplate-test-surfaces.c index 501866bad..3e7490ec5 100644 --- a/boilerplate/cairo-boilerplate-test-surfaces.c +++ b/boilerplate/cairo-boilerplate-test-surfaces.c @@ -28,16 +28,20 @@ #include "cairo-boilerplate-private.h" +#include + #include #include +#if CAIRO_HAS_TEST_PAGINATED_SURFACE #include -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3) +#endif +#if CAIRO_HAS_TEST_NULL_SURFACE #include +#endif +#if CAIRO_HAS_TEST_WRAPPING_SURFACE #include #endif -#include - static cairo_surface_t * _cairo_boilerplate_test_fallback_create_surface (const char *name, cairo_content_t content, @@ -70,6 +74,7 @@ _cairo_boilerplate_test_fallback16_create_surface (const char *name, ceil (width), ceil (height)); } +#if CAIRO_HAS_TEST_NULL_SURFACE static cairo_surface_t * _cairo_boilerplate_test_null_create_surface (const char *name, cairo_content_t content, @@ -82,13 +87,11 @@ _cairo_boilerplate_test_null_create_surface (const char *name, void **closure) { *closure = NULL; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3) return _cairo_test_null_surface_create (content); -#else - return NULL; -#endif } +#endif +#if CAIRO_HAS_TEST_PAGINATED_SURFACE static const cairo_user_data_key_t test_paginated_closure_key; typedef struct { @@ -196,7 +199,9 @@ _cairo_boilerplate_test_paginated_cleanup (void *closure) cairo_surface_destroy (tpc->target); free (tpc); } +#endif +#if CAIRO_HAS_TEST_WRAPPING_SURFACE static cairo_surface_t * _cairo_boilerplate_test_wrapping_create_surface (const char *name, cairo_content_t content, @@ -208,7 +213,6 @@ _cairo_boilerplate_test_wrapping_create_surface (const char *name, int id, void **closure) { -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3) cairo_surface_t *target; cairo_surface_t *surface; cairo_format_t format; @@ -221,11 +225,8 @@ _cairo_boilerplate_test_wrapping_create_surface (const char *name, cairo_surface_destroy (target); return surface; -#else - *closure = NULL; - return NULL; -#endif } +#endif static const cairo_boilerplate_target_t targets[] = { { @@ -264,6 +265,7 @@ static const cairo_boilerplate_target_t targets[] = { NULL, /* _cairo_boilerplate_get_image_surface, */ cairo_surface_write_to_png }, +#if CAIRO_HAS_TEST_PAGINATED_SURFACE { "test-paginated", "image", NULL, NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, @@ -288,6 +290,8 @@ static const cairo_boilerplate_target_t targets[] = { NULL, FALSE, TRUE }, +#endif +#if CAIRO_HAS_TEST_WRAPPING_SURFACE { "test-wrapping", "image", NULL, NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING, @@ -297,6 +301,8 @@ static const cairo_boilerplate_target_t targets[] = { _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, }, +#endif +#if CAIRO_HAS_TEST_NULL_SURFACE { "null", "image", NULL, NULL, CAIRO_INTERNAL_SURFACE_TYPE_NULL, @@ -307,5 +313,6 @@ static const cairo_boilerplate_target_t targets[] = { NULL, TRUE, FALSE }, +#endif }; CAIRO_BOILERPLATE (test, targets) diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c index a0810457a..f15f7393f 100644 --- a/boilerplate/cairo-boilerplate.c +++ b/boilerplate/cairo-boilerplate.c @@ -129,6 +129,7 @@ _cairo_boilerplate_image_create_surface (const char *name, return cairo_image_surface_create (format, ceil (width), ceil (height)); } +#if CAIRO_HAS_META_SURFACE static cairo_surface_t * _cairo_boilerplate_meta_create_surface (const char *name, cairo_content_t content, @@ -151,8 +152,6 @@ _cairo_boilerplate_meta_create_surface (const char *name, return cairo_meta_surface_create (content, &extents); } -const cairo_user_data_key_t cairo_boilerplate_output_basename_key; - #if CAIRO_HAS_SCRIPT_SURFACE static cairo_status_t stdio_write (void *closure, const unsigned char *data, unsigned int len) @@ -163,6 +162,9 @@ stdio_write (void *closure, const unsigned char *data, unsigned int len) return CAIRO_STATUS_SUCCESS; } #endif +#endif + +const cairo_user_data_key_t cairo_boilerplate_output_basename_key; cairo_surface_t * _cairo_boilerplate_get_image_surface (cairo_surface_t *src, @@ -186,7 +188,7 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src, image = cairo_surface_reference (surface); /* open a logging channel (only interesting for meta surfaces) */ -#if CAIRO_HAS_SCRIPT_SURFACE +#if CAIRO_HAS_SCRIPT_SURFACE && CAIRO_HAS_META_SURFACE if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_META) { const char *test_name; @@ -307,6 +309,7 @@ static const cairo_boilerplate_target_t builtin_targets[] = { _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, +#if CAIRO_HAS_META_SURFACE { "meta", "image", NULL, NULL, CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR_ALPHA, 0, @@ -327,6 +330,7 @@ static const cairo_boilerplate_target_t builtin_targets[] = { NULL, NULL, FALSE, TRUE }, +#endif }; CAIRO_BOILERPLATE (builtin, builtin_targets) diff --git a/perf/Makefile.am b/perf/Makefile.am index 2fd427c72..a62ad95f8 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -144,9 +144,14 @@ perf: cairo-perf$(EXEEXT) cairo-perf-trace$(EXEEXT) html-local: index.html -index.html: cairo-perf$(EXEEXT) - $(CAIRO_PERF_ENVIRONMENT) ./cairo-perf-diff -t -h HEAD > $@ +perf-tag.html : cairo-perf${EXEEXT} + $(CAIRO_PERF_ENVIRONMENT) ./cairo-perf-diff -t -h $@ `git describe --abbrev=0` HEAD +perf-commit.html : cairo-perf${EXEEXT} + $(CAIRO_PERF_ENVIRONMENT) ./cairo-perf-diff -t -h $@ HEAD +# Summarise changes in index.html, with details in links +index.html: perf-tag.html perf-commit.html + echo "Performance ChangesAgainst "`git describe --abbrev=0`"
Latest commit" > $@ EXTRA_VALGRIND_FLAGS = $(CAIRO_EXTRA_VALGRIND_FLAGS) VALGRIND_MEMCHECK_FLAGS = \ diff --git a/perf/cairo-perf-diff b/perf/cairo-perf-diff index 50a014a02..469da891c 100755 --- a/perf/cairo-perf-diff +++ b/perf/cairo-perf-diff @@ -58,7 +58,7 @@ benchmarks="cairo-perf" while true; do case $1 in -f|--force) force_cairo_perf="true";; - -h|--html) html_output="true";; + -h|--html) html_output="$2"; shift ;; -t|--trace) benchmarks="${benchmarks} cairo-perf-trace";; *) break;; esac @@ -243,9 +243,9 @@ if [ ! -e $new ]; then new=`rev2perf $new` fi -if [ "$html_output" != "true" ]; then +if [ -z "$html_output" ]; then $CAIRO_DIR/perf/cairo-perf-diff-files $old $new else $CAIRO_DIR/perf/cairo-perf-diff-files $old $new | - $CAIRO_DIR/perf/make-html.py + $CAIRO_DIR/perf/make-html.py > $html_output fi diff --git a/src/Makefile.sources b/src/Makefile.sources index 1a1d35f95..dd8501ecb 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -80,6 +80,7 @@ cairo_private = \ cairo-private.h \ cairo-reference-count-private.h \ cairo-region-private.h \ + cairo-rtree-private.h \ cairo-scaled-font-private.h \ cairo-skiplist-private.h \ cairo-spans-private.h \ @@ -133,6 +134,7 @@ cairo_sources = \ cairo-polygon.c \ cairo-rectangle.c \ cairo-region.c \ + cairo-rtree.c \ cairo-scaled-font.c \ cairo-skiplist.c \ cairo-slope.c \ diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index e7efdca17..627f9edd7 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -172,6 +172,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, surface->height = pixman_image_get_height (pixman_image); surface->stride = pixman_image_get_stride (pixman_image); surface->depth = pixman_image_get_depth (pixman_image); + surface->is_clear = FALSE; surface->clip_region = NULL; @@ -358,6 +359,8 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data, pixman_format); if (cairo_surface_status (surface)) pixman_image_unref (pixman_image); + else + ((cairo_image_surface_t *)surface)->is_clear = TRUE; return surface; } @@ -1113,6 +1116,8 @@ _cairo_image_surface_composite (cairo_operator_t op, _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr); _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr); + if (op != CAIRO_OPERATOR_CLEAR) + dst->is_clear = FALSE; return status; } @@ -1171,6 +1176,9 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, if (pixman_rects != stack_rects) free (pixman_rects); + if (op != CAIRO_OPERATOR_CLEAR) + surface->is_clear = FALSE; + return status; } @@ -1300,6 +1308,9 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, pixman_image_unref (mask); + if (op != CAIRO_OPERATOR_CLEAR) + dst->is_clear = FALSE; + if (! _cairo_operator_bounded_by_mask (op)) { status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, &attributes, @@ -1458,6 +1469,9 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer) rects->width, rects->height, dst->clip_region); } + + if (renderer->op != CAIRO_OPERATOR_CLEAR) + dst->is_clear = FALSE; } if (status != CAIRO_STATUS_SUCCESS) return _cairo_span_renderer_set_error (abstract_renderer, @@ -1567,6 +1581,25 @@ _cairo_image_surface_get_font_options (void *abstract_surface, cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); } +static cairo_int_status_t +_cairo_image_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + /* we know that surfaces are calloc, so ignore any redundant clears */ + if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) { + cairo_image_surface_t *surface = abstract_surface; + + if (surface->is_clear) + return CAIRO_STATUS_SUCCESS; + + surface->is_clear = TRUE; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + /** * _cairo_surface_is_image: * @surface: a #cairo_surface_t @@ -1605,7 +1638,7 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { NULL, /* font_fini */ NULL, /* glyph_fini */ - NULL, /* paint */ + _cairo_image_surface_paint, NULL, /* mask */ NULL, /* stroke */ NULL, /* fill */ diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index 23443a5d2..34c46765d 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -159,6 +159,16 @@ _cairo_paginated_surface_finish (void *abstract_surface) status = cairo_surface_status (abstract_surface); } + /* XXX We want to propagate any errors from destroy(), but those are not + * returned via the api. So we need to explicitly finish the target, + * and check the status afterwards. However, we can only call finish() + * on the target, if we own it. + */ + if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1) { + cairo_surface_finish (surface->target); + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface->target); + } cairo_surface_destroy (surface->target); cairo_surface_finish (surface->meta); diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 9819353b3..3befe42c8 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -488,6 +488,7 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, { cairo_status_t status; cairo_point_t point[3]; + cairo_slope_t slope, tangent; /* make sure subpaths are started properly */ if (! path->has_current_point) { @@ -502,6 +503,17 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, point[0].x = x0; point[0].y = y0; point[1].x = x1; point[1].y = y1; point[2].x = x2; point[2].y = y2; + + _cairo_slope_init (&slope, &path->current_point, &point[2]); + _cairo_slope_init (&tangent, &path->current_point, &point[0]); + if (_cairo_slope_compare (&slope, &tangent) == 0) { + _cairo_slope_init (&tangent, &point[1], &point[2]); + if (_cairo_slope_compare (&slope, &tangent) == 0) { + /* just a straight line... */ + return _cairo_path_fixed_line_to (path, x2, y2); + } + } + status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); if (unlikely (status)) return status; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 8cd46723e..4038f309c 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -244,6 +244,19 @@ _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface, &surface->cairo_to_pdf); } +static cairo_bool_t +_path_covers_bbox (cairo_pdf_surface_t *surface, + cairo_path_fixed_t *path) +{ + cairo_box_t box; + + return _cairo_path_fixed_is_rectangle (path, &box) && + box.p1.x <= 0 && + box.p1.y <= 0 && + box.p2.x >= _cairo_fixed_from_double (surface->width) && + box.p2.y >= _cairo_fixed_from_double (surface->height); +} + static cairo_status_t _cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, cairo_path_fixed_t *path, @@ -269,6 +282,9 @@ _cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper return CAIRO_STATUS_SUCCESS; } + if (_path_covers_bbox (surface, path)) + return CAIRO_STATUS_SUCCESS; + return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule); } @@ -3657,37 +3673,56 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface, _cairo_output_stream_printf (surface->output, "endcodespacerange\n"); - num_bfchar = font_subset->num_glyphs - 1; - - /* The CMap specification has a limit of 100 characters per beginbfchar operator */ - _cairo_output_stream_printf (surface->output, - "%d beginbfchar\n", - num_bfchar > 100 ? 100 : num_bfchar); - - for (i = 0; i < num_bfchar; i++) { - if (i != 0 && i % 100 == 0) { - _cairo_output_stream_printf (surface->output, - "endbfchar\n" - "%d beginbfchar\n", - num_bfchar - i > 100 ? 100 : num_bfchar - i); - } - if (is_composite) { - _cairo_output_stream_printf (surface->output, - "<%04x> ", - i + 1); - } else { - _cairo_output_stream_printf (surface->output, - "<%02x> ", - i + 1); - } - status = _cairo_pdf_surface_emit_unicode_for_glyph (surface, - font_subset->utf8[i + 1]); - if (unlikely (status)) - return status; + if (is_composite) { + num_bfchar = font_subset->num_glyphs - 1; + /* The CMap specification has a limit of 100 characters per beginbfchar operator */ _cairo_output_stream_printf (surface->output, - "\n"); + "%d beginbfchar\n", + num_bfchar > 100 ? 100 : num_bfchar); + + for (i = 0; i < num_bfchar; i++) { + if (i != 0 && i % 100 == 0) { + _cairo_output_stream_printf (surface->output, + "endbfchar\n" + "%d beginbfchar\n", + num_bfchar - i > 100 ? 100 : num_bfchar - i); + } + _cairo_output_stream_printf (surface->output, "<%04x> ", i + 1); + status = _cairo_pdf_surface_emit_unicode_for_glyph (surface, + font_subset->utf8[i + 1]); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "\n"); + } + } else { + num_bfchar = font_subset->num_glyphs; + + /* The CMap specification has a limit of 100 characters per beginbfchar operator */ + _cairo_output_stream_printf (surface->output, + "%d beginbfchar\n", + num_bfchar > 100 ? 100 : num_bfchar); + + for (i = 0; i < num_bfchar; i++) { + if (i != 0 && i % 100 == 0) { + _cairo_output_stream_printf (surface->output, + "endbfchar\n" + "%d beginbfchar\n", + num_bfchar - i > 100 ? 100 : num_bfchar - i); + } + _cairo_output_stream_printf (surface->output, "<%02x> ", i); + status = _cairo_pdf_surface_emit_unicode_for_glyph (surface, + font_subset->utf8[i]); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "\n"); + } } + _cairo_output_stream_printf (surface->output, "endbfchar\n"); diff --git a/src/cairo-rtree-private.h b/src/cairo-rtree-private.h new file mode 100644 index 000000000..33c6bc80d --- /dev/null +++ b/src/cairo-rtree-private.h @@ -0,0 +1,125 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 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_RTREE_PRIVATE_H +#define CAIRO_RTREE_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-types-private.h" + +#include "cairo-freelist-private.h" +#include "cairo-list-private.h" + +enum { + CAIRO_RTREE_NODE_AVAILABLE, + CAIRO_RTREE_NODE_DIVIDED, + CAIRO_RTREE_NODE_OCCUPIED, +}; + +typedef struct _cairo_rtree_node { + struct _cairo_rtree_node *children[4], *parent; + void **owner; + cairo_list_t link; + uint16_t pinned; + uint16_t state; + uint16_t x, y; + uint16_t width, height; +} cairo_rtree_node_t; + +typedef struct _cairo_rtree { + cairo_rtree_node_t root; + int min_size; + void (*evict) (void *node); + cairo_list_t pinned; + cairo_list_t available; + cairo_list_t evictable; + cairo_freepool_t node_freepool; +} cairo_rtree_t; + +cairo_private cairo_rtree_node_t * +_cairo_rtree_node_create (cairo_rtree_t *rtree, + cairo_rtree_node_t *parent, + int x, + int y, + int width, + int height); + +cairo_private cairo_status_t +_cairo_rtree_node_insert (cairo_rtree_t *rtree, + cairo_rtree_node_t *node, + int width, + int height, + cairo_rtree_node_t **out); + +cairo_private void +_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node); + +cairo_private void +_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node); + +cairo_private void +_cairo_rtree_init (cairo_rtree_t *rtree, + int width, + int height, + int min_size, + int node_size, + void (*evict) (void *node)); + +cairo_private cairo_int_status_t +_cairo_rtree_insert (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out); + +cairo_private cairo_int_status_t +_cairo_rtree_evict_random (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out); + +cairo_private void * +_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node); + +cairo_private void +_cairo_rtree_unpin (cairo_rtree_t *rtree); + +cairo_private void +_cairo_rtree_reset (cairo_rtree_t *rtree); + +cairo_private void +_cairo_rtree_fini (cairo_rtree_t *rtree); + +#endif /* CAIRO_RTREE_PRIVATE_H */ diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c new file mode 100644 index 000000000..ba142b7ac --- /dev/null +++ b/src/cairo-rtree.c @@ -0,0 +1,395 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 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-rtree-private.h" + +cairo_rtree_node_t * +_cairo_rtree_node_create (cairo_rtree_t *rtree, + cairo_rtree_node_t *parent, + int x, + int y, + int width, + int height) +{ + cairo_rtree_node_t *node; + + node = _cairo_freepool_alloc (&rtree->node_freepool); + if (node == NULL) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + node->children[0] = NULL; + node->parent = parent; + node->owner = NULL; + node->state = CAIRO_RTREE_NODE_AVAILABLE; + node->pinned = FALSE; + node->x = x; + node->y = y; + node->width = width; + node->height = height; + + cairo_list_add (&node->link, &rtree->available); + + return node; +} + +void +_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + int i; + + cairo_list_del (&node->link); + + if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { + if (node->owner != NULL) + *node->owner = NULL; + if (rtree->evict != NULL) + rtree->evict (node); + } else { + for (i = 0; i < 4 && node->children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, node->children[i]); + } + + _cairo_freepool_free (&rtree->node_freepool, node); +} + +void +_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + int i; + + assert (node->pinned == FALSE); + + do { + assert (node->state == CAIRO_RTREE_NODE_DIVIDED); + + for (i = 0; i < 4 && node->children[i] != NULL; i++) + if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE) + return; + + for (i = 0; i < 4 && node->children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, node->children[i]); + + node->children[0] = NULL; + node->state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_move (&node->link, &rtree->available); + + node = node->parent; + } while (node != NULL && ! node->pinned); +} + +cairo_status_t +_cairo_rtree_node_insert (cairo_rtree_t *rtree, + cairo_rtree_node_t *node, + int width, + int height, + cairo_rtree_node_t **out) +{ + int w, h, i; + + assert (node->state == CAIRO_RTREE_NODE_AVAILABLE); + assert (node->pinned == FALSE); + + if (node->width - width > rtree->min_size || + node->height - height > rtree->min_size) + { + w = node->width - width; + h = node->height - height; + + i = 0; + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x, node->y, + width, height); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + + if (w > rtree->min_size) { + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x + width, + node->y, + w, height); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + } + + if (h > rtree->min_size) { + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x, + node->y + height, + width, h); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + + if (w > rtree->min_size) { + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x + width, + node->y + height, + w, h); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + } + } + + if (i < 4) + node->children[i] = NULL; + + node->state = CAIRO_RTREE_NODE_DIVIDED; + cairo_list_move (&node->link, &rtree->evictable); + node = node->children[0]; + } + + node->state = CAIRO_RTREE_NODE_OCCUPIED; + cairo_list_move (&node->link, &rtree->evictable); + *out = node; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_rtree_insert (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out) +{ + cairo_rtree_node_t *node; + + cairo_list_foreach_entry (node, cairo_rtree_node_t, + &rtree->available, link) + { + if (node->width >= width && node->height >= height) + return _cairo_rtree_node_insert (rtree, node, width, height, out); + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + static uint32_t x; + return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; +#undef rol +} + +cairo_int_status_t +_cairo_rtree_evict_random (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out) +{ + cairo_rtree_node_t *node; + int i, cnt; + + cnt = 0; + cairo_list_foreach_entry (node, cairo_rtree_node_t, + &rtree->evictable, link) + { + if (node->width >= width && node->height >= height) + cnt++; + } + + if (cnt == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cnt = hars_petruska_f54_1_random () % cnt; + cairo_list_foreach_entry (node, cairo_rtree_node_t, + &rtree->evictable, link) + { + if (node->width >= width && node->height >= height && cnt-- == 0) { + if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { + if (node->owner != NULL) + *node->owner = NULL; + if (rtree->evict != NULL) + rtree->evict (node); + } else { + for (i = 0; i < 4 && node->children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, node->children[i]); + node->children[0] = NULL; + } + + node->state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_move (&node->link, &rtree->available); + + *out = node; + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +void * +_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + void *ptr = node; + + while (node->pinned == FALSE) { + cairo_list_move (&node->link, &rtree->pinned); + node->pinned = TRUE; + node = node->parent; + if (node == NULL) + break; + } + + return ptr; +} + +void +_cairo_rtree_unpin (cairo_rtree_t *rtree) +{ + cairo_rtree_node_t *node, *next; + cairo_list_t can_collapse; + + if (cairo_list_is_empty (&rtree->pinned)) + return; + + cairo_list_init (&can_collapse); + + cairo_list_foreach_entry_safe (node, next, + cairo_rtree_node_t, + &rtree->pinned, + link) + { + node->pinned = FALSE; + if (node->state == CAIRO_RTREE_NODE_OCCUPIED && node->owner == NULL) { + cairo_bool_t all_available; + int i; + + node->state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_move (&node->link, &rtree->available); + + all_available = TRUE; + node = node->parent; + for (i = 0; i < 4 && node->children[i] != NULL && all_available; i++) + all_available &= node->children[i]->state == CAIRO_RTREE_NODE_AVAILABLE; + + if (all_available) { + cairo_list_move (&node->link, &can_collapse); + for (i = 0; i < 4 && node->children[i] != NULL; i++) + cairo_list_del (&node->children[i]->link); + } + } + else + { + cairo_list_move (&node->link, &rtree->evictable); + } + } + + cairo_list_foreach_entry_safe (node, next, + cairo_rtree_node_t, + &can_collapse, + link) + { + _cairo_rtree_node_collapse (rtree, node); + } +} + +void +_cairo_rtree_init (cairo_rtree_t *rtree, + int width, + int height, + int min_size, + int node_size, + void (*evict) (void *node)) +{ + rtree->evict = evict; + + assert (node_size >= (int) sizeof (cairo_rtree_node_t)); + _cairo_freepool_init (&rtree->node_freepool, node_size); + + cairo_list_init (&rtree->available); + cairo_list_init (&rtree->pinned); + cairo_list_init (&rtree->evictable); + + rtree->min_size = min_size; + + memset (&rtree->root, 0, sizeof (rtree->root)); + rtree->root.width = width; + rtree->root.height = height; + rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_add (&rtree->root.link, &rtree->available); +} + +void +_cairo_rtree_reset (cairo_rtree_t *rtree) +{ + int i; + + if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { + if (rtree->root.owner != NULL) + *rtree->root.owner = NULL; + if (rtree->evict != NULL) + rtree->evict (&rtree->root); + } else { + for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); + rtree->root.children[0] = NULL; + } + + cairo_list_init (&rtree->available); + cairo_list_init (&rtree->evictable); + cairo_list_init (&rtree->pinned); + + rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE; + rtree->root.pinned = FALSE; + cairo_list_add (&rtree->root.link, &rtree->available); +} + +void +_cairo_rtree_fini (cairo_rtree_t *rtree) +{ + int i; + + if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { + if (rtree->root.owner != NULL) + *rtree->root.owner = NULL; + if (rtree->evict != NULL) + rtree->evict (&rtree->root); + } else { + for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); + } + + _cairo_freepool_fini (&rtree->node_freepool); +} diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index bf5a4f736..2b5b26dd6 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -1428,22 +1428,22 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, extents->x_advance = 0.0; extents->y_advance = 0.0; - if (scaled_font->status) - return; + if (unlikely (scaled_font->status)) + goto ZERO_EXTENTS; if (num_glyphs == 0) - return; + goto ZERO_EXTENTS; - if (num_glyphs < 0) { + if (unlikely (num_glyphs < 0)) { _cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT); /* XXX Can't propagate error */ - return; + goto ZERO_EXTENTS; } - if (glyphs == NULL) { + if (unlikely (glyphs == NULL)) { _cairo_error_throw (CAIRO_STATUS_NULL_POINTER); /* XXX Can't propagate error */ - return; + goto ZERO_EXTENTS; } _cairo_scaled_font_freeze_cache (scaled_font); @@ -1514,6 +1514,15 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, UNLOCK: _cairo_scaled_font_thaw_cache (scaled_font); + return; + +ZERO_EXTENTS: + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; } slim_hidden_def (cairo_scaled_font_glyph_extents); @@ -2028,7 +2037,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, for (i = 0; i < num_glyphs; i++) { int x, y; - cairo_surface_pattern_t glyph_pattern; cairo_image_surface_t *glyph_surface; cairo_scaled_glyph_t *scaled_glyph; @@ -2046,8 +2054,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, * glyph. Later we'll deal with different formats. */ if (mask == NULL) { mask_format = glyph_surface->format; - mask = cairo_image_surface_create (mask_format, - width, height); + mask = cairo_image_surface_create (mask_format, width, height); status = mask->status; if (unlikely (status)) goto CLEANUP_MASK; @@ -2074,10 +2081,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, break; } - new_mask = cairo_image_surface_create (mask_format, - width, height); - if (new_mask->status) { - status = new_mask->status; + new_mask = cairo_image_surface_create (mask_format, width, height); + status = new_mask->status; + if (unlikely (status)) { cairo_surface_destroy (new_mask); goto CLEANUP_MASK; } @@ -2105,33 +2111,41 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, mask = new_mask; } - /* round glyph locations to the nearest pixel */ - /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ - x = _cairo_lround (glyphs[i].x - glyph_surface->base.device_transform.x0); - y = _cairo_lround (glyphs[i].y - glyph_surface->base.device_transform.y0); + if (glyph_surface->width && glyph_surface->height) { + cairo_surface_pattern_t glyph_pattern; - _cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base); + /* round glyph locations to the nearest pixel */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (glyphs[i].x - + glyph_surface->base.device_transform.x0); + y = _cairo_lround (glyphs[i].y - + glyph_surface->base.device_transform.y0); - status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, - &white_pattern.base, - &glyph_pattern.base, - mask, - 0, 0, - 0, 0, - x - dest_x, y - dest_y, - glyph_surface->width, - glyph_surface->height, - NULL); + _cairo_pattern_init_for_surface (&glyph_pattern, + &glyph_surface->base); - _cairo_pattern_fini (&glyph_pattern.base); + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + &white_pattern.base, + &glyph_pattern.base, + mask, + 0, 0, + 0, 0, + x - dest_x, y - dest_y, + glyph_surface->width, + glyph_surface->height, + NULL); - if (unlikely (status)) - goto CLEANUP_MASK; + _cairo_pattern_fini (&glyph_pattern.base); + + if (unlikely (status)) + goto CLEANUP_MASK; + } } - if (mask_format == CAIRO_FORMAT_ARGB32) + if (mask_format == CAIRO_FORMAT_ARGB32) { pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)-> pixman_image, TRUE); + } _cairo_pattern_init_for_surface (&mask_pattern, mask); status = _cairo_surface_composite (op, pattern, &mask_pattern.base, diff --git a/src/cairo-spline.c b/src/cairo-spline.c index 45eedbd6a..8bebcb2a8 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -43,6 +43,8 @@ _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_slope_t slope; + spline->add_point_func = add_point_func; spline->closure = closure; @@ -67,6 +69,13 @@ _cairo_spline_init (cairo_spline_t *spline, else _cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d); + _cairo_slope_init (&slope, &spline->knots.a, &spline->knots.d); + if (_cairo_slope_compare (&slope, &spline->initial_slope) == 0 && + _cairo_slope_compare (&slope, &spline->final_slope) == 0) + { + return FALSE; /* just a straight line... */ + } + return TRUE; } diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index a68fe500b..b55362092 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -166,7 +166,6 @@ typedef enum _cairo_int_status { typedef enum _cairo_internal_surface_type { CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED = 0x1000, CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS, - CAIRO_INTERNAL_SURFACE_TYPE_TEST_META, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING, @@ -174,6 +173,10 @@ typedef enum _cairo_internal_surface_type { CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH } cairo_internal_surface_type_t; +#define CAIRO_HAS_TEST_PAGINATED_SURFACE 1 +#define CAIRO_HAS_TEST_NULL_SURFACE 1 +#define CAIRO_HAS_TEST_WRAPPING_SURFACE 1 + typedef struct _cairo_point { cairo_fixed_t x; cairo_fixed_t y; diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index 65df2b719..d9ee90483 100644 --- a/src/cairo-xlib-display.c +++ b/src/cairo-xlib-display.c @@ -457,6 +457,12 @@ _cairo_xlib_display_notify (cairo_xlib_display_t *display) cairo_xlib_job_t *jobs, *job, *freelist; Display *dpy = display->display; + /* Optimistic atomic pointer read -- don't care if it is wrong due to + * contention as we will check again very shortly. + */ + if (display->workqueue == NULL) + return; + CAIRO_MUTEX_LOCK (display->mutex); jobs = display->workqueue; while (jobs != NULL) { @@ -508,6 +514,12 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, { XRenderPictFormat *xrender_format; +#if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER + xrender_format = display->cached_xrender_formats[format]; + if (likely (xrender_format != NULL)) + return xrender_format; +#endif + CAIRO_MUTEX_LOCK (display->mutex); xrender_format = display->cached_xrender_formats[format]; if (xrender_format == NULL) { diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 647e61fb3..4bc244a51 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -39,6 +39,12 @@ * Karl Tomlinson , Mozilla Corporation */ +/* Heed well the words of Owen Taylor: + * "Any patch that works around a render bug, or claims to, without a + * specific reference to the bug filed in bugzilla.freedesktop.org will + * never pass approval." + */ + #include "cairoint.h" #include "cairo-xlib-private.h" diff --git a/src/cairoint.h b/src/cairoint.h index 3cd0cb374..6010e20fa 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -857,6 +857,7 @@ struct _cairo_image_surface { pixman_image_t *pixman_image; cairo_region_t *clip_region; + unsigned is_clear : 1; unsigned owns_data : 1; unsigned transparency : 2; }; diff --git a/test/Makefile.am b/test/Makefile.am index ec5dfac90..b79428344 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -679,6 +679,10 @@ REFERENCE_IMAGES = \ over-between-source.svg12.rgb24.xfail.png \ over-between-source.xlib.ref.png \ over-between-source.xlib.rgb24.ref.png \ + overlapping-glyphs.argb32.ref.png \ + overlapping-glyphs.rgb24.ref.png \ + overlapping-glyphs.pdf.argb32.xfail.png \ + overlapping-glyphs.pdf.rgb24.xfail.png \ paint-repeat.ref.png \ paint-source-alpha.ref.png \ paint-source-alpha.svg.ref.png \ diff --git a/test/Makefile.sources b/test/Makefile.sources index f8c63cd0a..b468bf266 100644 --- a/test/Makefile.sources +++ b/test/Makefile.sources @@ -132,6 +132,7 @@ test_sources = \ over-around-source.c \ over-below-source.c \ over-between-source.c \ + overlapping-glyphs.c \ paint.c \ paint-repeat.c \ paint-source-alpha.c \ diff --git a/test/cairo-test.c b/test/cairo-test.c index 34dd60020..430acc17c 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -1509,6 +1509,7 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx, #if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H) if (ctx->thread == 0 && ! RUNNING_ON_VALGRIND) { void (* volatile old_segfault_handler)(int); + void (* volatile old_segfpe_handler)(int); void (* volatile old_sigpipe_handler)(int); void (* volatile old_sigabrt_handler)(int); void (* volatile old_sigalrm_handler)(int); @@ -1517,6 +1518,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx, #ifdef SIGSEGV old_segfault_handler = signal (SIGSEGV, segfault_handler); #endif +#ifdef SIGFPE + old_segfpe_handler = signal (SIGFPE, segfault_handler); +#endif #ifdef SIGPIPE old_sigpipe_handler = signal (SIGPIPE, segfault_handler); #endif @@ -1533,6 +1537,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx, #ifdef SIGSEGV signal (SIGSEGV, old_segfault_handler); #endif +#ifdef SIGFPE + signal (SIGFPE, old_segfpe_handler); +#endif #ifdef SIGPIPE signal (SIGPIPE, old_sigpipe_handler); #endif diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png index 786587c3f..043322280 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.pdf.rgb24.ref.png b/test/meta-surface-pattern.pdf.rgb24.ref.png index f542dabf2..b59a9caf8 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/overlapping-glyphs.argb32.ref.png b/test/overlapping-glyphs.argb32.ref.png new file mode 100644 index 000000000..2e2d60c00 Binary files /dev/null and b/test/overlapping-glyphs.argb32.ref.png differ diff --git a/test/overlapping-glyphs.c b/test/overlapping-glyphs.c new file mode 100644 index 000000000..690a6dd25 --- /dev/null +++ b/test/overlapping-glyphs.c @@ -0,0 +1,123 @@ +/* + * Copyright © 2009 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 + +#define TEXT_SIZE 12 +#define HEIGHT (TEXT_SIZE + 4) +#define WIDTH 50 + +#define MAX_GLYPHS 80 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_glyph_t glyphs_stack[MAX_GLYPHS], *glyphs; + const char *cairo = "Cairo"; + const char *giza = "Giza"; + cairo_text_extents_t cairo_extents; + cairo_text_extents_t giza_extents; + int count, num_glyphs; + double x0, y0; + + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_select_font_face (cr, "Bitstream Vera Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + /* We want to overlap two strings, so compute overlapping glyphs. */ + + cairo_text_extents (cr, cairo, &cairo_extents); + cairo_text_extents (cr, giza, &giza_extents); + + x0 = WIDTH/2. - (cairo_extents.width/2. + cairo_extents.x_bearing); + y0 = HEIGHT/2. - (cairo_extents.height/2. + cairo_extents.y_bearing); + glyphs = glyphs_stack; + count = MAX_GLYPHS; + cairo_scaled_font_text_to_glyphs (cairo_get_scaled_font (cr), + x0, y0, + cairo, strlen (cairo), + &glyphs, &count, + NULL, NULL, + NULL); + assert (glyphs == glyphs_stack); + num_glyphs = count; + + x0 = WIDTH/2. - (giza_extents.width/2. + giza_extents.x_bearing); + y0 = HEIGHT/2. - (giza_extents.height/2. + giza_extents.y_bearing); + glyphs = glyphs_stack + count; + count = MAX_GLYPHS - count; + cairo_scaled_font_text_to_glyphs (cairo_get_scaled_font (cr), + x0, y0, + giza, strlen (giza), + &glyphs, &count, + NULL, NULL, + NULL); + assert (glyphs == glyphs_stack + num_glyphs); + glyphs = glyphs_stack; + num_glyphs += count; + + cairo_set_source_rgba (cr, 0, 0, 0, .5); /* translucent black, gray! */ + cairo_show_glyphs (cr, glyphs, num_glyphs); + + /* and compare with filling */ + cairo_translate (cr, 0, HEIGHT); + cairo_glyph_path (cr, glyphs, num_glyphs); + cairo_fill (cr); + + /* switch to using an unbounded operator for added complexity */ + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + + cairo_translate (cr, WIDTH, -HEIGHT); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + cairo_show_glyphs (cr, glyphs, num_glyphs); + cairo_restore (cr); + + cairo_translate (cr, 0, HEIGHT); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + cairo_glyph_path (cr, glyphs, num_glyphs); + cairo_fill (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (overlapping_glyphs, + "Test handing of overlapping glyphs", + "text, glyphs", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, 2 * HEIGHT, + NULL, draw) + diff --git a/test/overlapping-glyphs.pdf.argb32.xfail.png b/test/overlapping-glyphs.pdf.argb32.xfail.png new file mode 100644 index 000000000..e3e433727 Binary files /dev/null and b/test/overlapping-glyphs.pdf.argb32.xfail.png differ diff --git a/test/overlapping-glyphs.pdf.rgb24.xfail.png b/test/overlapping-glyphs.pdf.rgb24.xfail.png new file mode 100644 index 000000000..a3f1d7047 Binary files /dev/null and b/test/overlapping-glyphs.pdf.rgb24.xfail.png differ diff --git a/test/overlapping-glyphs.rgb24.ref.png b/test/overlapping-glyphs.rgb24.ref.png new file mode 100644 index 000000000..d97813836 Binary files /dev/null and b/test/overlapping-glyphs.rgb24.ref.png differ diff --git a/test/radial-gradient.c b/test/radial-gradient.c index 9793feae8..a6d145c63 100644 --- a/test/radial-gradient.c +++ b/test/radial-gradient.c @@ -29,7 +29,7 @@ #define NUM_GRADIENTS 4 #define NUM_EXTEND 4 #define SIZE 60 -#define WIDTH (SIZE * NUM_GRADIENTS) +#define WIDTH (SIZE * NUM_GRADIENTS * NUM_GRADIENTS) #define HEIGHT (SIZE * NUM_EXTEND) static void @@ -37,18 +37,22 @@ draw_gradient (cairo_t *cr, int x, int y, int size, - double offset, - double inner_radius, + double r1_offset, + double r1_radius, + double r2_offset, + double r2_radius, cairo_extend_t extend) { cairo_pattern_t *pattern; cairo_save (cr); - pattern = cairo_pattern_create_radial (x + size/2.0 + offset, - y + size/2.0 + offset, inner_radius, - x + size/2.0, - y + size/2.0, size/3.0); + pattern = cairo_pattern_create_radial (x + size/2.0 + r1_offset, + y + size/2.0 + r1_offset, + r1_radius, + x + size/2.0 + r2_offset, + y + size/2.0 + r2_offset, + r2_radius); cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1.0, 0.0, 0.0, 1.0); cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0), @@ -71,8 +75,7 @@ draw_gradient (cairo_t *cr, static cairo_test_status_t draw (cairo_t *cr, int width, int height) { - int i, j; - double inner_radius, offset; + int i, j, k; cairo_extend_t extend[NUM_EXTEND] = { CAIRO_EXTEND_NONE, CAIRO_EXTEND_REPEAT, @@ -84,10 +87,17 @@ draw (cairo_t *cr, int width, int height) for (j = 0; j < NUM_EXTEND; j++) { for (i = 0; i < NUM_GRADIENTS; i++) { - offset = i % 2 ? SIZE / 12.0 : 0.0; - inner_radius = i >= NUM_EXTEND / 2 ? SIZE / 6.0 : 0.0; - draw_gradient (cr, i * SIZE, j * SIZE, SIZE, - offset, inner_radius, extend[j]); + double r1_offset = i % 2 ? SIZE / 12.0 : 0.0; + double r1_radius = i >= NUM_GRADIENTS / 2 ? SIZE / 6.0 : 0.0; + for (k = 0; k < NUM_GRADIENTS; k++) { + double r2_offset = k % 2 ? SIZE / 12.0 : 0.0; + double r2_radius = k >= NUM_GRADIENTS / 2 ? SIZE / 3.0 : SIZE / 12.; + draw_gradient (cr, + i * SIZE * NUM_GRADIENTS + k * SIZE, j * SIZE, SIZE, + r1_offset, r1_radius, + r2_offset, r2_radius, + extend[j]); + } } } diff --git a/test/radial-gradient.pdf.ref.png b/test/radial-gradient.pdf.ref.png index dbb7312a6..5bbd733f5 100644 Binary files a/test/radial-gradient.pdf.ref.png and b/test/radial-gradient.pdf.ref.png differ diff --git a/test/radial-gradient.ref.png b/test/radial-gradient.ref.png index ab1085816..bec83b7fa 100644 Binary files a/test/radial-gradient.ref.png and b/test/radial-gradient.ref.png differ diff --git a/test/scale-offset-image.pdf.xfail.png b/test/scale-offset-image.pdf.xfail.png index 4c7fe2831..3eacbbc86 100644 Binary files a/test/scale-offset-image.pdf.xfail.png and b/test/scale-offset-image.pdf.xfail.png differ diff --git a/test/scale-offset-similar.pdf.xfail.png b/test/scale-offset-similar.pdf.xfail.png index 4b600f4c9..7808aeb9a 100644 Binary files a/test/scale-offset-similar.pdf.xfail.png and b/test/scale-offset-similar.pdf.xfail.png differ diff --git a/test/user-font-rescale.c b/test/user-font-rescale.c index ae56ef849..54b3a20ca 100644 --- a/test/user-font-rescale.c +++ b/test/user-font-rescale.c @@ -257,11 +257,11 @@ get_user_font_face (cairo_font_face_t *substitute_font, text, -1, &glyphs, &num_glyphs, NULL, NULL, NULL); - if (status) { - cairo_font_options_destroy (options); - cairo_scaled_font_destroy (measure); + cairo_font_options_destroy (options); + cairo_scaled_font_destroy (measure); + + if (status) return status; - } /* find the glyph range the text covers */ max_index = glyphs[0].index; @@ -274,7 +274,7 @@ get_user_font_face (cairo_font_face_t *substitute_font, } count = max_index - min_index + 1; - widths = xmalloc (sizeof(double) * count); + widths = xcalloc (sizeof (double), count); /* measure all of the necessary glyphs individually */ for (i=0; ibase.ref == 0) csi_string_free (ctx, source); + if (source->deflate) { + _csi_free (ctx, bytes); + bytes = data->blob.bytes + vec[0].num_bytes; + } else + bytes = data->blob.bytes; + data->source = NULL; data->bytes = NULL; } else { @@ -5714,6 +5720,7 @@ _integer_constants[] = { { "XOR", CAIRO_OPERATOR_XOR }, { "ADD", CAIRO_OPERATOR_ADD }, { "SATURATE", CAIRO_OPERATOR_SATURATE }, +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 9, 4) { "MULTIPLY", CAIRO_OPERATOR_MULTIPLY }, { "SCREEN", CAIRO_OPERATOR_SCREEN }, { "OVERLAY", CAIRO_OPERATOR_OVERLAY }, @@ -5729,6 +5736,7 @@ _integer_constants[] = { { "HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION }, { "HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR }, { "HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY }, +#endif { "WINDING", CAIRO_FILL_RULE_WINDING }, { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD }, diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c index 3cc395757..1d717f4b5 100644 --- a/util/cairo-script/cairo-script-scanner.c +++ b/util/cairo-script/cairo-script-scanner.c @@ -665,17 +665,17 @@ base85_end (csi_t *ctx, csi_scanner_t *scan, cairo_bool_t deflate) longjmp (scan->jmpbuf, status); } -static void +static inline void scan_read (csi_scanner_t *scan, csi_file_t *src, void *ptr, int len) { uint8_t *data = ptr; - while (len) { + do { int ret = csi_file_read (src, data, len); if (_csi_unlikely (ret == 0)) longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_READ_ERROR)); data += ret; len -= ret; - } + } while (_csi_unlikely (len)); } static void