summaryrefslogtreecommitdiff
path: root/src/cairo_gl_surface.c
diff options
context:
space:
mode:
authorDavid Reveman <davidr@novell.com>2004-04-09 14:19:47 +0000
committerDavid Reveman <davidr@novell.com>2004-04-09 14:19:47 +0000
commit73df0e81cb6a5d43a1325f4722a7236bd554738f (patch)
tree1856e38877155f9d117281beacc64773b5bcc397 /src/cairo_gl_surface.c
parentf713fe43cf18c221a840caab710dfdb25aaf6898 (diff)
Added OpenGL surface backend
Diffstat (limited to 'src/cairo_gl_surface.c')
-rw-r--r--src/cairo_gl_surface.c821
1 files changed, 821 insertions, 0 deletions
diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c
new file mode 100644
index 00000000..cb9871f6
--- /dev/null
+++ b/src/cairo_gl_surface.c
@@ -0,0 +1,821 @@
+/*
+ * Copyright © 2002 University of Southern California
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * University of Southern California not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. The University of Southern
+ * California makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
+ * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <c99drn@cs.umu.se>
+ */
+
+#include "cairoint.h"
+
+static cairo_surface_t *
+_cairo_gl_surface_create (glitz_surface_t *surface,
+ int owns_surface);
+
+void
+cairo_set_target_gl (cairo_t *cr, glitz_surface_t *surface)
+{
+ cairo_surface_t *crsurface;
+
+ if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
+ return;
+
+ if (glitz_surface_get_hints (surface) & GLITZ_HINT_PROGRAMMATIC_MASK) {
+ cr->status = CAIRO_STATUS_NO_TARGET_SURFACE;
+ return;
+ }
+
+ crsurface = _cairo_gl_surface_create (surface, 0);
+ if (crsurface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, crsurface);
+
+ cairo_surface_destroy (crsurface);
+}
+
+typedef struct cairo_gl_surface cairo_gl_surface_t;
+
+struct cairo_gl_surface {
+ cairo_surface_t base;
+
+ glitz_format_t *format;
+ long int features;
+ long int hints;
+ int owns_surface;
+
+ cairo_pattern_t pattern;
+ cairo_box_t pattern_box;
+
+ glitz_surface_t *surface;
+};
+
+#define CAIRO_GL_OFFSCREEN_SUPPORT(surface) \
+ (surface->features & GLITZ_FEATURE_OFFSCREEN_DRAWING_MASK)
+
+#define CAIRO_GL_CONVOLUTION_SUPPORT(surface) \
+ (surface->features & GLITZ_FEATURE_CONVOLUTION_FILTER_MASK)
+
+#define CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT(surface) \
+ (surface->features & GLITZ_FEATURE_ARB_FRAGMENT_PROGRAM_MASK)
+
+#define CAIRO_GL_TEXTURE_NPOT_SUPPORT(surface) \
+ (surface->features & GLITZ_FEATURE_TEXTURE_NPOT_MASK)
+
+#define CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT(surface) \
+ (surface->features & GLITZ_FEATURE_TEXTURE_MIRRORED_REPEAT_MASK)
+
+#define CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT(surface) \
+ ((surface->format->stencil_size < \
+ ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) && \
+ (!CAIRO_GL_OFFSCREEN_SUPPORT (surface)))
+
+#define CAIRO_GL_SURFACE_IS_OFFSCREEN(surface) \
+ (surface->hints & GLITZ_HINT_OFFSCREEN_MASK)
+
+static void
+_cairo_gl_surface_destroy (void *abstract_surface)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+
+ if (surface->owns_surface && surface->surface)
+ glitz_surface_destroy (surface->surface);
+
+ _cairo_pattern_fini (&surface->pattern);
+
+ free (surface);
+}
+
+static double
+_cairo_gl_surface_pixels_per_inch (void *abstract_surface)
+{
+ return 96.0;
+}
+
+static cairo_image_surface_t *
+_cairo_gl_surface_get_image (void *abstract_surface)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ char *pixels;
+ int width, height;
+ int rowstride;
+ cairo_format_masks_t format;
+
+ if (surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK)
+ return _cairo_pattern_get_image (&surface->pattern,
+ &surface->pattern_box);
+
+ width = glitz_surface_get_width (surface->surface);
+ height = glitz_surface_get_height (surface->surface);
+
+ rowstride = width * (surface->format->bpp / 8);
+ rowstride += (rowstride % 4) ? (4 - (rowstride % 4)) : 0;
+
+ pixels = (char *) malloc (sizeof (char) * height * rowstride);
+
+ glitz_surface_read_pixels (surface->surface, 0, 0, width, height, pixels);
+
+ format.bpp = surface->format->bpp;
+ format.red_mask = surface->format->red_mask;
+ format.green_mask = surface->format->green_mask;
+ format.blue_mask = surface->format->blue_mask;
+ format.alpha_mask = surface->format->alpha_mask;
+
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_masks (pixels,
+ &format,
+ width, height, rowstride);
+
+ _cairo_image_surface_assume_ownership_of_data (image);
+
+ _cairo_image_surface_set_repeat (image, surface->base.repeat);
+ _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
+
+ return image;
+}
+
+static cairo_status_t
+_cairo_gl_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+
+ glitz_surface_draw_pixels (surface->surface, 0, 0,
+ image->width, image->height, image->data);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+ glitz_transform_t transform;
+
+ if (!surface->surface)
+ return CAIRO_STATUS_SUCCESS;
+
+ transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
+ transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
+ transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+
+ transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
+ transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
+ transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+
+ transform.matrix[2][0] = 0;
+ transform.matrix[2][1] = 0;
+ transform.matrix[2][2] = _cairo_fixed_from_double (1);
+
+ glitz_surface_set_transform (surface->surface, &transform);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+{
+ static glitz_convolution_t gaussian = {
+ {
+ {0, 1 << 16, 0},
+ {1 << 16, 4 << 16, 1 << 16},
+ {0, 1 << 16, 0}
+ }
+ };
+ cairo_gl_surface_t *surface = abstract_surface;
+ glitz_filter_t gl_filter;
+ glitz_convolution_t *convolution = NULL;
+
+ if (!surface->surface)
+ return CAIRO_STATUS_SUCCESS;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ gl_filter = GLITZ_FILTER_FAST;
+ break;
+ case CAIRO_FILTER_GOOD:
+ gl_filter = GLITZ_FILTER_GOOD;
+ break;
+ case CAIRO_FILTER_BEST:
+ gl_filter = GLITZ_FILTER_BEST;
+ break;
+ case CAIRO_FILTER_NEAREST:
+ gl_filter = GLITZ_FILTER_NEAREST;
+ break;
+ case CAIRO_FILTER_GAUSSIAN:
+ if (CAIRO_GL_CONVOLUTION_SUPPORT (surface))
+ convolution = &gaussian;
+ /* fall-through */
+ case CAIRO_FILTER_BILINEAR:
+ gl_filter = GLITZ_FILTER_BILINEAR;
+ break;
+ default:
+ gl_filter = GLITZ_FILTER_BEST;
+ }
+
+ glitz_surface_set_filter (surface->surface, gl_filter);
+ glitz_surface_set_convolution (surface->surface, convolution);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_surface_set_repeat (void *abstract_surface, int repeat)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+
+ if (!surface->surface)
+ return CAIRO_STATUS_SUCCESS;
+
+ glitz_surface_set_repeat (surface->surface, repeat);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static glitz_operator_t
+_glitz_operator (cairo_operator_t operator)
+{
+ switch (operator) {
+ case CAIRO_OPERATOR_CLEAR:
+ return GLITZ_OPERATOR_CLEAR;
+ case CAIRO_OPERATOR_SRC:
+ return GLITZ_OPERATOR_SRC;
+ case CAIRO_OPERATOR_DST:
+ return GLITZ_OPERATOR_DST;
+ case CAIRO_OPERATOR_OVER:
+ return GLITZ_OPERATOR_OVER;
+ case CAIRO_OPERATOR_OVER_REVERSE:
+ return GLITZ_OPERATOR_OVER_REVERSE;
+ case CAIRO_OPERATOR_IN:
+ return GLITZ_OPERATOR_IN;
+ case CAIRO_OPERATOR_IN_REVERSE:
+ return GLITZ_OPERATOR_IN_REVERSE;
+ case CAIRO_OPERATOR_OUT:
+ return GLITZ_OPERATOR_OUT;
+ case CAIRO_OPERATOR_OUT_REVERSE:
+ return GLITZ_OPERATOR_OUT_REVERSE;
+ case CAIRO_OPERATOR_ATOP:
+ return GLITZ_OPERATOR_ATOP;
+ case CAIRO_OPERATOR_ATOP_REVERSE:
+ return GLITZ_OPERATOR_ATOP_REVERSE;
+ case CAIRO_OPERATOR_XOR:
+ return GLITZ_OPERATOR_XOR;
+ case CAIRO_OPERATOR_ADD:
+ return GLITZ_OPERATOR_ADD;
+ case CAIRO_OPERATOR_SATURATE:
+ return GLITZ_OPERATOR_SATURATE;
+ default:
+ return GLITZ_OPERATOR_OVER;
+ }
+}
+
+static glitz_format_name_t
+_glitz_format (cairo_format_t format)
+{
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ return GLITZ_STANDARD_A1;
+ break;
+ case CAIRO_FORMAT_A8:
+ return GLITZ_STANDARD_A8;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ return GLITZ_STANDARD_RGB24;
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ default:
+ return GLITZ_STANDARD_ARGB32;
+ break;
+ }
+}
+
+static cairo_surface_t *
+_cairo_gl_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ cairo_gl_surface_t *src = abstract_src;
+ glitz_surface_t *surface;
+ cairo_surface_t *crsurface;
+
+ surface = glitz_surface_create_similar (src->surface,
+ _glitz_format (format),
+ width, height);
+ if (surface == NULL)
+ return NULL;
+
+ crsurface = _cairo_gl_surface_create (surface, 1);
+ if (crsurface == NULL)
+ glitz_surface_destroy (surface);
+
+ return crsurface;
+}
+
+static cairo_gl_surface_t *
+_cairo_gl_surface_clone_similar (cairo_surface_t *src,
+ cairo_gl_surface_t *template,
+ cairo_format_t format)
+{
+ cairo_gl_surface_t *clone;
+ cairo_image_surface_t *src_image;
+
+ src_image = _cairo_surface_get_image (src);
+
+ clone = (cairo_gl_surface_t *)
+ _cairo_gl_surface_create_similar (template, format,
+ src_image->width,
+ src_image->height);
+ if (clone == NULL)
+ return NULL;
+
+ _cairo_gl_surface_set_filter (clone, cairo_surface_get_filter (src));
+
+ _cairo_gl_surface_set_image (clone, src_image);
+
+ _cairo_gl_surface_set_matrix (clone, &(src_image->base.matrix));
+
+ cairo_surface_destroy (&src_image->base);
+
+ return clone;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_composite (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ cairo_gl_surface_t *dst = abstract_dst;
+ cairo_gl_surface_t *src = (cairo_gl_surface_t *) generic_src;
+ cairo_gl_surface_t *mask = (cairo_gl_surface_t *) generic_mask;
+ cairo_gl_surface_t *src_clone = NULL;
+ cairo_gl_surface_t *mask_clone = NULL;
+
+ /* If destination surface is offscreen, then offscreen drawing support is
+ required. */
+ if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) &&
+ (!CAIRO_GL_OFFSCREEN_SUPPORT (dst)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Fragment program or offscreen drawing required for composite with
+ mask. */
+ if (mask &&
+ (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (dst)) &&
+ (!CAIRO_GL_OFFSCREEN_SUPPORT (dst)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (generic_src->backend != dst->base.backend) {
+ src_clone = _cairo_gl_surface_clone_similar (generic_src, dst,
+ CAIRO_FORMAT_ARGB32);
+ if (!src_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ src = src_clone;
+ }
+ if (generic_mask && (generic_mask->backend != dst->base.backend)) {
+ mask_clone = _cairo_gl_surface_clone_similar (generic_mask, dst,
+ CAIRO_FORMAT_A8);
+ if (!mask_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ mask = mask_clone;
+ }
+
+ glitz_composite (_glitz_operator (operator),
+ src->surface,
+ mask ? mask->surface : 0,
+ dst->surface,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+
+ if (src_clone)
+ cairo_surface_destroy (&src_clone->base);
+ if (mask_clone)
+ cairo_surface_destroy (&mask_clone->base);
+
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+ glitz_color_t glitz_color;
+
+ /* If destination surface is offscreen, then offscreen drawing support is
+ required. */
+ if (CAIRO_GL_SURFACE_IS_OFFSCREEN (surface) &&
+ (!CAIRO_GL_OFFSCREEN_SUPPORT (surface)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ glitz_color.red = color->red_short;
+ glitz_color.green = color->green_short;
+ glitz_color.blue = color->blue_short;
+ glitz_color.alpha = color->alpha_short;
+
+ glitz_fill_rectangles (_glitz_operator (operator),
+ surface->surface,
+ &glitz_color, (glitz_rectangle_t *) rects,
+ num_rects);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* This function will produce incorrect drawing if alpha is not 1.0. */
+static cairo_int_status_t
+_cairo_gl_surface_fill_trapezoids (cairo_gl_surface_t *surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ glitz_color_t glitz_color;
+
+ glitz_color.red = color->red_short;
+ glitz_color.green = color->green_short;
+ glitz_color.blue = color->blue_short;
+ glitz_color.alpha = color->alpha_short;
+
+ glitz_fill_trapezoids (_glitz_operator (operator),
+ surface->surface,
+ &glitz_color,
+ (glitz_trapezoid_t *) traps, num_traps);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_gl_surface_t *dst = abstract_dst;
+ cairo_gl_surface_t *src = (cairo_gl_surface_t *) generic_src;
+ cairo_gl_surface_t *src_clone = NULL;
+
+ /* If destination surface is offscreen, then offscreen drawing support is
+ required. */
+ if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) &&
+ (!CAIRO_GL_OFFSCREEN_SUPPORT (dst)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Need to get current hints as clipping might have changed. */
+ dst->hints = glitz_surface_get_hints (dst->surface);
+
+ /* Solid source? */
+ if ((generic_src->backend == dst->base.backend) &&
+ (src->pattern.type == CAIRO_PATTERN_SOLID)) {
+
+ /* We can use fill trapezoids if only one trapezoid should be drawn or
+ if solid color alpha is 1.0. If composite trapezoid support
+ is missing we always use fill trapezoids. */
+ if ((num_traps == 1) ||
+ (src->pattern.color.alpha == 1.0) ||
+ (!CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT (dst)))
+ return _cairo_gl_surface_fill_trapezoids (dst, operator,
+ &src->pattern.color,
+ traps, num_traps);
+ }
+
+ if (generic_src->backend != dst->base.backend) {
+ src_clone = _cairo_gl_surface_clone_similar (generic_src, dst,
+ CAIRO_FORMAT_ARGB32);
+ if (!src_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ src = src_clone;
+ }
+
+ glitz_composite_trapezoids (_glitz_operator (operator),
+ src->surface, dst->surface,
+ x_src, y_src, (glitz_trapezoid_t *) traps,
+ num_traps);
+
+ if (src_clone)
+ cairo_surface_destroy (&src_clone->base);
+
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_copy_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_show_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static void
+_cario_gl_uint_to_power_of_two (unsigned int *value)
+{
+ unsigned int x = 1;
+
+ while (x < *value)
+ x <<= 1;
+
+ *value = x;
+}
+
+static void
+_cairo_gl_create_color_range (cairo_pattern_t *pattern,
+ unsigned char *data,
+ unsigned int size)
+{
+ unsigned int i, bytes = size * 4;
+
+ for (i = 0; i < bytes; i += 4)
+ _cairo_pattern_calc_color_at_pixel (pattern, i / (double) bytes,
+ (int *) &data[i]);
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_create_pattern (void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *box)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+ glitz_surface_t *programmatic = NULL;
+ cairo_gl_surface_t *gl_surface;
+ double x = floor (_cairo_fixed_to_double (box->p1.x));
+ double y = floor (_cairo_fixed_to_double (box->p1.y));
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID: {
+ glitz_color_t color;
+
+ color.red = pattern->color.red_short;
+ color.green = pattern->color.green_short;
+ color.blue = pattern->color.blue_short;
+ color.alpha = pattern->color.alpha_short;
+
+ programmatic = glitz_surface_create_solid (&color);
+ }
+ break;
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ unsigned int color_range_size;
+ glitz_color_range_t *color_range;
+
+ if (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* reflect could be emulated for hardware that doesn't support mirrored
+ repeat of textures, but I don't know of any card that support
+ fragment programs but not mirrored repeat, so what's the use. */
+ if (pattern->extend == CAIRO_EXTEND_REFLECT &&
+ (!CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT (surface)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (pattern->type == CAIRO_PATTERN_LINEAR) {
+ double dx, dy;
+
+ dx = (pattern->u.linear.point1.x - x) -
+ (pattern->u.linear.point0.x - x);
+ dy = (pattern->u.linear.point1.y - y) -
+ (pattern->u.linear.point0.y - y);
+
+ color_range_size = sqrt (dx * dx + dy * dy);
+ } else {
+ /* libglitz doesn't support inner circle. */
+ if (pattern->u.radial.center0.x !=
+ pattern->u.radial.center1.x
+ || pattern->u.radial.center0.y !=
+ pattern->u.radial.center1.y
+ || pattern->u.radial.radius0.dx
+ || pattern->u.radial.radius0.dy)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ color_range_size = sqrt (pattern->u.radial.radius1.dx *
+ pattern->u.radial.radius1.dx +
+ pattern->u.radial.radius1.dy *
+ pattern->u.radial.radius1.dy);
+ }
+
+ if ((!CAIRO_GL_TEXTURE_NPOT_SUPPORT (surface)))
+ _cario_gl_uint_to_power_of_two (&color_range_size);
+
+ color_range = glitz_color_range_create (color_range_size);
+ if (!color_range)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_gl_create_color_range (pattern,
+ glitz_color_range_get_data
+ (color_range), color_range_size);
+
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_REPEAT:
+ glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REPEAT);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REFLECT);
+ break;
+ case CAIRO_EXTEND_NONE:
+ glitz_color_range_set_extend (color_range, GLITZ_EXTEND_PAD);
+ break;
+ }
+
+ if (pattern->type == CAIRO_PATTERN_LINEAR) {
+ glitz_point_fixed_t start;
+ glitz_point_fixed_t stop;
+
+ start.x =
+ _cairo_fixed_from_double (pattern->u.linear.point0.x - x);
+ start.y =
+ _cairo_fixed_from_double (pattern->u.linear.point0.y - y);
+ stop.x = _cairo_fixed_from_double (pattern->u.linear.point1.x - x);
+ stop.y = _cairo_fixed_from_double (pattern->u.linear.point1.y - y);
+
+ programmatic =
+ glitz_surface_create_linear (&start, &stop, color_range);
+ } else {
+ glitz_point_fixed_t center;
+ glitz_distance_fixed_t radius;
+
+ center.x =
+ _cairo_fixed_from_double (pattern->u.radial.center1.x - x);
+ center.y =
+ _cairo_fixed_from_double (pattern->u.radial.center1.y - y);
+ radius.dx =
+ _cairo_fixed_from_double (pattern->u.radial.radius1.dx);
+ radius.dy =
+ _cairo_fixed_from_double (pattern->u.radial.radius1.dy);
+
+ programmatic =
+ glitz_surface_create_radial (&center, &radius, color_range);
+ }
+
+ glitz_color_range_destroy (color_range);
+ }
+ break;
+ default:
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ break;
+ }
+
+ if (!programmatic)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ gl_surface = (cairo_gl_surface_t *)
+ _cairo_gl_surface_create (programmatic, 1);
+ if (!gl_surface) {
+ glitz_surface_destroy (programmatic);
+
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _cairo_pattern_init_copy (&gl_surface->pattern, pattern);
+ gl_surface->pattern_box = *box;
+
+ pattern->source = &gl_surface->base;
+ _cairo_pattern_add_source_offset (pattern,
+ floor (_cairo_fixed_to_double (box->p1.x)),
+ floor (_cairo_fixed_to_double (box->p1.y)));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+ glitz_rectangle_t *clip_rects;
+ pixman_box16_t *box;
+ int n, i;
+
+ if (region == NULL) {
+ glitz_rectangle_t rect;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = glitz_surface_get_width (surface->surface);
+ rect.height = glitz_surface_get_height (surface->surface);
+
+ glitz_surface_clip_rectangles (surface->surface,
+ GLITZ_CLIP_OPERATOR_SET, &rect, 1);
+ }
+
+ if (surface->format->stencil_size < 1)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ n = pixman_region_num_rects (region);
+ if (n == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ box = pixman_region_rects (region);
+
+ clip_rects = malloc (n * sizeof (glitz_rectangle_t));
+ if (!clip_rects)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < n; n++, box++) {
+ clip_rects[i].x = (short) box->x1;
+ clip_rects[i].y = (short) box->y1;
+ clip_rects[i].width = (unsigned short) (box->x2 - box->x1);
+ clip_rects[i].height = (unsigned short) (box->y2 - box->y1);
+ }
+
+ glitz_surface_clip_rectangles (surface->surface,
+ GLITZ_CLIP_OPERATOR_SET, clip_rects, n);
+
+ free (clip_rects);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const struct cairo_surface_backend cairo_gl_surface_backend = {
+ _cairo_gl_surface_create_similar,
+ _cairo_gl_surface_destroy,
+ _cairo_gl_surface_pixels_per_inch,
+ _cairo_gl_surface_get_image,
+ _cairo_gl_surface_set_image,
+ _cairo_gl_surface_set_matrix,
+ _cairo_gl_surface_set_filter,
+ _cairo_gl_surface_set_repeat,
+ _cairo_gl_surface_composite,
+ _cairo_gl_surface_fill_rectangles,
+ _cairo_gl_surface_composite_trapezoids,
+ _cairo_gl_surface_copy_page,
+ _cairo_gl_surface_show_page,
+ _cairo_gl_surface_set_clip_region,
+ _cairo_gl_surface_create_pattern
+};
+
+static cairo_surface_t *
+_cairo_gl_surface_create (glitz_surface_t *surface, int owns_surface)
+{
+ cairo_gl_surface_t *crsurface;
+
+ if (!surface)
+ return NULL;
+
+ crsurface = malloc (sizeof (cairo_gl_surface_t));
+ if (crsurface == NULL)
+ return NULL;
+
+ _cairo_surface_init (&crsurface->base, &cairo_gl_surface_backend);
+ _cairo_pattern_init (&crsurface->pattern);
+ crsurface->pattern.type = CAIRO_PATTERN_SURFACE;
+ crsurface->pattern.u.surface.surface = NULL;
+ crsurface->format = glitz_surface_get_format (surface);
+ crsurface->surface = surface;
+ crsurface->features = glitz_surface_get_features (surface);
+ crsurface->hints = glitz_surface_get_hints (surface);
+ crsurface->owns_surface = owns_surface;
+
+ return (cairo_surface_t *) crsurface;
+}
+
+cairo_surface_t *
+cairo_gl_surface_create (glitz_surface_t *surface)
+{
+ return _cairo_gl_surface_create (surface, 0);
+}