📄 cairo-surface-fallback.c
字号:
/* 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_int16_t extents; cairo_image_surface_t *image; cairo_rectangle_int16_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);}typedef cairo_status_t (*cairo_draw_func_t) (void *closure, cairo_operator_t op, cairo_pattern_t *src, cairo_surface_t *dst, int dst_x, int dst_y, const cairo_rectangle_int16_t *extents);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_int16_t *extents){ cairo_surface_t *mask; cairo_status_t status; mask = cairo_surface_create_similar (dst, CAIRO_CONTENT_ALPHA, extents->width, extents->height); if (mask->status) return CAIRO_STATUS_NO_MEMORY; status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD, NULL, mask, extents->x, extents->y, extents); if (status) goto CLEANUP_SURFACE; if (clip && clip->surface) status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN, mask, extents->x, extents->y, extents); if (status) goto CLEANUP_SURFACE; _cairo_pattern_init_for_surface (mask_pattern, mask); CLEANUP_SURFACE: 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, cairo_pattern_t *src, cairo_draw_func_t draw_func, void *draw_closure, cairo_surface_t *dst, const cairo_rectangle_int16_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 (status) return status; status = _cairo_surface_composite (op, src, &mask_pattern.base, dst, extents->x, extents->y, 0, 0, extents->x, extents->y, extents->width, extents->height); _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, cairo_pattern_t *src, cairo_draw_func_t draw_func, void *draw_closure, cairo_surface_t *dst, const cairo_rectangle_int16_t *extents){ cairo_surface_t *intermediate; cairo_surface_pattern_t dst_pattern; cairo_surface_pattern_t intermediate_pattern; 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. * A CAIRO_CONTENT_CLONE or something might be useful. * cairo_surface_create_similar() also unnecessarily clears the surface. */ intermediate = cairo_surface_create_similar (dst, CAIRO_CONTENT_COLOR_ALPHA, extents->width, extents->height); if (intermediate->status) return CAIRO_STATUS_NO_MEMORY; /* Initialize the intermediate surface from the destination surface */ _cairo_pattern_init_for_surface (&dst_pattern, dst); status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, &dst_pattern.base, NULL, intermediate, extents->x, extents->y, 0, 0, 0, 0, extents->width, extents->height); _cairo_pattern_fini (&dst_pattern.base); if (status) goto CLEANUP_SURFACE; status = (*draw_func) (draw_closure, op, src, intermediate, extents->x, extents->y, extents); if (status) goto CLEANUP_SURFACE; /* Combine that with the clip */ status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN, intermediate, extents->x, extents->y, extents); if (status) goto CLEANUP_SURFACE; /* Punch the clip out of the destination */ status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT, dst, 0, 0, extents); if (status) goto CLEANUP_SURFACE; /* Now add the two results together */ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, &intermediate_pattern.base, NULL, dst, 0, 0, 0, 0, extents->x, extents->y, extents->width, extents->height); _cairo_pattern_fini (&intermediate_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, cairo_pattern_t *src, cairo_draw_func_t draw_func, void *draw_closure, cairo_surface_t *dst, const cairo_rectangle_int16_t *extents){ cairo_surface_pattern_t mask_pattern; 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 (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); if (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); CLEANUP_MASK_PATTERN: _cairo_pattern_fini (&mask_pattern.base); return status;}static int_cairo_rectangle_empty (const cairo_rectangle_int16_t *rect){ return rect->width == 0 || rect->height == 0;}/** * _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, cairo_pattern_t *src, cairo_draw_func_t draw_func, void *draw_closure, cairo_surface_t *dst, const cairo_rectangle_int16_t *extents){ cairo_pattern_union_t solid_pattern; cairo_status_t status; if (_cairo_rectangle_empty (extents)) /* Nothing to do */ return CAIRO_STATUS_SUCCESS; if (op == CAIRO_OPERATOR_CLEAR) { _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); src = &solid_pattern.base; op = CAIRO_OPERATOR_DEST_OUT; } if ((clip && clip->surface) || op == CAIRO_OPERATOR_SOURCE) { if (op == CAIRO_OPERATOR_SOURCE) status = _clip_and_composite_source (clip, src, draw_func, draw_closure, dst, extents); else 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -