diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | cairo.pc.in | 2 | ||||
-rw-r--r-- | configure.in | 26 | ||||
-rw-r--r-- | src/Makefile.am | 9 | ||||
-rw-r--r-- | src/cairo-features.h.in | 2 | ||||
-rw-r--r-- | src/cairo-pattern.c | 14 | ||||
-rw-r--r-- | src/cairo-surface.c | 12 | ||||
-rw-r--r-- | src/cairo.h | 16 | ||||
-rw-r--r-- | src/cairo_gl_surface.c | 821 | ||||
-rw-r--r-- | src/cairo_pattern.c | 14 | ||||
-rw-r--r-- | src/cairo_surface.c | 12 |
12 files changed, 912 insertions, 29 deletions
@@ -9,6 +9,7 @@ Thomas Hunger <info@teh-web.de> Initial version of cairo_in_stroke/fill Jordi Mas <jordi@ximian.com> Bug fix for cairo_show_text Keith Packard <keithp@keithp.com> Original concept, polygon tessellation, dashing Christof Petig <christof@petig-baender.de> Build fixes related to freetype +David Reveman <davidr@freedesktop.org> New pattern API, OpenGL backend Jamey Sharp <jamey@minilop.net> Surface/font backend virtualization, XCB backend Bill Spitzak <spitzak@d2.com> Build fix to find Xrender.h without xrender.pc Sasha Vasko <sasha@aftercode.net> Build fix to compile without xlib backend @@ -1,5 +1,17 @@ 2004-04-09 David Reveman <c99drn@cs.umu.se> + * src/cairo_surface.c (_cairo_surface_create_pattern): + * src/cairo_pattern.c (_cairo_pattern_get_image): Fixed + incorrect rounding of pattern image size. + + * AUTHORS: Added myself to the AUTHORS file. + + * cairo.pc.in: + * src/Makefile.am: + * src/cairo-features.h.in: + * src/cairo.h: + * src/cairo_gl_surface.c (added): Added OpenGL surface backend. + * configure.in: Automatically detect available backends. 2004-04-06 Carl Worth <cworth@isi.edu> diff --git a/cairo.pc.in b/cairo.pc.in index 316e6f337..c67dc05cb 100644 --- a/cairo.pc.in +++ b/cairo.pc.in @@ -7,7 +7,7 @@ Name: cairo Description: Multi-platform 2D graphics library Version: @VERSION@ -Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ +Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ @GL_REQUIRES@ Libs: -L${libdir} -lcairo -lm @XRENDER_LIBS@ @PS_LIBS@ @FREETYPE_LIBS@ Cflags: -I${includedir} @FREETYPE_CFLAGS@ diff --git a/configure.in b/configure.in index 2a0a7dc09..42dfd9d22 100644 --- a/configure.in +++ b/configure.in @@ -136,6 +136,31 @@ AC_SUBST(PNG_REQUIRES) dnl =========================================================================== +AC_ARG_ENABLE(gl, + [ --disable-gl Disable cairo's OpenGL backend], + [use_gl=$enableval], [use_gl=yes]) + +if test "x$use_gl" = "xyes"; then + PKG_CHECK_MODULES(GL, glitz >= 0.1.0, [ + GL_REQUIRES=glitz + use_gl=yes], [use_gl="no (requires glitz http://freedesktop.org/software/glitz)"]) +fi + +if test "x$use_gl" != "xyes"; then + GL_SURFACE_FEATURE=CAIRO_HAS_NO_GL_SURFACE + AM_CONDITIONAL(CAIRO_HAS_GL_SURFACE, false) +else + GL_SURFACE_FEATURE=CAIRO_HAS_GL_SURFACE + AM_CONDITIONAL(CAIRO_HAS_GL_SURFACE, true) +fi + +AC_SUBST(GL_LIBS) +AC_SUBST(GL_CFLAGS) +AC_SUBST(GL_SURFACE_FEATURE) +AC_SUBST(GL_REQUIRES) + +dnl =========================================================================== + PKG_CHECK_MODULES(FONTCONFIG, fontconfig) PKG_CHECK_MODULES(CAIRO, libpixman >= 0.1.0) @@ -203,5 +228,6 @@ echo " Xlib: $use_xlib" echo " XCB: $use_xcb" echo " PostScript: $use_ps" echo " PNG: $use_png" +echo " OpenGL: $use_gl" echo "" diff --git a/src/Makefile.am b/src/Makefile.am index 518e69f21..3b42d0e53 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,10 @@ if CAIRO_HAS_XCB_SURFACE libcairo_xcb_sources = cairo_xcb_surface.c endif +if CAIRO_HAS_GL_SURFACE +libcairo_gl_sources = cairo_gl_surface.c +endif + # These names match automake style variable definition conventions so # without these lines, automake will complain during the handling of # the libcairo_la_LIBADD below. (The INCLUDES is an autoconf only @@ -50,10 +54,11 @@ libcairo_la_SOURCES = \ $(libcairo_png_sources) \ $(libcairo_xlib_sources)\ $(libcairo_xcb_sources) \ + $(libcairo_gl_sources) \ cairoint.h libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) +INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) $(GL_CFLAGS) -libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) -lm +libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) $(GL_LIBS) -lm diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in index e9dacad51..7eec9780c 100644 --- a/src/cairo-features.h.in +++ b/src/cairo-features.h.in @@ -36,4 +36,6 @@ #define @XCB_SURFACE_FEATURE@ +#define @GL_SURFACE_FEATURE@ + #endif diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index dcdb1566a..6464d23f9 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -656,18 +656,18 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) case CAIRO_PATTERN_LINEAR: case CAIRO_PATTERN_RADIAL: { char *data; - int width = ceil (_cairo_fixed_to_double (box->p2.x) - - _cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y) - - _cairo_fixed_to_double (box->p1.y)); - + int width = ceil (_cairo_fixed_to_double (box->p2.x)) - + floor (_cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y)) - + floor (_cairo_fixed_to_double (box->p1.y)); + data = malloc (width * height * 4); if (!data) return NULL; _cairo_pattern_add_source_offset (pattern, - _cairo_fixed_to_double (box->p1.x), - _cairo_fixed_to_double (box->p1.y)); + floor (_cairo_fixed_to_double (box->p1.x)), + floor (_cairo_fixed_to_double (box->p1.y))); if (pattern->type == CAIRO_PATTERN_RADIAL) _cairo_image_data_set_radial (pattern, diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 91ab8aba4..60b4487d4 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -424,10 +424,10 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, /* handle pattern opacity */ if (pattern->color.alpha != 1.0) { - int width = ceil (_cairo_fixed_to_double (box->p2.x) - - _cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y) - - _cairo_fixed_to_double (box->p1.y)); + int width = ceil (_cairo_fixed_to_double (box->p2.x)) - + floor (_cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y)) - + floor (_cairo_fixed_to_double (box->p1.y)); cairo_pattern_t alpha; pattern->source = @@ -463,8 +463,8 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, if (status == CAIRO_STATUS_SUCCESS) { _cairo_pattern_add_source_offset (pattern, - _cairo_fixed_to_double (box->p1.x), - _cairo_fixed_to_double (box->p1.y)); + floor (_cairo_fixed_to_double (box->p1.x)), + floor (_cairo_fixed_to_double (box->p1.y))); } else cairo_surface_destroy (pattern->source); } diff --git a/src/cairo.h b/src/cairo.h index ab3c80e82..33ce402ee 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -141,6 +141,15 @@ cairo_set_target_xcb (cairo_t *cr, cairo_format_t format); #endif /* CAIRO_HAS_XCB_SURFACE */ +#ifdef CAIRO_HAS_GL_SURFACE + +#include <glitz.h> + +void +cairo_set_target_gl (cairo_t *cr, + glitz_surface_t *surface); +#endif /* CAIRO_HAS_GL_SURFACE */ + typedef enum cairo_operator { CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SRC, @@ -778,6 +787,13 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); #endif /* CAIRO_HAS_XLIB_SURFACE */ +#ifdef CAIRO_HAS_GL_SURFACE + +cairo_surface_t * +cairo_gl_surface_create (glitz_surface_t *surface); + +#endif /* CAIRO_HAS_GL_SURFACE */ + /* Matrix functions */ /* XXX: Rename all of these to cairo_transform_t */ diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c new file mode 100644 index 000000000..cb9871f6b --- /dev/null +++ b/src/cairo_gl_surface.c @@ -0,0 +1,821 @@ +/* + * Copyright © 2002 University of Southern California + * + * 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 the + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: David Reveman <c99drn@cs.umu.se> + */ + +#include "cairoint.h" + +static cairo_surface_t * +_cairo_gl_surface_create (glitz_surface_t *surface, + int owns_surface); + +void +cairo_set_target_gl (cairo_t *cr, glitz_surface_t *surface) +{ + cairo_surface_t *crsurface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + if (glitz_surface_get_hints (surface) & GLITZ_HINT_PROGRAMMATIC_MASK) { + cr->status = CAIRO_STATUS_NO_TARGET_SURFACE; + return; + } + + crsurface = _cairo_gl_surface_create (surface, 0); + if (crsurface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, crsurface); + + cairo_surface_destroy (crsurface); +} + +typedef struct cairo_gl_surface cairo_gl_surface_t; + +struct cairo_gl_surface { + cairo_surface_t base; + + glitz_format_t *format; + long int features; + long int hints; + int owns_surface; + + cairo_pattern_t pattern; + cairo_box_t pattern_box; + + glitz_surface_t *surface; +}; + +#define CAIRO_GL_OFFSCREEN_SUPPORT(surface) \ + (surface->features & GLITZ_FEATURE_OFFSCREEN_DRAWING_MASK) + +#define CAIRO_GL_CONVOLUTION_SUPPORT(surface) \ + (surface->features & GLITZ_FEATURE_CONVOLUTION_FILTER_MASK) + +#define CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT(surface) \ + (surface->features & GLITZ_FEATURE_ARB_FRAGMENT_PROGRAM_MASK) + +#define CAIRO_GL_TEXTURE_NPOT_SUPPORT(surface) \ + (surface->features & GLITZ_FEATURE_TEXTURE_NPOT_MASK) + +#define CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT(surface) \ + (surface->features & GLITZ_FEATURE_TEXTURE_MIRRORED_REPEAT_MASK) + +#define CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT(surface) \ + ((surface->format->stencil_size < \ + ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) && \ + (!CAIRO_GL_OFFSCREEN_SUPPORT (surface))) + +#define CAIRO_GL_SURFACE_IS_OFFSCREEN(surface) \ + (surface->hints & GLITZ_HINT_OFFSCREEN_MASK) + +static void +_cairo_gl_surface_destroy (void *abstract_surface) +{ + cairo_gl_surface_t *surface = abstract_surface; + + if (surface->owns_surface && surface->surface) + glitz_surface_destroy (surface->surface); + + _cairo_pattern_fini (&surface->pattern); + + free (surface); +} + +static double +_cairo_gl_surface_pixels_per_inch (void *abstract_surface) +{ + return 96.0; +} + +static cairo_image_surface_t * +_cairo_gl_surface_get_image (void *abstract_surface) +{ + cairo_gl_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + char *pixels; + int width, height; + int rowstride; + cairo_format_masks_t format; + + if (surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) + return _cairo_pattern_get_image (&surface->pattern, + &surface->pattern_box); + + width = glitz_surface_get_width (surface->surface); + height = glitz_surface_get_height (surface->surface); + + rowstride = width * (surface->format->bpp / 8); + rowstride += (rowstride % 4) ? (4 - (rowstride % 4)) : 0; + + pixels = (char *) malloc (sizeof (char) * height * rowstride); + + glitz_surface_read_pixels (surface->surface, 0, 0, width, height, pixels); + + format.bpp = surface->format->bpp; + format.red_mask = surface->format->red_mask; + format.green_mask = surface->format->green_mask; + format.blue_mask = surface->format->blue_mask; + format.alpha_mask = surface->format->alpha_mask; + + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_masks (pixels, + &format, + width, height, rowstride); + + _cairo_image_surface_assume_ownership_of_data (image); + + _cairo_image_surface_set_repeat (image, surface->base.repeat); + _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); + + return image; +} + +static cairo_status_t +_cairo_gl_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_gl_surface_t *surface = abstract_surface; + + glitz_surface_draw_pixels (surface->surface, 0, 0, + image->width, image->height, image->data); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_gl_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) +{ + cairo_gl_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + if (!surface->surface) + return CAIRO_STATUS_SUCCESS; + + transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + + transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); + + transform.matrix[2][0] = 0; + transform.matrix[2][1] = 0; + transform.matrix[2][2] = _cairo_fixed_from_double (1); + + glitz_surface_set_transform (surface->surface, &transform); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +{ + static glitz_convolution_t gaussian = { + { + {0, 1 << 16, 0}, + {1 << 16, 4 << 16, 1 << 16}, + {0, 1 << 16, 0} + } + }; + cairo_gl_surface_t *surface = abstract_surface; + glitz_filter_t gl_filter; + glitz_convolution_t *convolution = NULL; + + if (!surface->surface) + return CAIRO_STATUS_SUCCESS; + + switch (filter) { + case CAIRO_FILTER_FAST: + gl_filter = GLITZ_FILTER_FAST; + break; + case CAIRO_FILTER_GOOD: + gl_filter = GLITZ_FILTER_GOOD; + break; + case CAIRO_FILTER_BEST: + gl_filter = GLITZ_FILTER_BEST; + break; + case CAIRO_FILTER_NEAREST: + gl_filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GAUSSIAN: + if (CAIRO_GL_CONVOLUTION_SUPPORT (surface)) + convolution = &gaussian; + /* fall-through */ + case CAIRO_FILTER_BILINEAR: + gl_filter = GLITZ_FILTER_BILINEAR; + break; + default: + gl_filter = GLITZ_FILTER_BEST; + } + + glitz_surface_set_filter (surface->surface, gl_filter); + glitz_surface_set_convolution (surface->surface, convolution); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_gl_surface_set_repeat (void *abstract_surface, int repeat) +{ + cairo_gl_surface_t *surface = abstract_surface; + + if (!surface->surface) + return CAIRO_STATUS_SUCCESS; + + glitz_surface_set_repeat (surface->surface, repeat); + + return CAIRO_STATUS_SUCCESS; +} + +static glitz_operator_t +_glitz_operator (cairo_operator_t operator) +{ + switch (operator) { + case CAIRO_OPERATOR_CLEAR: + return GLITZ_OPERATOR_CLEAR; + case CAIRO_OPERATOR_SRC: + return GLITZ_OPERATOR_SRC; + case CAIRO_OPERATOR_DST: + return GLITZ_OPERATOR_DST; + case CAIRO_OPERATOR_OVER: + return GLITZ_OPERATOR_OVER; + case CAIRO_OPERATOR_OVER_REVERSE: + return GLITZ_OPERATOR_OVER_REVERSE; + case CAIRO_OPERATOR_IN: + return GLITZ_OPERATOR_IN; + case CAIRO_OPERATOR_IN_REVERSE: + return GLITZ_OPERATOR_IN_REVERSE; + case CAIRO_OPERATOR_OUT: + return GLITZ_OPERATOR_OUT; + case CAIRO_OPERATOR_OUT_REVERSE: + return GLITZ_OPERATOR_OUT_REVERSE; + case CAIRO_OPERATOR_ATOP: + return GLITZ_OPERATOR_ATOP; + case CAIRO_OPERATOR_ATOP_REVERSE: + return GLITZ_OPERATOR_ATOP_REVERSE; + case CAIRO_OPERATOR_XOR: + return GLITZ_OPERATOR_XOR; + case CAIRO_OPERATOR_ADD: + return GLITZ_OPERATOR_ADD; + case CAIRO_OPERATOR_SATURATE: + return GLITZ_OPERATOR_SATURATE; + default: + return GLITZ_OPERATOR_OVER; + } +} + +static glitz_format_name_t +_glitz_format (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_A1: + return GLITZ_STANDARD_A1; + break; + case CAIRO_FORMAT_A8: + return GLITZ_STANDARD_A8; + break; + case CAIRO_FORMAT_RGB24: + return GLITZ_STANDARD_RGB24; + break; + case CAIRO_FORMAT_ARGB32: + default: + return GLITZ_STANDARD_ARGB32; + break; + } +} + +static cairo_surface_t * +_cairo_gl_surface_create_similar (void *abstract_src, + cairo_format_t format, + int width, + int height) +{ + cairo_gl_surface_t *src = abstract_src; + glitz_surface_t *surface; + cairo_surface_t *crsurface; + + surface = glitz_surface_create_similar (src->surface, + _glitz_format (format), + width, height); + if (surface == NULL) + return NULL; + + crsurface = _cairo_gl_surface_create (surface, 1); + if (crsurface == NULL) + glitz_surface_destroy (surface); + + return crsurface; +} + +static cairo_gl_surface_t * +_cairo_gl_surface_clone_similar (cairo_surface_t *src, + cairo_gl_surface_t *template, + cairo_format_t format) +{ + cairo_gl_surface_t *clone; + cairo_image_surface_t *src_image; + + src_image = _cairo_surface_get_image (src); + + clone = (cairo_gl_surface_t *) + _cairo_gl_surface_create_similar (template, format, + src_image->width, + src_image->height); + if (clone == NULL) + return NULL; + + _cairo_gl_surface_set_filter (clone, cairo_surface_get_filter (src)); + + _cairo_gl_surface_set_image (clone, src_image); + + _cairo_gl_surface_set_matrix (clone, &(src_image->base.matrix)); + + cairo_surface_destroy (&src_image->base); + + return clone; +} + +static cairo_int_status_t +_cairo_gl_surface_composite (cairo_operator_t operator, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_gl_surface_t *dst = abstract_dst; + cairo_gl_surface_t *src = (cairo_gl_surface_t *) generic_src; + cairo_gl_surface_t *mask = (cairo_gl_surface_t *) generic_mask; + cairo_gl_surface_t *src_clone = NULL; + cairo_gl_surface_t *mask_clone = NULL; + + /* If destination surface is offscreen, then offscreen drawing support is + required. */ + if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) && + (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Fragment program or offscreen drawing required for composite with + mask. */ + if (mask && + (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (dst)) && + (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (generic_src->backend != dst->base.backend) { + src_clone = _cairo_gl_surface_clone_similar (generic_src, dst, + CAIRO_FORMAT_ARGB32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + src = src_clone; + } + if (generic_mask && (generic_mask->backend != dst->base.backend)) { + mask_clone = _cairo_gl_surface_clone_similar (generic_mask, dst, + CAIRO_FORMAT_A8); + if (!mask_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + mask = mask_clone; + } + + glitz_composite (_glitz_operator (operator), + src->surface, + mask ? mask->surface : 0, + dst->surface, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + if (src_clone) + cairo_surface_destroy (&src_clone->base); + if (mask_clone) + cairo_surface_destroy (&mask_clone->base); + + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_gl_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + cairo_gl_surface_t *surface = abstract_surface; + glitz_color_t glitz_color; + + /* If destination surface is offscreen, then offscreen drawing support is + required. */ + if (CAIRO_GL_SURFACE_IS_OFFSCREEN (surface) && + (!CAIRO_GL_OFFSCREEN_SUPPORT (surface))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + glitz_color.red = color->red_short; + glitz_color.green = color->green_short; + glitz_color.blue = color->blue_short; + glitz_color.alpha = color->alpha_short; + + glitz_fill_rectangles (_glitz_operator (operator), + surface->surface, + &glitz_color, (glitz_rectangle_t *) rects, + num_rects); + + return CAIRO_STATUS_SUCCESS; +} + +/* This function will produce incorrect drawing if alpha is not 1.0. */ +static cairo_int_status_t +_cairo_gl_surface_fill_trapezoids (cairo_gl_surface_t *surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_trapezoid_t *traps, + int num_traps) +{ + glitz_color_t glitz_color; + + glitz_color.red = color->red_short; + glitz_color.green = color->green_short; + glitz_color.blue = color->blue_short; + glitz_color.alpha = color->alpha_short; + + glitz_fill_trapezoids (_glitz_operator (operator), + surface->surface, + &glitz_color, + (glitz_trapezoid_t *) traps, num_traps); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_gl_surface_composite_trapezoids (cairo_operator_t operator, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int num_traps) +{ + cairo_gl_surface_t *dst = abstract_dst; + cairo_gl_surface_t *src = (cairo_gl_surface_t *) generic_src; + cairo_gl_surface_t *src_clone = NULL; + + /* If destination surface is offscreen, then offscreen drawing support is + required. */ + if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) && + (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Need to get current hints as clipping might have changed. */ + dst->hints = glitz_surface_get_hints (dst->surface); + + /* Solid source? */ + if ((generic_src->backend == dst->base.backend) && + (src->pattern.type == CAIRO_PATTERN_SOLID)) { + + /* We can use fill trapezoids if only one trapezoid should be drawn or + if solid color alpha is 1.0. If composite trapezoid support + is missing we always use fill trapezoids. */ + if ((num_traps == 1) || + (src->pattern.color.alpha == 1.0) || + (!CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT (dst))) + return _cairo_gl_surface_fill_trapezoids (dst, operator, + &src->pattern.color, + traps, num_traps); + } + + if (generic_src->backend != dst->base.backend) { + src_clone = _cairo_gl_surface_clone_similar (generic_src, dst, + CAIRO_FORMAT_ARGB32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + src = src_clone; + } + + glitz_composite_trapezoids (_glitz_operator (operator), + src->surface, dst->surface, + x_src, y_src, (glitz_trapezoid_t *) traps, + num_traps); + + if (src_clone) + cairo_surface_destroy (&src_clone->base); + + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_gl_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_gl_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static void +_cario_gl_uint_to_power_of_two (unsigned int *value) +{ + unsigned int x = 1; + + while (x < *value) + x <<= 1; + + *value = x; +} + +static void +_cairo_gl_create_color_range (cairo_pattern_t *pattern, + unsigned char *data, + unsigned int size) +{ + unsigned int i, bytes = size * 4; + + for (i = 0; i < bytes; i += 4) + _cairo_pattern_calc_color_at_pixel (pattern, i / (double) bytes, + (int *) &data[i]); +} + +static cairo_int_status_t +_cairo_gl_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_gl_surface_t *surface = abstract_surface; + glitz_surface_t *programmatic = NULL; + cairo_gl_surface_t *gl_surface; + double x = floor (_cairo_fixed_to_double (box->p1.x)); + double y = floor (_cairo_fixed_to_double (box->p1.y)); + + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: { + glitz_color_t color; + + color.red = pattern->color.red_short; + color.green = pattern->color.green_short; + color.blue = pattern->color.blue_short; + color.alpha = pattern->color.alpha_short; + + programmatic = glitz_surface_create_solid (&color); + } + break; + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + unsigned int color_range_size; + glitz_color_range_t *color_range; + + if (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* reflect could be emulated for hardware that doesn't support mirrored + repeat of textures, but I don't know of any card that support + fragment programs but not mirrored repeat, so what's the use. */ + if (pattern->extend == CAIRO_EXTEND_REFLECT && + (!CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT (surface))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (pattern->type == CAIRO_PATTERN_LINEAR) { + double dx, dy; + + dx = (pattern->u.linear.point1.x - x) - + (pattern->u.linear.point0.x - x); + dy = (pattern->u.linear.point1.y - y) - + (pattern->u.linear.point0.y - y); + + color_range_size = sqrt (dx * dx + dy * dy); + } else { + /* libglitz doesn't support inner circle. */ + if (pattern->u.radial.center0.x != + pattern->u.radial.center1.x + || pattern->u.radial.center0.y != + pattern->u.radial.center1.y + || pattern->u.radial.radius0.dx + || pattern->u.radial.radius0.dy) + return CAIRO_INT_STATUS_UNSUPPORTED; + + color_range_size = sqrt (pattern->u.radial.radius1.dx * + pattern->u.radial.radius1.dx + + pattern->u.radial.radius1.dy * + pattern->u.radial.radius1.dy); + } + + if ((!CAIRO_GL_TEXTURE_NPOT_SUPPORT (surface))) + _cario_gl_uint_to_power_of_two (&color_range_size); + + color_range = glitz_color_range_create (color_range_size); + if (!color_range) + return CAIRO_STATUS_NO_MEMORY; + + _cairo_gl_create_color_range (pattern, + glitz_color_range_get_data + (color_range), color_range_size); + + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REPEAT); + break; + case CAIRO_EXTEND_REFLECT: + glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REFLECT); + break; + case CAIRO_EXTEND_NONE: + glitz_color_range_set_extend (color_range, GLITZ_EXTEND_PAD); + break; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) { + glitz_point_fixed_t start; + glitz_point_fixed_t stop; + + start.x = + _cairo_fixed_from_double (pattern->u.linear.point0.x - x); + start.y = + _cairo_fixed_from_double (pattern->u.linear.point0.y - y); + stop.x = _cairo_fixed_from_double (pattern->u.linear.point1.x - x); + stop.y = _cairo_fixed_from_double (pattern->u.linear.point1.y - y); + + programmatic = + glitz_surface_create_linear (&start, &stop, color_range); + } else { + glitz_point_fixed_t center; + glitz_distance_fixed_t radius; + + center.x = + _cairo_fixed_from_double (pattern->u.radial.center1.x - x); + center.y = + _cairo_fixed_from_double (pattern->u.radial.center1.y - y); + radius.dx = + _cairo_fixed_from_double (pattern->u.radial.radius1.dx); + radius.dy = + _cairo_fixed_from_double (pattern->u.radial.radius1.dy); + + programmatic = + glitz_surface_create_radial (¢er, &radius, color_range); + } + + glitz_color_range_destroy (color_range); + } + break; + default: + return CAIRO_INT_STATUS_UNSUPPORTED; + break; + } + + if (!programmatic) + return CAIRO_STATUS_NO_MEMORY; + + gl_surface = (cairo_gl_surface_t *) + _cairo_gl_surface_create (programmatic, 1); + if (!gl_surface) { + glitz_surface_destroy (programmatic); + + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_pattern_init_copy (&gl_surface->pattern, pattern); + gl_surface->pattern_box = *box; + + pattern->source = &gl_surface->base; + _cairo_pattern_add_source_offset (pattern, + floor (_cairo_fixed_to_double (box->p1.x)), + floor (_cairo_fixed_to_double (box->p1.y))); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_gl_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_gl_surface_t *surface = abstract_surface; + glitz_rectangle_t *clip_rects; + pixman_box16_t *box; + int n, i; + + if (region == NULL) { + glitz_rectangle_t rect; + + rect.x = 0; + rect.y = 0; + rect.width = glitz_surface_get_width (surface->surface); + rect.height = glitz_surface_get_height (surface->surface); + + glitz_surface_clip_rectangles (surface->surface, + GLITZ_CLIP_OPERATOR_SET, &rect, 1); + } + + if (surface->format->stencil_size < 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + n = pixman_region_num_rects (region); + if (n == 0) + return CAIRO_STATUS_SUCCESS; + + box = pixman_region_rects (region); + + clip_rects = malloc (n * sizeof (glitz_rectangle_t)); + if (!clip_rects) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < n; n++, box++) { + clip_rects[i].x = (short) box->x1; + clip_rects[i].y = (short) box->y1; + clip_rects[i].width = (unsigned short) (box->x2 - box->x1); + clip_rects[i].height = (unsigned short) (box->y2 - box->y1); + } + + glitz_surface_clip_rectangles (surface->surface, + GLITZ_CLIP_OPERATOR_SET, clip_rects, n); + + free (clip_rects); + + return CAIRO_STATUS_SUCCESS; +} + +static const struct cairo_surface_backend cairo_gl_surface_backend = { + _cairo_gl_surface_create_similar, + _cairo_gl_surface_destroy, + _cairo_gl_surface_pixels_per_inch, + _cairo_gl_surface_get_image, + _cairo_gl_surface_set_image, + _cairo_gl_surface_set_matrix, + _cairo_gl_surface_set_filter, + _cairo_gl_surface_set_repeat, + _cairo_gl_surface_composite, + _cairo_gl_surface_fill_rectangles, + _cairo_gl_surface_composite_trapezoids, + _cairo_gl_surface_copy_page, + _cairo_gl_surface_show_page, + _cairo_gl_surface_set_clip_region, + _cairo_gl_surface_create_pattern +}; + +static cairo_surface_t * +_cairo_gl_surface_create (glitz_surface_t *surface, int owns_surface) +{ + cairo_gl_surface_t *crsurface; + + if (!surface) + return NULL; + + crsurface = malloc (sizeof (cairo_gl_surface_t)); + if (crsurface == NULL) + return NULL; + + _cairo_surface_init (&crsurface->base, &cairo_gl_surface_backend); + _cairo_pattern_init (&crsurface->pattern); + crsurface->pattern.type = CAIRO_PATTERN_SURFACE; + crsurface->pattern.u.surface.surface = NULL; + crsurface->format = glitz_surface_get_format (surface); + crsurface->surface = surface; + crsurface->features = glitz_surface_get_features (surface); + crsurface->hints = glitz_surface_get_hints (surface); + crsurface->owns_surface = owns_surface; + + return (cairo_surface_t *) crsurface; +} + +cairo_surface_t * +cairo_gl_surface_create (glitz_surface_t *surface) +{ + return _cairo_gl_surface_create (surface, 0); +} diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c index dcdb1566a..6464d23f9 100644 --- a/src/cairo_pattern.c +++ b/src/cairo_pattern.c @@ -656,18 +656,18 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) case CAIRO_PATTERN_LINEAR: case CAIRO_PATTERN_RADIAL: { char *data; - int width = ceil (_cairo_fixed_to_double (box->p2.x) - - _cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y) - - _cairo_fixed_to_double (box->p1.y)); - + int width = ceil (_cairo_fixed_to_double (box->p2.x)) - + floor (_cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y)) - + floor (_cairo_fixed_to_double (box->p1.y)); + data = malloc (width * height * 4); if (!data) return NULL; _cairo_pattern_add_source_offset (pattern, - _cairo_fixed_to_double (box->p1.x), - _cairo_fixed_to_double (box->p1.y)); + floor (_cairo_fixed_to_double (box->p1.x)), + floor (_cairo_fixed_to_double (box->p1.y))); if (pattern->type == CAIRO_PATTERN_RADIAL) _cairo_image_data_set_radial (pattern, diff --git a/src/cairo_surface.c b/src/cairo_surface.c index 91ab8aba4..60b4487d4 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -424,10 +424,10 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, /* handle pattern opacity */ if (pattern->color.alpha != 1.0) { - int width = ceil (_cairo_fixed_to_double (box->p2.x) - - _cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y) - - _cairo_fixed_to_double (box->p1.y)); + int width = ceil (_cairo_fixed_to_double (box->p2.x)) - + floor (_cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y)) - + floor (_cairo_fixed_to_double (box->p1.y)); cairo_pattern_t alpha; pattern->source = @@ -463,8 +463,8 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, if (status == CAIRO_STATUS_SUCCESS) { _cairo_pattern_add_source_offset (pattern, - _cairo_fixed_to_double (box->p1.x), - _cairo_fixed_to_double (box->p1.y)); + floor (_cairo_fixed_to_double (box->p1.x)), + floor (_cairo_fixed_to_double (box->p1.y))); } else cairo_surface_destroy (pattern->source); } |