summaryrefslogtreecommitdiff
path: root/src/cairo-surface-fallback.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-30 17:28:21 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-09-12 08:29:48 +0100
commitaf9fbd176b145f042408ef5391eef2a51d7531f8 (patch)
tree5f75d1087d4325a013af6f0a4204a666fb4ca4f0 /src/cairo-surface-fallback.c
parent0540bf384aed344899417d3b0313bd6704679c1c (diff)
downloadcairo-af9fbd176b145f042408ef5391eef2a51d7531f8.tar.gz
Introduce a new compositor architecture
Having spent the last dev cycle looking at how we could specialize the compositors for various backends, we once again look for the commonalities in order to reduce the duplication. In part this is motivated by the idea that spans is a good interface for both the existent GL backend and pixman, and so they deserve a dedicated compositor. xcb/xlib target an identical rendering system and so they should be using the same compositor, and it should be possible to run that same compositor locally against pixman to generate reference tests. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> P.S. This brings massive upheaval (read breakage) I've tried delaying in order to fix as many things as possible but now this one patch does far, far, far too much. Apologies in advance for breaking your favourite backend, but trust me in that the end result will be much better. :)
Diffstat (limited to 'src/cairo-surface-fallback.c')
-rw-r--r--src/cairo-surface-fallback.c1563
1 files changed, 47 insertions, 1516 deletions
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index ec6946be5..a0af15969 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -3,6 +3,7 @@
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -40,1545 +41,75 @@
#include "cairoint.h"
-#include "cairo-boxes-private.h"
-#include "cairo-clip-private.h"
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-pattern-private.h"
-#include "cairo-region-private.h"
-#include "cairo-spans-private.h"
+#include "cairo-compositor-private.h"
#include "cairo-surface-fallback-private.h"
-typedef struct {
- cairo_surface_t *dst;
- cairo_rectangle_int_t extents;
- cairo_image_surface_t *image;
- cairo_rectangle_int_t image_rect;
- void *image_extra;
-} fallback_state_t;
-
-/**
- * _fallback_init:
- *
- * Acquire destination image surface needed for an image-based
- * fallback.
- *
- * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
- * visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all
- * went well, or some error status otherwise.
- **/
-static cairo_int_status_t
-_fallback_init (fallback_state_t *state,
- cairo_surface_t *dst,
- int x,
- int y,
- int width,
- int height)
-{
- cairo_status_t status;
-
- state->extents.x = x;
- state->extents.y = y;
- state->extents.width = width;
- state->extents.height = height;
-
- state->dst = dst;
-
- status = _cairo_surface_acquire_dest_image (dst, &state->extents,
- &state->image, &state->image_rect,
- &state->image_extra);
- if (unlikely (status))
- return status;
-
-
- /* XXX: This NULL value tucked away in state->image is a rather
- * ugly interface. Cleaner would be to push the
- * CAIRO_INT_STATUS_NOTHING_TO_DO value down into
- * _cairo_surface_acquire_dest_image and its backend
- * counterparts. */
- assert (state->image != NULL);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_fallback_fini (fallback_state_t *state)
-{
- _cairo_surface_release_dest_image (state->dst, &state->extents,
- state->image, &state->image_rect,
- state->image_extra);
-}
-
-typedef cairo_status_t
-(*cairo_draw_func_t) (void *closure,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_surface_t *dst,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region);
-
-static void do_unaligned_row(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b,
- int tx, int y, int h,
- uint16_t coverage)
-{
- int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
- int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
- if (x2 > x1) {
- if (! _cairo_fixed_is_integer (b->p1.x)) {
- blt(closure, x1, y, 1, h,
- coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
- x1++;
- }
-
- if (x2 > x1)
- blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
-
- if (! _cairo_fixed_is_integer (b->p2.x))
- blt(closure, x2, y, 1, h,
- coverage * _cairo_fixed_fractional_part (b->p2.x));
- } else
- blt(closure, x1, y, 1, h,
- coverage * (b->p2.x - b->p1.x));
-}
-
-static void do_unaligned_box(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b, int tx, int ty)
-{
- int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
- int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
- if (y2 > y1) {
- if (! _cairo_fixed_is_integer (b->p1.y)) {
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- 256 - _cairo_fixed_fractional_part (b->p1.y));
- y1++;
- }
-
- if (y2 > y1)
- do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
-
- if (! _cairo_fixed_is_integer (b->p2.y))
- do_unaligned_row(blt, closure, b, tx, y2, 1,
- _cairo_fixed_fractional_part (b->p2.y));
- } else
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- b->p2.y - b->p1.y);
-}
-
-static void blt_in(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage)
-{
- cairo_color_t color;
- cairo_rectangle_int_t rect;
-
- if (coverage == 0xffff)
- return;
-
- _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
-
- rect.x = x;
- rect.y = y;
- rect.width = w;
- rect.height = h;
-
- _cairo_surface_fill_rectangles (closure, CAIRO_OPERATOR_IN,
- &color, &rect, 1);
-}
-
-static cairo_status_t
-_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
- cairo_clip_t *clip,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_t *mask;
- cairo_status_t status;
- cairo_region_t *clip_region;
- int i;
-
- /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with
- * a mask (as called via _cairo_surface_mask) triggers assertion failures.
- */
- mask = _cairo_surface_create_similar_solid (dst,
- CAIRO_CONTENT_ALPHA,
- extents->width,
- extents->height,
- CAIRO_COLOR_TRANSPARENT,
- TRUE);
- if (unlikely (mask->status))
- return mask->status;
-
- clip_region = _cairo_clip_get_region (clip);
- if (clip_region && (extents->x | extents->y))
- cairo_region_translate (clip_region, -extents->x, -extents->y);
-
- status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
- &_cairo_pattern_white.base, mask,
- extents->x, extents->y,
- extents,
- clip_region);
-
- if (clip_region && (extents->x | extents->y))
- cairo_region_translate (clip_region, extents->x, extents->y);
-
- if (unlikely (status))
- goto CLEANUP;
-
- if (clip) {
- for (i = 0; i < clip->num_boxes; i++) {
- cairo_box_t *b = &clip->boxes[i];
-
- if (! _cairo_fixed_is_integer (b->p1.x) ||
- ! _cairo_fixed_is_integer (b->p1.y) ||
- ! _cairo_fixed_is_integer (b->p2.x) ||
- ! _cairo_fixed_is_integer (b->p2.y))
- {
- do_unaligned_box(blt_in, mask, b, extents->x, extents->y);
- }
- }
-
- if (clip->path != NULL) {
- status = _cairo_clip_combine_with_surface (clip, mask,
- extents->x, extents->y);
- if (unlikely (status))
- goto CLEANUP;
- }
- }
-
- _cairo_pattern_init_for_surface (mask_pattern, mask);
-
- CLEANUP:
- cairo_surface_destroy (mask);
-
- return status;
-}
-
-/* Handles compositing with a clip surface when the operator allows
- * us to combine the clip with the mask
- */
-static cairo_status_t
-_clip_and_composite_with_mask (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_pattern_t mask_pattern;
- cairo_status_t status;
-
- status = _create_composite_mask_pattern (&mask_pattern,
- clip,
- draw_func, draw_closure,
- dst, extents);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _cairo_surface_composite (op,
- src, &mask_pattern.base, dst,
- extents->x, extents->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height,
- NULL);
-
- _cairo_pattern_fini (&mask_pattern.base);
- }
-
- return status;
-}
-
-/* Handles compositing with a clip surface when we have to do the operation
- * in two pieces and combine them together.
- */
-static cairo_status_t
-_clip_and_composite_combine (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t pattern;
- cairo_surface_pattern_t clip_pattern;
- cairo_surface_t *clip_surface;
- int clip_x, clip_y;
- cairo_status_t status;
-
- /* We'd be better off here creating a surface identical in format
- * to dst, but we have no way of getting that information. Instead
- * we ask the backend to create a similar surface of identical content,
- * in the belief that the backend will do something useful - like use
- * an identical format. For example, the xlib backend will endeavor to
- * use a compatible depth to enable core protocol routines.
- */
- intermediate =
- _cairo_surface_create_similar_scratch (dst, dst->content,
- extents->width,
- extents->height);
- if (intermediate == NULL) {
- intermediate =
- _cairo_image_surface_create_with_content (dst->content,
- extents->width,
- extents->width);
- }
- if (unlikely (intermediate->status))
- return intermediate->status;
-
- /* Initialize the intermediate surface from the destination surface */
- _cairo_pattern_init_for_surface (&pattern, dst);
- status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL, intermediate,
- extents->x, extents->y,
- 0, 0,
- 0, 0,
- extents->width, extents->height,
- NULL);
- _cairo_pattern_fini (&pattern.base);
- if (unlikely (status))
- goto CLEANUP_SURFACE;
-
- status = (*draw_func) (draw_closure, op,
- src, intermediate,
- extents->x, extents->y,
- extents,
- NULL);
- if (unlikely (status))
- goto CLEANUP_SURFACE;
-
- clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
- if (unlikely (clip_surface->status))
- goto CLEANUP_SURFACE;
-
- _cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
-
- /* Combine that with the clip */
- status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
- &clip_pattern.base, NULL, intermediate,
- extents->x - clip_x,
- extents->y - clip_y,
- 0, 0,
- 0, 0,
- extents->width, extents->height,
- NULL);
- if (unlikely (status))
- goto CLEANUP_CLIP;
-
- /* Punch the clip out of the destination */
- status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
- &clip_pattern.base, NULL, dst,
- extents->x - clip_x,
- extents->y - clip_y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height,
- NULL);
- if (unlikely (status))
- goto CLEANUP_CLIP;
-
- /* Now add the two results together */
- _cairo_pattern_init_for_surface (&pattern, intermediate);
- status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
- &pattern.base, NULL, dst,
- 0, 0,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height,
- NULL);
- _cairo_pattern_fini (&pattern.base);
-
- CLEANUP_CLIP:
- _cairo_pattern_fini (&clip_pattern.base);
- CLEANUP_SURFACE:
- cairo_surface_destroy (intermediate);
-
- return status;
-}
-
-/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
- * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
- */
-static cairo_status_t
-_clip_and_composite_source (cairo_clip_t *clip,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_pattern_t mask_pattern;
- cairo_region_t *clip_region = _cairo_clip_get_region (clip);
- cairo_status_t status;
-
- /* Create a surface that is mask IN clip */
- status = _create_composite_mask_pattern (&mask_pattern,
- clip,
- draw_func, draw_closure,
- dst, extents);
- if (unlikely (status))
- return status;
-
- /* Compute dest' = dest OUT (mask IN clip) */
- status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
- &mask_pattern.base, NULL, dst,
- 0, 0,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height,
- clip_region);
-
- if (unlikely (status))
- goto CLEANUP_MASK_PATTERN;
-
- /* Now compute (src IN (mask IN clip)) ADD dest' */
- status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
- src, &mask_pattern.base, dst,
- extents->x, extents->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height,
- clip_region);
-
- CLEANUP_MASK_PATTERN:
- _cairo_pattern_fini (&mask_pattern.base);
- return status;
-}
-
-/**
- * _clip_and_composite:
- * @clip: a #cairo_clip_t
- * @op: the operator to draw with
- * @src: source pattern
- * @draw_func: function that can be called to draw with the mask onto a surface.
- * @draw_closure: data to pass to @draw_func.
- * @dst: destination surface
- * @extents: rectangle holding a bounding box for the operation; this
- * rectangle will be used as the size for the temporary
- * surface.
- *
- * When there is a surface clip, we typically need to create an intermediate
- * surface. This function handles the logic of creating a temporary surface
- * drawing to it, then compositing the result onto the target surface.
- *
- * @draw_func is to called to draw the mask; it will be called no more
- * than once.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
- **/
-static cairo_status_t
-_clip_and_composite (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_status_t status;
-
- if (op == CAIRO_OPERATOR_CLEAR) {
- src = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- if (op == CAIRO_OPERATOR_SOURCE) {
- status = _clip_and_composite_source (clip,
- src,
- draw_func, draw_closure,
- dst, extents);
- } else {
- if (! _cairo_clip_is_region (clip)) {
- if (_cairo_operator_bounded_by_mask (op)) {
- status = _clip_and_composite_with_mask (clip, op,
- src,
- draw_func, draw_closure,
- dst, extents);
- } else {
- status = _clip_and_composite_combine (clip, op,
- src,
- draw_func, draw_closure,
- dst, extents);
- }
- } else {
- status = draw_func (draw_closure, op,
- src, dst,
- 0, 0,
- extents,
- _cairo_clip_get_region (clip));
- }
- }
-
- return status;
-}
-
-/* Composites a region representing a set of trapezoids.
- */
-static cairo_status_t
-_composite_trap_region (cairo_clip_t *clip,
- const cairo_pattern_t *src,
- cairo_operator_t op,
- cairo_surface_t *dst,
- cairo_region_t *trap_region,
- const cairo_rectangle_int_t *extents)
-{
- cairo_status_t status;
- cairo_surface_pattern_t mask_pattern;
- cairo_pattern_t *mask = NULL;
- int mask_x = 0, mask_y =0;
-
- if (clip != NULL) {
- cairo_surface_t *clip_surface = NULL;
- int clip_x, clip_y;
-
- clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
- if (unlikely (clip_surface->status))
- return clip_surface->status;
-
- if (op == CAIRO_OPERATOR_CLEAR) {
- src = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- _cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
- mask_x = extents->x - clip_x;
- mask_y = extents->y - clip_y;
- mask = &mask_pattern.base;
- }
-
- status = _cairo_surface_composite (op, src, mask, dst,
- extents->x, extents->y,
- mask_x, mask_y,
- extents->x, extents->y,
- extents->width, extents->height,
- trap_region);
-
- if (mask != NULL)
- _cairo_pattern_fini (mask);
-
- return status;
-}
-
-typedef struct {
- cairo_traps_t *traps;
- cairo_antialias_t antialias;
-} cairo_composite_traps_info_t;
-
-static cairo_status_t
-_composite_traps_draw_func (void *closure,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_surface_t *dst,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region)
-{
- cairo_composite_traps_info_t *info = closure;
- cairo_status_t status;
- cairo_region_t *extents_region = NULL;
-
- if (dst_x != 0 || dst_y != 0)
- _cairo_traps_translate (info->traps, - dst_x, - dst_y);
-
- if (clip_region == NULL &&
- !_cairo_operator_bounded_by_source (op)) {
- extents_region = cairo_region_create_rectangle (extents);
- if (unlikely (extents_region->status))
- return extents_region->status;
- cairo_region_translate (extents_region, -dst_x, -dst_y);
- clip_region = extents_region;
- }
-
- status = _cairo_surface_composite_trapezoids (op,
- src, dst, info->antialias,
- extents->x, extents->y,
- extents->x - dst_x, extents->y - dst_y,
- extents->width, extents->height,
- info->traps->traps,
- info->traps->num_traps,
- clip_region);
-
- if (extents_region)
- cairo_region_destroy (extents_region);
-
- return status;
-}
-
-enum {
- HAS_CLEAR_REGION = 0x1,
-};
-
-static cairo_status_t
-_clip_and_composite_region (const cairo_pattern_t *src,
- cairo_operator_t op,
- cairo_surface_t *dst,
- cairo_region_t *trap_region,
- cairo_clip_t *clip,
- cairo_rectangle_int_t *extents)
-{
- cairo_region_t clear_region;
- unsigned int has_region = 0;
- cairo_status_t status;
-
- if (! _cairo_operator_bounded_by_mask (op) && clip == NULL) {
- /* If we optimize drawing with an unbounded operator to
- * _cairo_surface_fill_rectangles() or to drawing with a
- * clip region, then we have an additional region to clear.
- */
- _cairo_region_init_rectangle (&clear_region, extents);
- status = cairo_region_subtract (&clear_region, trap_region);
- if (unlikely (status))
- return status;
-
- if (! cairo_region_is_empty (&clear_region))
- has_region |= HAS_CLEAR_REGION;
- }
-
- if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
- clip == NULL)
- {
- const cairo_color_t *color;
-
- if (op == CAIRO_OPERATOR_CLEAR)
- color = CAIRO_COLOR_TRANSPARENT;
- else
- color = &((cairo_solid_pattern_t *)src)->color;
-
- /* Solid rectangles special case */
- status = _cairo_surface_fill_region (dst, op, color, trap_region);
- } else {
- /* For a simple rectangle, we can just use composite(), for more
- * rectangles, we have to set a clip region. The cost of rasterizing
- * trapezoids is pretty high for most backends currently, so it's
- * worthwhile even if a region is needed.
- *
- * If we have a clip surface, we set it as the mask; this only works
- * for bounded operators other than SOURCE; for unbounded operators,
- * clip and mask cannot be interchanged. For SOURCE, the operator
- * as implemented by the backends is different in its handling
- * of the mask then what we want.
- *
- * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
- * more than rectangle and the destination doesn't support clip
- * regions. In that case, we fall through.
- */
- status = _composite_trap_region (clip, src, op, dst,
- trap_region, extents);
- }
-
- if (has_region & HAS_CLEAR_REGION) {
- if (status == CAIRO_STATUS_SUCCESS) {
- status = _cairo_surface_fill_region (dst,
- CAIRO_OPERATOR_CLEAR,
- CAIRO_COLOR_TRANSPARENT,
- &clear_region);
- }
- _cairo_region_fini (&clear_region);
- }
-
- return status;
-}
-
-/* avoid using region code to re-validate boxes */
-static cairo_status_t
-_fill_rectangles (cairo_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_traps_t *traps,
- cairo_clip_t *clip)
-{
- const cairo_color_t *color;
- cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
- cairo_rectangle_int_t *rects = stack_rects;
- cairo_status_t status;
- int i;
-
- if (! traps->is_rectilinear || ! traps->maybe_region)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* XXX: convert clip region to geometric boxes? */
- if (clip != NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* XXX: fallback for the region_subtract() operation */
- if (! _cairo_operator_bounded_by_mask (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (traps->has_intersections) {
- if (traps->is_rectangular) {
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
- } else {
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
- }
- if (unlikely (status))
- return status;
- }
-
- for (i = 0; i < traps->num_traps; i++) {
- if (! _cairo_fixed_is_integer (traps->traps[i].top) ||
- ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
- ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
- ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
- {
- traps->maybe_region = FALSE;
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
- }
-
- if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
- rects = _cairo_malloc_ab (traps->num_traps,
- sizeof (cairo_rectangle_int_t));
- if (unlikely (rects == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- for (i = 0; i < traps->num_traps; i++) {
- int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
- int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
- int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
- int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
-
- rects[i].x = x1;
- rects[i].y = y1;
- rects[i].width = x2 - x1;
- rects[i].height = y2 - y1;
- }
-
- if (op == CAIRO_OPERATOR_CLEAR)
- color = CAIRO_COLOR_TRANSPARENT;
- else
- color = &((cairo_solid_pattern_t *)src)->color;
-
- status = _cairo_surface_fill_rectangles (dst, op, color, rects, i);
-
- if (rects != stack_rects)
- free (rects);
-
- return status;
-}
-
-/* fast-path for very common composite of a single rectangle */
-static cairo_status_t
-_composite_rectangle (cairo_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_traps_t *traps,
- cairo_clip_t *clip)
-{
- cairo_rectangle_int_t rect;
-
- if (clip != NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_fixed_is_integer (traps->traps[0].top) ||
- ! _cairo_fixed_is_integer (traps->traps[0].bottom) ||
- ! _cairo_fixed_is_integer (traps->traps[0].left.p1.x) ||
- ! _cairo_fixed_is_integer (traps->traps[0].right.p1.x))
- {
- traps->maybe_region = FALSE;
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x);
- rect.y = _cairo_fixed_integer_part (traps->traps[0].top);
- rect.width = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x;
- rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y;
-
- return _cairo_surface_composite (op, src, NULL, dst,
- rect.x, rect.y,
- 0, 0,
- rect.x, rect.y,
- rect.width, rect.height,
- NULL);
-}
-
-/* Warning: This call modifies the coordinates of traps */
-static cairo_status_t
-_clip_and_composite_trapezoids (const cairo_pattern_t *src,
- cairo_operator_t op,
- cairo_surface_t *dst,
- cairo_traps_t *traps,
- cairo_antialias_t antialias,
- cairo_clip_t *clip,
- cairo_rectangle_int_t *extents)
-{
- cairo_composite_traps_info_t traps_info;
- cairo_bool_t clip_surface = ! _cairo_clip_is_region (clip);
- cairo_int_status_t status;
-
- if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op))
- return CAIRO_STATUS_SUCCESS;
-
- /* Use a fast path if the trapezoids consist of a simple region,
- * but we can only do this if we do not have a clip surface, or can
- * substitute the mask with the clip.
- */
- if (! clip_surface ||
- (_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE))
- {
- cairo_region_t *trap_region = NULL;
-
- if (_cairo_operator_bounded_by_source (op)) {
- status = _fill_rectangles (dst, op, src, traps, clip);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- status = _composite_rectangle (dst, op, src, traps, clip);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- status = _cairo_traps_extract_region (traps, antialias, &trap_region);
- if (unlikely (_cairo_int_status_is_error (status)))
- return status;
-
- if (trap_region != NULL) {
- status = cairo_region_intersect_rectangle (trap_region, extents);
- if (unlikely (status)) {
- cairo_region_destroy (trap_region);
- return status;
- }
-
- if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t trap_extents;
-
- cairo_region_get_extents (trap_region, &trap_extents);
- if (! _cairo_rectangle_intersect (extents, &trap_extents)) {
- cairo_region_destroy (trap_region);
- return CAIRO_INT_STATUS_SUCCESS;
- }
- }
-
- status = _clip_and_composite_region (src, op, dst,
- trap_region,
- clip_surface ? clip : NULL,
- extents);
- cairo_region_destroy (trap_region);
-
- if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
- return status;
- }
- }
-
- /* No fast path, exclude self-intersections and clip trapezoids. */
- if (traps->has_intersections) {
- if (traps->is_rectangular)
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
- else if (traps->is_rectilinear)
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
- else
- status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
- if (unlikely (status))
- return status;
- }
-
- /* Otherwise render the trapezoids to a mask and composite in the usual
- * fashion.
- */
- traps_info.traps = traps;
- traps_info.antialias = antialias;
-
- return _clip_and_composite (clip, op, src,
- _composite_traps_draw_func,
- &traps_info, dst, extents);
-}
-
-cairo_status_t
-_cairo_surface_fallback_paint (cairo_surface_t *surface,
+cairo_int_status_t
+_cairo_surface_fallback_paint (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_boxes_t boxes;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_paint (&extents, &rect,
- op, source,
- clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_clip_to_boxes (extents.clip, &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- cairo_traps_t traps;
-
- /* meh, surface-fallback is dying anyway... */
- status = _cairo_traps_init_boxes (&traps, &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _clip_and_composite_trapezoids (source, op, surface,
- &traps, CAIRO_ANTIALIAS_DEFAULT,
- extents.clip,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
- _cairo_traps_fini (&traps);
- }
- }
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_paint (&_cairo_fallback_compositor,
+ surface, op, source, clip);
}
-static cairo_status_t
-_cairo_surface_mask_draw_func (void *closure,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_surface_t *dst,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region)
-{
- cairo_pattern_t *mask = closure;
- cairo_int_status_t status;
- cairo_region_t *extents_region = NULL;
-
- if (clip_region == NULL &&
- !_cairo_operator_bounded_by_source (op)) {
- extents_region = cairo_region_create_rectangle (extents);
- if (unlikely (extents_region->status))
- return extents_region->status;
- cairo_region_translate (extents_region, -dst_x, -dst_y);
- clip_region = extents_region;
- }
-
- if (src) {
- status = _cairo_surface_composite (op,
- src, mask, dst,
- extents->x, extents->y,
- extents->x, extents->y,
- extents->x - dst_x, extents->y - dst_y,
- extents->width, extents->height,
- clip_region);
- } else {
- status = _cairo_surface_composite (op,
- mask, NULL, dst,
- extents->x, extents->y,
- 0, 0, /* unused */
- extents->x - dst_x, extents->y - dst_y,
- extents->width, extents->height,
- clip_region);
- }
-
- if (extents_region)
- cairo_region_destroy (extents_region);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_mask (cairo_surface_t *surface,
+cairo_int_status_t
+_cairo_surface_fallback_mask (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_mask (&extents, &rect,
- op, source, mask, clip);
- if (unlikely (status))
- return status;
-
- status = _clip_and_composite (extents.clip, op, source,
- _cairo_surface_mask_draw_func,
- (void *) mask,
- surface,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_mask (&_cairo_fallback_compositor,
+ surface, op, source, mask, clip);
}
-cairo_status_t
-_cairo_surface_fallback_stroke (cairo_surface_t *surface,
+cairo_int_status_t
+_cairo_surface_fallback_stroke (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
+ const cairo_path_fixed_t*path,
+ const cairo_stroke_style_t*style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_polygon_t polygon;
- cairo_traps_t traps;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_stroke (&extents, &rect,
- op, source,
- path, stroke_style, ctm,
- clip);
- if (unlikely (status))
- return status;
-
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- _cairo_traps_init_with_clip (&traps, extents.clip);
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- /* Did I mention, that I need to rewrite surface-fallback? */
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
- stroke_style,
- ctm,
- antialias,
- &boxes);
- if (status == CAIRO_INT_STATUS_SUCCESS)
- status = _cairo_traps_init_boxes (&traps, &boxes);
- _cairo_boxes_fini (&boxes);
-
- if (unlikely (_cairo_int_status_is_error (status)))
- goto CLEANUP;
- }
-
- /* Fall back to trapezoid fills. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_path_fixed_stroke_to_polygon (path,
- stroke_style,
- ctm, ctm_inverse,
- tolerance,
- &polygon);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
- &polygon.extents);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
- &polygon,
- CAIRO_FILL_RULE_WINDING);
- if (unlikely (status))
- goto CLEANUP;
- }
-
- status = _clip_and_composite_trapezoids (source, op, surface,
- &traps, antialias,
- extents.clip,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
- CLEANUP:
- _cairo_traps_fini (&traps);
- _cairo_polygon_fini (&polygon);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_fill (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_polygon_t polygon;
- cairo_traps_t traps;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_fill (&extents, &rect,
- op, source, path,
- clip);
- if (unlikely (status))
- return status;
-
- _cairo_traps_init_with_clip (&traps, extents.clip);
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
-
- if (_cairo_path_fixed_fill_is_empty (path))
- goto DO_TRAPS;
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_fill_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- /* meh, surface-fallback is dying anyway... */
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
- fill_rule,
- antialias,
- &boxes);
- if (unlikely (status))
- goto CLEANUP;
-
- if (status == CAIRO_INT_STATUS_SUCCESS)
- status = _cairo_traps_init_boxes (&traps, &boxes);
- _cairo_boxes_fini (&boxes);
- if (unlikely (_cairo_int_status_is_error (status)))
- goto CLEANUP;
- }
-
- /* Fall back to trapezoid fills. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
- &polygon.extents);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
- &polygon,
- fill_rule);
- if (unlikely (status))
- goto CLEANUP;
- }
-
- DO_TRAPS:
- status = _clip_and_composite_trapezoids (source, op, surface,
- &traps, antialias,
- extents.clip,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
- CLEANUP:
- _cairo_traps_fini (&traps);
- _cairo_polygon_fini (&polygon);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-typedef struct {
- cairo_scaled_font_t *font;
- cairo_glyph_t *glyphs;
- int num_glyphs;
-} cairo_show_glyphs_info_t;
-
-static cairo_status_t
-_cairo_surface_old_show_glyphs_draw_func (void *closure,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_surface_t *dst,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region)
+ const cairo_clip_t *clip)
{
- cairo_show_glyphs_info_t *glyph_info = closure;
- cairo_int_status_t status;
-
- /* Modifying the glyph array is fine because we know that this function
- * will be called only once, and we've already made a copy of the
- * glyphs in the wrapper.
- */
- if (dst_x != 0 || dst_y != 0) {
- int i;
-
- for (i = 0; i < glyph_info->num_glyphs; ++i) {
- ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
- ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
- }
- }
-
- status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
- dst,
- extents->x, extents->y,
- extents->x - dst_x,
- extents->y - dst_y,
- extents->width,
- extents->height,
- glyph_info->glyphs,
- glyph_info->num_glyphs,
- clip_region);
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_scaled_font_show_glyphs (glyph_info->font,
- op,
- src, dst,
- extents->x, extents->y,
- extents->x - dst_x,
- extents->y - dst_y,
- extents->width, extents->height,
- glyph_info->glyphs,
- glyph_info->num_glyphs,
- clip_region);
- }
-
- return status;
+ return _cairo_compositor_stroke (&_cairo_fallback_compositor,
+ surface, op, source, path,
+ style, ctm,ctm_inverse,
+ tolerance, antialias, clip);
}
-cairo_status_t
-_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip)
+cairo_int_status_t
+_cairo_surface_fallback_fill (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
- cairo_show_glyphs_info_t glyph_info;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_glyphs (&extents, &rect,
- op, source,
- scaled_font,
- glyphs, num_glyphs,
- clip,
- NULL);
- if (unlikely (status))
- return status;
-
- glyph_info.font = scaled_font;
- glyph_info.glyphs = glyphs;
- glyph_info.num_glyphs = num_glyphs;
-
- status = _clip_and_composite (extents.clip, op, source,
- _cairo_surface_old_show_glyphs_draw_func,
- &glyph_info, surface,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_fill (&_cairo_fallback_compositor,
+ surface, op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
}
-cairo_surface_t *
-_cairo_surface_fallback_snapshot (cairo_surface_t *surface)
-{
- cairo_surface_t *snapshot;
- cairo_status_t status;
- cairo_format_t format;
- cairo_surface_pattern_t pattern;
- cairo_image_surface_t *image;
- void *image_extra;
-
- status = _cairo_surface_acquire_source_image (surface,
- &image, &image_extra);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- format = image->format;
- if (format == CAIRO_FORMAT_INVALID) {
- /* Non-standard images formats can be generated when retrieving
- * images from unusual xservers, for example.
- */
- format = _cairo_format_from_content (image->base.content);
- }
- snapshot = cairo_image_surface_create (format,
- image->width,
- image->height);
- if (cairo_surface_status (snapshot)) {
- _cairo_surface_release_source_image (surface, image, image_extra);
- return snapshot;
- }
-
- _cairo_pattern_init_for_surface (&pattern, &image->base);
- status = _cairo_surface_paint (snapshot,
- CAIRO_OPERATOR_SOURCE,
- &pattern.base,
- NULL);
- _cairo_pattern_fini (&pattern.base);
- _cairo_surface_release_source_image (surface, image, image_extra);
- if (unlikely (status)) {
- cairo_surface_destroy (snapshot);
- return _cairo_surface_create_in_error (status);
- }
-
- return snapshot;
-}
-
-cairo_status_t
-_cairo_surface_fallback_composite (cairo_operator_t op,
- const cairo_pattern_t *src,
- const cairo_pattern_t *mask,
- cairo_surface_t *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_region_t *clip_region)
-{
- fallback_state_t state;
- cairo_region_t *fallback_region = NULL;
- cairo_status_t status;
-
- status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (unlikely (status))
- return status;
-
- /* We know this will never fail with the image backend; but
- * instead of calling into it directly, we call
- * _cairo_surface_composite so that we get the correct device
- * offset handling.
- */
-
- if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) {
- fallback_region = cairo_region_copy (clip_region);
- status = fallback_region->status;
- if (unlikely (status))
- goto FAIL;
-
- cairo_region_translate (fallback_region,
- -state.image_rect.x,
- -state.image_rect.y);
- clip_region = fallback_region;
- }
-
- status = _cairo_surface_composite (op, src, mask,
- &state.image->base,
- src_x, src_y, mask_x, mask_y,
- dst_x - state.image_rect.x,
- dst_y - state.image_rect.y,
- width, height,
- clip_region);
- FAIL:
- if (fallback_region != NULL)
- cairo_region_destroy (fallback_region);
- _fallback_fini (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- fallback_state_t state;
- cairo_rectangle_int_t *offset_rects = NULL;
- cairo_status_t status;
- int x1, y1, x2, y2;
- int i;
-
- assert (surface->snapshot_of == NULL);
-
- if (num_rects <= 0)
- return CAIRO_STATUS_SUCCESS;
-
- /* Compute the bounds of the rectangles, so that we know what area of the
- * destination surface to fetch
- */
- x1 = rects[0].x;
- y1 = rects[0].y;
- x2 = rects[0].x + rects[0].width;
- y2 = rects[0].y + rects[0].height;
-
- for (i = 1; i < num_rects; i++) {
- if (rects[i].x < x1)
- x1 = rects[i].x;
- if (rects[i].y < y1)
- y1 = rects[i].y;
-
- if ((int) (rects[i].x + rects[i].width) > x2)
- x2 = rects[i].x + rects[i].width;
- if ((int) (rects[i].y + rects[i].height) > y2)
- y2 = rects[i].y + rects[i].height;
- }
-
- status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
- if (unlikely (status))
- return status;
-
- /* If the fetched image isn't at 0,0, we need to offset the rectangles */
-
- if (state.image_rect.x != 0 || state.image_rect.y != 0) {
- offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
- if (unlikely (offset_rects == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto DONE;
- }
-
- for (i = 0; i < num_rects; i++) {
- offset_rects[i].x = rects[i].x - state.image_rect.x;
- offset_rects[i].y = rects[i].y - state.image_rect.y;
- offset_rects[i].width = rects[i].width;
- offset_rects[i].height = rects[i].height;
- }
-
- rects = offset_rects;
- }
-
- status = _cairo_surface_fill_rectangles (&state.image->base,
- op, color,
- rects, num_rects);
-
- free (offset_rects);
-
- DONE:
- _fallback_fini (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
-{
- fallback_state_t state;
- cairo_region_t *fallback_region = NULL;
- cairo_trapezoid_t *offset_traps = NULL;
- cairo_status_t status;
-
- status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (unlikely (status))
- return status;
-
- /* If the destination image isn't at 0,0, we need to offset the trapezoids */
-
- if (state.image_rect.x != 0 || state.image_rect.y != 0) {
- offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
- if (offset_traps == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto FAIL;
- }
-
- _cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
- - state.image_rect.x, - state.image_rect.y,
- 1.0, 1.0);
- traps = offset_traps;
-
- /* similarly we need to adjust the region */
- if (clip_region != NULL) {
- fallback_region = cairo_region_copy (clip_region);
- status = fallback_region->status;
- if (unlikely (status))
- goto FAIL;
-
- cairo_region_translate (fallback_region,
- -state.image_rect.x,
- -state.image_rect.y);
- clip_region = fallback_region;
- }
- }
-
- status = _cairo_surface_composite_trapezoids (op, pattern,
- &state.image->base,
- antialias,
- src_x, src_y,
- dst_x - state.image_rect.x,
- dst_y - state.image_rect.y,
- width, height,
- traps, num_traps,
- clip_region);
- FAIL:
- free (offset_traps);
-
- if (fallback_region != NULL)
- cairo_region_destroy (fallback_region);
-
- _fallback_fini (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_surface_t *new_surface;
- cairo_surface_pattern_t pattern;
- cairo_status_t status;
-
- new_surface = _cairo_surface_create_similar_scratch (surface,
- src->content,
- width, height);
- if (new_surface == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- if (unlikely (new_surface->status))
- return new_surface->status;
-
- /* We have to copy these here, so that the coordinate spaces are correct */
- new_surface->device_transform = src->device_transform;
- new_surface->device_transform_inverse = src->device_transform_inverse;
-
- _cairo_pattern_init_for_surface (&pattern, src);
- cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
- pattern.base.filter = CAIRO_FILTER_NEAREST;
-
- status = _cairo_surface_paint (new_surface,
- CAIRO_OPERATOR_SOURCE,
- &pattern.base,
- NULL);
- _cairo_pattern_fini (&pattern.base);
-
- if (unlikely (status)) {
- cairo_surface_destroy (new_surface);
- return status;
- }
-
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
- *clone_out = new_surface;
- return CAIRO_STATUS_SUCCESS;
+cairo_int_status_t
+_cairo_surface_fallback_glyphs (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip)
+{
+ return _cairo_compositor_glyphs (&_cairo_fallback_compositor,
+ surface, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip);
}