diff options
author | Carl Worth <cworth@cworth.org> | 2005-12-19 22:45:41 +0000 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2005-12-19 22:45:41 +0000 |
commit | ff486bec0fb1f991217ac9023c0559176ba19a0f (patch) | |
tree | ba6e2266f6cc0cf9d6b98e2c310ea251d7fbd2a1 | |
parent | 75b2fe93f09324b509630d86e0b01de830d853cf (diff) |
Begin moving fallback code out of cairo-surface.c and into cairo-surface-fallback.c.
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/cairo-surface-fallback-private.h | 119 | ||||
-rw-r--r-- | src/cairo-surface-fallback.c | 625 | ||||
-rw-r--r-- | src/cairo-surface.c | 644 |
5 files changed, 797 insertions, 615 deletions
@@ -1,5 +1,27 @@ 2005-12-19 Carl Worth <cworth@cworth.org> + * src/Makefile.am: + * src/cairo-surface-fallback-private.h: + * src/cairo-surface-fallback.c: (_fallback_init), (_fallback_fini), + (_cairo_surface_fallback_paint), (_cairo_surface_mask_draw_func), + (_cairo_surface_fallback_mask), (_cairo_surface_fallback_stroke), + (_cairo_surface_fallback_fill), + (_cairo_surface_old_show_glyphs_draw_func), + (_cairo_surface_fallback_show_glyphs), + (_cairo_surface_fallback_snapshot), + (_cairo_surface_fallback_composite), + (_cairo_surface_fallback_fill_rectangles), + (_cairo_surface_fallback_composite_trapezoids): + * src/cairo-surface.c: (_cairo_surface_snapshot), + (_cairo_surface_composite), (_cairo_surface_fill_rectangles), + (_cairo_surface_paint), (_cairo_surface_mask), + (_cairo_surface_stroke), (_cairo_surface_fill), + (_cairo_surface_composite_trapezoids), + (_cairo_surface_show_glyphs): Begin moving fallback code out of + cairo-surface.c and into cairo-surface-fallback.c. + +2005-12-19 Carl Worth <cworth@cworth.org> + * src/cairo-surface.c: (_cairo_surface_create_similar_solid): Use _cairo_surface_paint rather than _cairo_surface_fill_rectangle as only the former is guaranteed to work with all backends. diff --git a/src/Makefile.am b/src/Makefile.am index ce3cd43f..687d968d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -154,6 +154,8 @@ libcairo_la_SOURCES = \ cairo-spline.c \ cairo-stroke-style.c \ cairo-surface.c \ + cairo-surface-fallback.c \ + cairo-surface-fallback-private.h \ cairo-traps.c \ cairo-pattern.c \ cairo-unicode.c \ diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h new file mode 100644 index 00000000..8bd158a3 --- /dev/null +++ b/src/cairo-surface-fallback-private.h @@ -0,0 +1,119 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + */ + +#ifndef CAIRO_SURFACE_FALLBACK_PRIVATE_H +#define CAIRO_SURFACE_FALLBACK_PRIVATE_H + +#include "cairoint.h" + +cairo_private cairo_status_t +_cairo_surface_fallback_paint (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source); +cairo_private cairo_status_t +_cairo_surface_fallback_mask (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_pattern_t *mask); + +cairo_private cairo_status_t +_cairo_surface_fallback_stroke (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *stroke_style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias); + +cairo_private cairo_status_t +_cairo_surface_fallback_fill (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias); + +cairo_private cairo_status_t +_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font); + +cairo_private cairo_surface_t * +_cairo_surface_fallback_snapshot (cairo_surface_t *surface); + +cairo_private cairo_status_t +_cairo_surface_fallback_composite (cairo_operator_t op, + cairo_pattern_t *src, + 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_private cairo_status_t +_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects); + +cairo_private cairo_status_t +_cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, + 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); + +#endif diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c new file mode 100644 index 00000000..17684b19 --- /dev/null +++ b/src/cairo-surface-fallback.c @@ -0,0 +1,625 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + */ + +#include "cairo-surface-fallback-private.h" +#include "cairo-clip-private.h" + +typedef struct { + cairo_surface_t *dst; + cairo_rectangle_t extents; + cairo_image_surface_t *image; + cairo_rectangle_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 (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. */ + if (state->image == NULL) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + 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); +} + +cairo_status_t +_cairo_surface_fallback_paint (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source) +{ + cairo_status_t status; + cairo_rectangle_t extents; + cairo_box_t box; + cairo_traps_t traps; + + status = _cairo_surface_get_extents (surface, &extents); + if (status) + return status; + + if (_cairo_operator_bounded_by_source (op)) { + cairo_rectangle_t source_extents; + status = _cairo_pattern_get_extents (source, &source_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &source_extents); + } + + status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); + if (status) + return status; + + box.p1.x = _cairo_fixed_from_int (extents.x); + box.p1.y = _cairo_fixed_from_int (extents.y); + box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); + box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); + + status = _cairo_traps_init_box (&traps, &box); + if (status) + return status; + + _cairo_surface_clip_and_composite_trapezoids (source, + op, + surface, + &traps, + surface->clip, + CAIRO_ANTIALIAS_NONE); + + _cairo_traps_fini (&traps); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_surface_mask_draw_func (void *closure, + cairo_operator_t op, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_pattern_t *mask = closure; + + if (src) + return _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); + else + return _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); +} + +cairo_status_t +_cairo_surface_fallback_mask (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_pattern_t *mask) +{ + cairo_status_t status; + cairo_rectangle_t extents, source_extents, mask_extents; + + status = _cairo_surface_get_extents (surface, &extents); + if (status) + return status; + + if (_cairo_operator_bounded_by_source (op)) { + status = _cairo_pattern_get_extents (source, &source_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &source_extents); + } + + if (_cairo_operator_bounded_by_mask (op)) { + status = _cairo_pattern_get_extents (mask, &mask_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &mask_extents); + } + + status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); + if (status) + return status; + + status = _cairo_gstate_clip_and_composite (surface->clip, op, + source, + _cairo_surface_mask_draw_func, + mask, + surface, + &extents); + + return status; +} + +cairo_status_t +_cairo_surface_fallback_stroke (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *stroke_style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_status_t status; + cairo_traps_t traps; + + _cairo_traps_init (&traps); + + status = _cairo_path_fixed_stroke_to_traps (path, + stroke_style, + ctm, ctm_inverse, + tolerance, + &traps); + if (status) { + _cairo_traps_fini (&traps); + return status; + } + + _cairo_surface_clip_and_composite_trapezoids (source, + op, + surface, + &traps, + surface->clip, + antialias); + + _cairo_traps_fini (&traps); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_surface_fallback_fill (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_status_t status; + cairo_traps_t traps; + + _cairo_traps_init (&traps); + + status = _cairo_path_fixed_fill_to_traps (path, + fill_rule, + tolerance, + &traps); + if (status) { + _cairo_traps_fini (&traps); + return status; + } + + status = _cairo_surface_clip_and_composite_trapezoids (source, + op, + surface, + &traps, + surface->clip, + antialias); + + _cairo_traps_fini (&traps); + + return status; +} + +typedef struct { + cairo_scaled_font_t *font; + const 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, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_show_glyphs_info_t *glyph_info = closure; + cairo_pattern_union_t pattern; + cairo_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; + } + } + + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + if (!src) + src = &pattern.base; + + 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); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + 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); + + if (src == &pattern.base) + _cairo_pattern_fini (&pattern.base); + + return status; +} + +cairo_status_t +_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, + cairo_operator_t op, + cairo_pattern_t *source, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) +{ + cairo_status_t status; + cairo_rectangle_t extents, glyph_extents; + cairo_show_glyphs_info_t glyph_info; + + status = _cairo_surface_get_extents (surface, &extents); + if (status) + return status; + + if (_cairo_operator_bounded_by_mask (op)) { + status = _cairo_scaled_font_glyph_device_extents (scaled_font, + glyphs, + num_glyphs, + &glyph_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &glyph_extents); + } + + status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); + if (status) + return status; + + glyph_info.font = scaled_font; + glyph_info.glyphs = glyphs; + glyph_info.num_glyphs = num_glyphs; + + status = _cairo_gstate_clip_and_composite (surface->clip, + op, + source, + _cairo_surface_old_show_glyphs_draw_func, + &glyph_info, + surface, + &extents); + + return status; +} + +cairo_surface_t * +_cairo_surface_fallback_snapshot (cairo_surface_t *surface) +{ + cairo_surface_t *snapshot; + cairo_status_t status; + cairo_pattern_union_t pattern; + cairo_image_surface_t *image; + void *image_extra; + + status = _cairo_surface_acquire_source_image (surface, + &image, &image_extra); + if (status != CAIRO_STATUS_SUCCESS) + return (cairo_surface_t *) &_cairo_surface_nil; + + snapshot = cairo_image_surface_create (image->format, + image->width, + image->height); + if (cairo_surface_status (snapshot)) + return snapshot; + + _cairo_pattern_init_for_surface (&pattern.surface, &image->base); + + _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL, + snapshot, + 0, 0, + 0, 0, + 0, 0, + image->width, + image->height); + + _cairo_pattern_fini (&pattern.base); + + _cairo_surface_release_source_image (surface, + image, &image_extra); + + snapshot->is_snapshot = TRUE; + + return snapshot; +} + +cairo_status_t +_cairo_surface_fallback_composite (cairo_operator_t op, + cairo_pattern_t *src, + 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) +{ + fallback_state_t state; + cairo_status_t status; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (status) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + return status; + } + + status = state.image->base.backend->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); + _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_t *rects, + int num_rects) +{ + fallback_state_t state; + cairo_rectangle_t *offset_rects = NULL; + cairo_status_t status; + int x1, y1, x2, y2; + int i; + + assert (! surface->is_snapshot); + + 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 (rects[i].x + rects[i].width > x2) + x2 = rects[i].x + rects[i].width; + if (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 (status) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + 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 = malloc (sizeof (cairo_rectangle_t) * num_rects); + if (offset_rects == NULL) { + status = 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 = state.image->base.backend->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, + 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) +{ + fallback_state_t state; + cairo_trapezoid_t *offset_traps = NULL; + cairo_status_t status; + int i; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (status) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + 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) { + + cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x); + cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y); + + offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); + if (!offset_traps) { + status = CAIRO_STATUS_NO_MEMORY; + goto DONE; + } + + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = traps[i].top - yoff; + offset_traps[i].bottom = traps[i].bottom - yoff; + offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff; + offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff; + offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff; + offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff; + offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff; + offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff; + offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff; + offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff; + } + + traps = offset_traps; + } + + state.image->base.backend->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); + if (offset_traps) + free (offset_traps); + + DONE: + _fallback_fini (&state); + + return status; +} diff --git a/src/cairo-surface.c b/src/cairo-surface.c index e34cb6c1..4865fc71 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -38,6 +38,7 @@ #include <stdlib.h> #include "cairoint.h" +#include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" const cairo_surface_t _cairo_surface_nil = { @@ -735,48 +736,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, /* XXX: Shouldn't really need to do this here. */ #include "cairo-meta-surface-private.h" -static cairo_surface_t * -_fallback_snapshot (cairo_surface_t *surface) -{ - cairo_surface_t *snapshot; - cairo_status_t status; - cairo_pattern_union_t pattern; - cairo_image_surface_t *image; - void *image_extra; - - status = _cairo_surface_acquire_source_image (surface, - &image, &image_extra); - if (status != CAIRO_STATUS_SUCCESS) - return (cairo_surface_t *) &_cairo_surface_nil; - - snapshot = cairo_image_surface_create (image->format, - image->width, - image->height); - if (cairo_surface_status (snapshot)) - return snapshot; - - _cairo_pattern_init_for_surface (&pattern.surface, &image->base); - - _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - &pattern.base, - NULL, - snapshot, - 0, 0, - 0, 0, - 0, 0, - image->width, - image->height); - - _cairo_pattern_fini (&pattern.base); - - _cairo_surface_release_source_image (surface, - image, &image_extra); - - snapshot->is_snapshot = TRUE; - - return snapshot; -} - /** * _cairo_surface_snapshot * @surface: a #cairo_surface_t @@ -800,102 +759,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface) if (surface->backend->snapshot) return surface->backend->snapshot (surface); - return _fallback_snapshot (surface); -} - -typedef struct { - cairo_surface_t *dst; - cairo_rectangle_t extents; - cairo_image_surface_t *image; - cairo_rectangle_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 (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. */ - if (state->image == NULL) - return CAIRO_INT_STATUS_NOTHING_TO_DO; - - 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); -} - -static cairo_status_t -_fallback_composite (cairo_operator_t op, - cairo_pattern_t *src, - 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) -{ - fallback_state_t state; - cairo_status_t status; - - status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (status) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - return status; - } - - status = state.image->base.backend->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); - _fallback_fini (&state); - - return status; + return _cairo_surface_fallback_snapshot (surface); } cairo_status_t @@ -940,12 +804,12 @@ _cairo_surface_composite (cairo_operator_t op, return status; } - return _fallback_composite (op, - src, mask, dst, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); + return _cairo_surface_fallback_composite (op, + src, mask, dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); } /** @@ -1039,82 +903,6 @@ _cairo_surface_fill_region (cairo_surface_t *surface, return status; } -static cairo_status_t -_fallback_fill_rectangles (cairo_surface_t *surface, - cairo_operator_t op, - const cairo_color_t *color, - cairo_rectangle_t *rects, - int num_rects) -{ - fallback_state_t state; - cairo_rectangle_t *offset_rects = NULL; - cairo_status_t status; - int x1, y1, x2, y2; - int i; - - assert (! surface->is_snapshot); - - 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 (rects[i].x + rects[i].width > x2) - x2 = rects[i].x + rects[i].width; - if (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 (status) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - 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 = malloc (sizeof (cairo_rectangle_t) * num_rects); - if (offset_rects == NULL) { - status = 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 = state.image->base.backend->fill_rectangles (&state.image->base, - op, color, - rects, num_rects); - - free (offset_rects); - - DONE: - _fallback_fini (&state); - - return status; -} - /** * _cairo_surface_fill_rectangles: * @surface: a #cairo_surface_t @@ -1152,63 +940,14 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; if (surface->backend->fill_rectangles) { - status = surface->backend->fill_rectangles (surface, - op, - color, + status = surface->backend->fill_rectangles (surface, op, color, rects, num_rects); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } - return _fallback_fill_rectangles (surface, op, color, rects, num_rects); -} - -static cairo_status_t -_fallback_paint (cairo_surface_t *surface, - cairo_operator_t op, - cairo_pattern_t *source) -{ - cairo_status_t status; - cairo_rectangle_t extents; - cairo_box_t box; - cairo_traps_t traps; - - status = _cairo_surface_get_extents (surface, &extents); - if (status) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_t source_extents; - status = _cairo_pattern_get_extents (source, &source_extents); - if (status) - return status; - - _cairo_rectangle_intersect (&extents, &source_extents); - } - - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) - return status; - - box.p1.x = _cairo_fixed_from_int (extents.x); - box.p1.y = _cairo_fixed_from_int (extents.y); - box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); - box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); - - status = _cairo_traps_init_box (&traps, &box); - if (status) - return status; - - _cairo_surface_clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - CAIRO_ANTIALIAS_NONE); - - _cairo_traps_fini (&traps); - - return CAIRO_STATUS_SUCCESS; + return _cairo_surface_fallback_fill_rectangles (surface, op, color, + rects, num_rects); } cairo_status_t @@ -1226,77 +965,7 @@ _cairo_surface_paint (cairo_surface_t *surface, return status; } - return _fallback_paint (surface, op, source); -} - -static cairo_status_t -_cairo_surface_mask_draw_func (void *closure, - cairo_operator_t op, - cairo_pattern_t *src, - cairo_surface_t *dst, - int dst_x, - int dst_y, - const cairo_rectangle_t *extents) -{ - cairo_pattern_t *mask = closure; - - if (src) - return _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); - else - return _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); -} - -static cairo_status_t -_fallback_mask (cairo_surface_t *surface, - cairo_operator_t op, - cairo_pattern_t *source, - cairo_pattern_t *mask) -{ - cairo_status_t status; - cairo_rectangle_t extents, source_extents, mask_extents; - - status = _cairo_surface_get_extents (surface, &extents); - if (status) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - status = _cairo_pattern_get_extents (source, &source_extents); - if (status) - return status; - - _cairo_rectangle_intersect (&extents, &source_extents); - } - - if (_cairo_operator_bounded_by_mask (op)) { - status = _cairo_pattern_get_extents (mask, &mask_extents); - if (status) - return status; - - _cairo_rectangle_intersect (&extents, &mask_extents); - } - - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) - return status; - - status = _cairo_gstate_clip_and_composite (surface->clip, op, - source, - _cairo_surface_mask_draw_func, - mask, - surface, - &extents); - - return status; + return _cairo_surface_fallback_paint (surface, op, source); } cairo_status_t @@ -1315,45 +984,7 @@ _cairo_surface_mask (cairo_surface_t *surface, return status; } - return _fallback_mask (surface, op, source, mask); -} - -static cairo_status_t -_fallback_stroke (cairo_surface_t *surface, - cairo_operator_t op, - cairo_pattern_t *source, - cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_status_t status; - cairo_traps_t traps; - - _cairo_traps_init (&traps); - - status = _cairo_path_fixed_stroke_to_traps (path, - stroke_style, - ctm, ctm_inverse, - tolerance, - &traps); - if (status) { - _cairo_traps_fini (&traps); - return status; - } - - _cairo_surface_clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - antialias); - - _cairo_traps_fini (&traps); - - return CAIRO_STATUS_SUCCESS; + return _cairo_surface_fallback_mask (surface, op, source, mask); } cairo_status_t @@ -1379,45 +1010,10 @@ _cairo_surface_stroke (cairo_surface_t *surface, return status; } - return _fallback_stroke (surface, op, source, - path, stroke_style, - ctm, ctm_inverse, - tolerance, antialias); -} - -static cairo_status_t -_fallback_fill (cairo_surface_t *surface, - cairo_operator_t op, - cairo_pattern_t *source, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_status_t status; - cairo_traps_t traps; - - _cairo_traps_init (&traps); - - status = _cairo_path_fixed_fill_to_traps (path, - fill_rule, - tolerance, - &traps); - if (status) { - _cairo_traps_fini (&traps); - return status; - } - - status = _cairo_surface_clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - antialias); - - _cairo_traps_fini (&traps); - - return status; + return _cairo_surface_fallback_stroke (surface, op, source, + path, stroke_style, + ctm, ctm_inverse, + tolerance, antialias); } cairo_status_t @@ -1441,82 +1037,11 @@ _cairo_surface_fill (cairo_surface_t *surface, return status; } - return _fallback_fill (surface, op, source, - path, fill_rule, - tolerance, antialias); + return _cairo_surface_fallback_fill (surface, op, source, + path, fill_rule, + tolerance, antialias); } -static cairo_status_t -_fallback_composite_trapezoids (cairo_operator_t op, - 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) -{ - fallback_state_t state; - cairo_trapezoid_t *offset_traps = NULL; - cairo_status_t status; - int i; - - status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (status) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - 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) { - - cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x); - cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y); - - offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); - if (!offset_traps) { - status = CAIRO_STATUS_NO_MEMORY; - goto DONE; - } - - for (i = 0; i < num_traps; i++) { - offset_traps[i].top = traps[i].top - yoff; - offset_traps[i].bottom = traps[i].bottom - yoff; - offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff; - offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff; - offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff; - offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff; - offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff; - offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff; - offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff; - offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff; - } - - traps = offset_traps; - } - - state.image->base.backend->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); - if (offset_traps) - free (offset_traps); - - DONE: - _fallback_fini (&state); - - return status; -} - cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t op, cairo_pattern_t *pattern, @@ -1558,12 +1083,12 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, return status; } - return _fallback_composite_trapezoids (op, pattern, dst, - antialias, - src_x, src_y, - dst_x, dst_y, - width, height, - traps, num_traps); + return _cairo_surface_fallback_composite_trapezoids (op, pattern, dst, + antialias, + src_x, src_y, + dst_x, dst_y, + width, height, + traps, num_traps); } cairo_status_t @@ -1854,117 +1379,6 @@ _cairo_surface_get_extents (cairo_surface_t *surface, return surface->backend->get_extents (surface, rectangle); } -typedef struct { - cairo_scaled_font_t *font; - const 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, - cairo_pattern_t *src, - cairo_surface_t *dst, - int dst_x, - int dst_y, - const cairo_rectangle_t *extents) -{ - cairo_show_glyphs_info_t *glyph_info = closure; - cairo_pattern_union_t pattern; - cairo_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; - } - } - - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); - if (!src) - src = &pattern.base; - - 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); - - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - - 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); - - if (src == &pattern.base) - _cairo_pattern_fini (&pattern.base); - - return status; -} - -static cairo_status_t -_fallback_show_glyphs (cairo_surface_t *surface, - cairo_operator_t op, - cairo_pattern_t *source, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font) -{ - cairo_status_t status; - cairo_rectangle_t extents, glyph_extents; - cairo_show_glyphs_info_t glyph_info; - - status = _cairo_surface_get_extents (surface, &extents); - if (status) - return status; - - if (_cairo_operator_bounded_by_mask (op)) { - status = _cairo_scaled_font_glyph_device_extents (scaled_font, - glyphs, - num_glyphs, - &glyph_extents); - if (status) - return status; - - _cairo_rectangle_intersect (&extents, &glyph_extents); - } - - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) - return status; - - glyph_info.font = scaled_font; - glyph_info.glyphs = glyphs; - glyph_info.num_glyphs = num_glyphs; - - status = _cairo_gstate_clip_and_composite (surface->clip, - op, - source, - _cairo_surface_old_show_glyphs_draw_func, - &glyph_info, - surface, - &extents); - - return status; -} - cairo_status_t _cairo_surface_show_glyphs (cairo_surface_t *surface, cairo_operator_t op, @@ -1985,9 +1399,9 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface, return status; } - return _fallback_show_glyphs (surface, op, source, - glyphs, num_glyphs, - scaled_font); + return _cairo_surface_fallback_show_glyphs (surface, op, source, + glyphs, num_glyphs, + scaled_font); } /* XXX: Previously, we had a function named _cairo_surface_show_glyphs |