diff --git a/ChangeLog b/ChangeLog index 27e435a51..e09f60604 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2004-09-11 David Reveman + + * src/cairo.h: CAIRO_HAS_GL_SURFACE -> CAIRO_HAS_GLITZ_SURFACE. + cairo_set_target_gl -> cairo_set_target_glitz. + cairo_gl_surface_create -> cairo_glitz_surface_create. + + * src/cairo-features.h.in: GL_SURFACE_FEATURE -> GLITZ_SURFACE_FEATURE. + + * src/Makefile.am: CAIRO_HAS_GL_SURFACE -> CAIRO_HAS_GLITZ_SURFACE, + libcairo_gl_sources -> libcairo_glitz_sources, cairo_gl_surface.c -> + cairo_glitz_surface.c, GL_CFLAGS -> GLITZ_CFLAGS and + GL_LIBS -> GLITZ_LIBS. + + * cairo.pc.in (Requires): GL_REQUIRES -> GLITZ_REQUIRES. + + * configure.in: Replaced the gl backend with the new glitz backend. + Cairo now requires version 0.2.1 of glitz. + 2004-09-04 Carl Worth * COPYING: diff --git a/cairo.pc.in b/cairo.pc.in index c67dc05cb..b2859b24b 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@ @GL_REQUIRES@ +Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ @GLITZ_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 5ab37391a..a682d47ec 100644 --- a/configure.in +++ b/configure.in @@ -136,28 +136,28 @@ AC_SUBST(PNG_REQUIRES) dnl =========================================================================== -AC_ARG_ENABLE(gl, - [ --disable-gl Disable cairo's OpenGL backend], - [use_gl=$enableval], [use_gl=yes]) +AC_ARG_ENABLE(glitz, + [ --disable-glitz Disable cairo's glitz backend], + [use_glitz=$enableval], [use_glitz=yes]) -if test "x$use_gl" = "xyes"; then - PKG_CHECK_MODULES(GL, glitz >= 0.1.5, [ - GL_REQUIRES=glitz - use_gl=yes], [use_gl="no (requires glitz http://freedesktop.org/software/glitz)"]) +if test "x$use_glitz" = "xyes"; then + PKG_CHECK_MODULES(GLITZ, glitz >= 0.2.1, [ + GLITZ_REQUIRES=glitz + use_glitz=yes], [use_glitz="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) +if test "x$use_glitz" != "xyes"; then + GLITZ_SURFACE_FEATURE=CAIRO_HAS_NO_GLITZ_SURFACE + AM_CONDITIONAL(CAIRO_HAS_GLITZ_SURFACE, false) else - GL_SURFACE_FEATURE=CAIRO_HAS_GL_SURFACE - AM_CONDITIONAL(CAIRO_HAS_GL_SURFACE, true) + GLITZ_SURFACE_FEATURE=CAIRO_HAS_GLITZ_SURFACE + AM_CONDITIONAL(CAIRO_HAS_GLITZ_SURFACE, true) fi -AC_SUBST(GL_LIBS) -AC_SUBST(GL_CFLAGS) -AC_SUBST(GL_SURFACE_FEATURE) -AC_SUBST(GL_REQUIRES) +AC_SUBST(GLITZ_LIBS) +AC_SUBST(GLITZ_CFLAGS) +AC_SUBST(GLITZ_SURFACE_FEATURE) +AC_SUBST(GLITZ_REQUIRES) dnl =========================================================================== @@ -258,6 +258,6 @@ echo " Xlib: $use_xlib" echo " XCB: $use_xcb" echo " PostScript: $use_ps" echo " PNG: $use_png" -echo " OpenGL: $use_gl" +echo " glitz: $use_glitz" echo "" diff --git a/src/Makefile.am b/src/Makefile.am index 38a30adef..5dfa079e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,8 +17,8 @@ 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 +if CAIRO_HAS_GLITZ_SURFACE +libcairo_glitz_sources = cairo_glitz_surface.c endif # These names match automake style variable definition conventions so @@ -56,11 +56,11 @@ libcairo_la_SOURCES = \ $(libcairo_png_sources) \ $(libcairo_xlib_sources)\ $(libcairo_xcb_sources) \ - $(libcairo_gl_sources) \ + $(libcairo_glitz_sources)\ cairoint.h libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -INCLUDES = -I$(srcdir) $(WARN_CFLAGS) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) $(GL_CFLAGS) +INCLUDES = -I$(srcdir) $(WARN_CFLAGS) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) $(GLITZ_CFLAGS) -libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) $(GL_LIBS) -lm +libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) $(GLITZ_LIBS) -lm diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in index b26ad0482..632ad8d72 100644 --- a/src/cairo-features.h.in +++ b/src/cairo-features.h.in @@ -45,7 +45,7 @@ #define @XCB_SURFACE_FEATURE@ -#define @GL_SURFACE_FEATURE@ +#define @GLITZ_SURFACE_FEATURE@ #define @SANITY_CHECKING_FEATURE@ diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c new file mode 100644 index 000000000..83269dc12 --- /dev/null +++ b/src/cairo-glitz-surface.c @@ -0,0 +1,907 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 David Reveman + * + * 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 David + * Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. David Reveman makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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 + */ + +#include "cairoint.h" + +#define GLITZ_FIXED_TO_FLOAT(f) \ + (((glitz_float_t) (f)) / 65536) + +#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x)) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((((line).p2.y - (line).p1.y) - 1) + \ + ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x))) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +void +cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) +{ + cairo_surface_t *crsurface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + glitz_surface_reference (surface); + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, crsurface); + + cairo_surface_destroy (crsurface); +} + +typedef struct cairo_glitz_surface { + cairo_surface_t base; + + unsigned long features; + glitz_surface_t *surface; + glitz_format_t *format; + + cairo_pattern_t pattern; + cairo_box_t pattern_box; +} cairo_glitz_surface_t; + +static void +_cairo_glitz_surface_destroy (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_destroy (surface->surface); + + _cairo_pattern_fini (&surface->pattern); + + free (surface); +} + +static double +_cairo_glitz_surface_pixels_per_inch (void *abstract_surface) +{ + return 96.0; +} + +static cairo_image_surface_t * +_cairo_glitz_surface_get_image (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + char *pixels; + int width, height, rowstride, size; + cairo_format_masks_t format; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + if (surface->pattern.type != CAIRO_PATTERN_SURFACE) { + cairo_box_t box; + + box.p1.x = box.p1.y = 0; + box.p2.x = surface->pattern_box.p2.x; + box.p2.y = surface->pattern_box.p2.y; + + return _cairo_pattern_get_image (&surface->pattern, &box); + } + + + width = glitz_surface_get_width (surface->surface); + height = glitz_surface_get_height (surface->surface); + + if (surface->format->red_size > 0) { + format.bpp = 32; + + if (surface->format->alpha_size > 0) + format.alpha_mask = 0xff000000; + else + format.alpha_mask = 0x0; + + format.red_mask = 0xff0000; + format.green_mask = 0xff00; + format.blue_mask = 0xff; + } else { + format.bpp = 8; + format.blue_mask = format.green_mask = format.red_mask = 0x0; + format.alpha_mask = 0xff; + } + + rowstride = (((width * format.bpp) / 8) + 3) & -4; + + pf.masks.bpp = format.bpp; + pf.masks.alpha_mask = format.alpha_mask; + pf.masks.red_mask = format.red_mask; + pf.masks.green_mask = format.green_mask; + pf.masks.blue_mask = format.blue_mask; + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = rowstride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + size = height * rowstride; + + pixels = malloc (size); + if (!pixels) + return NULL; + + buffer = glitz_pixel_buffer_create (surface->surface, NULL, size, + GLITZ_BUFFER_HINT_DYNAMIC_READ); + if (!buffer) { + free (pixels); + return NULL; + } + + glitz_get_pixels (surface->surface, + 0, 0, + width, height, + &pf, + buffer); + + glitz_buffer_get_data (buffer, 0, size, pixels); + + glitz_buffer_destroy (buffer); + + 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_glitz_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + if (image->depth > 8) { + pf.masks.bpp = 32; + + if (surface->format->alpha_size) + pf.masks.alpha_mask = 0xff000000; + else + pf.masks.alpha_mask = 0x0; + + pf.masks.red_mask = 0xff0000; + pf.masks.green_mask = 0xff00; + pf.masks.blue_mask = 0xff; + } else { + pf.masks.bpp = 8; + pf.masks.alpha_mask = 0xff; + pf.masks.red_mask = pf.masks.green_mask = pf.masks.blue_mask = 0x0; + } + + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = (((image->width * pf.masks.bpp) / 8) + 3) & -4; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + + buffer = glitz_pixel_buffer_create (surface->surface, + image->data, + pf.bytes_per_line * image->height, + GLITZ_BUFFER_HINT_STREAM_DRAW); + if (!buffer) + return CAIRO_STATUS_NO_MEMORY; + + glitz_set_pixels (surface->surface, + 0, 0, + image->width, image->height, + &pf, + buffer); + + glitz_buffer_destroy (buffer); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_matrix (void *abstract_surface, + cairo_matrix_t *matrix) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + 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] = 1 << 16; + + glitz_surface_set_transform (surface->surface, &transform); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_filter_t glitz_filter; + + switch (filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + glitz_filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + default: + glitz_filter = GLITZ_FILTER_BILINEAR; + break; + } + + glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_set_fill (surface->surface, + (repeat)? GLITZ_FILL_REPEAT: + GLITZ_FILL_TRANSPARENT); + + return CAIRO_STATUS_SUCCESS; +} + +static glitz_operator_t +_glitz_operator (cairo_operator_t op) +{ + switch (op) { + 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_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; + case CAIRO_OPERATOR_OVER: + 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; + case CAIRO_FORMAT_A8: + return GLITZ_STANDARD_A8; + case CAIRO_FORMAT_RGB24: + return GLITZ_STANDARD_RGB24; + case CAIRO_FORMAT_ARGB32: + default: + return GLITZ_STANDARD_ARGB32; + } +} + +static glitz_surface_t * +_glitz_surface_create_solid (glitz_surface_t *other, + glitz_format_name_t format_name, + glitz_color_t *color) +{ + glitz_surface_t *surface; + glitz_format_t *format; + + format = glitz_surface_find_similar_standard_format (other, format_name); + if (format == NULL) + return NULL; + + surface = glitz_surface_create_similar (other, format, 1, 1); + if (surface == NULL) + return NULL; + + glitz_set_rectangle (surface, color, 0, 0, 1, 1); + + glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT); + + return surface; +} + +static cairo_surface_t * +_cairo_glitz_surface_create_similar (void *abstract_src, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_glitz_surface_t *src = abstract_src; + glitz_surface_t *surface; + cairo_surface_t *crsurface; + glitz_format_t *glitz_format; + + glitz_format = + glitz_surface_find_similar_standard_format (src->surface, + _glitz_format (format)); + if (glitz_format == NULL) + return NULL; + + surface = glitz_surface_create_similar (src->surface, glitz_format, + width, height); + if (surface == NULL) + return NULL; + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) + glitz_surface_destroy (surface); + + return crsurface; +} + +static cairo_glitz_surface_t * +_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ, + cairo_surface_t *src, + cairo_format_t format) +{ + cairo_glitz_surface_t *clone; + cairo_image_surface_t *src_image; + + src_image = _cairo_surface_get_image (src); + + clone = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (templ, format, 0, + src_image->width, + src_image->height); + if (clone == NULL) + return NULL; + + _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src)); + + _cairo_glitz_surface_set_image (clone, src_image); + + _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix)); + + cairo_surface_destroy (&src_image->base); + + return clone; +} + +static cairo_int_status_t +_glitz_composite (glitz_operator_t op, + glitz_surface_t *src, + glitz_surface_t *mask, + glitz_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + int width, + int height, + glitz_buffer_t *geometry, + glitz_geometry_format_t *format) +{ + if (glitz_surface_get_status (dst)) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + glitz_set_geometry (dst, + 0, 0, + format, geometry); + + glitz_composite (op, + src, + mask, + dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + glitz_set_geometry (dst, 0, 0, NULL, NULL); + + if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite (cairo_operator_t op, + 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_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask; + cairo_glitz_surface_t *src_clone = NULL; + cairo_glitz_surface_t *mask_clone = NULL; + cairo_int_status_t status; + + if (generic_src->backend != dst->base.backend) { + src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src, + 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_glitz_surface_clone_similar (dst, generic_mask, + CAIRO_FORMAT_ARGB32); + if (!mask_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + + mask = mask_clone; + } + + status = _glitz_composite (_glitz_operator (op), + src->surface, + (mask)? mask->surface: NULL, + dst->surface, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height, + NULL, NULL); + + if (src_clone) + cairo_surface_destroy (&src_clone->base); + + if (mask_clone) + cairo_surface_destroy (&mask_clone->base); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int n_rects) +{ + cairo_glitz_surface_t *dst = abstract_dst; + 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; + + if (op != CAIRO_OPERATOR_SRC) { + glitz_surface_t *solid; + glitz_float_t *data; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int width = 0; + int height = 0; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_rects * 4; + + buffer = + glitz_geometry_buffer_create (dst->surface, NULL, + n_rects * 8 * sizeof (glitz_float_t), + GLITZ_BUFFER_HINT_STREAM_DRAW); + if (buffer == NULL) + return CAIRO_STATUS_NO_MEMORY; + + data = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_rects; rects++, n_rects--) { + *data++ = (glitz_float_t) rects->x; + *data++ = (glitz_float_t) rects->y; + *data++ = (glitz_float_t) (rects->x + rects->width); + *data++ = (glitz_float_t) rects->y; + *data++ = (glitz_float_t) (rects->x + rects->width); + *data++ = (glitz_float_t) (rects->y + rects->height); + *data++ = (glitz_float_t) rects->x; + *data++ = (glitz_float_t) (rects->y + rects->height); + + if ((rects->x + rects->width) > width) + width = rects->x + rects->width; + + if ((rects->y + rects->height) > height) + height = rects->y + rects->height; + } + glitz_buffer_unmap (buffer); + + solid = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_ARGB32, + &glitz_color); + if (solid == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _glitz_composite (_glitz_operator (op), + solid, + NULL, + dst->surface, + 0, 0, + 0, 0, + 0, 0, + width, height, + buffer, &gf); + + glitz_surface_destroy (solid); + glitz_buffer_destroy (buffer); + + return status; + } else + glitz_set_rectangles (dst->surface, &glitz_color, + (glitz_rectangle_t *) rects, n_rects); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int n_traps) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + glitz_surface_t *mask = NULL; + glitz_float_t *data; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int x_dst, y_dst, x_rel, y_rel, width, height; + + if (generic_src->backend != dst->base.backend) + return CAIRO_INT_STATUS_UNSUPPORTED; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_traps * 4; + + buffer = + glitz_geometry_buffer_create (dst->surface, NULL, + n_traps * 8 * sizeof (glitz_float_t), + GLITZ_BUFFER_HINT_STREAM_DRAW); + if (buffer == NULL) + return CAIRO_STATUS_NO_MEMORY; + + x_dst = traps[0].left.p1.x >> 16; + y_dst = traps[0].left.p1.y >> 16; + + data = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_traps; traps++, n_traps--) { + glitz_float_t top, bottom; + + top = GLITZ_FIXED_TO_FLOAT (traps->top); + bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom); + + *data++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top); + *data++ = top; + *data++ = GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top); + *data++ = top; + *data++ = + GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom); + *data++ = bottom; + *data++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom); + *data++ = bottom; + } + glitz_buffer_unmap (buffer); + + if ((src->pattern.type == CAIRO_PATTERN_SURFACE) && + (src->pattern.color.alpha != 1.0)) { + glitz_color_t color; + + color.red = color.green = color.blue = 0; + color.alpha = src->pattern.color.alpha_short; + + mask = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_A8, + &color); + } + + x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst; + y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst; + + x_dst = src->pattern_box.p1.x >> 16; + y_dst = src->pattern_box.p1.y >> 16; + + width = ((src->pattern_box.p2.x + 65535) >> 16) - + (src->pattern_box.p1.x >> 16); + height = ((src->pattern_box.p2.y + 65535) >> 16) - + (src->pattern_box.p1.y >> 16); + + status = _glitz_composite (_glitz_operator (op), + src->surface, + mask, + dst->surface, + x_rel, y_rel, + 0, 0, + x_dst, y_dst, + width, height, + buffer, &gf); + + if (mask) + glitz_surface_destroy (mask); + + glitz_buffer_destroy (buffer); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_create_pattern (void *abstract_dst, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_surface_t *generic_src = NULL; + cairo_image_surface_t *image = NULL; + cairo_glitz_surface_t *src; + + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + generic_src = + _cairo_surface_create_similar_solid (&dst->base, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (generic_src) + cairo_surface_set_repeat (generic_src, 1); + break; + case CAIRO_PATTERN_RADIAL: + /* glitz doesn't support inner and outer circle with different + center points. */ + if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || + pattern->u.radial.center0.y != pattern->u.radial.center1.y) + break; + /* fall-through */ + case CAIRO_PATTERN_LINEAR: { + glitz_fixed16_16_t *params; + int i, n_params; + + if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + break; + + if (pattern->filter != CAIRO_FILTER_BILINEAR) + break; + + n_params = pattern->n_stops * 3 + 4; + + params = malloc (sizeof (glitz_fixed16_16_t) * n_params); + if (params == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = + _cairo_glitz_surface_create_similar (abstract_dst, + CAIRO_FORMAT_ARGB32, 0, + pattern->n_stops, 1); + if (generic_src == NULL) { + free (params); + return CAIRO_STATUS_NO_MEMORY; + } + + src = (cairo_glitz_surface_t *) generic_src; + + for (i = 0; i < pattern->n_stops; i++) { + glitz_color_t color; + + color.red = pattern->stops[i].color_char[0] * 256; + color.green = pattern->stops[i].color_char[1] * 256; + color.blue = pattern->stops[i].color_char[2] * 256; + color.alpha = pattern->stops[i].color_char[3] * 256; + + glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + + params[4 + 3 * i] = pattern->stops[i].offset; + params[5 + 3 * i] = 0x8000 | (i << 16); + params[6 + 3 * i] = 0x8000; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) { + params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x); + params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y); + params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x); + params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_LINEAR_GRADIENT, + params, n_params); + } else { + params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x); + params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y); + params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0); + params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_RADIAL_GRADIENT, + params, n_params); + } + + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); + break; + case CAIRO_EXTEND_REFLECT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT); + break; + case CAIRO_EXTEND_NONE: + default: + glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST); + break; + } + + cairo_surface_set_matrix (&src->base, &pattern->matrix); + + free (params); + } break; + case CAIRO_PATTERN_SURFACE: + generic_src = pattern->u.surface.surface; + cairo_surface_reference (generic_src); + break; + } + + if (generic_src == NULL) { + image = _cairo_pattern_get_image (pattern, box); + if (image == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = &image->base; + } + + if (generic_src->backend != dst->base.backend) { + src = _cairo_glitz_surface_clone_similar (dst, generic_src, + CAIRO_FORMAT_ARGB32); + if (src == NULL) + return CAIRO_STATUS_NO_MEMORY; + } else + src = (cairo_glitz_surface_t *) generic_src; + + if (image) + cairo_surface_destroy (&image->base); + + _cairo_pattern_init_copy (&src->pattern, pattern); + src->pattern_box = *box; + + pattern->source = &src->base; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static const struct cairo_surface_backend cairo_glitz_surface_backend = { + _cairo_glitz_surface_create_similar, + _cairo_glitz_surface_destroy, + _cairo_glitz_surface_pixels_per_inch, + _cairo_glitz_surface_get_image, + _cairo_glitz_surface_set_image, + _cairo_glitz_surface_set_matrix, + _cairo_glitz_surface_set_filter, + _cairo_glitz_surface_set_repeat, + _cairo_glitz_surface_composite, + _cairo_glitz_surface_fill_rectangles, + _cairo_glitz_surface_composite_trapezoids, + _cairo_glitz_surface_copy_page, + _cairo_glitz_surface_show_page, + _cairo_glitz_surface_set_clip_region, + _cairo_glitz_surface_create_pattern +}; + +cairo_surface_t * +cairo_glitz_surface_create (glitz_surface_t *surface) +{ + cairo_glitz_surface_t *crsurface; + + if (!surface) + return NULL; + + crsurface = malloc (sizeof (cairo_glitz_surface_t)); + if (crsurface == NULL) + return NULL; + + _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); + + crsurface->surface = surface; + crsurface->features = glitz_surface_get_features (surface); + crsurface->format = glitz_surface_get_format (surface); + + _cairo_pattern_init (&crsurface->pattern); + crsurface->pattern.type = CAIRO_PATTERN_SURFACE; + crsurface->pattern.u.surface.surface = NULL; + + return (cairo_surface_t *) crsurface; +} diff --git a/src/cairo.h b/src/cairo.h index 328b53cd6..44b631633 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -150,14 +150,14 @@ cairo_set_target_xcb (cairo_t *cr, cairo_format_t format); #endif /* CAIRO_HAS_XCB_SURFACE */ -#ifdef CAIRO_HAS_GL_SURFACE +#ifdef CAIRO_HAS_GLITZ_SURFACE #include void -cairo_set_target_gl (cairo_t *cr, - glitz_surface_t *surface); -#endif /* CAIRO_HAS_GL_SURFACE */ +cairo_set_target_glitz (cairo_t *cr, + glitz_surface_t *surface); +#endif /* CAIRO_HAS_GLITZ_SURFACE */ typedef enum cairo_operator { CAIRO_OPERATOR_CLEAR, @@ -784,12 +784,12 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); #endif /* CAIRO_HAS_XLIB_SURFACE */ -#ifdef CAIRO_HAS_GL_SURFACE +#ifdef CAIRO_HAS_GLITZ_SURFACE cairo_surface_t * -cairo_gl_surface_create (glitz_surface_t *surface); +cairo_glitz_surface_create (glitz_surface_t *surface); -#endif /* CAIRO_HAS_GL_SURFACE */ +#endif /* CAIRO_HAS_GLITZ_SURFACE */ /* Matrix functions */ diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c deleted file mode 100644 index b56fc5fc3..000000000 --- a/src/cairo_gl_surface.c +++ /dev/null @@ -1,967 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2004 David Reveman - * - * 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 David - * Reveman not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. David Reveman makes no representations about the - * suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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 - */ - -#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; - unsigned short opacity; - - cairo_pattern_t pattern; - cairo_box_t pattern_box; - - glitz_surface_t *surface; -}; - -#define CAIRO_GL_MULTITEXTURE_SUPPORT(surface) \ - (surface->features & GLITZ_FEATURE_ARB_MULTITEXTURE_MASK) - -#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)) - -#define CAIRO_GL_SURFACE_IS_DRAWABLE(surface) \ - ((surface->hints & GLITZ_HINT_OFFSCREEN_MASK)? \ - surface->format->draw.offscreen: surface->format->draw.onscreen) - -#define CAIRO_GL_SURFACE_IS_SOLID(surface) \ - ((surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) && \ - (surface->pattern.type == CAIRO_PATTERN_SOLID)) - -#define CAIRO_GL_SURFACE_MULTISAMPLE(surface) \ - (surface->hints & GLITZ_HINT_MULTISAMPLE_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; - glitz_pixel_buffer_t *buffer; - glitz_pixel_format_t pf; - - 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); - - if (surface->format->red_size > 0) { - format.bpp = 32; - - if (surface->format->alpha_size > 0) - format.alpha_mask = 0xff000000; - else - format.alpha_mask = 0x0; - - format.red_mask = 0xff0000; - format.green_mask = 0xff00; - format.blue_mask = 0xff; - } else { - format.bpp = 8; - format.blue_mask = format.green_mask = format.red_mask = 0x0; - format.alpha_mask = 0xff; - } - - rowstride = (((width * format.bpp) / 8) + 3) & -4; - - pf.masks.bpp = format.bpp; - pf.masks.alpha_mask = format.alpha_mask; - pf.masks.red_mask = format.red_mask; - pf.masks.green_mask = format.green_mask; - pf.masks.blue_mask = format.blue_mask; - pf.xoffset = 0; - pf.skip_lines = 0; - pf.bytes_per_line = rowstride; - pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - - pixels = (char *) malloc (height * rowstride); - if (!pixels) - return NULL; - - buffer = glitz_pixel_buffer_create_for_data (pixels, &pf); - if (!buffer) { - free (pixels); - return NULL; - } - - glitz_get_pixels (surface->surface, - 0, 0, - width, height, - buffer); - - glitz_pixel_buffer_destroy (buffer); - - 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_pixel_buffer_t *buffer; - glitz_pixel_format_t pf; - - if (image->depth > 8) { - pf.masks.bpp = 32; - - if (surface->format->alpha_size) - pf.masks.alpha_mask = 0xff000000; - else - pf.masks.alpha_mask = 0x0; - - pf.masks.red_mask = 0xff0000; - pf.masks.green_mask = 0xff00; - pf.masks.blue_mask = 0xff; - } else { - pf.masks.bpp = 8; - pf.masks.alpha_mask = 0xff; - pf.masks.red_mask = pf.masks.green_mask = pf.masks.blue_mask = 0x0; - } - - pf.xoffset = 0; - pf.skip_lines = 0; - pf.bytes_per_line = (((image->width * pf.masks.bpp) / 8) + 3) & -4; - pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - - buffer = glitz_pixel_buffer_create_for_data (image->data, &pf); - if (!buffer) - return CAIRO_STATUS_NO_MEMORY; - - glitz_put_pixels (surface->surface, - 0, 0, - image->width, image->height, - buffer); - - glitz_pixel_buffer_destroy (buffer); - - 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) -{ - cairo_gl_surface_t *surface = abstract_surface; - glitz_filter_t gl_filter; - - 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_BILINEAR: - gl_filter = GLITZ_FILTER_BILINEAR; - break; - default: - gl_filter = GLITZ_FILTER_BEST; - } - - glitz_surface_set_filter (surface->surface, gl_filter); - - 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 drawable, - int width, - int height) -{ - cairo_gl_surface_t *src = abstract_src; - glitz_surface_t *surface; - cairo_surface_t *crsurface; - glitz_format_t *glitz_format; - unsigned long option_mask; - glitz_format_name_t format_name = _glitz_format (format); - - option_mask = GLITZ_FORMAT_OPTION_OFFSCREEN_MASK; - - if (drawable) - option_mask |= GLITZ_FORMAT_OPTION_READDRAW_MASK; - else - option_mask |= GLITZ_FORMAT_OPTION_READONLY_MASK; - - if (src->format->multisample.samples < 2) - option_mask |= GLITZ_FORMAT_OPTION_NO_MULTISAMPLE_MASK; - - glitz_format = - glitz_surface_find_similar_standard_format (src->surface, option_mask, - format_name); - if (glitz_format == NULL) { - option_mask &= ~GLITZ_FORMAT_OPTION_READDRAW_MASK; - glitz_format = - glitz_surface_find_similar_standard_format (src->surface, - option_mask, - format_name); - } - - if (glitz_format == NULL) - return NULL; - - surface = glitz_surface_create_similar (src->surface, glitz_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, 0, - 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; - - /* Make sure that target surface is OK. */ - if (glitz_surface_get_status (dst->surface)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - /* Make sure target surface is drawable */ - if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* We need multi-texturing or offscreen drawing when compositing with - non-solid mask. */ - if (mask && - (!CAIRO_GL_SURFACE_IS_SOLID (mask)) && - (!CAIRO_GL_MULTITEXTURE_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; - - /* Make sure that target surface is OK. */ - if (glitz_surface_get_status (surface->surface)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - /* Make sure target surface is drawable */ - if (!CAIRO_GL_SURFACE_IS_DRAWABLE (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 int -_cairo_gl_extract_rectangle (cairo_trapezoid_t *trap, - cairo_rectangle_t *rect) -{ - if (trap->left.p1.x == trap->left.p2.x && - trap->right.p1.x == trap->right.p2.x && - trap->left.p1.y == trap->right.p1.y && - trap->left.p2.y == trap->right.p2.y && - _cairo_fixed_is_integer (trap->left.p1.x) && - _cairo_fixed_is_integer (trap->left.p1.y) && - _cairo_fixed_is_integer (trap->left.p2.x) && - _cairo_fixed_is_integer (trap->left.p2.y) && - _cairo_fixed_is_integer (trap->right.p1.x) && - _cairo_fixed_is_integer (trap->right.p1.y) && - _cairo_fixed_is_integer (trap->right.p2.x) && - _cairo_fixed_is_integer (trap->right.p2.y)) { - - rect->x = _cairo_fixed_integer_part (trap->left.p1.x); - rect->y = _cairo_fixed_integer_part (trap->left.p1.y); - rect->width = _cairo_fixed_integer_part (trap->right.p1.x) - rect->x; - rect->height = _cairo_fixed_integer_part (trap->left.p2.y) - rect->y; - - return 1; - } - - return 0; -} - -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; - - /* Make sure that target surface is OK. */ - if (glitz_surface_get_status (dst->surface)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - /* Make sure target surface is drawable */ - if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* Need to get current hints as clipping may 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)) { - cairo_rectangle_t rect; - - /* Check to see if we can represent these traps as a rectangle. */ - if (num_traps == 1 && _cairo_gl_extract_rectangle (traps, &rect)) - return _cairo_gl_surface_fill_rectangles (dst, operator, - &src->pattern.color, - &rect, 1); - - /* If we're not using software multi-sampling, then we can use - fill trapezoids if only one trapezoid should be drawn or if - solid color alpha is 1.0. */ - if ((!CAIRO_GL_SURFACE_MULTISAMPLE (dst)) && - (num_traps == 1 || src->pattern.color.alpha == 1.0)) - 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_surface_set_polyopacity (dst->surface, src->opacity); - - glitz_composite_trapezoids (_glitz_operator (operator), - src->surface, dst->surface, - x_src, y_src, (glitz_trapezoid_t *) traps, - num_traps); - - glitz_surface_set_polyopacity (dst->surface, 0xffff); - - 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 -_cairo_gl_create_color_range (cairo_pattern_t *pattern, - unsigned char *data, - unsigned int size) -{ - unsigned int i, bytes = size * 4; - cairo_shader_op_t op; - - _cairo_pattern_shader_init (pattern, &op); - - for (i = 0; i < bytes; i += 4) - _cairo_pattern_calc_color_at_pixel (&op, - ((double) i / bytes) * 65536, - (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 *source = NULL; - cairo_gl_surface_t *src; - - 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; - - source = glitz_surface_create_solid (&color); - } break; - case CAIRO_PATTERN_RADIAL: - /* glitz doesn't support inner circle yet. */ - if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || - pattern->u.radial.center0.y != pattern->u.radial.center1.y) - return CAIRO_INT_STATUS_UNSUPPORTED; - /* fall-through */ - case CAIRO_PATTERN_LINEAR: { - int color_range_size; - glitz_color_range_t *color_range; - int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); - int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); - - 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; - - /* TODO: how do we figure out the color range resolution? transforming - the gradient vector with the inverse of the pattern matrix should - give us a good hint. */ - color_range_size = 512; - - /* destination surface size less than color range size, an image - gradient is probably more efficient. */ - if ((width * height) <= color_range_size) - return CAIRO_INT_STATUS_UNSUPPORTED; - - color_range = glitz_color_range_create (surface->surface, - 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); - - glitz_color_range_put_back_data (color_range); - - 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; - } - - glitz_color_range_set_filter (color_range, GLITZ_FILTER_BILINEAR); - - 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); - start.y = _cairo_fixed_from_double (pattern->u.linear.point0.y); - stop.x = _cairo_fixed_from_double (pattern->u.linear.point1.x); - stop.y = _cairo_fixed_from_double (pattern->u.linear.point1.y); - - source = glitz_surface_create_linear (&start, &stop, color_range); - } else { - glitz_point_fixed_t center; - - center.x = _cairo_fixed_from_double (pattern->u.radial.center1.x); - center.y = _cairo_fixed_from_double (pattern->u.radial.center1.y); - - source = glitz_surface_create_radial - (¢er, - _cairo_fixed_from_double (pattern->u.radial.radius0), - _cairo_fixed_from_double (pattern->u.radial.radius1), - color_range); - } - - glitz_color_range_destroy (color_range); - } break; - case CAIRO_PATTERN_SURFACE: - if (CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT (surface)) { - cairo_gl_surface_t *src_clone = NULL; - cairo_surface_t *generic_src = pattern->u.surface.surface; - - src = (cairo_gl_surface_t *) generic_src; - if (generic_src->backend != surface->base.backend) { - src_clone = - _cairo_gl_surface_clone_similar (generic_src, surface, - CAIRO_FORMAT_ARGB32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - } else { - src_clone = (cairo_gl_surface_t *) - _cairo_gl_surface_create (src->surface, 0); - if (!src_clone) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_filter - (&src_clone->base, cairo_surface_get_filter (generic_src)); - - cairo_surface_set_matrix (&src_clone->base, - &generic_src->matrix); - } - - cairo_surface_set_repeat (&src_clone->base, generic_src->repeat); - - src_clone->opacity = (unsigned short) - (pattern->color.alpha * 0xffff); - - pattern->source = &src_clone->base; - - return CAIRO_STATUS_SUCCESS; - } - return CAIRO_INT_STATUS_UNSUPPORTED; - break; - } - - if (!source) - return CAIRO_STATUS_NO_MEMORY; - - src = (cairo_gl_surface_t *) _cairo_gl_surface_create (source, 1); - if (!src) { - glitz_surface_destroy (source); - - return CAIRO_STATUS_NO_MEMORY; - } - - if (pattern->type == CAIRO_PATTERN_LINEAR || - pattern->type == CAIRO_PATTERN_RADIAL) - cairo_surface_set_matrix (&src->base, &pattern->matrix); - - _cairo_pattern_init_copy (&src->pattern, pattern); - src->pattern_box = *box; - - pattern->source = &src->base; - - 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 = box->x1; - clip_rects[i].y = 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; - crsurface->opacity = 0xffff; - - 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_glitz_surface.c b/src/cairo_glitz_surface.c new file mode 100644 index 000000000..83269dc12 --- /dev/null +++ b/src/cairo_glitz_surface.c @@ -0,0 +1,907 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 David Reveman + * + * 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 David + * Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. David Reveman makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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 + */ + +#include "cairoint.h" + +#define GLITZ_FIXED_TO_FLOAT(f) \ + (((glitz_float_t) (f)) / 65536) + +#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x)) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((((line).p2.y - (line).p1.y) - 1) + \ + ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x))) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +void +cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) +{ + cairo_surface_t *crsurface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + glitz_surface_reference (surface); + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, crsurface); + + cairo_surface_destroy (crsurface); +} + +typedef struct cairo_glitz_surface { + cairo_surface_t base; + + unsigned long features; + glitz_surface_t *surface; + glitz_format_t *format; + + cairo_pattern_t pattern; + cairo_box_t pattern_box; +} cairo_glitz_surface_t; + +static void +_cairo_glitz_surface_destroy (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_destroy (surface->surface); + + _cairo_pattern_fini (&surface->pattern); + + free (surface); +} + +static double +_cairo_glitz_surface_pixels_per_inch (void *abstract_surface) +{ + return 96.0; +} + +static cairo_image_surface_t * +_cairo_glitz_surface_get_image (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + char *pixels; + int width, height, rowstride, size; + cairo_format_masks_t format; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + if (surface->pattern.type != CAIRO_PATTERN_SURFACE) { + cairo_box_t box; + + box.p1.x = box.p1.y = 0; + box.p2.x = surface->pattern_box.p2.x; + box.p2.y = surface->pattern_box.p2.y; + + return _cairo_pattern_get_image (&surface->pattern, &box); + } + + + width = glitz_surface_get_width (surface->surface); + height = glitz_surface_get_height (surface->surface); + + if (surface->format->red_size > 0) { + format.bpp = 32; + + if (surface->format->alpha_size > 0) + format.alpha_mask = 0xff000000; + else + format.alpha_mask = 0x0; + + format.red_mask = 0xff0000; + format.green_mask = 0xff00; + format.blue_mask = 0xff; + } else { + format.bpp = 8; + format.blue_mask = format.green_mask = format.red_mask = 0x0; + format.alpha_mask = 0xff; + } + + rowstride = (((width * format.bpp) / 8) + 3) & -4; + + pf.masks.bpp = format.bpp; + pf.masks.alpha_mask = format.alpha_mask; + pf.masks.red_mask = format.red_mask; + pf.masks.green_mask = format.green_mask; + pf.masks.blue_mask = format.blue_mask; + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = rowstride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + size = height * rowstride; + + pixels = malloc (size); + if (!pixels) + return NULL; + + buffer = glitz_pixel_buffer_create (surface->surface, NULL, size, + GLITZ_BUFFER_HINT_DYNAMIC_READ); + if (!buffer) { + free (pixels); + return NULL; + } + + glitz_get_pixels (surface->surface, + 0, 0, + width, height, + &pf, + buffer); + + glitz_buffer_get_data (buffer, 0, size, pixels); + + glitz_buffer_destroy (buffer); + + 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_glitz_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + if (image->depth > 8) { + pf.masks.bpp = 32; + + if (surface->format->alpha_size) + pf.masks.alpha_mask = 0xff000000; + else + pf.masks.alpha_mask = 0x0; + + pf.masks.red_mask = 0xff0000; + pf.masks.green_mask = 0xff00; + pf.masks.blue_mask = 0xff; + } else { + pf.masks.bpp = 8; + pf.masks.alpha_mask = 0xff; + pf.masks.red_mask = pf.masks.green_mask = pf.masks.blue_mask = 0x0; + } + + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = (((image->width * pf.masks.bpp) / 8) + 3) & -4; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + + buffer = glitz_pixel_buffer_create (surface->surface, + image->data, + pf.bytes_per_line * image->height, + GLITZ_BUFFER_HINT_STREAM_DRAW); + if (!buffer) + return CAIRO_STATUS_NO_MEMORY; + + glitz_set_pixels (surface->surface, + 0, 0, + image->width, image->height, + &pf, + buffer); + + glitz_buffer_destroy (buffer); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_matrix (void *abstract_surface, + cairo_matrix_t *matrix) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + 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] = 1 << 16; + + glitz_surface_set_transform (surface->surface, &transform); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_filter_t glitz_filter; + + switch (filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + glitz_filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + default: + glitz_filter = GLITZ_FILTER_BILINEAR; + break; + } + + glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_set_fill (surface->surface, + (repeat)? GLITZ_FILL_REPEAT: + GLITZ_FILL_TRANSPARENT); + + return CAIRO_STATUS_SUCCESS; +} + +static glitz_operator_t +_glitz_operator (cairo_operator_t op) +{ + switch (op) { + 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_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; + case CAIRO_OPERATOR_OVER: + 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; + case CAIRO_FORMAT_A8: + return GLITZ_STANDARD_A8; + case CAIRO_FORMAT_RGB24: + return GLITZ_STANDARD_RGB24; + case CAIRO_FORMAT_ARGB32: + default: + return GLITZ_STANDARD_ARGB32; + } +} + +static glitz_surface_t * +_glitz_surface_create_solid (glitz_surface_t *other, + glitz_format_name_t format_name, + glitz_color_t *color) +{ + glitz_surface_t *surface; + glitz_format_t *format; + + format = glitz_surface_find_similar_standard_format (other, format_name); + if (format == NULL) + return NULL; + + surface = glitz_surface_create_similar (other, format, 1, 1); + if (surface == NULL) + return NULL; + + glitz_set_rectangle (surface, color, 0, 0, 1, 1); + + glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT); + + return surface; +} + +static cairo_surface_t * +_cairo_glitz_surface_create_similar (void *abstract_src, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_glitz_surface_t *src = abstract_src; + glitz_surface_t *surface; + cairo_surface_t *crsurface; + glitz_format_t *glitz_format; + + glitz_format = + glitz_surface_find_similar_standard_format (src->surface, + _glitz_format (format)); + if (glitz_format == NULL) + return NULL; + + surface = glitz_surface_create_similar (src->surface, glitz_format, + width, height); + if (surface == NULL) + return NULL; + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) + glitz_surface_destroy (surface); + + return crsurface; +} + +static cairo_glitz_surface_t * +_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ, + cairo_surface_t *src, + cairo_format_t format) +{ + cairo_glitz_surface_t *clone; + cairo_image_surface_t *src_image; + + src_image = _cairo_surface_get_image (src); + + clone = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (templ, format, 0, + src_image->width, + src_image->height); + if (clone == NULL) + return NULL; + + _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src)); + + _cairo_glitz_surface_set_image (clone, src_image); + + _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix)); + + cairo_surface_destroy (&src_image->base); + + return clone; +} + +static cairo_int_status_t +_glitz_composite (glitz_operator_t op, + glitz_surface_t *src, + glitz_surface_t *mask, + glitz_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + int width, + int height, + glitz_buffer_t *geometry, + glitz_geometry_format_t *format) +{ + if (glitz_surface_get_status (dst)) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + glitz_set_geometry (dst, + 0, 0, + format, geometry); + + glitz_composite (op, + src, + mask, + dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + glitz_set_geometry (dst, 0, 0, NULL, NULL); + + if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite (cairo_operator_t op, + 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_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask; + cairo_glitz_surface_t *src_clone = NULL; + cairo_glitz_surface_t *mask_clone = NULL; + cairo_int_status_t status; + + if (generic_src->backend != dst->base.backend) { + src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src, + 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_glitz_surface_clone_similar (dst, generic_mask, + CAIRO_FORMAT_ARGB32); + if (!mask_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + + mask = mask_clone; + } + + status = _glitz_composite (_glitz_operator (op), + src->surface, + (mask)? mask->surface: NULL, + dst->surface, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height, + NULL, NULL); + + if (src_clone) + cairo_surface_destroy (&src_clone->base); + + if (mask_clone) + cairo_surface_destroy (&mask_clone->base); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int n_rects) +{ + cairo_glitz_surface_t *dst = abstract_dst; + 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; + + if (op != CAIRO_OPERATOR_SRC) { + glitz_surface_t *solid; + glitz_float_t *data; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int width = 0; + int height = 0; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_rects * 4; + + buffer = + glitz_geometry_buffer_create (dst->surface, NULL, + n_rects * 8 * sizeof (glitz_float_t), + GLITZ_BUFFER_HINT_STREAM_DRAW); + if (buffer == NULL) + return CAIRO_STATUS_NO_MEMORY; + + data = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_rects; rects++, n_rects--) { + *data++ = (glitz_float_t) rects->x; + *data++ = (glitz_float_t) rects->y; + *data++ = (glitz_float_t) (rects->x + rects->width); + *data++ = (glitz_float_t) rects->y; + *data++ = (glitz_float_t) (rects->x + rects->width); + *data++ = (glitz_float_t) (rects->y + rects->height); + *data++ = (glitz_float_t) rects->x; + *data++ = (glitz_float_t) (rects->y + rects->height); + + if ((rects->x + rects->width) > width) + width = rects->x + rects->width; + + if ((rects->y + rects->height) > height) + height = rects->y + rects->height; + } + glitz_buffer_unmap (buffer); + + solid = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_ARGB32, + &glitz_color); + if (solid == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _glitz_composite (_glitz_operator (op), + solid, + NULL, + dst->surface, + 0, 0, + 0, 0, + 0, 0, + width, height, + buffer, &gf); + + glitz_surface_destroy (solid); + glitz_buffer_destroy (buffer); + + return status; + } else + glitz_set_rectangles (dst->surface, &glitz_color, + (glitz_rectangle_t *) rects, n_rects); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int n_traps) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + glitz_surface_t *mask = NULL; + glitz_float_t *data; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int x_dst, y_dst, x_rel, y_rel, width, height; + + if (generic_src->backend != dst->base.backend) + return CAIRO_INT_STATUS_UNSUPPORTED; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_traps * 4; + + buffer = + glitz_geometry_buffer_create (dst->surface, NULL, + n_traps * 8 * sizeof (glitz_float_t), + GLITZ_BUFFER_HINT_STREAM_DRAW); + if (buffer == NULL) + return CAIRO_STATUS_NO_MEMORY; + + x_dst = traps[0].left.p1.x >> 16; + y_dst = traps[0].left.p1.y >> 16; + + data = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_traps; traps++, n_traps--) { + glitz_float_t top, bottom; + + top = GLITZ_FIXED_TO_FLOAT (traps->top); + bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom); + + *data++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top); + *data++ = top; + *data++ = GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top); + *data++ = top; + *data++ = + GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom); + *data++ = bottom; + *data++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom); + *data++ = bottom; + } + glitz_buffer_unmap (buffer); + + if ((src->pattern.type == CAIRO_PATTERN_SURFACE) && + (src->pattern.color.alpha != 1.0)) { + glitz_color_t color; + + color.red = color.green = color.blue = 0; + color.alpha = src->pattern.color.alpha_short; + + mask = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_A8, + &color); + } + + x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst; + y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst; + + x_dst = src->pattern_box.p1.x >> 16; + y_dst = src->pattern_box.p1.y >> 16; + + width = ((src->pattern_box.p2.x + 65535) >> 16) - + (src->pattern_box.p1.x >> 16); + height = ((src->pattern_box.p2.y + 65535) >> 16) - + (src->pattern_box.p1.y >> 16); + + status = _glitz_composite (_glitz_operator (op), + src->surface, + mask, + dst->surface, + x_rel, y_rel, + 0, 0, + x_dst, y_dst, + width, height, + buffer, &gf); + + if (mask) + glitz_surface_destroy (mask); + + glitz_buffer_destroy (buffer); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_create_pattern (void *abstract_dst, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_surface_t *generic_src = NULL; + cairo_image_surface_t *image = NULL; + cairo_glitz_surface_t *src; + + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + generic_src = + _cairo_surface_create_similar_solid (&dst->base, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (generic_src) + cairo_surface_set_repeat (generic_src, 1); + break; + case CAIRO_PATTERN_RADIAL: + /* glitz doesn't support inner and outer circle with different + center points. */ + if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || + pattern->u.radial.center0.y != pattern->u.radial.center1.y) + break; + /* fall-through */ + case CAIRO_PATTERN_LINEAR: { + glitz_fixed16_16_t *params; + int i, n_params; + + if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + break; + + if (pattern->filter != CAIRO_FILTER_BILINEAR) + break; + + n_params = pattern->n_stops * 3 + 4; + + params = malloc (sizeof (glitz_fixed16_16_t) * n_params); + if (params == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = + _cairo_glitz_surface_create_similar (abstract_dst, + CAIRO_FORMAT_ARGB32, 0, + pattern->n_stops, 1); + if (generic_src == NULL) { + free (params); + return CAIRO_STATUS_NO_MEMORY; + } + + src = (cairo_glitz_surface_t *) generic_src; + + for (i = 0; i < pattern->n_stops; i++) { + glitz_color_t color; + + color.red = pattern->stops[i].color_char[0] * 256; + color.green = pattern->stops[i].color_char[1] * 256; + color.blue = pattern->stops[i].color_char[2] * 256; + color.alpha = pattern->stops[i].color_char[3] * 256; + + glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + + params[4 + 3 * i] = pattern->stops[i].offset; + params[5 + 3 * i] = 0x8000 | (i << 16); + params[6 + 3 * i] = 0x8000; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) { + params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x); + params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y); + params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x); + params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_LINEAR_GRADIENT, + params, n_params); + } else { + params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x); + params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y); + params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0); + params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_RADIAL_GRADIENT, + params, n_params); + } + + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); + break; + case CAIRO_EXTEND_REFLECT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT); + break; + case CAIRO_EXTEND_NONE: + default: + glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST); + break; + } + + cairo_surface_set_matrix (&src->base, &pattern->matrix); + + free (params); + } break; + case CAIRO_PATTERN_SURFACE: + generic_src = pattern->u.surface.surface; + cairo_surface_reference (generic_src); + break; + } + + if (generic_src == NULL) { + image = _cairo_pattern_get_image (pattern, box); + if (image == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = &image->base; + } + + if (generic_src->backend != dst->base.backend) { + src = _cairo_glitz_surface_clone_similar (dst, generic_src, + CAIRO_FORMAT_ARGB32); + if (src == NULL) + return CAIRO_STATUS_NO_MEMORY; + } else + src = (cairo_glitz_surface_t *) generic_src; + + if (image) + cairo_surface_destroy (&image->base); + + _cairo_pattern_init_copy (&src->pattern, pattern); + src->pattern_box = *box; + + pattern->source = &src->base; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static const struct cairo_surface_backend cairo_glitz_surface_backend = { + _cairo_glitz_surface_create_similar, + _cairo_glitz_surface_destroy, + _cairo_glitz_surface_pixels_per_inch, + _cairo_glitz_surface_get_image, + _cairo_glitz_surface_set_image, + _cairo_glitz_surface_set_matrix, + _cairo_glitz_surface_set_filter, + _cairo_glitz_surface_set_repeat, + _cairo_glitz_surface_composite, + _cairo_glitz_surface_fill_rectangles, + _cairo_glitz_surface_composite_trapezoids, + _cairo_glitz_surface_copy_page, + _cairo_glitz_surface_show_page, + _cairo_glitz_surface_set_clip_region, + _cairo_glitz_surface_create_pattern +}; + +cairo_surface_t * +cairo_glitz_surface_create (glitz_surface_t *surface) +{ + cairo_glitz_surface_t *crsurface; + + if (!surface) + return NULL; + + crsurface = malloc (sizeof (cairo_glitz_surface_t)); + if (crsurface == NULL) + return NULL; + + _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); + + crsurface->surface = surface; + crsurface->features = glitz_surface_get_features (surface); + crsurface->format = glitz_surface_get_format (surface); + + _cairo_pattern_init (&crsurface->pattern); + crsurface->pattern.type = CAIRO_PATTERN_SURFACE; + crsurface->pattern.u.surface.surface = NULL; + + return (cairo_surface_t *) crsurface; +}