forked from KolibriOS/kolibrios
44d189b67c
git-svn-id: svn://kolibrios.org@3959 a494cfbc-eb01-0410-851d-a64ba20cac60
825 lines
24 KiB
C
825 lines
24 KiB
C
/* -*- 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);
|
|
}
|