summaryrefslogtreecommitdiff
path: root/src/cairo-glitz-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-glitz-surface.c')
-rw-r--r--src/cairo-glitz-surface.c1484
1 files changed, 893 insertions, 591 deletions
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 69fc82f2e..ee664e1cc 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -21,30 +21,12 @@
* 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>
+ * Author: David Reveman <davidr@novell.com>
*/
#include "cairoint.h"
#include "cairo-glitz.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)
{
@@ -65,13 +47,11 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
}
typedef struct _cairo_glitz_surface {
- cairo_surface_t base;
-
- glitz_surface_t *surface;
- glitz_format_t *format;
+ cairo_surface_t base;
- cairo_pattern_t pattern;
- cairo_box_t pattern_box;
+ glitz_surface_t *surface;
+ glitz_format_t *format;
+ pixman_region16_t *clip;
} cairo_glitz_surface_t;
static void
@@ -79,11 +59,60 @@ _cairo_glitz_surface_destroy (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
+ if (surface->clip)
+ {
+ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
+ pixman_region_destroy (surface->clip);
+ }
+
glitz_surface_destroy (surface->surface);
+ free (surface);
+}
- _cairo_pattern_fini (&surface->pattern);
+static glitz_format_name_t
+_glitz_format (cairo_format_t format)
+{
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ return GLITZ_STANDARD_ARGB32;
+ case CAIRO_FORMAT_RGB24:
+ return GLITZ_STANDARD_RGB24;
+ case CAIRO_FORMAT_A8:
+ return GLITZ_STANDARD_A8;
+ case CAIRO_FORMAT_A1:
+ return GLITZ_STANDARD_A1;
+ }
+}
- free (surface);
+static cairo_surface_t *
+_cairo_glitz_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int draw,
+ int width,
+ int height)
+{
+ cairo_glitz_surface_t *src = abstract_src;
+ cairo_surface_t *crsurface;
+ glitz_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_format_t *gformat;
+
+ drawable = glitz_surface_get_drawable (src->surface);
+
+ gformat = glitz_find_standard_format (drawable, _glitz_format (format));
+ if (!gformat)
+ return NULL;
+
+ surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL);
+ if (!surface)
+ return NULL;
+
+ crsurface = cairo_glitz_surface_create (surface);
+
+ glitz_surface_destroy (surface);
+
+ return crsurface;
}
static double
@@ -92,31 +121,54 @@ _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)
+static cairo_status_t
+_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
+ cairo_rectangle_t *interest,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *rect_out)
{
- cairo_glitz_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
- char *pixels;
- int width, height;
- 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);
+ int x1, y1, x2, y2;
+ int width, height;
+ char *pixels;
+ cairo_format_masks_t format;
+ glitz_buffer_t *buffer;
+ glitz_pixel_format_t pf;
+
+ x1 = 0;
+ y1 = 0;
+ x2 = glitz_surface_get_width (surface->surface);
+ y2 = glitz_surface_get_height (surface->surface);
+
+ if (interest)
+ {
+ if (interest->x > x1)
+ x1 = interest->x;
+ if (interest->y > y1)
+ y1 = interest->y;
+ if (interest->x + interest->width < x2)
+ x2 = interest->x + interest->width;
+ if (interest->y + interest->height < y2)
+ y2 = interest->y + interest->height;
+
+ if (x1 >= x2 || y1 >= y2)
+ {
+ *image_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
}
+ width = x2 - x1;
+ height = y2 - y1;
- width = glitz_surface_get_width (surface->surface);
- height = glitz_surface_get_height (surface->surface);
-
+ if (rect_out)
+ {
+ rect_out->x = x1;
+ rect_out->y = y1;
+ rect_out->width = width;
+ rect_out->height = height;
+ }
+
if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
if (surface->format->color.red_size > 0) {
format.bpp = 32;
@@ -149,21 +201,24 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
pf.masks.blue_mask = format.blue_mask;
pf.xoffset = 0;
pf.skip_lines = 0;
+
+ /* XXX: we should eventually return images with negative stride,
+ need to verify that libpixman have no problem with this first. */
pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4;
pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
pixels = malloc (height * pf.bytes_per_line);
if (!pixels)
- return NULL;
+ return CAIRO_STATUS_NO_MEMORY;
buffer = glitz_buffer_create_for_data (pixels);
if (!buffer) {
free (pixels);
- return NULL;
+ return CAIRO_STATUS_NO_MEMORY;
}
glitz_get_pixels (surface->surface,
- 0, 0,
+ x1, y1,
width, height,
&pf,
buffer);
@@ -175,27 +230,38 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
&format,
width, height,
pf.bytes_per_line);
-
+
+ if (!image)
+ {
+ free (pixels);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
_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;
+ *image_out = image;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_glitz_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_cairo_glitz_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ int x_dst,
+ int y_dst)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
- pixman_format_t *format;
- int am, rm, gm, bm;
+ glitz_buffer_t *buffer;
+ glitz_pixel_format_t pf;
+ pixman_format_t *format;
+ int am, rm, gm, bm;
+ char *data;
format = pixman_image_get_format (image->pixman_image);
- if (format == NULL)
+ if (!format)
return CAIRO_STATUS_NO_MEMORY;
pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
@@ -206,15 +272,27 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
pf.masks.blue_mask = bm;
pf.xoffset = 0;
pf.skip_lines = 0;
- pf.bytes_per_line = image->stride;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
- buffer = glitz_buffer_create_for_data (image->data);
+ /* check for negative stride */
+ if (image->stride < 0)
+ {
+ pf.bytes_per_line = -image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
+ data = (char *) image->data + image->stride * (image->height - 1);
+ }
+ else
+ {
+ pf.bytes_per_line = image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
+ data = (char *) image->data;
+ }
+
+ buffer = glitz_buffer_create_for_data (data);
if (!buffer)
return CAIRO_STATUS_NO_MEMORY;
glitz_set_pixels (surface->surface,
- 0, 0,
+ x_dst, y_dst,
image->width, image->height,
&pf,
buffer);
@@ -225,63 +303,118 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
}
static cairo_status_t
-_cairo_glitz_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_glitz_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
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]);
+ *image_extra = NULL;
+
+ return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);
+}
- 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]);
+static void
+_cairo_glitz_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_destroy (&image->base);
+}
- transform.matrix[2][0] = 0;
- transform.matrix[2][1] = 0;
- transform.matrix[2][2] = 1 << 16;
+static cairo_status_t
+_cairo_glitz_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
- glitz_surface_set_transform (surface->surface, &transform);
+ status = _cairo_glitz_surface_get_image (surface, interest_rect, &image,
+ image_rect_out);
+ if (status)
+ return status;
- return CAIRO_STATUS_SUCCESS;
+ *image_out = image;
+ *image_extra = NULL;
+
+ return status;
}
+static void
+_cairo_glitz_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+
+ _cairo_glitz_surface_set_image (surface, image,
+ image_rect->x, image_rect->y);
+
+ cairo_surface_destroy (&image->base);
+}
+
+
static cairo_status_t
-_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+_cairo_glitz_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_filter_t glitz_filter;
+ cairo_glitz_surface_t *clone;
- 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;
+ if (src->backend == surface->base.backend)
+ {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
}
+ else if (_cairo_surface_is_image (src))
+ {
+ cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
+
+ clone = (cairo_glitz_surface_t *)
+ _cairo_glitz_surface_create_similar (surface, image_src->format, 0,
+ image_src->width,
+ image_src->height);
+ if (!clone)
+ return CAIRO_STATUS_NO_MEMORY;
- glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0);
+ _cairo_glitz_surface_set_image (clone, image_src, 0, 0);
+
+ *clone_out = &clone->base;
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_status_t
-_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat)
+static void
+_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *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]);
- glitz_surface_set_fill (surface->surface,
- (repeat)? GLITZ_FILL_REPEAT:
- GLITZ_FILL_TRANSPARENT);
+ 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]);
- return CAIRO_STATUS_SUCCESS;
+ transform.matrix[2][0] = 0;
+ transform.matrix[2][1] = 0;
+ transform.matrix[2][2] = 1 << 16;
+
+ glitz_surface_set_transform (surface->surface, &transform);
}
static glitz_operator_t
@@ -318,32 +451,6 @@ _glitz_operator (cairo_operator_t op)
}
}
-static glitz_surface_t *
-_glitz_surface_create_solid (glitz_surface_t *other,
- glitz_format_name_t format_name,
- glitz_color_t *color)
-{
- glitz_drawable_t *drawable;
- glitz_format_t *format;
- glitz_surface_t *surface;
-
- drawable = glitz_surface_get_drawable (other);
-
- format = glitz_find_standard_format (drawable, format_name);
- if (format == NULL)
- return NULL;
-
- surface = glitz_surface_create (drawable, 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 glitz_status_t
_glitz_ensure_target (glitz_surface_t *surface)
{
@@ -355,7 +462,6 @@ _glitz_ensure_target (glitz_surface_t *surface)
glitz_drawable_format_t templ;
glitz_format_t *format;
glitz_drawable_t *pbuffer;
- glitz_pbuffer_attributes_t attributes;
unsigned long mask;
int i;
@@ -397,21 +503,13 @@ _glitz_ensure_target (glitz_surface_t *surface)
if (!dformat)
return CAIRO_INT_STATUS_UNSUPPORTED;
- attributes.width = glitz_surface_get_width (surface);
- attributes.height = glitz_surface_get_height (surface);
- mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK;
-
- pbuffer = glitz_create_pbuffer_drawable (drawable, dformat,
- &attributes, mask);
+ pbuffer =
+ glitz_create_pbuffer_drawable (drawable, dformat,
+ glitz_surface_get_width (surface),
+ glitz_surface_get_height (surface));
if (!pbuffer)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (glitz_drawable_get_width (pbuffer) < attributes.width ||
- glitz_drawable_get_height (pbuffer) < attributes.height) {
- glitz_drawable_destroy (pbuffer);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
glitz_surface_attach (surface, pbuffer,
GLITZ_DRAWABLE_BUFFER_FRONT_COLOR,
0, 0);
@@ -422,388 +520,711 @@ _glitz_ensure_target (glitz_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
-static glitz_format_name_t
-_glitz_format (cairo_format_t format)
+typedef struct _cairo_glitz_surface_attributes {
+ cairo_surface_attributes_t base;
+
+ glitz_fill_t fill;
+ glitz_filter_t filter;
+ glitz_fixed16_16_t *params;
+ int n_params;
+ cairo_bool_t acquired;
+} cairo_glitz_surface_attributes_t;
+
+static cairo_int_status_t
+_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
+ cairo_glitz_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glitz_surface_t **surface_out,
+ cairo_glitz_surface_attributes_t *attr)
{
- switch (format) {
+ cairo_glitz_surface_t *src = NULL;
+
+ attr->acquired = FALSE;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *gradient =
+ (cairo_gradient_pattern_t *) pattern;
+ glitz_drawable_t *drawable;
+ glitz_fixed16_16_t *params;
+ int n_params;
+ int i;
+ unsigned short alpha;
+
+ /* XXX: the current color gradient acceleration provided by glitz is
+ * experimental, it's been proven inappropriate in a number of ways,
+ * most importantly, it's currently implemented as filters and
+ * gradients are not filters. eventually, it will be replaced with
+ * something more appropriate.
+ */
+
+ if (gradient->n_stops < 2)
+ break;
+
+ /* glitz doesn't support inner and outer circle with different
+ center points. */
+ if (pattern->type == CAIRO_PATTERN_RADIAL)
+ {
+ cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
+
+ if (grad->center0.x != grad->center1.x ||
+ grad->center0.y != grad->center1.y)
+ break;
+ }
+
+ drawable = glitz_surface_get_drawable (dst->surface);
+ if (!(glitz_drawable_get_features (drawable) &
+ GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
+ break;
+
+ if (pattern->filter != CAIRO_FILTER_BILINEAR &&
+ pattern->filter != CAIRO_FILTER_GOOD &&
+ pattern->filter != CAIRO_FILTER_BEST)
+ break;
+
+ alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff;
+ for (i = 1; i < gradient->n_stops; i++)
+ {
+ unsigned short a;
+
+ a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff;
+ if (a != alpha)
+ break;
+ }
+
+ /* we can't have color stops with different alpha as gradient color
+ interpolation should be done to unpremultiplied colors. */
+ if (i < gradient->n_stops)
+ break;
+
+ n_params = gradient->n_stops * 3 + 4;
+
+ params = malloc (sizeof (glitz_fixed16_16_t) * n_params);
+ if (!params)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ src = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ CAIRO_FORMAT_ARGB32, 0,
+ gradient->n_stops, 1);
+ if (!src)
+ {
+ free (params);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < gradient->n_stops; i++) {
+ glitz_color_t color;
+
+ color.red = gradient->stops[i].color.red * alpha;
+ color.green = gradient->stops[i].color.green * alpha;
+ color.blue = gradient->stops[i].color.blue * alpha;
+ color.alpha = alpha;
+
+ glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
+
+ params[4 + 3 * i] = gradient->stops[i].offset;
+ params[5 + 3 * i] = i << 16;
+ params[6 + 3 * i] = 0;
+ }
+
+ if (pattern->type == CAIRO_PATTERN_LINEAR)
+ {
+ cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
+
+ params[0] = _cairo_fixed_from_double (grad->point0.x);
+ params[1] = _cairo_fixed_from_double (grad->point0.y);
+ params[2] = _cairo_fixed_from_double (grad->point1.x);
+ params[3] = _cairo_fixed_from_double (grad->point1.y);
+ attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
+ }
+ else
+ {
+ cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
+
+ params[0] = _cairo_fixed_from_double (grad->center0.x);
+ params[1] = _cairo_fixed_from_double (grad->center0.y);
+ params[2] = _cairo_fixed_from_double (grad->radius0);
+ params[3] = _cairo_fixed_from_double (grad->radius1);
+ attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
+ }
+
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_NONE:
+ attr->fill = GLITZ_FILL_NEAREST;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ attr->fill = GLITZ_FILL_REPEAT;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ attr->fill = GLITZ_FILL_REFLECT;
+ break;
+ }
+
+ attr->params = params;
+ attr->n_params = n_params;
+ attr->base.matrix = pattern->matrix;
+ attr->base.x_offset = 0;
+ attr->base.y_offset = 0;
+ } break;
default:
- case CAIRO_FORMAT_ARGB32:
- return GLITZ_STANDARD_ARGB32;
- case CAIRO_FORMAT_RGB24:
- return GLITZ_STANDARD_RGB24;
- case CAIRO_FORMAT_A8:
- return GLITZ_STANDARD_A8;
- case CAIRO_FORMAT_A1:
- return GLITZ_STANDARD_A1;
+ break;
}
-}
-static cairo_surface_t *
-_cairo_glitz_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int draw,
- int width,
- int height)
-{
- cairo_glitz_surface_t *src = abstract_src;
- cairo_surface_t *crsurface;
- glitz_drawable_t *drawable;
- glitz_surface_t *surface;
- glitz_format_t *gformat;
+ if (!src)
+ {
+ cairo_int_status_t status;
- drawable = glitz_surface_get_drawable (src->surface);
-
- gformat = glitz_find_standard_format (drawable, _glitz_format (format));
- if (gformat == NULL)
- return NULL;
-
- surface = glitz_surface_create (drawable, gformat, width, height);
- if (surface == NULL)
- return NULL;
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ x, y, width, height,
+ (cairo_surface_t **) &src,
+ &attr->base);
+ if (status)
+ return status;
+
+ if (src)
+ {
+ switch (attr->base.extend) {
+ case CAIRO_EXTEND_NONE:
+ attr->fill = GLITZ_FILL_TRANSPARENT;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ attr->fill = GLITZ_FILL_REPEAT;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ attr->fill = GLITZ_FILL_REFLECT;
+ break;
+ }
- crsurface = cairo_glitz_surface_create (surface);
-
- glitz_surface_destroy (surface);
+ switch (attr->base.filter) {
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ attr->filter = GLITZ_FILTER_NEAREST;
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ default:
+ attr->filter = GLITZ_FILTER_BILINEAR;
+ break;
+ }
+
+ attr->params = NULL;
+ attr->n_params = 0;
+ attr->acquired = TRUE;
+ }
+ }
- return crsurface;
+ *surface_out = src;
+
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_glitz_surface_t *
-_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ,
- cairo_surface_t *src,
- cairo_format_t format)
+static void
+_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst,
+ cairo_glitz_surface_t *surface,
+ cairo_glitz_surface_attributes_t *attr)
{
- cairo_glitz_surface_t *clone;
- cairo_image_surface_t *src_image;
+ if (attr->acquired)
+ _cairo_pattern_release_surface (&dst->base, &surface->base,
+ &attr->base);
+ else
+ _cairo_glitz_surface_destroy (surface);
+}
- src_image = _cairo_surface_get_image (src);
+static cairo_int_status_t
+_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_glitz_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glitz_surface_t **src_out,
+ cairo_glitz_surface_t **mask_out,
+ cairo_glitz_surface_attributes_t *sattr,
+ cairo_glitz_surface_attributes_t *mattr)
+{
+ cairo_int_status_t status;
+ cairo_pattern_union_t tmp;
+ cairo_bool_t src_opaque, mask_opaque;
+ double src_alpha, mask_alpha;
- 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));
+ src_opaque = _cairo_pattern_is_opaque (src);
+ mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
- _cairo_glitz_surface_set_image (clone, src_image);
-
- _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix));
+ /* For surface patterns, we move any translucency from src->alpha
+ * to mask->alpha so we can use the source unchanged. Otherwise we
+ * move the translucency from mask->alpha to src->alpha so that
+ * we can drop the mask if possible.
+ */
+ if (src->type == CAIRO_PATTERN_SURFACE)
+ {
+ if (mask) {
+ mask_opaque = mask_opaque && src_opaque;
+ mask_alpha = mask->alpha * src->alpha;
+ } else {
+ mask_opaque = src_opaque;
+ mask_alpha = src->alpha;
+ }
+
+ src_alpha = 1.0;
+ src_opaque = TRUE;
+ }
+ else
+ {
+ if (mask)
+ {
+ src_opaque = mask_opaque && src_opaque;
+ src_alpha = mask->alpha * src->alpha;
+ /* FIXME: This needs changing when we support RENDER
+ * style 4-channel masks.
+ */
+ if (mask->type == CAIRO_PATTERN_SOLID)
+ mask = NULL;
+ } else
+ src_alpha = src->alpha;
+
+ mask_alpha = 1.0;
+ mask_opaque = TRUE;
+ }
+
+ _cairo_pattern_init_copy (&tmp.base, src);
+ _cairo_pattern_set_alpha (&tmp.base, src_alpha);
+
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ src_out, sattr);
- cairo_surface_destroy (&src_image->base);
+ _cairo_pattern_fini (&tmp.base);
- return clone;
-}
+ if (status)
+ return status;
-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_ensure_target (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask || !mask_opaque)
+ {
+ if (mask)
+ _cairo_pattern_init_copy (&tmp.base, mask);
+ else
+ _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
- 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);
+ _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ mask_x, mask_y,
+ width, height,
+ mask_out, mattr);
+
+ _cairo_pattern_fini (&tmp.base);
- if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (status)
+ {
+ _cairo_glitz_pattern_release_surface (dst, *src_out, sattr);
+ return status;
+ }
+ }
+ else
+ {
+ *mask_out = NULL;
+ }
return CAIRO_STATUS_SUCCESS;
}
+static void
+_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
+ cairo_glitz_surface_attributes_t *a)
+{
+ _cairo_glitz_surface_set_matrix (surface, &a->base.matrix);
+ glitz_surface_set_fill (surface->surface, a->fill);
+ glitz_surface_set_filter (surface->surface, a->filter,
+ a->params, a->n_params);
+}
+
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_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
+ 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;
+ cairo_glitz_surface_attributes_t src_attr, mask_attr;
+ cairo_glitz_surface_t *dst = abstract_dst;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_surface_t *mask;
+ cairo_int_status_t status;
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
- 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;
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ &src, &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ _cairo_glitz_surface_set_attributes (src, &src_attr);
+ if (mask)
+ {
+ _cairo_glitz_surface_set_attributes (mask, &mask_attr);
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ mask->surface,
+ dst->surface,
+ src_x + src_attr.base.x_offset,
+ src_y + src_attr.base.y_offset,
+ mask_x + mask_attr.base.x_offset,
+ mask_y + mask_attr.base.y_offset,
+ dst_x, dst_y,
+ width, height);
- src = src_clone;
- }
-
- if (generic_mask && (generic_mask->backend != dst->base.backend)) {
- mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask,
- CAIRO_FORMAT_A8);
- if (!mask_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask_attr.n_params)
+ free (mask_attr.params);
- mask = mask_clone;
+ _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr);
+ }
+ else
+ {
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ NULL,
+ dst->surface,
+ src_x + src_attr.base.x_offset,
+ src_y + src_attr.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
}
- 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);
+ if (src_attr.n_params)
+ free (src_attr.params);
- return status;
+ _cairo_glitz_pattern_release_surface (dst, src, &src_attr);
+
+ 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_glitz_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
+_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_rectangle_t *rects,
+ int n_rects)
{
cairo_glitz_surface_t *dst = abstract_dst;
- glitz_color_t glitz_color;
- if (op == CAIRO_OPERATOR_SATURATE)
- 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;
+ if (op == CAIRO_OPERATOR_SRC)
+ {
+ 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 (glitz_surface_get_width (dst->surface) != 1 ||
+ glitz_surface_get_height (dst->surface) != 1)
+ _glitz_ensure_target (dst->surface);
- if (op != CAIRO_OPERATOR_SRC) {
- glitz_surface_t *solid;
- glitz_float_t *vertices;
- glitz_buffer_t *buffer;
- glitz_geometry_format_t gf;
- cairo_int_status_t status;
- int width, height;
- void *data;
+ glitz_set_rectangles (dst->surface, &glitz_color,
+ (glitz_rectangle_t *) rects, n_rects);
+ }
+ else
+ {
+ cairo_glitz_surface_t *src;
- 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;
-
- data = malloc (n_rects * 8 * sizeof (glitz_float_t));
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (data);
- if (buffer == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- width = height = 0;
- vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY);
- for (; n_rects; rects++, n_rects--) {
- *vertices++ = (glitz_float_t) rects->x;
- *vertices++ = (glitz_float_t) rects->y;
- *vertices++ = (glitz_float_t) (rects->x + rects->width);
- *vertices++ = (glitz_float_t) rects->y;
- *vertices++ = (glitz_float_t) (rects->x + rects->width);
- *vertices++ = (glitz_float_t) (rects->y + rects->height);
- *vertices++ = (glitz_float_t) rects->x;
- *vertices++ = (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);
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- solid = _glitz_surface_create_solid (dst->surface,
- GLITZ_STANDARD_ARGB32,
- &glitz_color);
- if (solid == NULL)
+ src = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_solid (&dst->base,
+ CAIRO_FORMAT_ARGB32, 1, 1,
+ (cairo_color_t *) color);
+ if (!src)
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);
- free (data);
-
- return status;
- } else {
- if (glitz_surface_get_width (dst->surface) != 1 ||
- glitz_surface_get_height (dst->surface) != 1) {
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ while (n_rects--)
+ {
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ NULL,
+ dst->surface,
+ 0, 0,
+ 0, 0,
+ rects->x, rects->y,
+ rects->width, rects->height);
+ rects++;
}
- glitz_set_rectangles (dst->surface, &glitz_color,
- (glitz_rectangle_t *) rects, n_rects);
+ cairo_surface_destroy (&src->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_glitz_surface_composite_trapezoids (cairo_operator_t op,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
+_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
- int n_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 *vertices;
- 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;
- void *data;
+ cairo_glitz_surface_attributes_t attributes;
+ cairo_glitz_surface_t *dst = abstract_dst;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_surface_t *mask = NULL;
+ glitz_buffer_t *buffer = NULL;
+ void *data = NULL;
+ cairo_int_status_t status;
+ unsigned short alpha;
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend)
+ if (_glitz_ensure_target (dst->surface))
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;
+ if (pattern->type == CAIRO_PATTERN_SURFACE)
+ {
+ cairo_pattern_union_t tmp;
- data = malloc (n_traps * 8 * sizeof (glitz_float_t));
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (data);
- if (buffer == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- x_dst = traps[0].left.p1.x >> 16;
- y_dst = traps[0].left.p1.y >> 16;
+ _cairo_pattern_init_copy (&tmp.base, pattern);
+ _cairo_pattern_set_alpha (&tmp.base, 1.0);
- vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY);
- for (; n_traps; traps++, n_traps--) {
- glitz_float_t top, bottom;
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
- top = GLITZ_FIXED_TO_FLOAT (traps->top);
- bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom);
+ _cairo_pattern_fini (&tmp.base);
- *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top);
- *vertices++ = top;
- *vertices++ =
- GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top);
- *vertices++ = top;
- *vertices++ =
- GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom);
- *vertices++ = bottom;
- *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom);
- *vertices++ = bottom;
+ alpha = pattern->alpha * 0xffff;
}
- glitz_buffer_unmap (buffer);
+ else
+ {
+ status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
+ alpha = 0xffff;
+ }
+
+ if (status)
+ return status;
+
+ if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
+ {
+ static glitz_color_t clear_black = { 0, 0, 0, 0 };
+ glitz_color_t color;
+ glitz_geometry_format_t format;
+ int n_trap_added;
+ int offset = 0;
+ int data_size = 0;
+ int size = 30 * n_traps; /* just a guess */
+
+ format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
+ format.vertex.type = GLITZ_DATA_TYPE_FLOAT;
+ format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t);
+ format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
+ format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT;
+ format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X;
+ format.vertex.mask.offset = 2 * sizeof (glitz_float_t);
+
+ mask = (cairo_glitz_surface_t *)
+ _cairo_glitz_surface_create_similar (&dst->base,
+ CAIRO_FORMAT_A8, 0,
+ 2, 1);
+ if (!mask)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ color.red = color.green = color.blue = color.alpha = alpha;
- if ((src->pattern.type == CAIRO_PATTERN_SURFACE) &&
- (src->pattern.color.alpha != 1.0)) {
- glitz_color_t color;
+ glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
+ glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
+
+ glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST);
+ glitz_surface_set_filter (mask->surface,
+ GLITZ_FILTER_BILINEAR,
+ NULL, 0);
+
+ size *= format.vertex.bytes_per_vertex;
- color.red = color.green = color.blue = 0;
- color.alpha = src->pattern.color.alpha_short;
+ while (n_traps)
+ {
+ if (data_size < size)
+ {
+ data_size = size;
+ data = realloc (data, data_size);
+ if (!data)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src,
+ &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ if (buffer)
+ glitz_buffer_destroy (buffer);
+
+ buffer = glitz_buffer_create_for_data (data);
+ if (!buffer) {
+ free (data);
+ _cairo_glitz_pattern_release_surface (dst, src,
+ &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+ }
- mask = _glitz_surface_create_solid (dst->surface,
- GLITZ_STANDARD_A8,
- &color);
+ offset +=
+ glitz_add_trapezoids (buffer,
+ offset, size - offset,
+ format.vertex.type, mask->surface,
+ (glitz_trapezoid_t *) traps, n_traps,
+ &n_trap_added);
+
+ n_traps -= n_trap_added;
+ traps += n_trap_added;
+ size *= 2;
+ }
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_VERTEX,
+ &format, buffer);
+ glitz_set_array (dst->surface, 0, 3,
+ offset / format.vertex.bytes_per_vertex,
+ 0, 0);
}
+ else
+ {
+ cairo_image_surface_t *image;
+ char *ptr;
+ int stride;
+
+ stride = (width + 3) & -4;
+ data = malloc (stride * height);
+ if (!data)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ memset (data, 0, stride * height);
- x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst;
- y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst;
+ /* using negative stride */
+ ptr = (char *) data + stride * (height - 1);
+
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (ptr,
+ CAIRO_FORMAT_A8,
+ width, height,
+ -stride);
+ if (!image)
+ {
+ cairo_surface_destroy (&src->base);
+ free (data);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
- x_dst = src->pattern_box.p1.x >> 16;
- y_dst = src->pattern_box.p1.y >> 16;
+ pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
+ (pixman_trapezoid_t *) traps, n_traps);
+
+ if (alpha != 0xffff)
+ {
+ pixman_color_t color;
+
+ color.red = color.green = color.blue = color.alpha = alpha;
+
+ pixman_fill_rectangle (PIXMAN_OPERATOR_IN,
+ image->pixman_image,
+ &color,
+ 0, 0, width, height);
+ }
+
+ mask = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ CAIRO_FORMAT_A8, 0,
+ width, height);
+ if (!mask)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ free (data);
+ cairo_surface_destroy (&image->base);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _cairo_glitz_surface_set_image (mask, image, 0, 0);
+ }
+
+ _cairo_glitz_surface_set_attributes (src, &attributes);
- 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);
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ mask->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset,
+ src_y + attributes.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ if (attributes.n_params)
+ free (attributes.params);
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_NONE,
+ NULL, NULL);
+
+ if (buffer)
+ glitz_buffer_destroy (buffer);
- 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);
+ free (data);
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
if (mask)
- glitz_surface_destroy (mask);
+ cairo_surface_destroy (&mask->base);
- glitz_buffer_destroy (buffer);
- free (data);
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -819,173 +1240,56 @@ _cairo_glitz_surface_show_page (void *abstract_surface)
}
static cairo_int_status_t
-_cairo_glitz_surface_create_pattern (void *abstract_dst,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
+_cairo_glitz_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
{
- 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 (abstract_dst,
- 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_drawable_t *drawable;
- glitz_fixed16_16_t *params;
- int i, n_params;
-
- drawable = glitz_surface_get_drawable (dst->surface);
- if (!(glitz_drawable_get_features (drawable) &
- 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;
+ cairo_glitz_surface_t *surface = abstract_surface;
- color.alpha = pattern->stops[i].color_char[3];
- color.red = pattern->stops[i].color_char[0] * color.alpha;
- color.green = pattern->stops[i].color_char[1] * color.alpha;
- color.blue = pattern->stops[i].color_char[2] * color.alpha;
- color.alpha *= 256;
+ if (region)
+ {
+ glitz_box_t *box;
+ int n;
- glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
-
- params[4 + 3 * i] = pattern->stops[i].offset;
- params[5 + 3 * i] = i << 16;
- params[6 + 3 * i] = 0;
- }
-
- 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;
+ if (!surface->clip)
+ {
+ surface->clip = pixman_region_create ();
+ if (!surface->clip)
+ return CAIRO_STATUS_NO_MEMORY;
}
+ pixman_region_copy (surface->clip, region);
- 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;
+ box = (glitz_box_t *) pixman_region_rects (surface->clip);
+ n = pixman_region_num_rects (surface->clip);
+ glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
}
+ else
+ {
+ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
- 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;
-
- cairo_surface_set_repeat (&src->base, generic_src->repeat);
- } else
- src = (cairo_glitz_surface_t *) generic_src;
+ if (surface->clip)
+ pixman_region_destroy (surface->clip);
- if (image)
- cairo_surface_destroy (&image->base);
-
- _cairo_pattern_init_copy (&src->pattern, pattern);
- src->pattern_box = *box;
-
- pattern->source = &src->base;
+ surface->clip = NULL;
+ }
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 cairo_surface_backend_t 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_acquire_source_image,
+ _cairo_glitz_surface_release_source_image,
+ _cairo_glitz_surface_acquire_dest_image,
+ _cairo_glitz_surface_release_dest_image,
+ _cairo_glitz_surface_clone_similar,
_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,
NULL /* show_glyphs */
};
@@ -1004,12 +1308,10 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
glitz_surface_reference (surface);
- crsurface->surface = 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;
+ crsurface->surface = surface;
+ crsurface->format = glitz_surface_get_format (surface);
+ crsurface->clip = NULL;
return (cairo_surface_t *) crsurface;
}