diff options
Diffstat (limited to 'src/cairo-glitz-surface.c')
-rw-r--r-- | src/cairo-glitz-surface.c | 293 |
1 files changed, 176 insertions, 117 deletions
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index cd0d254..a649d50 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -27,6 +27,7 @@ #include "cairoint.h" #include "cairo-glitz.h" #include "cairo-glitz-private.h" +#include "cairo-region-private.h" typedef struct _cairo_glitz_surface { cairo_surface_t base; @@ -34,6 +35,7 @@ typedef struct _cairo_glitz_surface { glitz_surface_t *surface; glitz_format_t *format; + cairo_region_t *clip_region; cairo_bool_t has_clip; glitz_box_t *clip_boxes; int num_clip_boxes; @@ -50,6 +52,7 @@ _cairo_glitz_surface_finish (void *abstract_surface) if (surface->clip_boxes) free (surface->clip_boxes); + cairo_region_destroy (surface->clip_region); glitz_surface_destroy (surface->surface); return CAIRO_STATUS_SUCCESS; @@ -107,43 +110,6 @@ _cairo_glitz_surface_create_similar (void *abstract_src, } static cairo_status_t -_cairo_glitz_get_boxes_from_region (cairo_region_t *region, - glitz_box_t **boxes, - int *nboxes) -{ - pixman_box32_t *pboxes; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - int n, i; - - n = 0; - pboxes = pixman_region32_rectangles (®ion->rgn, &n); - if (n == 0) { - *nboxes = 0; - return CAIRO_STATUS_SUCCESS; - } - - if (n > *nboxes) { - *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t)); - if (*boxes == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto done; - } - } - - for (i = 0; i < n; i++) { - (*boxes)[i].x1 = pboxes[i].x1; - (*boxes)[i].y1 = pboxes[i].y1; - (*boxes)[i].x2 = pboxes[i].x2; - (*boxes)[i].y2 = pboxes[i].y2; - } - - *nboxes = n; -done: - return status; -} - -static cairo_status_t _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, cairo_rectangle_int_t *interest, cairo_image_surface_t **image_out, @@ -441,10 +407,57 @@ _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface, glitz_surface_set_transform (surface->surface, &transform); } +static cairo_bool_t +_is_supported_operator (cairo_operator_t op) +{ + /* This is really just a if (op < SATURATE), but we use a switch + * so the compiler will warn if we ever add more operators. + */ + switch (op) { + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_DEST_ATOP: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + return TRUE; + + default: + ASSERT_NOT_REACHED; + case CAIRO_OPERATOR_SATURATE: + /* nobody likes saturate, expect that it's required to do + * seamless polygons! + */ + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return FALSE; + } +} + static glitz_operator_t _glitz_operator (cairo_operator_t op) { - switch (op) { + switch ((int) op) { case CAIRO_OPERATOR_CLEAR: return GLITZ_OPERATOR_CLEAR; @@ -474,24 +487,17 @@ _glitz_operator (cairo_operator_t op) return GLITZ_OPERATOR_XOR; case CAIRO_OPERATOR_ADD: return GLITZ_OPERATOR_ADD; - case CAIRO_OPERATOR_SATURATE: - /* XXX: This line should never be reached. Glitz backend should bail - out earlier if saturate operator is used. OpenGL can't do saturate - with pre-multiplied colors. Solid colors can still be done as we - can just un-pre-multiply them. However, support for that will have - to be added to glitz. */ - /* fall-through */ - break; - } - - ASSERT_NOT_REACHED; + default: + ASSERT_NOT_REACHED; - /* Something's very broken if this line of code can be reached, so - we want to return something that would give a noticeably - incorrect result. The XOR operator seems so rearely desired - that it should fit the bill here. */ - return CAIRO_OPERATOR_XOR; + /* Something's very broken if this line of code can be reached, so + * we want to return something that would give a noticeably + * incorrect result. The XOR operator seems so rearely desired + * that it should fit the bill here. + */ + return CAIRO_OPERATOR_XOR; + } } #define CAIRO_GLITZ_FEATURE_OK(surface, name) \ @@ -649,9 +655,9 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern, } src = (cairo_glitz_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, - CAIRO_CONTENT_COLOR_ALPHA, - gradient->n_stops, 1); + _cairo_glitz_surface_create_similar (&dst->base, + CAIRO_CONTENT_COLOR_ALPHA, + gradient->n_stops, 1); if (src->base.status) { glitz_buffer_destroy (buffer); free (data); @@ -877,6 +883,77 @@ _cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface, a->params, a->n_params); } +static cairo_status_t +_cairo_glitz_get_boxes_from_region (cairo_region_t *region, + glitz_box_t **boxes, + int *nboxes) +{ + pixman_box32_t *pboxes; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + int n, i; + + n = 0; + pboxes = pixman_region32_rectangles (®ion->rgn, &n); + if (n == 0) { + *nboxes = 0; + return CAIRO_STATUS_SUCCESS; + } + + if (n > *nboxes) { + *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t)); + if (*boxes == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto done; + } + } + + for (i = 0; i < n; i++) { + (*boxes)[i].x1 = pboxes[i].x1; + (*boxes)[i].y1 = pboxes[i].y1; + (*boxes)[i].x2 = pboxes[i].x2; + (*boxes)[i].y2 = pboxes[i].y2; + } + + *nboxes = n; +done: + return status; +} + +static cairo_status_t +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + cairo_region_t *region) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + if (region == surface->clip_region) + return CAIRO_STATUS_SUCCESS; + + cairo_region_destroy (surface->clip_region); + surface->clip_region = cairo_region_reference (region); + + if (region != NULL) { + cairo_status_t status; + + status = _cairo_glitz_get_boxes_from_region (region, + &surface->clip_boxes, + &surface->num_clip_boxes); + if (status) + return status; + + glitz_surface_set_clip_region (surface->surface, + 0, 0, + surface->clip_boxes, + surface->num_clip_boxes); + surface->has_clip = TRUE; + } else { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); + surface->has_clip = FALSE; + } + + return CAIRO_STATUS_SUCCESS; +} + static cairo_int_status_t _cairo_glitz_surface_composite (cairo_operator_t op, const cairo_pattern_t *src_pattern, @@ -889,7 +966,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_glitz_surface_attributes_t src_attr, mask_attr; cairo_glitz_surface_t *dst = abstract_dst; @@ -897,12 +975,16 @@ _cairo_glitz_surface_composite (cairo_operator_t op, cairo_glitz_surface_t *mask; cairo_int_status_t status; - if (op == CAIRO_OPERATOR_SATURATE) + if (! _is_supported_operator (op)) return CAIRO_INT_STATUS_UNSUPPORTED; if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_glitz_surface_set_clip_region (dst, clip_region); + if (status) + return status; + status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern, dst, src_x, src_y, @@ -969,7 +1051,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op, mask_width, mask_height, src_x, src_y, mask_x, mask_y, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); } if (mask) @@ -1000,8 +1083,15 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)]; glitz_rectangle_t *glitz_rects = stack_rects; glitz_rectangle_t *current_rect; + cairo_status_t status; int i; + if (! _is_supported_operator (op)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_glitz_surface_set_clip_region (dst, NULL); + assert (status == CAIRO_STATUS_SUCCESS); + if (n_rects > ARRAY_LENGTH (stack_rects)) { glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t)); if (glitz_rects == NULL) @@ -1064,12 +1154,12 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, _cairo_surface_create_similar_solid (&dst->base, CAIRO_CONTENT_COLOR_ALPHA, 1, 1, - (cairo_color_t *) color); - if (src->base.status) - { + (cairo_color_t *) color, + FALSE); + if (src == NULL || src->base.status) { if (glitz_rects != stack_rects) free (glitz_rects); - return src->base.status; + return src ? src->base.status : CAIRO_INT_STATUS_UNSUPPORTED; } glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); @@ -1113,7 +1203,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int n_traps) + int n_traps, + cairo_region_t *clip_region) { cairo_glitz_surface_attributes_t attributes; cairo_glitz_surface_t *dst = abstract_dst; @@ -1133,12 +1224,16 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, return CAIRO_INT_STATUS_UNSUPPORTED; } - if (op == CAIRO_OPERATOR_SATURATE) + if (! _is_supported_operator (op)) return CAIRO_INT_STATUS_UNSUPPORTED; if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_glitz_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; + /* Convert traps to pixman traps */ if (n_traps > ARRAY_LENGTH (stack_traps)) { pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t)); @@ -1281,7 +1376,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, n_traps, (pixman_trapezoid_t *) pixman_traps); mask = (cairo_glitz_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, + _cairo_glitz_surface_create_similar (&dst->base, CAIRO_CONTENT_ALPHA, width, height); status = mask->base.status; @@ -1338,7 +1433,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, 0, 0, dst_x, dst_y, - width, height); + width, height, + clip_region); } FAIL: @@ -1353,35 +1449,7 @@ FAIL: return status; } -static cairo_int_status_t -_cairo_glitz_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_glitz_surface_t *surface = abstract_surface; - - if (region != NULL) { - cairo_status_t status; - - status = _cairo_glitz_get_boxes_from_region (region, - &surface->clip_boxes, - &surface->num_clip_boxes); - if (status) - return status; - - glitz_surface_set_clip_region (surface->surface, - 0, 0, - surface->clip_boxes, - surface->num_clip_boxes); - surface->has_clip = TRUE; - } else { - glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - surface->has_clip = FALSE; - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t +static cairo_bool_t _cairo_glitz_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -1392,7 +1460,7 @@ _cairo_glitz_surface_get_extents (void *abstract_surface, rectangle->width = glitz_surface_get_width (surface->surface); rectangle->height = glitz_surface_get_height (surface->surface); - return CAIRO_STATUS_SUCCESS; + return TRUE; } #define CAIRO_GLITZ_AREA_AVAILABLE 0 @@ -1995,7 +2063,8 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_region_t *clip_region) { cairo_glitz_surface_attributes_t attributes; cairo_glitz_surface_glyph_private_t *glyph_private; @@ -2028,7 +2097,7 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, scaled_font->surface_backend != _cairo_glitz_surface_get_backend ()) return CAIRO_INT_STATUS_UNSUPPORTED; - if (op == CAIRO_OPERATOR_SATURATE) + if (! _is_supported_operator (op)) return CAIRO_INT_STATUS_UNSUPPORTED; /* XXX Unbounded operators are not handled correctly */ @@ -2038,6 +2107,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_glitz_surface_set_clip_region (dst, NULL); + if (unlikely (status)) + return status; + status = _cairo_glitz_pattern_acquire_surface (pattern, dst, src_x, src_y, width, height, @@ -2286,25 +2359,13 @@ _cairo_glitz_surface_is_similar (void *surface_a, return drawable_a == drawable_b; } -static cairo_status_t -_cairo_glitz_surface_reset (void *abstract_surface) -{ - cairo_glitz_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = _cairo_glitz_surface_set_clip_region (surface, NULL); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; -} - static const cairo_surface_backend_t cairo_glitz_surface_backend = { CAIRO_SURFACE_TYPE_GLITZ, _cairo_glitz_surface_create_similar, _cairo_glitz_surface_finish, _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, @@ -2313,10 +2374,9 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_composite_trapezoids, NULL, /* create_span_renderer */ NULL, /* check_span_renderer */ + NULL, /* copy_page */ NULL, /* show_page */ - _cairo_glitz_surface_set_clip_region, - NULL, /* intersect_clip_path */ _cairo_glitz_surface_get_extents, _cairo_glitz_surface_old_show_glyphs, NULL, /* get_font_options */ @@ -2333,8 +2393,6 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_snapshot, _cairo_glitz_surface_is_similar, - - _cairo_glitz_surface_reset }; static const cairo_surface_backend_t * @@ -2384,6 +2442,7 @@ cairo_glitz_surface_create (glitz_surface_t *surface) crsurface->has_clip = FALSE; crsurface->clip_boxes = NULL; crsurface->num_clip_boxes = 0; + crsurface->clip_region = NULL; return &crsurface->base; } |