0,0 → 1,824 |
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
/* cairo - a vector graphics library with display and print output |
* |
* 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 |
* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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> |
* Joonas Pihlaja <jpihlaja@cc.helsinki.fi> |
* Chris Wilson <chris@chris-wilson.co.uk> |
*/ |
|
#include "cairoint.h" |
|
#include "test-compositor-surface-private.h" |
|
#include "cairo-clip-private.h" |
#include "cairo-composite-rectangles-private.h" |
#include "cairo-compositor-private.h" |
#include "cairo-error-private.h" |
#include "cairo-image-surface-private.h" |
#include "cairo-region-private.h" |
#include "cairo-traps-private.h" |
|
/* The intention is that this is a surface that just works, and most |
* important of all does not try to be clever! |
*/ |
|
typedef cairo_int_status_t |
(*draw_func_t) (cairo_image_surface_t *dst, |
void *closure, |
cairo_operator_t op, |
const cairo_pattern_t *pattern, |
int dst_x, |
int dst_y, |
const cairo_rectangle_int_t *extents); |
|
static pixman_op_t |
_pixman_operator (cairo_operator_t op) |
{ |
switch ((int) op) { |
case CAIRO_OPERATOR_CLEAR: |
return PIXMAN_OP_CLEAR; |
|
case CAIRO_OPERATOR_SOURCE: |
return PIXMAN_OP_SRC; |
case CAIRO_OPERATOR_OVER: |
return PIXMAN_OP_OVER; |
case CAIRO_OPERATOR_IN: |
return PIXMAN_OP_IN; |
case CAIRO_OPERATOR_OUT: |
return PIXMAN_OP_OUT; |
case CAIRO_OPERATOR_ATOP: |
return PIXMAN_OP_ATOP; |
|
case CAIRO_OPERATOR_DEST: |
return PIXMAN_OP_DST; |
case CAIRO_OPERATOR_DEST_OVER: |
return PIXMAN_OP_OVER_REVERSE; |
case CAIRO_OPERATOR_DEST_IN: |
return PIXMAN_OP_IN_REVERSE; |
case CAIRO_OPERATOR_DEST_OUT: |
return PIXMAN_OP_OUT_REVERSE; |
case CAIRO_OPERATOR_DEST_ATOP: |
return PIXMAN_OP_ATOP_REVERSE; |
|
case CAIRO_OPERATOR_XOR: |
return PIXMAN_OP_XOR; |
case CAIRO_OPERATOR_ADD: |
return PIXMAN_OP_ADD; |
case CAIRO_OPERATOR_SATURATE: |
return PIXMAN_OP_SATURATE; |
|
case CAIRO_OPERATOR_MULTIPLY: |
return PIXMAN_OP_MULTIPLY; |
case CAIRO_OPERATOR_SCREEN: |
return PIXMAN_OP_SCREEN; |
case CAIRO_OPERATOR_OVERLAY: |
return PIXMAN_OP_OVERLAY; |
case CAIRO_OPERATOR_DARKEN: |
return PIXMAN_OP_DARKEN; |
case CAIRO_OPERATOR_LIGHTEN: |
return PIXMAN_OP_LIGHTEN; |
case CAIRO_OPERATOR_COLOR_DODGE: |
return PIXMAN_OP_COLOR_DODGE; |
case CAIRO_OPERATOR_COLOR_BURN: |
return PIXMAN_OP_COLOR_BURN; |
case CAIRO_OPERATOR_HARD_LIGHT: |
return PIXMAN_OP_HARD_LIGHT; |
case CAIRO_OPERATOR_SOFT_LIGHT: |
return PIXMAN_OP_SOFT_LIGHT; |
case CAIRO_OPERATOR_DIFFERENCE: |
return PIXMAN_OP_DIFFERENCE; |
case CAIRO_OPERATOR_EXCLUSION: |
return PIXMAN_OP_EXCLUSION; |
case CAIRO_OPERATOR_HSL_HUE: |
return PIXMAN_OP_HSL_HUE; |
case CAIRO_OPERATOR_HSL_SATURATION: |
return PIXMAN_OP_HSL_SATURATION; |
case CAIRO_OPERATOR_HSL_COLOR: |
return PIXMAN_OP_HSL_COLOR; |
case CAIRO_OPERATOR_HSL_LUMINOSITY: |
return PIXMAN_OP_HSL_LUMINOSITY; |
|
default: |
ASSERT_NOT_REACHED; |
return PIXMAN_OP_OVER; |
} |
} |
|
static cairo_image_surface_t * |
create_composite_mask (cairo_image_surface_t *dst, |
void *draw_closure, |
draw_func_t draw_func, |
const cairo_composite_rectangles_t *extents) |
{ |
cairo_image_surface_t *surface; |
cairo_int_status_t status; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
surface = (cairo_image_surface_t *) |
_cairo_image_surface_create_with_pixman_format (NULL, PIXMAN_a8, |
extents->bounded.width, |
extents->bounded.height, |
0); |
if (unlikely (surface->base.status)) |
return surface; |
|
status = draw_func (surface, draw_closure, |
CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, |
extents->bounded.x, extents->bounded.y, |
&extents->bounded); |
if (unlikely (status)) |
goto error; |
|
status = _cairo_clip_combine_with_surface (extents->clip, |
&surface->base, |
extents->bounded.x, |
extents->bounded.y); |
if (unlikely (status)) |
goto error; |
|
return surface; |
|
error: |
cairo_surface_destroy (&surface->base); |
return (cairo_image_surface_t *)_cairo_surface_create_in_error (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 (const cairo_composite_rectangles_t*extents, |
draw_func_t draw_func, |
void *draw_closure) |
{ |
cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; |
cairo_image_surface_t *mask; |
pixman_image_t *src; |
cairo_status_t status = CAIRO_STATUS_SUCCESS; |
int src_x, src_y; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
mask = create_composite_mask (dst, draw_closure, draw_func, extents); |
if (unlikely (mask->base.status)) |
return mask->base.status; |
|
src = _pixman_image_for_pattern (dst, |
&extents->source_pattern.base, FALSE, |
&extents->bounded, |
&extents->source_sample_area, |
&src_x, &src_y); |
if (unlikely (src == NULL)) { |
status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
goto error; |
} |
|
pixman_image_composite32 (_pixman_operator (extents->op), |
src, mask->pixman_image, dst->pixman_image, |
extents->bounded.x + src_x, |
extents->bounded.y + src_y, |
0, 0, |
extents->bounded.x, extents->bounded.y, |
extents->bounded.width, extents->bounded.height); |
|
pixman_image_unref (src); |
error: |
cairo_surface_destroy (&mask->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 (const cairo_composite_rectangles_t*extents, |
draw_func_t draw_func, |
void *draw_closure) |
{ |
cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; |
cairo_image_surface_t *tmp, *clip; |
int clip_x, clip_y; |
cairo_status_t status; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
tmp = (cairo_image_surface_t *) |
_cairo_image_surface_create_with_pixman_format (NULL, |
dst->pixman_format, |
extents->bounded.width, |
extents->bounded.height, |
0); |
if (unlikely (tmp->base.status)) |
return tmp->base.status; |
|
pixman_image_composite32 (PIXMAN_OP_SRC, |
dst->pixman_image, NULL, tmp->pixman_image, |
extents->bounded.x, extents->bounded.y, |
0, 0, |
0, 0, |
extents->bounded.width, extents->bounded.height); |
|
status = draw_func (tmp, draw_closure, |
extents->op, &extents->source_pattern.base, |
extents->bounded.x, extents->bounded.y, |
&extents->bounded); |
if (unlikely (status)) |
goto error; |
|
clip = (cairo_image_surface_t *) |
_cairo_clip_get_surface (extents->clip, &dst->base, &clip_x, &clip_y); |
if (unlikely (clip->base.status)) |
goto error; |
|
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, |
clip->pixman_image, NULL, dst->pixman_image, |
extents->bounded.x - clip_x, extents->bounded.y - clip_y, |
0, 0, |
extents->bounded.x, extents->bounded.y, |
extents->bounded.width, extents->bounded.height); |
pixman_image_composite32 (PIXMAN_OP_ADD, |
tmp->pixman_image, clip->pixman_image, dst->pixman_image, |
0, 0, |
extents->bounded.x - clip_x, extents->bounded.y - clip_y, |
extents->bounded.x, extents->bounded.y, |
extents->bounded.width, extents->bounded.height); |
|
cairo_surface_destroy (&clip->base); |
|
error: |
cairo_surface_destroy (&tmp->base); |
|
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 (const cairo_composite_rectangles_t *extents, |
draw_func_t draw_func, |
void *draw_closure) |
{ |
cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; |
cairo_image_surface_t *mask; |
pixman_image_t *src; |
int src_x, src_y; |
cairo_status_t status = CAIRO_STATUS_SUCCESS; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
mask = create_composite_mask (dst, draw_closure, draw_func, extents); |
if (unlikely (mask->base.status)) |
return mask->base.status; |
|
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, |
mask->pixman_image, NULL, dst->pixman_image, |
0, 0, |
0, 0, |
extents->bounded.x, extents->bounded.y, |
extents->bounded.width, extents->bounded.height); |
|
src = _pixman_image_for_pattern (dst, |
&extents->source_pattern.base, FALSE, |
&extents->bounded, |
&extents->source_sample_area, |
&src_x, &src_y); |
if (unlikely (src == NULL)) { |
status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
goto error; |
} |
|
pixman_image_composite32 (PIXMAN_OP_ADD, |
src, mask->pixman_image, dst->pixman_image, |
extents->bounded.x + src_x, extents->bounded.y + src_y, |
0, 0, |
extents->bounded.x, extents->bounded.y, |
extents->bounded.width, extents->bounded.height); |
|
pixman_image_unref (src); |
|
error: |
cairo_surface_destroy (&mask->base); |
return status; |
} |
|
static cairo_status_t |
fixup_unbounded (const cairo_composite_rectangles_t *extents) |
{ |
cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; |
pixman_image_t *mask; |
int mask_x, mask_y; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
if (! _cairo_clip_is_region (extents->clip)) { |
cairo_image_surface_t *clip; |
|
clip = (cairo_image_surface_t *) |
_cairo_clip_get_surface (extents->clip, &dst->base, |
&mask_x, &mask_y); |
if (unlikely (clip->base.status)) |
return clip->base.status; |
|
mask = pixman_image_ref (clip->pixman_image); |
cairo_surface_destroy (&clip->base); |
} else { |
mask_x = mask_y = 0; |
mask = _pixman_image_for_color (CAIRO_COLOR_WHITE); |
if (unlikely (mask == NULL)) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
} |
|
/* top */ |
if (extents->bounded.y != extents->unbounded.y) { |
int x = extents->unbounded.x; |
int y = extents->unbounded.y; |
int width = extents->unbounded.width; |
int height = extents->bounded.y - y; |
|
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, |
mask, NULL, dst->pixman_image, |
x - mask_x, y - mask_y, |
0, 0, |
x, y, |
width, height); |
} |
|
/* left */ |
if (extents->bounded.x != extents->unbounded.x) { |
int x = extents->unbounded.x; |
int y = extents->bounded.y; |
int width = extents->bounded.x - x; |
int height = extents->bounded.height; |
|
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, |
mask, NULL, dst->pixman_image, |
x - mask_x, y - mask_y, |
0, 0, |
x, y, |
width, height); |
} |
|
/* right */ |
if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { |
int x = extents->bounded.x + extents->bounded.width; |
int y = extents->bounded.y; |
int width = extents->unbounded.x + extents->unbounded.width - x; |
int height = extents->bounded.height; |
|
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, |
mask, NULL, dst->pixman_image, |
x - mask_x, y - mask_y, |
0, 0, |
x, y, |
width, height); |
} |
|
/* bottom */ |
if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { |
int x = extents->unbounded.x; |
int y = extents->bounded.y + extents->bounded.height; |
int width = extents->unbounded.width; |
int height = extents->unbounded.y + extents->unbounded.height - y; |
|
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, |
mask, NULL, dst->pixman_image, |
x - mask_x, y - mask_y, |
0, 0, |
x, y, |
width, height); |
} |
|
pixman_image_unref (mask); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_int_status_t |
set_clip_region (cairo_composite_rectangles_t *extents) |
{ |
cairo_image_surface_t *dst = (cairo_image_surface_t *) extents->surface; |
cairo_region_t *region = _cairo_clip_get_region (extents->clip); |
pixman_region32_t *rgn = region ? ®ion->rgn : NULL; |
if (! pixman_image_set_clip_region32 (dst->pixman_image, rgn)) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_status_t |
clip_and_composite (cairo_composite_rectangles_t *extents, |
draw_func_t draw_func, |
void *draw_closure) |
{ |
cairo_status_t status; |
|
status = set_clip_region (extents); |
if (unlikely (status)) |
return status; |
|
if (extents->op == CAIRO_OPERATOR_SOURCE) { |
status = clip_and_composite_source (extents, draw_func, draw_closure); |
} else { |
if (extents->op == CAIRO_OPERATOR_CLEAR) { |
extents->source_pattern.solid = _cairo_pattern_white; |
extents->op = CAIRO_OPERATOR_DEST_OUT; |
} |
if (! _cairo_clip_is_region (extents->clip)) { |
if (extents->is_bounded) |
status = clip_and_composite_with_mask (extents, draw_func, draw_closure); |
else |
status = clip_and_composite_combine (extents, draw_func, draw_closure); |
} else { |
status = draw_func ((cairo_image_surface_t *) extents->surface, |
draw_closure, |
extents->op, |
&extents->source_pattern.base, |
0, 0, |
&extents->bounded); |
} |
} |
|
if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) |
status = fixup_unbounded (extents); |
|
return status; |
} |
|
/* high-level compositor interface */ |
|
static cairo_int_status_t |
composite_paint (cairo_image_surface_t *dst, |
void *closure, |
cairo_operator_t op, |
const cairo_pattern_t *pattern, |
int dst_x, |
int dst_y, |
const cairo_rectangle_int_t *extents) |
{ |
cairo_rectangle_int_t sample; |
pixman_image_t *src; |
int src_x, src_y; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
_cairo_pattern_sampled_area (pattern, extents, &sample); |
src = _pixman_image_for_pattern (dst, |
pattern, FALSE, |
extents, &sample, |
&src_x, &src_y); |
if (unlikely (src == NULL)) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
TRACE ((stderr, "%s: src=(%d, %d), dst=(%d, %d) size=%dx%d\n", __FUNCTION__, |
extents->x + src_x, extents->y + src_y, |
extents->x - dst_x, extents->y - dst_y, |
extents->width, extents->height)); |
|
pixman_image_composite32 (_pixman_operator (op), |
src, NULL, dst->pixman_image, |
extents->x + src_x, extents->y + src_y, |
0, 0, |
extents->x - dst_x, extents->y - dst_y, |
extents->width, extents->height); |
|
pixman_image_unref (src); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_int_status_t |
base_compositor_paint (const cairo_compositor_t *_compositor, |
cairo_composite_rectangles_t *extents) |
{ |
TRACE ((stderr, "%s\n", __FUNCTION__)); |
return clip_and_composite (extents, composite_paint, NULL); |
} |
|
static cairo_int_status_t |
composite_mask (cairo_image_surface_t *dst, |
void *closure, |
cairo_operator_t op, |
const cairo_pattern_t *pattern, |
int dst_x, |
int dst_y, |
const cairo_rectangle_int_t *extents) |
{ |
cairo_rectangle_int_t sample; |
pixman_image_t *src, *mask; |
int src_x, src_y; |
int mask_x, mask_y; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
_cairo_pattern_sampled_area (pattern, extents, &sample); |
src = _pixman_image_for_pattern (dst, pattern, FALSE, |
extents, &sample, |
&src_x, &src_y); |
if (unlikely (src == NULL)) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
_cairo_pattern_sampled_area (closure, extents, &sample); |
mask = _pixman_image_for_pattern (dst, closure, TRUE, |
extents, &sample, |
&mask_x, &mask_y); |
if (unlikely (mask == NULL)) { |
pixman_image_unref (src); |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
} |
|
pixman_image_composite32 (_pixman_operator (op), |
src, mask, dst->pixman_image, |
extents->x + src_x, extents->y + src_y, |
extents->x + mask_x, extents->y + mask_y, |
extents->x - dst_x, extents->y - dst_y, |
extents->width, extents->height); |
|
pixman_image_unref (mask); |
pixman_image_unref (src); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_int_status_t |
base_compositor_mask (const cairo_compositor_t *_compositor, |
cairo_composite_rectangles_t *extents) |
{ |
TRACE ((stderr, "%s\n", __FUNCTION__)); |
return clip_and_composite (extents, composite_mask, &extents->mask_pattern.base); |
} |
|
typedef struct { |
cairo_traps_t traps; |
cairo_antialias_t antialias; |
} composite_traps_info_t; |
|
static cairo_int_status_t |
composite_traps (cairo_image_surface_t *dst, |
void *closure, |
cairo_operator_t op, |
const cairo_pattern_t *pattern, |
int dst_x, |
int dst_y, |
const cairo_rectangle_int_t *extents) |
{ |
composite_traps_info_t *info = closure; |
cairo_rectangle_int_t sample; |
pixman_image_t *src, *mask; |
int src_x, src_y; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
_cairo_pattern_sampled_area (pattern, extents, &sample); |
src = _pixman_image_for_pattern (dst, pattern, FALSE, |
extents, &sample, |
&src_x, &src_y); |
if (unlikely (src == NULL)) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
mask = pixman_image_create_bits (info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8, |
extents->width, extents->height, |
NULL, 0); |
if (unlikely (mask == NULL)) { |
pixman_image_unref (src); |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
} |
|
_pixman_image_add_traps (mask, extents->x, extents->y, &info->traps); |
pixman_image_composite32 (_pixman_operator (op), |
src, mask, dst->pixman_image, |
extents->x + src_x - dst_x, extents->y + src_y - dst_y, |
0, 0, |
extents->x - dst_x, extents->y - dst_y, |
extents->width, extents->height); |
|
pixman_image_unref (mask); |
pixman_image_unref (src); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_int_status_t |
trim_extents_to_traps (cairo_composite_rectangles_t *extents, |
cairo_traps_t *traps) |
{ |
cairo_box_t box; |
|
/* X trims the affected area to the extents of the trapezoids, so |
* we need to compensate when fixing up the unbounded area. |
*/ |
_cairo_traps_extents (traps, &box); |
return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); |
} |
|
static cairo_int_status_t |
base_compositor_stroke (const cairo_compositor_t *_compositor, |
cairo_composite_rectangles_t *extents, |
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) |
{ |
composite_traps_info_t info; |
cairo_int_status_t status; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
info.antialias = antialias; |
_cairo_traps_init_with_clip (&info.traps, extents->clip); |
status = _cairo_path_fixed_stroke_polygon_to_traps (path, style, |
ctm, ctm_inverse, |
tolerance, |
&info.traps); |
if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
status = trim_extents_to_traps (extents, &info.traps); |
if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
status = clip_and_composite (extents, composite_traps, &info); |
_cairo_traps_fini (&info.traps); |
|
return status; |
} |
|
static cairo_int_status_t |
base_compositor_fill (const cairo_compositor_t *_compositor, |
cairo_composite_rectangles_t *extents, |
const cairo_path_fixed_t *path, |
cairo_fill_rule_t fill_rule, |
double tolerance, |
cairo_antialias_t antialias) |
{ |
composite_traps_info_t info; |
cairo_int_status_t status; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
info.antialias = antialias; |
_cairo_traps_init_with_clip (&info.traps, extents->clip); |
status = _cairo_path_fixed_fill_to_traps (path, |
fill_rule, tolerance, |
&info.traps); |
if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
status = trim_extents_to_traps (extents, &info.traps); |
if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
status = clip_and_composite (extents, composite_traps, &info); |
_cairo_traps_fini (&info.traps); |
|
return status; |
} |
|
static cairo_int_status_t |
composite_glyphs (cairo_image_surface_t *dst, |
void *closure, |
cairo_operator_t op, |
const cairo_pattern_t *pattern, |
int dst_x, |
int dst_y, |
const cairo_rectangle_int_t *extents) |
{ |
cairo_composite_glyphs_info_t *info = closure; |
pixman_image_t *mask; |
cairo_status_t status; |
int i; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
|
mask = pixman_image_create_bits (PIXMAN_a8, |
extents->width, extents->height, |
NULL, 0); |
if (unlikely (mask == NULL)) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
status = CAIRO_STATUS_SUCCESS; |
_cairo_scaled_font_freeze_cache (info->font); |
for (i = 0; i < info->num_glyphs; i++) { |
cairo_image_surface_t *glyph_surface; |
cairo_scaled_glyph_t *scaled_glyph; |
unsigned long glyph_index = info->glyphs[i].index; |
int x, y; |
|
status = _cairo_scaled_glyph_lookup (info->font, glyph_index, |
CAIRO_SCALED_GLYPH_INFO_SURFACE, |
&scaled_glyph); |
|
if (unlikely (status)) |
break; |
|
glyph_surface = scaled_glyph->surface; |
if (glyph_surface->width && glyph_surface->height) { |
/* round glyph locations to the nearest pixel */ |
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ |
x = _cairo_lround (info->glyphs[i].x - |
glyph_surface->base.device_transform.x0); |
y = _cairo_lround (info->glyphs[i].y - |
glyph_surface->base.device_transform.y0); |
|
pixman_image_composite32 (PIXMAN_OP_ADD, |
glyph_surface->pixman_image, NULL, mask, |
0, 0, |
0, 0, |
x - extents->x, y - extents->y, |
glyph_surface->width, |
glyph_surface->height); |
} |
} |
_cairo_scaled_font_thaw_cache (info->font); |
|
if (status == CAIRO_STATUS_SUCCESS) { |
cairo_rectangle_int_t sample; |
pixman_image_t *src; |
int src_x, src_y; |
|
_cairo_pattern_sampled_area (pattern, extents, &sample); |
src = _pixman_image_for_pattern (dst, pattern, FALSE, |
extents, &sample, |
&src_x, &src_y); |
if (src != NULL) { |
dst_x = extents->x - dst_x; |
dst_y = extents->y - dst_y; |
pixman_image_composite32 (_pixman_operator (op), |
src, mask, dst->pixman_image, |
src_x + dst_x, src_y + dst_y, |
0, 0, |
dst_x, dst_y, |
extents->width, extents->height); |
pixman_image_unref (src); |
} else |
status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
} |
pixman_image_unref (mask); |
|
return status; |
} |
|
static cairo_int_status_t |
base_compositor_glyphs (const cairo_compositor_t *_compositor, |
cairo_composite_rectangles_t *extents, |
cairo_scaled_font_t *scaled_font, |
cairo_glyph_t *glyphs, |
int num_glyphs, |
cairo_bool_t overlap) |
{ |
cairo_composite_glyphs_info_t info; |
|
info.font = scaled_font; |
info.glyphs = glyphs; |
info.num_glyphs = num_glyphs; |
|
TRACE ((stderr, "%s\n", __FUNCTION__)); |
return clip_and_composite (extents, composite_glyphs, &info); |
} |
|
static const cairo_compositor_t base_compositor = { |
&__cairo_no_compositor, |
|
base_compositor_paint, |
base_compositor_mask, |
base_compositor_stroke, |
base_compositor_fill, |
base_compositor_glyphs, |
}; |
|
cairo_surface_t * |
_cairo_test_base_compositor_surface_create (cairo_content_t content, |
int width, |
int height) |
{ |
return test_compositor_surface_create (&base_compositor, |
content, width, height); |
} |