Replaced the gl backend with the new glitz backend

This commit is contained in:
David Reveman 2004-09-11 04:23:17 +00:00
parent 211cf9a2ce
commit 27d2de8c2d
9 changed files with 1863 additions and 998 deletions

View file

@ -1,3 +1,21 @@
2004-09-11 David Reveman <c99drn@cs.umu.se>
* 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 <cworth@brudder.east.isi.edu>
* COPYING:

View file

@ -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@

View file

@ -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 ""

View file

@ -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

View file

@ -45,7 +45,7 @@
#define @XCB_SURFACE_FEATURE@
#define @GL_SURFACE_FEATURE@
#define @GLITZ_SURFACE_FEATURE@
#define @SANITY_CHECKING_FEATURE@

907
src/cairo-glitz-surface.c Normal file
View file

@ -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 <c99drn@cs.umu.se>
*/
#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;
}

View file

@ -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 <glitz.h>
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 */

View file

@ -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 <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;
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
(&center,
_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);
}

907
src/cairo_glitz_surface.c Normal file
View file

@ -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 <c99drn@cs.umu.se>
*/
#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;
}