From a44bf947bc4c5bf8d6398d9bb9b4d8284d8393b5 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Mon, 26 Jul 2010 10:04:52 +1200 Subject: [PATCH 1/2] xlib: use XCopyArea for operator SOURCE with compatible COLOR_ALPHA surfaces Use the same XCopyArea path used for CONTENT_COLOR surfaces if it is suitable for CONTENT_COLOR_ALPHA surfaces. This provides expected behavior for simple self-copies. The check for matching source and destination formats is also tightened. Different formats may have the same depth. test: Added self-copy-source-overlap. https://bugs.freedesktop.org/show_bug.cgi?id=29250 --- src/cairo-xlib-surface.c | 27 +++---- test/Makefile.sources | 1 + test/self-copy-source-overlap.c | 102 +++++++++++++++++++++++++ test/self-copy-source-overlap.image.xfail.png | Bin 0 -> 670 bytes test/self-copy-source-overlap.ref.png | Bin 0 -> 658 bytes 5 files changed, 116 insertions(+), 14 deletions(-) create mode 100644 test/self-copy-source-overlap.c create mode 100644 test/self-copy-source-overlap.image.xfail.png create mode 100644 test/self-copy-source-overlap.ref.png diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 350331d..6a5ef67 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -1839,20 +1839,21 @@ _surface_has_alpha (cairo_xlib_surface_t *surface) } } -/* Returns true if the given operator and source-alpha combination - * requires alpha compositing to complete. +/* Returns true if the given operator and alpha combination requires alpha + * compositing to complete on source and destination surfaces with the same + * format. i.e. if a simple bitwise copy is not appropriate. */ static cairo_bool_t _operator_needs_alpha_composite (cairo_operator_t op, - cairo_bool_t destination_has_alpha, - cairo_bool_t source_has_alpha) + cairo_bool_t surfaces_have_alpha) { - if (op == CAIRO_OPERATOR_SOURCE || - (! source_has_alpha && - (op == CAIRO_OPERATOR_OVER || - op == CAIRO_OPERATOR_ATOP || - op == CAIRO_OPERATOR_IN))) - return destination_has_alpha; + if (op == CAIRO_OPERATOR_SOURCE) + return FALSE; + + if (op == CAIRO_OPERATOR_OVER || + op == CAIRO_OPERATOR_IN || + op == CAIRO_OPERATOR_ATOP) + return surfaces_have_alpha; return TRUE; } @@ -1963,11 +1964,9 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst, /* Can we use the core protocol? */ if (! have_mask && src->owns_pixmap && - src->depth == dst->depth && + _surfaces_compatible (src, dst) && _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) && - ! _operator_needs_alpha_composite (op, - _surface_has_alpha (dst), - _surface_has_alpha (src))) + ! _operator_needs_alpha_composite (op, _surface_has_alpha (dst))) { if (src_attr->extend == CAIRO_EXTEND_NONE) return DO_XCOPYAREA; diff --git a/test/Makefile.sources b/test/Makefile.sources index 42afafd..8cc994e 100644 --- a/test/Makefile.sources +++ b/test/Makefile.sources @@ -227,6 +227,7 @@ test_sources = \ select-font-no-show-text.c \ self-copy.c \ self-copy-overlap.c \ + self-copy-source-overlap.c \ self-intersecting.c \ set-source.c \ show-glyphs-many.c \ diff --git a/test/self-copy-source-overlap.c b/test/self-copy-source-overlap.c new file mode 100644 index 0000000..4b458d0 --- /dev/null +++ b/test/self-copy-source-overlap.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2005 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. + * + * Authors: Owen Taylor + * Karl Tomlinson + */ + +#include "cairo-test.h" + +#define SIZE 200 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *target = cairo_get_group_target (cr); + cairo_content_t content = cairo_surface_get_content (target); + int pushed_group = 0; + + /* The xlib backend currently only passes if it knows that the surface is + a Pixmap, which is currently only for surfaces from + cairo_surface_create_similar. Other surfaces behave like Windows. + See http://lists.cairographics.org/archives/cairo/2010-July/020352.html + When that is resolved, this push_group should be removed. + */ + if (cairo_surface_get_type (target) == CAIRO_SURFACE_TYPE_XLIB) { + cairo_push_group_with_content (cr, content); + pushed_group = 1; + target = cairo_get_group_target (cr); + if (cairo_surface_get_type (target) == CAIRO_SURFACE_TYPE_IMAGE) { + /* Don't test a fallback image surface. xlib-fallback passes + without push-group, but image fails (tested separately). */ + cairo_pattern_destroy (cairo_pop_group (cr)); + pushed_group = 0; + target = cairo_get_group_target (cr); + } + } + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + /* Paint a 4-square checker board as a test image */ + cairo_set_source_rgb (cr, 1, 1, 1); /* White */ + cairo_paint (cr); + + cairo_rectangle (cr, 0, 0, SIZE / 2, SIZE / 2); + cairo_rectangle (cr, SIZE / 2, SIZE / 2, SIZE / 2, SIZE / 2); + + cairo_set_source_rgb (cr, 0, 0, 0); /* Black */ + cairo_fill (cr); + + /* Copy from nearer the middle of the target surface to each of the corner + quarters. */ + + cairo_set_source_surface (cr, target, - SIZE / 8, - SIZE / 8); + cairo_rectangle (cr, 0, 0, SIZE / 2, SIZE / 2); + cairo_fill (cr); + + cairo_set_source_surface (cr, target, - SIZE / 8, SIZE / 8); + cairo_rectangle (cr, 0, SIZE / 2, SIZE / 2, SIZE / 2); + cairo_fill (cr); + + cairo_set_source_surface (cr, target, SIZE / 8, - SIZE / 8); + cairo_rectangle (cr, SIZE / 2, 0, SIZE / 2, SIZE / 2); + cairo_fill (cr); + + cairo_set_source_surface (cr, target, SIZE / 8, SIZE / 8); + cairo_rectangle (cr, SIZE / 2, SIZE / 2, SIZE / 2, SIZE / 2); + cairo_fill (cr); + + if (pushed_group) { + cairo_pop_group_to_source (cr); + cairo_paint (cr); + } + + return CAIRO_TEST_SUCCESS; + +} + +CAIRO_TEST (self_copy_source_overlap, + "Test operator-source copying from a surface to itself with integer overlap", + "self-copy", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/test/self-copy-source-overlap.image.xfail.png b/test/self-copy-source-overlap.image.xfail.png new file mode 100644 index 0000000000000000000000000000000000000000..5469d5e48cfa9d5e407909e581cbbdbb5b77a934 GIT binary patch literal 670 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k2}mkgS)K$^Y)RhkE)4%caKYZ?lNlJ8f<0Xv zLn`LHy?c=NkbwY$W6z8IPcJyh#XU7JW?c{*arga`uU2QqITE4`cWRAt0QzsNs&BaW8eNcb1GAJ6|S0@L!Jp>iw(cDUVXgYC*5!B z#9j)5q)cv&T>bgXRlg~5%f`=z=VnfyY<%`lnDp{Z8$CF>TQ-nI9GO*Vd9v2{zoRs{ eCIBt2VYCU=Mh{yWs=l2-hwYWMnhXQXDzTjW|c)id0Ia$im z-7OnDILIS@B!1-v8e_g`Be^DUbRSu0zh++MpQ$h1C&&