mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-04 14:10:36 +01:00
Add a function to test whether a cairo_operator_t is bounded (does nothing for 0 src/mask)
cairoint.h: Add a helper function to take clearing areas that are outside the source/mask but are cleared by unbounded operations. src/cairo-xlib-surface.c (_cairo_xlib_surface_composite): Use _cairo_surface_composite_fixup_unbounded() as needed. src/cairo-image-surface.c src/cairint.h: Keep track of whether the surface has a clip or not ... we need this for determining when we can bypass an intermediate mask for composite_trapezoids(). Create an intermediate mask of the right size with pixman_add_trapezoids() and composite that. When rendering with an unbounded operator, create the intermediate mask ourselves and render with ADD to that, then composite the result. Create an intermediate surface the size of the extents, render the glyphs to that then composite the results. Add the size of the glyph Compute the size of the glyph mask, then use _cairo_surface_composite_fixup_unbounded(). Use the right mask format. (Unrelated bugfix) New function taking a drawing function as a parameter to encapsulate shared logic between compositing trapezoid, glyphs, and masks. Use _cairo_gstate_clip_and_composite(). Also fix extents computations for unbounded operators. src/cairo-clip.c src/cairo-clip-private.h (_cairo_clip_combine_to_surface): Add the destination as an extra parameter to allow combining to an intermediate surface. tests/unbounded-operator.c tests/Makefile.am: Add a test for the operation of the 6 unbounded operators against different shapes. tests/clip-operator.c tests/Makefile.am: Add a test that tests surface clipping with different shapes against all the operators. Make use OVER like the name and description. With fixed semantics, SOURCE does something different.
This commit is contained in:
parent
31ef9a80e9
commit
8f19aaf9a8
13 changed files with 1519 additions and 353 deletions
60
ChangeLog
60
ChangeLog
|
|
@ -1,3 +1,63 @@
|
|||
2005-08-08 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* src/cairo-gstate.c (_cairo_operator_bounded): Add a function to test
|
||||
whether a cairo_operator_t is bounded (does nothing for 0 src/mask)
|
||||
|
||||
* src/cairo-surface.c (_cairo_surface_composite_fixup_unbounded) cairoint.h:
|
||||
Add a helper function to take clearing areas that are outside the source/mask
|
||||
but are cleared by unbounded operations.
|
||||
|
||||
* src/cairo-image-surface.c (_cairo_image_surface_composite)
|
||||
src/cairo-xlib-surface.c (_cairo_xlib_surface_composite): Use
|
||||
_cairo_surface_composite_fixup_unbounded() as needed.
|
||||
|
||||
* src/cairo-image-surface.c src/cairint.h: Keep track of whether the surface
|
||||
has a clip or not ... we need this for determining when we can bypass
|
||||
an intermediate mask for composite_trapezoids().
|
||||
|
||||
* src/cairo-image-surface.c (_cairo_image_surface_composite_trapezoids):
|
||||
Create an intermediate mask of the right size with pixman_add_trapezoids()
|
||||
and composite that.
|
||||
|
||||
* src/cairo-xlib-surface.c (_cairo_xlib_surface_composite_trapezoids):
|
||||
When rendering with an unbounded operator, create the intermediate mask
|
||||
ourselves and render with ADD to that, then composite the result.
|
||||
|
||||
* src/cairo-ft-font.c (_cairo_ft_scaled_font_show_glyphs): Create an
|
||||
intermediate surface the size of the extents, render the glyphs to that
|
||||
then composite the results.
|
||||
|
||||
* src/cairo-xlib-surface.c (glyphset_cache_entry_t): Add the size of the glyph
|
||||
|
||||
* src/cairo-xlib-surface.c (_show_glyphs_fixup_unbounded): Compute the size
|
||||
of the glyph mask, then use _cairo_surface_composite_fixup_unbounded().
|
||||
|
||||
* src/cairo-xlib-surface.c (_cairo_xlib_surface_show_glyphs32): Use the right
|
||||
mask format. (Unrelated bugfix)
|
||||
|
||||
* src/cairo-gstate.c (_cairo_gstate_clip_and_composite): New function taking
|
||||
a drawing function as a parameter to encapsulate shared logic between
|
||||
compositing trapezoid, glyphs, and masks.
|
||||
|
||||
* src/cairo-gstate.c (_cairo_gstate_mask,
|
||||
_cairo_surface_clip_and_composite_trapezoids, _cairo_gstate_show_glyphs):
|
||||
Use _cairo_gstate_clip_and_composite(). Also fix extents computations for
|
||||
unbounded operators.
|
||||
|
||||
* src/cairo-clip.c src/cairo-clip-private.h (_cairo_clip_combine_to_surface):
|
||||
Add the destination as an extra parameter to allow combining to an intermediate
|
||||
surface.
|
||||
|
||||
* tests/unbounded-operator.c tests/Makefile.am: Add a test for the
|
||||
operation of the 6 unbounded operators against different shapes.
|
||||
|
||||
* tests/clip-operator.c tests/Makefile.am: Add a test that tests
|
||||
surface clipping with different shapes against all the operators.
|
||||
|
||||
* test/composite-integer-translate-over-repeat.c (draw): Make use OVER
|
||||
like the name and description. With fixed semantics, SOURCE does something
|
||||
different.
|
||||
|
||||
2005-08-06 Carl Worth <cworth@cworth.org>
|
||||
|
||||
* BUGS: Remove several bugs that have been fixed.
|
||||
|
|
|
|||
|
|
@ -111,8 +111,11 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip,
|
|||
pixman_region16_t *region);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
|
||||
cairo_surface_t *intermediate,
|
||||
cairo_rectangle_t *extents);
|
||||
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *dst,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
const cairo_rectangle_t *extents);
|
||||
|
||||
#endif /* CAIRO_CLIP_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -208,28 +208,32 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Combines clip->surface using the IN operator with the given
|
||||
* intermediate surface, which corresponds to the rectangle of the
|
||||
* destination space given by @extents.
|
||||
/* Combines the region of clip->surface given by extents in
|
||||
* device backend coordinates into the given temporary surface,
|
||||
* which has its origin at dst_x, dst_y in backend coordinates
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
|
||||
cairo_surface_t *intermediate,
|
||||
cairo_rectangle_t *extents)
|
||||
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *dst,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
const cairo_rectangle_t *extents)
|
||||
{
|
||||
cairo_pattern_union_t pattern;
|
||||
cairo_status_t status;
|
||||
|
||||
_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
|
||||
|
||||
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
|
||||
status = _cairo_surface_composite (operator,
|
||||
&pattern.base,
|
||||
NULL,
|
||||
intermediate,
|
||||
dst,
|
||||
extents->x - clip->surface_rect.x,
|
||||
extents->y - clip->surface_rect.y,
|
||||
0, 0,
|
||||
0, 0,
|
||||
extents->x - dst_x,
|
||||
extents->y - dst_y,
|
||||
extents->width, extents->height);
|
||||
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
|
|
|
|||
|
|
@ -1844,6 +1844,26 @@ _cairo_ft_scaled_font_glyph_bbox (void *abstract_font,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_format_t
|
||||
_select_text_mask_format (cairo_bool_t have_a1_glyphs,
|
||||
cairo_bool_t have_a8_glyphs,
|
||||
cairo_bool_t have_argb32_glyphs)
|
||||
{
|
||||
if (have_a8_glyphs)
|
||||
return CAIRO_FORMAT_A8;
|
||||
|
||||
if (have_a1_glyphs && have_argb32_glyphs)
|
||||
return CAIRO_FORMAT_A8;
|
||||
|
||||
if (have_a1_glyphs)
|
||||
return CAIRO_FORMAT_A1;
|
||||
|
||||
if (have_argb32_glyphs)
|
||||
return CAIRO_FORMAT_ARGB32;
|
||||
|
||||
/* when there are no glyphs to draw, just pick something */
|
||||
return CAIRO_FORMAT_A8;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ft_scaled_font_show_glyphs (void *abstract_font,
|
||||
|
|
@ -1859,12 +1879,16 @@ _cairo_ft_scaled_font_show_glyphs (void *abstract_font,
|
|||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
cairo_image_glyph_cache_entry_t *img;
|
||||
cairo_image_glyph_cache_entry_t **entries;
|
||||
cairo_cache_t *cache;
|
||||
cairo_glyph_cache_key_t key;
|
||||
cairo_ft_scaled_font_t *scaled_font = abstract_font;
|
||||
cairo_surface_pattern_t glyph_pattern;
|
||||
cairo_status_t status;
|
||||
cairo_surface_t *mask;
|
||||
cairo_surface_pattern_t mask_pattern;
|
||||
cairo_format_t mask_format = CAIRO_FORMAT_A1;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_bool_t have_a1_glyphs, have_a8_glyphs, have_argb32_glyphs;
|
||||
int x, y;
|
||||
int i;
|
||||
|
||||
|
|
@ -1884,44 +1908,98 @@ _cairo_ft_scaled_font_show_glyphs (void *abstract_font,
|
|||
key.scale = scaled_font->base.scale;
|
||||
key.flags = scaled_font->load_flags;
|
||||
|
||||
entries = malloc (num_glyphs * sizeof (cairo_image_glyph_cache_entry_t));
|
||||
if (!entries)
|
||||
goto CLEANUP_CACHE;
|
||||
|
||||
have_a1_glyphs = FALSE;
|
||||
have_a8_glyphs = FALSE;
|
||||
have_argb32_glyphs = FALSE;
|
||||
|
||||
for (i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
img = NULL;
|
||||
entries[i] = NULL;
|
||||
key.index = glyphs[i].index;
|
||||
|
||||
if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
|
||||
!= CAIRO_STATUS_SUCCESS
|
||||
|| img == NULL
|
||||
|| img->image == NULL)
|
||||
if (_cairo_cache_lookup (cache, &key, (void **) &entries[i], NULL) != CAIRO_STATUS_SUCCESS)
|
||||
continue;
|
||||
|
||||
switch (entries[i]->image->format) {
|
||||
case CAIRO_FORMAT_A1:
|
||||
have_a1_glyphs = TRUE;
|
||||
break;
|
||||
case CAIRO_FORMAT_A8:
|
||||
have_a8_glyphs = TRUE;
|
||||
break;
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
have_argb32_glyphs = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mask_format = _select_text_mask_format (have_a1_glyphs, have_a8_glyphs, have_argb32_glyphs);
|
||||
|
||||
mask = cairo_image_surface_create (mask_format, width, height);
|
||||
if (!mask)
|
||||
goto CLEANUP_ENTRIES;
|
||||
|
||||
status = _cairo_surface_fill_rectangle (mask, CAIRO_OPERATOR_SOURCE,
|
||||
CAIRO_COLOR_TRANSPARENT,
|
||||
0, 0, width, height);
|
||||
if (status)
|
||||
goto CLEANUP_MASK;
|
||||
|
||||
for (i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
if (entries[i] == NULL
|
||||
|| entries[i]->image == NULL)
|
||||
continue;
|
||||
|
||||
x = (int) floor (glyphs[i].x + 0.5);
|
||||
y = (int) floor (glyphs[i].y + 0.5);
|
||||
|
||||
_cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base));
|
||||
_cairo_pattern_init_for_surface (&glyph_pattern, &(entries[i]->image->base));
|
||||
|
||||
status = _cairo_surface_composite (operator, pattern,
|
||||
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, pattern,
|
||||
&glyph_pattern.base,
|
||||
surface,
|
||||
x + img->size.x,
|
||||
y + img->size.y,
|
||||
mask,
|
||||
x + entries[i]->size.x,
|
||||
y + entries[i]->size.y,
|
||||
0, 0,
|
||||
x + img->size.x,
|
||||
y + img->size.y,
|
||||
(double) img->size.width,
|
||||
(double) img->size.height);
|
||||
x + entries[i]->size.x - dest_x,
|
||||
y + entries[i]->size.y - dest_y,
|
||||
entries[i]->size.width,
|
||||
entries[i]->size.height);
|
||||
|
||||
_cairo_pattern_fini (&glyph_pattern.base);
|
||||
|
||||
if (status) {
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (status)
|
||||
goto CLEANUP_MASK;
|
||||
}
|
||||
|
||||
_cairo_pattern_init_for_surface (&mask_pattern, mask);
|
||||
|
||||
status = _cairo_surface_composite (operator, pattern, &mask_pattern.base,
|
||||
surface,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
dest_x, dest_y,
|
||||
width, height);
|
||||
|
||||
_cairo_pattern_fini (&mask_pattern.base);
|
||||
|
||||
CLEANUP_MASK:
|
||||
cairo_surface_destroy (mask);
|
||||
|
||||
CLEANUP_ENTRIES:
|
||||
free (entries);
|
||||
|
||||
CLEANUP_CACHE:
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -705,6 +705,257 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_operator_bounded:
|
||||
* @operator: a #cairo_operator_t
|
||||
*
|
||||
* A bounded operator is one where a source or mask pixel
|
||||
* of zero results in no effect on the destination image.
|
||||
*
|
||||
* Unbounded operators often require special handling; if you, for
|
||||
* example, draw trapezoids with an unbounded operator, the effect
|
||||
* extends past the bounding box of the trapezoids.
|
||||
*
|
||||
* Return value: %TRUE if the operator is bounded
|
||||
**/
|
||||
cairo_bool_t
|
||||
_cairo_operator_bounded (cairo_operator_t operator)
|
||||
{
|
||||
switch (operator) {
|
||||
case CAIRO_OPERATOR_OVER:
|
||||
case CAIRO_OPERATOR_ATOP:
|
||||
case CAIRO_OPERATOR_DEST:
|
||||
case CAIRO_OPERATOR_DEST_OVER:
|
||||
case CAIRO_OPERATOR_DEST_OUT:
|
||||
case CAIRO_OPERATOR_XOR:
|
||||
case CAIRO_OPERATOR_ADD:
|
||||
case CAIRO_OPERATOR_SATURATE:
|
||||
return TRUE;
|
||||
case CAIRO_OPERATOR_CLEAR:
|
||||
case CAIRO_OPERATOR_SOURCE:
|
||||
case CAIRO_OPERATOR_OUT:
|
||||
case CAIRO_OPERATOR_IN:
|
||||
case CAIRO_OPERATOR_DEST_IN:
|
||||
case CAIRO_OPERATOR_DEST_ATOP:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED;
|
||||
}
|
||||
|
||||
typedef cairo_status_t (*cairo_draw_func_t) (void *closure,
|
||||
cairo_operator_t operator,
|
||||
cairo_pattern_t *src,
|
||||
cairo_surface_t *dst,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
const cairo_rectangle_t *extents);
|
||||
|
||||
/* Handles compositing with a clip surface when the operator allows
|
||||
* us to combine the clip with the mask
|
||||
*/
|
||||
static cairo_status_t
|
||||
_cairo_gstate_clip_and_composite_with_mask (cairo_clip_t *clip,
|
||||
cairo_operator_t operator,
|
||||
cairo_pattern_t *src,
|
||||
cairo_draw_func_t draw_func,
|
||||
void *draw_closure,
|
||||
cairo_surface_t *dst,
|
||||
const cairo_rectangle_t *extents)
|
||||
{
|
||||
cairo_surface_t *intermediate;
|
||||
cairo_surface_pattern_t intermediate_pattern;
|
||||
cairo_status_t status;
|
||||
|
||||
intermediate = cairo_surface_create_similar (clip->surface,
|
||||
CAIRO_CONTENT_ALPHA,
|
||||
extents->width,
|
||||
extents->height);
|
||||
if (intermediate->status)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
status = (*draw_func) (draw_closure, CAIRO_OPERATOR_SOURCE,
|
||||
NULL, intermediate,
|
||||
extents->x, extents->y,
|
||||
extents);
|
||||
if (status)
|
||||
goto CLEANUP_SURFACE;
|
||||
|
||||
status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN,
|
||||
intermediate,
|
||||
extents->x, extents->y,
|
||||
extents);
|
||||
if (status)
|
||||
goto CLEANUP_SURFACE;
|
||||
|
||||
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
|
||||
|
||||
status = _cairo_surface_composite (operator,
|
||||
src, &intermediate_pattern.base, dst,
|
||||
extents->x, extents->y,
|
||||
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 with a clip surface when the operator allows
|
||||
* us to combine the clip with the mask
|
||||
*/
|
||||
static cairo_status_t
|
||||
_cairo_gstate_clip_and_composite_combine (cairo_clip_t *clip,
|
||||
cairo_operator_t operator,
|
||||
cairo_pattern_t *src,
|
||||
cairo_draw_func_t draw_func,
|
||||
void *draw_closure,
|
||||
cairo_surface_t *dst,
|
||||
const cairo_rectangle_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.
|
||||
*/
|
||||
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, operator,
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_rectangle_empty (const cairo_rectangle_t *rect)
|
||||
{
|
||||
return rect->width == 0 || rect->height == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_gstate_clip_and_composite:
|
||||
* @gstate: a #cairo_gstate_t
|
||||
* @operator: 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
|
||||
_cairo_gstate_clip_and_composite (cairo_clip_t *clip,
|
||||
cairo_operator_t operator,
|
||||
cairo_pattern_t *src,
|
||||
cairo_draw_func_t draw_func,
|
||||
void *draw_closure,
|
||||
cairo_surface_t *dst,
|
||||
const cairo_rectangle_t *extents)
|
||||
{
|
||||
if (_cairo_rectangle_empty (extents))
|
||||
/* Nothing to do */
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (clip->surface)
|
||||
{
|
||||
if (_cairo_operator_bounded (operator))
|
||||
return _cairo_gstate_clip_and_composite_with_mask (clip, operator,
|
||||
src,
|
||||
draw_func, draw_closure,
|
||||
dst, extents);
|
||||
else
|
||||
return _cairo_gstate_clip_and_composite_combine (clip, operator,
|
||||
src,
|
||||
draw_func, draw_closure,
|
||||
dst, extents);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (*draw_func) (draw_closure, operator,
|
||||
src, dst,
|
||||
0, 0,
|
||||
extents);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_get_mask_extents (cairo_gstate_t *gstate,
|
||||
cairo_pattern_t *mask,
|
||||
|
|
@ -714,7 +965,8 @@ _get_mask_extents (cairo_gstate_t *gstate,
|
|||
|
||||
/*
|
||||
* XXX should take mask extents into account, but
|
||||
* that involves checking the transform... For now,
|
||||
* that involves checking the transform and
|
||||
* _cairo_operator_bounded (operator)... For now,
|
||||
* be lazy and just use the destination extents
|
||||
*/
|
||||
status = _cairo_surface_get_extents (gstate->target, extents);
|
||||
|
|
@ -724,16 +976,40 @@ _get_mask_extents (cairo_gstate_t *gstate,
|
|||
return _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_gstate_mask_draw_func (void *closure,
|
||||
cairo_operator_t operator,
|
||||
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 (operator,
|
||||
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 (operator,
|
||||
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_gstate_mask (cairo_gstate_t *gstate,
|
||||
cairo_pattern_t *mask)
|
||||
{
|
||||
cairo_rectangle_t extents;
|
||||
cairo_pattern_union_t source_pattern, mask_pattern;
|
||||
cairo_surface_pattern_t intermediate_pattern;
|
||||
cairo_pattern_t *effective_mask;
|
||||
cairo_status_t status;
|
||||
int mask_x, mask_y;
|
||||
|
||||
if (mask->status)
|
||||
return mask->status;
|
||||
|
|
@ -745,64 +1021,17 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
_get_mask_extents (gstate, mask, &extents);
|
||||
|
||||
if (gstate->clip.surface) {
|
||||
/* When there is clip surface, we'll need to create a
|
||||
* temporary surface that combines the clip and mask
|
||||
*/
|
||||
cairo_surface_t *intermediate;
|
||||
|
||||
intermediate = cairo_surface_create_similar (gstate->clip.surface,
|
||||
CAIRO_CONTENT_ALPHA,
|
||||
extents.width,
|
||||
extents.height);
|
||||
if (intermediate->status)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
|
||||
mask, NULL, intermediate,
|
||||
extents.x, extents.y,
|
||||
0, 0,
|
||||
0, 0,
|
||||
extents.width, extents.height);
|
||||
if (status) {
|
||||
cairo_surface_destroy (intermediate);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = _cairo_clip_combine_to_surface (&gstate->clip, intermediate, &extents);
|
||||
if (status) {
|
||||
cairo_surface_destroy (intermediate);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
|
||||
cairo_surface_destroy (intermediate);
|
||||
|
||||
effective_mask = &intermediate_pattern.base;
|
||||
mask_x = extents.x;
|
||||
mask_y = extents.y;
|
||||
|
||||
} else {
|
||||
effective_mask = mask;
|
||||
mask_x = mask_y = 0;
|
||||
}
|
||||
|
||||
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
|
||||
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, effective_mask);
|
||||
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
|
||||
|
||||
_get_mask_extents (gstate, &mask_pattern.base, &extents);
|
||||
|
||||
status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator,
|
||||
&source_pattern.base,
|
||||
_cairo_gstate_mask_draw_func, &mask_pattern.base,
|
||||
gstate->target,
|
||||
&extents);
|
||||
|
||||
status = _cairo_surface_composite (gstate->operator,
|
||||
&source_pattern.base,
|
||||
&mask_pattern.base,
|
||||
gstate->target,
|
||||
extents.x, extents.y,
|
||||
extents.x - mask_x, extents.y - mask_y,
|
||||
extents.x, extents.y,
|
||||
extents.width, extents.height);
|
||||
|
||||
if (gstate->clip.surface)
|
||||
_cairo_pattern_fini (&intermediate_pattern.base);
|
||||
_cairo_pattern_fini (&source_pattern.base);
|
||||
_cairo_pattern_fini (&mask_pattern.base);
|
||||
|
||||
|
|
@ -916,12 +1145,6 @@ _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_rectangle_empty (cairo_rectangle_t *rect)
|
||||
{
|
||||
return rect->width == 0 || rect->height == 0;
|
||||
}
|
||||
|
||||
/* Composites a region representing a set of trapezoids.
|
||||
*/
|
||||
static cairo_status_t
|
||||
|
|
@ -971,73 +1194,6 @@ _composite_trap_region (cairo_clip_t *clip,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Composites a set of trapezoids in the case where we need to create
|
||||
* an intermediate surface to handle clip->surface
|
||||
*
|
||||
* Warning: This call modifies the coordinates of traps
|
||||
*/
|
||||
static cairo_status_t
|
||||
_composite_traps_intermediate_surface (cairo_clip_t *clip,
|
||||
cairo_pattern_t *src,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *dst,
|
||||
cairo_traps_t *traps,
|
||||
cairo_rectangle_t *extents)
|
||||
{
|
||||
cairo_pattern_union_t pattern;
|
||||
cairo_surface_t *intermediate;
|
||||
cairo_surface_pattern_t intermediate_pattern;
|
||||
cairo_status_t status;
|
||||
|
||||
_cairo_traps_translate (traps, -extents->x, -extents->y);
|
||||
|
||||
intermediate = _cairo_surface_create_similar_solid (clip->surface,
|
||||
CAIRO_CONTENT_ALPHA,
|
||||
extents->width,
|
||||
extents->height,
|
||||
CAIRO_COLOR_TRANSPARENT);
|
||||
if (intermediate->status)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
|
||||
|
||||
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
|
||||
&pattern.base,
|
||||
intermediate,
|
||||
extents->x, extents->y,
|
||||
0, 0,
|
||||
extents->width,
|
||||
extents->height,
|
||||
traps->traps,
|
||||
traps->num_traps);
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
status = _cairo_clip_combine_to_surface (clip, intermediate, extents);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
|
||||
|
||||
status = _cairo_surface_composite (operator,
|
||||
src,
|
||||
&intermediate_pattern.base,
|
||||
dst,
|
||||
extents->x, extents->y,
|
||||
0, 0,
|
||||
extents->x, extents->y,
|
||||
extents->width, extents->height);
|
||||
|
||||
_cairo_pattern_fini (&intermediate_pattern.base);
|
||||
|
||||
out:
|
||||
cairo_surface_destroy (intermediate);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Composites a region representing a set of trapezoids in the
|
||||
* case of a solid source (so we can use
|
||||
* _cairo_surface_fill_rectangles).
|
||||
|
|
@ -1077,27 +1233,34 @@ _composite_trap_region_solid (cairo_clip_t *clip,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Composites a set of trapezoids in the general case where
|
||||
clip->surface == NULL
|
||||
*/
|
||||
static cairo_status_t
|
||||
_composite_traps (cairo_clip_t *clip,
|
||||
cairo_pattern_t *src,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *dst,
|
||||
cairo_traps_t *traps,
|
||||
cairo_rectangle_t *extents)
|
||||
_composite_traps_draw_func (void *closure,
|
||||
cairo_operator_t operator,
|
||||
cairo_pattern_t *src,
|
||||
cairo_surface_t *dst,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
const cairo_rectangle_t *extents)
|
||||
{
|
||||
cairo_traps_t *traps = closure;
|
||||
cairo_pattern_union_t pattern;
|
||||
cairo_status_t status;
|
||||
|
||||
if (dst_x != 0 || dst_y != 0)
|
||||
_cairo_traps_translate (traps, - dst_x, - dst_y);
|
||||
|
||||
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
|
||||
if (!src)
|
||||
src = &pattern.base;
|
||||
|
||||
status = _cairo_surface_composite_trapezoids (operator,
|
||||
src, dst,
|
||||
extents->x, extents->y,
|
||||
extents->x, extents->y,
|
||||
extents->width,
|
||||
extents->height,
|
||||
extents->x, extents->y,
|
||||
extents->x - dst_x, extents->y - dst_y,
|
||||
extents->width, extents->height,
|
||||
traps->traps,
|
||||
traps->num_traps);
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -1134,65 +1297,65 @@ _cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src,
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
if (trap_region) {
|
||||
status = _cairo_clip_intersect_to_region (clip, trap_region);
|
||||
_region_rect_extents (trap_region, &extents);
|
||||
} else {
|
||||
cairo_box_t trap_extents;
|
||||
_cairo_traps_extents (traps, &trap_extents);
|
||||
_cairo_box_round_to_rectangle (&trap_extents, &extents);
|
||||
if (_cairo_operator_bounded (operator))
|
||||
{
|
||||
if (trap_region) {
|
||||
status = _cairo_clip_intersect_to_region (clip, trap_region);
|
||||
_region_rect_extents (trap_region, &extents);
|
||||
} else {
|
||||
cairo_box_t trap_extents;
|
||||
_cairo_traps_extents (traps, &trap_extents);
|
||||
_cairo_box_round_to_rectangle (&trap_extents, &extents);
|
||||
status = _cairo_clip_intersect_to_rectangle (clip, &extents);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = _cairo_surface_get_extents (dst, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
status = _cairo_clip_intersect_to_rectangle (clip, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (_cairo_rectangle_empty (&extents))
|
||||
/* Nothing to do */
|
||||
goto out;
|
||||
|
||||
if (clip->surface) {
|
||||
if (trap_region) {
|
||||
/* If we are compositing a set of rectangles, we can set them as the
|
||||
* clip region for the destination surface and use the clip surface
|
||||
* as the mask. A clip region might not be supported, in which case
|
||||
* we fall through to the next method
|
||||
*/
|
||||
status = _composite_trap_region (clip, src, operator, dst,
|
||||
trap_region, &extents);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Handle a clip surface by creating an intermediate surface. */
|
||||
status = _composite_traps_intermediate_surface (clip, src, operator,
|
||||
dst, traps, &extents);
|
||||
} else {
|
||||
/* No clip surface */
|
||||
if (trap_region && src->type == CAIRO_PATTERN_SOLID) {
|
||||
/* Solid rectangles are handled specially */
|
||||
if (trap_region && _cairo_operator_bounded (operator))
|
||||
{
|
||||
if (src->type == CAIRO_PATTERN_SOLID &&
|
||||
!clip->surface &&
|
||||
trap_region->
|
||||
{
|
||||
/* Solid rectangles special case */
|
||||
status = _composite_trap_region_solid (clip, (cairo_solid_pattern_t *)src,
|
||||
operator, dst, trap_region);
|
||||
} else {
|
||||
if (trap_region) {
|
||||
/* For a simple rectangle, we can just use composite(), for more
|
||||
* rectangles, we have to set a clip region. The cost of rasterizing
|
||||
* trapezoids is pretty high for most backends currently, so it's
|
||||
* worthwhile even if a region is needed.
|
||||
*/
|
||||
status = _composite_trap_region (clip, src, operator, dst,
|
||||
trap_region, &extents);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
goto out;
|
||||
|
||||
/* If a clip regions aren't supported, fall through */
|
||||
}
|
||||
|
||||
status = _composite_traps (clip, src, operator,
|
||||
dst, traps, &extents);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* For a simple rectangle, we can just use composite(), for more
|
||||
* rectangles, we have to set a clip region. The cost of rasterizing
|
||||
* trapezoids is pretty high for most backends currently, so it's
|
||||
* worthwhile even if a region is needed.
|
||||
*
|
||||
* If we have a clip surface, we set it as the mask.
|
||||
*
|
||||
* CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
|
||||
* more than rectangle and the destination doesn't support clip
|
||||
* regions. In that case, we fall through.
|
||||
*/
|
||||
status = _composite_trap_region (clip, src, operator, dst,
|
||||
trap_region, &extents);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = _cairo_gstate_clip_and_composite (clip, operator, src,
|
||||
_composite_traps_draw_func, traps,
|
||||
dst,
|
||||
&extents);
|
||||
|
||||
out:
|
||||
if (trap_region)
|
||||
pixman_region_destroy (trap_region);
|
||||
|
|
@ -1209,7 +1372,7 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
|
|||
cairo_status_t status;
|
||||
|
||||
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
|
||||
|
||||
|
||||
status = _cairo_surface_clip_and_composite_trapezoids (&pattern.base,
|
||||
gstate->operator,
|
||||
gstate->target,
|
||||
|
|
@ -1681,6 +1844,58 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
cairo_scaled_font_t *font;
|
||||
cairo_glyph_t *glyphs;
|
||||
int num_glyphs;
|
||||
} cairo_show_glyphs_info_t;
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_gstate_show_glyphs_draw_func (void *closure,
|
||||
cairo_operator_t operator,
|
||||
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)
|
||||
{
|
||||
glyph_info->glyphs[i].x -= dst_x;
|
||||
glyph_info->glyphs[i].y -= dst_y;
|
||||
}
|
||||
}
|
||||
|
||||
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
|
||||
if (!src)
|
||||
src = &pattern.base;
|
||||
|
||||
status = _cairo_scaled_font_show_glyphs (glyph_info->font,
|
||||
operator,
|
||||
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_gstate_show_glyphs (cairo_gstate_t *gstate,
|
||||
cairo_glyph_t *glyphs,
|
||||
|
|
@ -1692,6 +1907,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
cairo_pattern_union_t pattern;
|
||||
cairo_box_t bbox;
|
||||
cairo_rectangle_t extents;
|
||||
cairo_show_glyphs_info_t glyph_info;
|
||||
|
||||
if (gstate->source->status)
|
||||
return gstate->source->status;
|
||||
|
|
@ -1715,113 +1931,42 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
&transformed_glyphs[i].x,
|
||||
&transformed_glyphs[i].y);
|
||||
}
|
||||
|
||||
status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&bbox);
|
||||
_cairo_box_round_to_rectangle (&bbox, &extents);
|
||||
|
||||
if (status)
|
||||
goto CLEANUP_GLYPHS;
|
||||
|
||||
if (gstate->clip.surface)
|
||||
if (_cairo_operator_bounded (gstate->operator))
|
||||
{
|
||||
cairo_surface_t *intermediate;
|
||||
cairo_surface_pattern_t intermediate_pattern;
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &gstate->clip.surface_rect);
|
||||
|
||||
/* Shortcut if empty */
|
||||
if (_cairo_rectangle_empty (&extents)) {
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
goto BAIL1;
|
||||
}
|
||||
|
||||
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
|
||||
CAIRO_CONTENT_ALPHA,
|
||||
extents.width,
|
||||
extents.height,
|
||||
CAIRO_COLOR_TRANSPARENT);
|
||||
if (intermediate->status) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
goto BAIL1;
|
||||
}
|
||||
|
||||
/* move the glyphs again, from dev space to intermediate space */
|
||||
for (i = 0; i < num_glyphs; ++i)
|
||||
{
|
||||
transformed_glyphs[i].x -= extents.x;
|
||||
transformed_glyphs[i].y -= extents.y;
|
||||
}
|
||||
|
||||
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
|
||||
|
||||
status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
|
||||
CAIRO_OPERATOR_ADD,
|
||||
&pattern.base, intermediate,
|
||||
extents.x, extents.y,
|
||||
0, 0,
|
||||
extents.width, extents.height,
|
||||
transformed_glyphs, num_glyphs);
|
||||
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
|
||||
status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&bbox);
|
||||
if (status)
|
||||
goto BAIL2;
|
||||
|
||||
_cairo_pattern_init_for_surface (&pattern.surface,
|
||||
gstate->clip.surface);
|
||||
|
||||
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
|
||||
&pattern.base,
|
||||
NULL,
|
||||
intermediate,
|
||||
extents.x - gstate->clip.surface_rect.x,
|
||||
extents.y - gstate->clip.surface_rect.y,
|
||||
0, 0,
|
||||
0, 0,
|
||||
extents.width, extents.height);
|
||||
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
|
||||
if (status)
|
||||
goto BAIL2;
|
||||
|
||||
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
|
||||
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
|
||||
|
||||
status = _cairo_surface_composite (gstate->operator,
|
||||
&pattern.base,
|
||||
&intermediate_pattern.base,
|
||||
gstate->target,
|
||||
extents.x, extents.y,
|
||||
0, 0,
|
||||
extents.x, extents.y,
|
||||
extents.width, extents.height);
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
_cairo_pattern_fini (&intermediate_pattern.base);
|
||||
|
||||
BAIL2:
|
||||
cairo_surface_destroy (intermediate);
|
||||
BAIL1:
|
||||
;
|
||||
goto CLEANUP_GLYPHS;
|
||||
|
||||
_cairo_box_round_to_rectangle (&bbox, &extents);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cairo_pattern_init_copy (&pattern.base, gstate->source);
|
||||
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
|
||||
|
||||
status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
|
||||
gstate->operator, &pattern.base,
|
||||
gstate->target,
|
||||
extents.x, extents.y,
|
||||
extents.x, extents.y,
|
||||
extents.width, extents.height,
|
||||
transformed_glyphs, num_glyphs);
|
||||
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
status = _cairo_surface_get_extents (gstate->target, &extents);
|
||||
if (status)
|
||||
goto CLEANUP_GLYPHS;
|
||||
}
|
||||
|
||||
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
|
||||
if (status)
|
||||
goto CLEANUP_GLYPHS;
|
||||
|
||||
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
|
||||
|
||||
glyph_info.font = gstate->scaled_font;
|
||||
glyph_info.glyphs = transformed_glyphs;
|
||||
glyph_info.num_glyphs = num_glyphs;
|
||||
|
||||
status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator,
|
||||
&pattern.base,
|
||||
_cairo_gstate_show_glyphs_draw_func, &glyph_info,
|
||||
gstate->target,
|
||||
&extents);
|
||||
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
|
||||
CLEANUP_GLYPHS:
|
||||
free (transformed_glyphs);
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
|
|||
|
||||
surface->format = format;
|
||||
surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
|
||||
surface->owns_data = 0;
|
||||
surface->owns_data = FALSE;
|
||||
surface->has_clip = FALSE;
|
||||
|
||||
surface->width = pixman_image_get_width (pixman_image);
|
||||
surface->height = pixman_image_get_height (pixman_image);
|
||||
|
|
@ -613,6 +614,16 @@ _cairo_image_surface_composite (cairo_operator_t operator,
|
|||
}
|
||||
}
|
||||
|
||||
if (!_cairo_operator_bounded (operator))
|
||||
_cairo_surface_composite_fixup_unbounded (&dst->base,
|
||||
&src_attr, src->width, src->height,
|
||||
mask ? &mask_attr : NULL,
|
||||
mask ? mask->width : 0,
|
||||
mask ? mask->height : 0,
|
||||
src_x, src_y,
|
||||
mask_x, mask_y,
|
||||
dst_x, dst_y, width, height);
|
||||
|
||||
if (mask)
|
||||
_cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
|
||||
|
||||
|
|
@ -644,6 +655,48 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static pixman_image_t *
|
||||
_create_mask_image (int width,
|
||||
int height)
|
||||
{
|
||||
pixman_image_t *image;
|
||||
pixman_color_t pixman_color = { 0, 0, 0, 0 }; /* transparent */
|
||||
pixman_rectangle_t rect;
|
||||
pixman_format_t *format;
|
||||
|
||||
format = pixman_format_create (PIXMAN_FORMAT_NAME_A8);
|
||||
if (!format)
|
||||
return NULL;
|
||||
|
||||
image = pixman_image_create (format, width, height);
|
||||
if (!image)
|
||||
return NULL;
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
|
||||
pixman_fill_rectangles (PIXMAN_OPERATOR_SRC, image,
|
||||
&pixman_color, &rect, 1);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_image_surface_is_alpha_only (cairo_image_surface_t *surface)
|
||||
{
|
||||
int bpp, alpha, red, green, blue;
|
||||
|
||||
if (surface->format != (cairo_format_t) -1)
|
||||
return surface->format == CAIRO_FORMAT_A1 || surface->format == CAIRO_FORMAT_A8;
|
||||
|
||||
pixman_format_get_masks (pixman_image_get_format (surface->pixman_image),
|
||||
&bpp, &alpha, &red, &green, &blue);
|
||||
|
||||
return red == 0 && blue == 0 && green == 0;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
|
|
@ -661,8 +714,30 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
|
|||
cairo_image_surface_t *dst = abstract_dst;
|
||||
cairo_image_surface_t *src;
|
||||
cairo_int_status_t status;
|
||||
int render_reference_x, render_reference_y;
|
||||
int render_src_x, render_src_y;
|
||||
pixman_image_t *mask;
|
||||
|
||||
/* Special case adding trapezoids onto a mask surface; we want to avoid
|
||||
* creating an intermediate temporary mask unecessarily.
|
||||
*
|
||||
* We make the assumption here that the portion of the trapezoids
|
||||
* contained within the surface is bounded by [dst_x,dst_y,width,height];
|
||||
* the Cairo core code passes bounds based on the trapezoid extents.
|
||||
*
|
||||
* Currently the check surface->has_clip is needed for correct
|
||||
* functioning, since pixman_add_trapezoids() doesn't obey the
|
||||
* surface clip, which is a libpixman bug , but there's no harm in
|
||||
* falling through to the general case when the surface is clipped
|
||||
* since libpixman would have to generate an intermediate mask anyways.
|
||||
*/
|
||||
if (operator == CAIRO_OPERATOR_ADD &&
|
||||
_cairo_pattern_is_opaque_solid (pattern) &&
|
||||
_cairo_image_surface_is_alpha_only (dst) &&
|
||||
!dst->has_clip)
|
||||
{
|
||||
pixman_add_trapezoids (dst->pixman_image, 0, 0,
|
||||
(pixman_trapezoid_t *) traps, num_traps);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
|
||||
src_x, src_y, width, height,
|
||||
|
|
@ -671,28 +746,35 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
if (traps[0].left.p1.y < traps[0].left.p2.y) {
|
||||
render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
|
||||
render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
|
||||
} else {
|
||||
render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
|
||||
render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
|
||||
}
|
||||
status = _cairo_image_surface_set_attributes (src, &attributes);
|
||||
if (status)
|
||||
goto CLEANUP_SOURCE;
|
||||
|
||||
render_src_x = src_x + render_reference_x - dst_x;
|
||||
render_src_y = src_y + render_reference_y - dst_y;
|
||||
mask = _create_mask_image (width, height);
|
||||
if (!mask) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
goto CLEANUP_MASK;
|
||||
}
|
||||
|
||||
/* XXX: The pixman_trapezoid_t cast is evil and needs to go away
|
||||
* somehow. */
|
||||
status = _cairo_image_surface_set_attributes (src, &attributes);
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
pixman_composite_trapezoids (_pixman_operator (operator),
|
||||
src->pixman_image,
|
||||
dst->pixman_image,
|
||||
render_src_x + attributes.x_offset,
|
||||
render_src_y + attributes.y_offset,
|
||||
(pixman_trapezoid_t *) traps, num_traps);
|
||||
pixman_add_trapezoids (mask, - dst_x, - dst_y,
|
||||
(pixman_trapezoid_t *) traps, num_traps);
|
||||
|
||||
pixman_composite (_pixman_operator (operator),
|
||||
src->pixman_image,
|
||||
mask,
|
||||
dst->pixman_image,
|
||||
src_x + attributes.x_offset,
|
||||
src_y + attributes.y_offset,
|
||||
0, 0,
|
||||
dst_x, dst_y,
|
||||
width, height);
|
||||
|
||||
CLEANUP_MASK:
|
||||
pixman_image_destroy (mask);
|
||||
|
||||
CLEANUP_SOURCE:
|
||||
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
|
||||
|
||||
return status;
|
||||
|
|
@ -713,6 +795,8 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
|
|||
{
|
||||
pixman_image_set_clip_region (surface->pixman_image, region);
|
||||
|
||||
surface->has_clip = region != NULL;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1396,3 +1396,154 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_surface_composite_fixup_unbounded:
|
||||
* @dst: the destination surface
|
||||
* @src_attr: source surface attributes (from _cairo_pattern_acquire_surface())
|
||||
* @src_width: width of source surface
|
||||
* @src_height: height of source surface
|
||||
* @mask_attr: mask surface attributes or %NULL if no mask
|
||||
* @mask_width: width of mask surface
|
||||
* @mask_height: height of mask surface
|
||||
* @src_x: @src_x from _cairo_surface_composite()
|
||||
* @src_y: @src_y from _cairo_surface_composite()
|
||||
* @mask_x: @mask_x from _cairo_surface_composite()
|
||||
* @mask_y: @mask_y from _cairo_surface_composite()
|
||||
* @dst_x: @dst_x from _cairo_surface_composite()
|
||||
* @dst_y: @dst_y from _cairo_surface_composite()
|
||||
* @width: @width from _cairo_surface_composite()
|
||||
* @height: @height_x from _cairo_surface_composite()
|
||||
*
|
||||
* Eeek! Too many parameters! This is a helper function to take care of fixing
|
||||
* up for bugs in libpixman and RENDER where, when asked to composite an
|
||||
* untransformed surface with an unbounded operator (like CLEAR or SOURCE)
|
||||
* only the region inside both the source and the mask is affected.
|
||||
* This function clears the region that should have been drawn but was wasn't.
|
||||
**/
|
||||
void
|
||||
_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
|
||||
cairo_surface_attributes_t *src_attr,
|
||||
int src_width,
|
||||
int src_height,
|
||||
cairo_surface_attributes_t *mask_attr,
|
||||
int mask_width,
|
||||
int mask_height,
|
||||
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_bool_t have_src = TRUE;
|
||||
cairo_bool_t have_mask = mask_attr != NULL;
|
||||
cairo_rectangle_t dst_rectangle;
|
||||
cairo_rectangle_t drawn_rectangle;
|
||||
cairo_rectangle_t rects[4];
|
||||
int num_rects = 0;
|
||||
|
||||
/* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
|
||||
* non-repeating sources and masks. Other sources and masks can be ignored.
|
||||
*/
|
||||
if (!_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) ||
|
||||
src_attr->extend != CAIRO_EXTEND_NONE)
|
||||
have_src = FALSE;
|
||||
|
||||
if (have_mask &&
|
||||
(!_cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) ||
|
||||
mask_attr->extend != CAIRO_EXTEND_NONE))
|
||||
have_mask = FALSE;
|
||||
|
||||
/* The area that was drawn is the area in the destination rectangle but not within
|
||||
* the source or the mask.
|
||||
*/
|
||||
dst_rectangle.x = dst_x;
|
||||
dst_rectangle.y = dst_y;
|
||||
dst_rectangle.width = width;
|
||||
dst_rectangle.height = height;
|
||||
|
||||
drawn_rectangle = dst_rectangle;
|
||||
|
||||
if (have_src) {
|
||||
cairo_rectangle_t src_rectangle;
|
||||
|
||||
src_rectangle.x = (dst_x - (src_x + src_attr->x_offset));
|
||||
src_rectangle.y = (dst_y - (src_y + src_attr->y_offset));
|
||||
src_rectangle.width = src_width;
|
||||
src_rectangle.height = src_height;
|
||||
|
||||
_cairo_rectangle_intersect (&drawn_rectangle, &src_rectangle);
|
||||
}
|
||||
|
||||
if (have_mask) {
|
||||
cairo_rectangle_t mask_rectangle;
|
||||
|
||||
mask_rectangle.x = (dst_x - (mask_x + mask_attr->x_offset));
|
||||
mask_rectangle.y = (dst_y - (mask_y + mask_attr->y_offset));
|
||||
mask_rectangle.width = mask_width;
|
||||
mask_rectangle.height = mask_height;
|
||||
|
||||
_cairo_rectangle_intersect (&drawn_rectangle, &mask_rectangle);
|
||||
}
|
||||
|
||||
/* Now compute the area that is in dst_rectangle but not in drawn_rectangle;
|
||||
* this is the area we must clear; This computation could be done with
|
||||
* regions, but the clumsiness of the libpixman API makes this easier.
|
||||
*/
|
||||
if (drawn_rectangle.width == 0 || drawn_rectangle.height == 0)
|
||||
{
|
||||
rects[num_rects].x = dst_rectangle.x;
|
||||
rects[num_rects].y = dst_rectangle.y;
|
||||
rects[num_rects].width = dst_rectangle.width;
|
||||
rects[num_rects].height = dst_rectangle.height;
|
||||
|
||||
num_rects++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst_rectangle.y < drawn_rectangle.y) {
|
||||
rects[num_rects].x = dst_rectangle.x;
|
||||
rects[num_rects].y = dst_rectangle.y;
|
||||
rects[num_rects].width = dst_rectangle.width;
|
||||
rects[num_rects].height = drawn_rectangle.y - dst_rectangle.y;
|
||||
|
||||
num_rects++;
|
||||
}
|
||||
|
||||
if (dst_rectangle.x < drawn_rectangle.x) {
|
||||
rects[num_rects].x = dst_rectangle.x;
|
||||
rects[num_rects].y = drawn_rectangle.y;
|
||||
rects[num_rects].width = drawn_rectangle.x - dst_rectangle.x;
|
||||
rects[num_rects].height = drawn_rectangle.height;
|
||||
|
||||
num_rects++;
|
||||
}
|
||||
|
||||
if (dst_rectangle.x + dst_rectangle.width > drawn_rectangle.x + drawn_rectangle.width) {
|
||||
rects[num_rects].x = drawn_rectangle.x + drawn_rectangle.width;
|
||||
rects[num_rects].y = drawn_rectangle.y;
|
||||
rects[num_rects].width = (dst_rectangle.x + dst_rectangle.width) - (drawn_rectangle.x + drawn_rectangle.width);
|
||||
rects[num_rects].height = drawn_rectangle.height;
|
||||
|
||||
num_rects++;
|
||||
}
|
||||
|
||||
if (dst_rectangle.y + dst_rectangle.height > drawn_rectangle.y + drawn_rectangle.height) {
|
||||
rects[num_rects].x = dst_rectangle.x;
|
||||
rects[num_rects].y = drawn_rectangle.y + drawn_rectangle.height;
|
||||
rects[num_rects].width = dst_rectangle.width;
|
||||
rects[num_rects].height = (dst_rectangle.y + dst_rectangle.height) - (drawn_rectangle.y + drawn_rectangle.height);
|
||||
|
||||
num_rects++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_rects > 0) {
|
||||
_cairo_surface_fill_rectangles (dst, CAIRO_OPERATOR_SOURCE, CAIRO_COLOR_TRANSPARENT,
|
||||
rects, num_rects);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1137,6 +1137,16 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
|
|||
dst_x, dst_y,
|
||||
width, height);
|
||||
}
|
||||
|
||||
if (!_cairo_operator_bounded (operator))
|
||||
_cairo_surface_composite_fixup_unbounded (&dst->base,
|
||||
&src_attr, src->width, src->height,
|
||||
mask ? &mask_attr : NULL,
|
||||
mask ? mask->width : 0,
|
||||
mask ? mask->height : 0,
|
||||
src_x, src_y,
|
||||
mask_x, mask_y,
|
||||
dst_x, dst_y, width, height);
|
||||
break;
|
||||
|
||||
case DO_XCOPYAREA:
|
||||
|
|
@ -1214,6 +1224,96 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Creates an A8 picture of size @width x @height, initialized with @color
|
||||
*/
|
||||
static Picture
|
||||
_create_a8_picture (cairo_xlib_surface_t *surface,
|
||||
XRenderColor *color,
|
||||
int width,
|
||||
int height,
|
||||
cairo_bool_t repeat)
|
||||
{
|
||||
XRenderPictureAttributes pa;
|
||||
unsigned long mask = 0;
|
||||
|
||||
Pixmap pixmap = XCreatePixmap (surface->dpy, surface->drawable,
|
||||
width, height,
|
||||
8);
|
||||
Picture picture;
|
||||
|
||||
if (repeat) {
|
||||
pa.repeat = TRUE;
|
||||
mask = CPRepeat;
|
||||
}
|
||||
|
||||
picture = XRenderCreatePicture (surface->dpy, pixmap,
|
||||
XRenderFindStandardFormat (surface->dpy, PictStandardA8),
|
||||
mask, &pa);
|
||||
XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color,
|
||||
0, 0, width, height);
|
||||
XFreePixmap (surface->dpy, pixmap);
|
||||
|
||||
return picture;
|
||||
}
|
||||
|
||||
/* Creates a temporary mask for the trapezoids covering the area
|
||||
* [@dst_x, @dst_y, @width, @height] of the destination surface.
|
||||
*/
|
||||
static Picture
|
||||
_create_trapezoid_mask (cairo_xlib_surface_t *dst,
|
||||
cairo_trapezoid_t *traps,
|
||||
int num_traps,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
|
||||
{
|
||||
XRenderColor transparent = { 0, 0, 0, 0 };
|
||||
XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff };
|
||||
Picture mask_picture, solid_picture;
|
||||
XTrapezoid *offset_traps;
|
||||
int i;
|
||||
|
||||
/* This would be considerably simpler using XRenderAddTraps(), but since
|
||||
* we are only using this in the unbounded-operator case, we stick with
|
||||
* XRenderCompositeTrapezoids, which is available on older versions
|
||||
* of RENDER rather than conditionalizing. We should still hit an
|
||||
* optimization that avoids creating another intermediate surface on
|
||||
* the servers that have XRenderAddTraps().
|
||||
*/
|
||||
mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
|
||||
solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
|
||||
|
||||
offset_traps = malloc (sizeof (XTrapezoid) * num_traps);
|
||||
if (!offset_traps)
|
||||
return None;
|
||||
|
||||
for (i = 0; i < num_traps; i++) {
|
||||
offset_traps[i].top = traps[i].top - 0x10000 * dst_y;
|
||||
offset_traps[i].bottom = traps[i].bottom - 0x10000 * dst_y;
|
||||
offset_traps[i].left.p1.x = traps[i].left.p1.x - 0x10000 * dst_x;
|
||||
offset_traps[i].left.p1.y = traps[i].left.p1.y - 0x10000 * dst_y;
|
||||
offset_traps[i].left.p2.x = traps[i].left.p2.x - 0x10000 * dst_x;
|
||||
offset_traps[i].left.p2.y = traps[i].left.p2.y - 0x10000 * dst_y;
|
||||
offset_traps[i].right.p1.x = traps[i].right.p1.x - 0x10000 * dst_x;
|
||||
offset_traps[i].right.p1.y = traps[i].right.p1.y - 0x10000 * dst_y;
|
||||
offset_traps[i].right.p2.x = traps[i].right.p2.x - 0x10000 * dst_x;
|
||||
offset_traps[i].right.p2.y = traps[i].right.p2.y - 0x10000 * dst_y;
|
||||
}
|
||||
|
||||
XRenderCompositeTrapezoids (dst->dpy, PictOpAdd,
|
||||
solid_picture, mask_picture,
|
||||
XRenderFindStandardFormat (dst->dpy, PictStandardA8),
|
||||
0, 0,
|
||||
offset_traps, num_traps);
|
||||
|
||||
XRenderFreePicture (dst->dpy, solid_picture);
|
||||
free (offset_traps);
|
||||
|
||||
return mask_picture;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
|
|
@ -1266,10 +1366,43 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
|
|||
render_src_x = src_x + render_reference_x - dst_x;
|
||||
render_src_y = src_y + render_reference_y - dst_y;
|
||||
|
||||
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
|
||||
_cairo_xlib_surface_ensure_dst_picture (dst);
|
||||
status = _cairo_xlib_surface_set_attributes (src, &attributes);
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
if (status)
|
||||
goto FAIL;
|
||||
|
||||
if (!_cairo_operator_bounded (operator)) {
|
||||
/* XRenderCompositeTrapezoids() creates a mask only large enough for the
|
||||
* trapezoids themselves, but if the operator is unbounded, then we need
|
||||
* to actually composite all the way out to the bounds, so we create
|
||||
* the mask and composite ourselves. There actually would
|
||||
* be benefit to doing this in all cases, since RENDER implementations
|
||||
* will frequently create a too temporary big mask, ignoring destination
|
||||
* bounds and clip. (XRenderAddTraps() could be used to make creating
|
||||
* the mask somewhat cheaper.)
|
||||
*/
|
||||
Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps,
|
||||
dst_x, dst_y, width, height);
|
||||
if (!mask_picture) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
XRenderComposite (dst->dpy,
|
||||
_render_operator (operator),
|
||||
src->src_picture,
|
||||
mask_picture,
|
||||
dst->dst_picture,
|
||||
src_x + attributes.x_offset,
|
||||
src_y + attributes.y_offset,
|
||||
0, 0,
|
||||
dst_x, dst_y,
|
||||
width, height);
|
||||
|
||||
XRenderFreePicture (dst->dpy, mask_picture);
|
||||
|
||||
} else {
|
||||
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
|
||||
XRenderCompositeTrapezoids (dst->dpy,
|
||||
_render_operator (operator),
|
||||
src->src_picture, dst->dst_picture,
|
||||
|
|
@ -1277,6 +1410,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
|
|||
render_src_x + attributes.x_offset,
|
||||
render_src_y + attributes.y_offset,
|
||||
(XTrapezoid *) traps, num_traps);
|
||||
}
|
||||
|
||||
FAIL:
|
||||
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
|
||||
|
|
@ -1735,6 +1869,7 @@ typedef struct {
|
|||
cairo_glyph_cache_key_t key;
|
||||
GlyphSet glyphset;
|
||||
Glyph glyph;
|
||||
cairo_glyph_size_t size;
|
||||
} glyphset_cache_entry_t;
|
||||
|
||||
static Glyph
|
||||
|
|
@ -1789,6 +1924,7 @@ _xlib_glyphset_cache_create_entry (void *abstract_cache,
|
|||
entry->glyph = None;
|
||||
entry->glyphset = None;
|
||||
entry->key.base.memory = 0;
|
||||
entry->size.x = entry->size.y = entry->size.width = entry->size.height = 0;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1797,6 +1933,8 @@ _xlib_glyphset_cache_create_entry (void *abstract_cache,
|
|||
|
||||
data = im->image->data;
|
||||
|
||||
entry->size = im->size;
|
||||
|
||||
glyph_info.width = im->size.width;
|
||||
glyph_info.height = im->size.height;
|
||||
|
||||
|
|
@ -2123,7 +2261,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font,
|
|||
_render_operator (operator),
|
||||
src->src_picture,
|
||||
self->dst_picture,
|
||||
cache->a8_pict_format,
|
||||
mask_format,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
elts, count);
|
||||
|
|
@ -2351,7 +2489,70 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font,
|
|||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Handles clearing the regions that are outside of the temporary
|
||||
* mask created by XRenderCompositeText[N] but should be affected
|
||||
* by an unbounded operator like CAIRO_OPERATOR_SOURCE.
|
||||
*/
|
||||
static void
|
||||
_show_glyphs_fixup_unbounded (cairo_xlib_surface_t *self,
|
||||
cairo_surface_attributes_t *src_attr,
|
||||
cairo_xlib_surface_t *src,
|
||||
const cairo_glyph_t *glyphs,
|
||||
glyphset_cache_entry_t **entries,
|
||||
int num_glyphs,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_surface_attributes_t mask_attr;
|
||||
int x1 = INT_MAX;
|
||||
int x2 = INT_MIN;
|
||||
int y1 = INT_MAX;
|
||||
int y2 = INT_MIN;
|
||||
int i;
|
||||
|
||||
/* Compute the size of the glyph mask as the bounding box
|
||||
* of all the glyphs.
|
||||
*/
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
int thisX, thisY;
|
||||
|
||||
if (entries[i] == NULL || !entries[i]->glyph)
|
||||
continue;
|
||||
|
||||
thisX = (int) floor (glyphs[i].x + 0.5);
|
||||
thisY = (int) floor (glyphs[i].y + 0.5);
|
||||
|
||||
if (thisX + entries[i]->size.x < x1)
|
||||
x1 = thisX + entries[i]->size.x;
|
||||
if (thisX + entries[i]->size.x + entries[i]->size.width > x2)
|
||||
x2 = thisX + entries[i]->size.x + entries[i]->size.width;
|
||||
if (thisY + entries[i]->size.y < y1)
|
||||
y1 = thisY + entries[i]->size.y;
|
||||
if (thisY + entries[i]->size.y + entries[i]->size.height > y2)
|
||||
y2 = thisY + entries[i]->size.y + entries[i]->size.height;
|
||||
}
|
||||
|
||||
if (x1 >= x2 || y1 >= y2)
|
||||
x1 = x2 = y1 = y2 = 0;
|
||||
|
||||
cairo_matrix_init_identity (&mask_attr.matrix);
|
||||
mask_attr.extend = CAIRO_EXTEND_NONE;
|
||||
mask_attr.filter = CAIRO_FILTER_NEAREST;
|
||||
mask_attr.x_offset = 0;
|
||||
mask_attr.y_offset = 0;
|
||||
|
||||
_cairo_surface_composite_fixup_unbounded (&self->base,
|
||||
src_attr, src->width, src->height,
|
||||
&mask_attr, x2 - x1, y2 - y1,
|
||||
src_x, src_y,
|
||||
dst_x - x1, dst_y - y1,
|
||||
dst_x, dst_y, width, height);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
|
||||
cairo_operator_t operator,
|
||||
|
|
@ -2462,6 +2663,13 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
|
|||
glyphs, entries, num_glyphs);
|
||||
}
|
||||
|
||||
if (!_cairo_operator_bounded (operator))
|
||||
_show_glyphs_fixup_unbounded (self,
|
||||
&attributes, src,
|
||||
glyphs, entries, num_glyphs,
|
||||
source_x, source_y,
|
||||
dest_x, dest_y, width, height);
|
||||
|
||||
UNLOCK:
|
||||
_unlock_xlib_glyphset_caches (cache);
|
||||
|
||||
|
|
|
|||
|
|
@ -879,7 +879,9 @@ struct _cairo_image_surface {
|
|||
/* libic-specific fields */
|
||||
cairo_format_t format;
|
||||
unsigned char *data;
|
||||
int owns_data;
|
||||
cairo_bool_t owns_data;
|
||||
cairo_bool_t has_clip;
|
||||
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
|
@ -1312,6 +1314,8 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
|||
int num_glyphs,
|
||||
cairo_path_fixed_t *path);
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_operator_bounded (cairo_operator_t operator);
|
||||
|
||||
/* cairo_color.c */
|
||||
cairo_private const cairo_color_t *
|
||||
|
|
@ -1695,6 +1699,23 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
|
|||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
void
|
||||
_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
|
||||
cairo_surface_attributes_t *src_attr,
|
||||
int src_width,
|
||||
int src_height,
|
||||
cairo_surface_attributes_t *mask_attr,
|
||||
int mask_width,
|
||||
int mask_height,
|
||||
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_image_surface.c */
|
||||
|
||||
cairo_private cairo_format_t
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
TESTS = \
|
||||
a8-mask \
|
||||
clip-nesting \
|
||||
clip-operator \
|
||||
clip-twice \
|
||||
composite-integer-translate-source \
|
||||
composite-integer-translate-over \
|
||||
|
|
@ -41,6 +42,7 @@ text-rotate \
|
|||
transforms \
|
||||
translate-show-surface \
|
||||
trap-clip \
|
||||
unbounded-operator \
|
||||
user-data \
|
||||
rel-path
|
||||
|
||||
|
|
@ -62,6 +64,7 @@ endif
|
|||
EXTRA_DIST = \
|
||||
a8-mask.png \
|
||||
clip-nesting-ref.png \
|
||||
clip-operator-ref.png \
|
||||
clip-twice-ref.png \
|
||||
composite-integer-translate-source-ref.png \
|
||||
composite-integer-translate-over-ref.png \
|
||||
|
|
@ -96,6 +99,7 @@ text-antialias-none-ref.png \
|
|||
transforms-ref.png \
|
||||
translate-show-surface-ref.png \
|
||||
trap-clip-ref.png \
|
||||
unbounded-operator-ref.png \
|
||||
rel-path-ref.png
|
||||
|
||||
# Any test for which the code committed to CVS is expected to fail
|
||||
|
|
@ -153,6 +157,7 @@ LDADDS = libcairotest.la $(top_builddir)/src/libcairo.la
|
|||
# from autogen.sh. My, but this is painful...
|
||||
a8_mask_LDADD = $(LDADDS)
|
||||
clip_nesting_LDADD = $(LDADDS)
|
||||
clip_operator_LDADD = $(LDADDS)
|
||||
clip_twice_LDADD = $(LDADDS)
|
||||
composite_integer_translate_source_LDADD = $(LDADDS)
|
||||
composite_integer_translate_over_LDADD = $(LDADDS)
|
||||
|
|
@ -195,6 +200,7 @@ text_rotate_LDADD = $(LDADDS)
|
|||
transforms_LDADD = $(LDADDS)
|
||||
translate_show_surface_LDADD = $(LDADDS)
|
||||
trap_clip_LDADD = $(LDADDS)
|
||||
unbounded_operator_LDADD = $(LDADDS)
|
||||
user_data_LDADD = $(LDADDS)
|
||||
rel_path_LDADD = $(LDADDS)
|
||||
xlib_surface_LDADD = $(LDADDS)
|
||||
|
|
|
|||
205
test/clip-operator.c
Normal file
205
test/clip-operator.c
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright © 2005 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of
|
||||
* Red Hat, Inc. not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Red Hat, Inc. makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Kristian Høgsberg <krh@redhat.com>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "cairo-test.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define WIDTH 64
|
||||
#define HEIGHT 64
|
||||
#define PAD 10
|
||||
|
||||
const char png_filename[] = "romedalen.png";
|
||||
|
||||
static void
|
||||
draw_mask (cairo_t *cr, int x, int y)
|
||||
{
|
||||
cairo_surface_t *mask_surface;
|
||||
cairo_t *cr2;
|
||||
|
||||
double width = (int)(0.9 * WIDTH);
|
||||
double height = (int)(0.9 * HEIGHT);
|
||||
x += 0.05 * WIDTH;
|
||||
y += 0.05 * HEIGHT;
|
||||
|
||||
mask_surface = cairo_surface_create_similar (cairo_get_target (cr),
|
||||
CAIRO_CONTENT_ALPHA,
|
||||
width, height);
|
||||
cr2 = cairo_create (mask_surface);
|
||||
|
||||
cairo_save (cr2);
|
||||
cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */
|
||||
cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
cairo_set_source_rgb (cr2, 1, 1, 1); /* white */
|
||||
|
||||
cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI);
|
||||
cairo_fill (cr2);
|
||||
|
||||
cairo_destroy (cr2);
|
||||
|
||||
cairo_mask_surface (cr, mask_surface, x, y);
|
||||
|
||||
cairo_surface_destroy (mask_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_glyphs (cairo_t *cr, int x, int y)
|
||||
{
|
||||
cairo_text_extents_t extents;
|
||||
|
||||
cairo_set_font_size (cr, 0.8 * HEIGHT);
|
||||
|
||||
cairo_text_extents (cr, "FG", &extents);
|
||||
cairo_move_to (cr,
|
||||
x + (WIDTH - extents.width) / 2 - extents.x_bearing,
|
||||
y + (HEIGHT - extents.height) / 2 - extents.y_bearing);
|
||||
cairo_show_text (cr, "FG");
|
||||
}
|
||||
|
||||
static void
|
||||
draw_polygon (cairo_t *cr, int x, int y)
|
||||
{
|
||||
double width = (int)(0.9 * WIDTH);
|
||||
double height = (int)(0.9 * HEIGHT);
|
||||
x += 0.05 * WIDTH;
|
||||
y += 0.05 * HEIGHT;
|
||||
|
||||
cairo_new_path (cr);
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_line_to (cr, x, y + height);
|
||||
cairo_line_to (cr, x + width / 2, y + 3 * height / 4);
|
||||
cairo_line_to (cr, x + width, y + height);
|
||||
cairo_line_to (cr, x + width, y);
|
||||
cairo_line_to (cr, x + width / 2, y + height / 4);
|
||||
cairo_close_path (cr);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_rects (cairo_t *cr, int x, int y)
|
||||
{
|
||||
double block_width = (int)(0.33 * WIDTH + 0.5);
|
||||
double block_height = (int)(0.33 * HEIGHT + 0.5);
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
for (j = 0; j < 3; j++)
|
||||
if ((i + j) % 2 == 0)
|
||||
cairo_rectangle (cr,
|
||||
x + block_width * i, y + block_height * j,
|
||||
block_width, block_height);
|
||||
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void (*draw_funcs[])(cairo_t *cr, int x, int y) = {
|
||||
draw_mask,
|
||||
draw_glyphs,
|
||||
draw_polygon,
|
||||
draw_rects
|
||||
};
|
||||
|
||||
#define N_OPERATORS (1 + CAIRO_OPERATOR_SATURATE - CAIRO_OPERATOR_CLEAR)
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
|
||||
#define IMAGE_WIDTH (N_OPERATORS * (WIDTH + PAD) + PAD)
|
||||
#define IMAGE_HEIGHT (ARRAY_SIZE (draw_funcs) * (HEIGHT + PAD) + PAD)
|
||||
|
||||
static cairo_test_t test = {
|
||||
"clip-operator",
|
||||
"Surface clipping with different operators",
|
||||
IMAGE_WIDTH, IMAGE_HEIGHT
|
||||
};
|
||||
|
||||
static cairo_test_status_t
|
||||
draw (cairo_t *cr, int width, int height)
|
||||
{
|
||||
int j, x, y;
|
||||
cairo_operator_t op;
|
||||
cairo_font_options_t *font_options;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
cairo_select_font_face (cr, "Bitstream Vera Sans",
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_NORMAL);
|
||||
cairo_set_font_size (cr, 0.9 * HEIGHT);
|
||||
|
||||
font_options = cairo_font_options_create ();
|
||||
|
||||
cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
|
||||
cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
|
||||
|
||||
cairo_set_font_options (cr, font_options);
|
||||
cairo_font_options_destroy (font_options);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) {
|
||||
for (op = CAIRO_OPERATOR_CLEAR; op <= CAIRO_OPERATOR_SATURATE; op++) {
|
||||
x = op * (WIDTH + PAD) + PAD;
|
||||
y = j * (HEIGHT + PAD) + PAD;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
pattern = cairo_pattern_create_linear (x + WIDTH, y,
|
||||
x, y + HEIGHT);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0.2,
|
||||
0.0, 0.0, 1.0, 1.0); /* Solid blue */
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0.8,
|
||||
0.0, 0.0, 1.0, 0.0); /* Transparent blue */
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_rectangle (cr, x, y, WIDTH, HEIGHT);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_operator (cr, op);
|
||||
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
|
||||
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_line_to (cr, x + WIDTH, y);
|
||||
cairo_line_to (cr, x, y + HEIGHT);
|
||||
cairo_clip (cr);
|
||||
|
||||
draw_funcs[j] (cr, x, y);
|
||||
if (cairo_status (cr))
|
||||
cairo_test_log ("%d %d HERE!\n", op, j);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
}
|
||||
|
||||
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
|
||||
cairo_test_log ("%d %d .HERE!\n", op, j);
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return cairo_test (&test, draw);
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ draw (cairo_t *cr, int width, int height)
|
|||
cairo_fill (cr);
|
||||
|
||||
cairo_translate (cr, OFFSET, OFFSET);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_set_source (cr, pat);
|
||||
cairo_rectangle (cr, 0, 0, SIZE - OFFSET, SIZE - OFFSET);
|
||||
cairo_fill (cr);
|
||||
|
|
|
|||
201
test/unbounded-operator.c
Normal file
201
test/unbounded-operator.c
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright © 2005 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of
|
||||
* Red Hat, Inc. not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Red Hat, Inc. makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Authors: Kristian Høgsberg <krh@redhat.com>
|
||||
* Owen Taylor <otaylor@redhat.com>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "cairo-test.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define WIDTH 64
|
||||
#define HEIGHT 64
|
||||
#define PAD 10
|
||||
|
||||
static void
|
||||
draw_mask (cairo_t *cr, int x, int y)
|
||||
{
|
||||
cairo_surface_t *mask_surface;
|
||||
cairo_t *cr2;
|
||||
|
||||
double width = (int)(0.9 * WIDTH);
|
||||
double height = (int)(0.9 * HEIGHT);
|
||||
x += 0.05 * WIDTH;
|
||||
y += 0.05 * HEIGHT;
|
||||
|
||||
mask_surface = cairo_surface_create_similar (cairo_get_target (cr),
|
||||
CAIRO_CONTENT_ALPHA,
|
||||
width, height);
|
||||
cr2 = cairo_create (mask_surface);
|
||||
|
||||
cairo_save (cr2);
|
||||
cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */
|
||||
cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
cairo_set_source_rgb (cr2, 1, 1, 1); /* white */
|
||||
|
||||
cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI);
|
||||
cairo_fill (cr2);
|
||||
|
||||
cairo_destroy (cr2);
|
||||
|
||||
cairo_mask_surface (cr, mask_surface, x, y);
|
||||
|
||||
cairo_surface_destroy (mask_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_glyphs (cairo_t *cr, int x, int y)
|
||||
{
|
||||
cairo_text_extents_t extents;
|
||||
|
||||
cairo_set_font_size (cr, 0.8 * HEIGHT);
|
||||
|
||||
cairo_text_extents (cr, "FG", &extents);
|
||||
cairo_move_to (cr,
|
||||
x + (WIDTH - extents.width) / 2 - extents.x_bearing,
|
||||
y + (HEIGHT - extents.height) / 2 - extents.y_bearing);
|
||||
cairo_show_text (cr, "FG");
|
||||
}
|
||||
|
||||
static void
|
||||
draw_polygon (cairo_t *cr, int x, int y)
|
||||
{
|
||||
double width = (int)(0.9 * WIDTH);
|
||||
double height = (int)(0.9 * HEIGHT);
|
||||
x += 0.05 * WIDTH;
|
||||
y += 0.05 * HEIGHT;
|
||||
|
||||
cairo_new_path (cr);
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_line_to (cr, x, y + height);
|
||||
cairo_line_to (cr, x + width / 2, y + 3 * height / 4);
|
||||
cairo_line_to (cr, x + width, y + height);
|
||||
cairo_line_to (cr, x + width, y);
|
||||
cairo_line_to (cr, x + width / 2, y + height / 4);
|
||||
cairo_close_path (cr);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_rects (cairo_t *cr, int x, int y)
|
||||
{
|
||||
double block_width = (int)(0.33 * WIDTH + 0.5);
|
||||
double block_height = (int)(0.33 * HEIGHT + 0.5);
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
for (j = 0; j < 3; j++)
|
||||
if ((i + j) % 2 == 0)
|
||||
cairo_rectangle (cr,
|
||||
x + block_width * i, y + block_height * j,
|
||||
block_width, block_height);
|
||||
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void (*draw_funcs[])(cairo_t *cr, int x, int y) = {
|
||||
draw_mask,
|
||||
draw_glyphs,
|
||||
draw_polygon,
|
||||
draw_rects
|
||||
};
|
||||
|
||||
static cairo_operator_t operators[] = {
|
||||
CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SOURCE, CAIRO_OPERATOR_IN,
|
||||
CAIRO_OPERATOR_OUT, CAIRO_OPERATOR_DEST_IN, CAIRO_OPERATOR_DEST_ATOP
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
|
||||
#define IMAGE_WIDTH (ARRAY_SIZE (operators) * (WIDTH + PAD) + PAD)
|
||||
#define IMAGE_HEIGHT (ARRAY_SIZE (draw_funcs) * (HEIGHT + PAD) + PAD)
|
||||
|
||||
static cairo_test_t test = {
|
||||
"unbounded-operator",
|
||||
"Operators with an effect for transparent source/mask",
|
||||
IMAGE_WIDTH, IMAGE_HEIGHT
|
||||
};
|
||||
|
||||
static cairo_test_status_t
|
||||
draw (cairo_t *cr, int width, int height)
|
||||
{
|
||||
int i, j, x, y;
|
||||
cairo_font_options_t *font_options;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
cairo_select_font_face (cr, "Bitstream Vera Sans",
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_NORMAL);
|
||||
|
||||
font_options = cairo_font_options_create ();
|
||||
|
||||
cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
|
||||
cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
|
||||
|
||||
cairo_set_font_options (cr, font_options);
|
||||
cairo_font_options_destroy (font_options);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) {
|
||||
for (i = 0; i < ARRAY_SIZE (operators); i++) {
|
||||
x = i * (WIDTH + PAD) + PAD;
|
||||
y = j * (HEIGHT + PAD) + PAD;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
pattern = cairo_pattern_create_linear (x + WIDTH, y,
|
||||
x, y + HEIGHT);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0.2,
|
||||
0.0, 0.0, 1.0, 1.0); /* Solid blue */
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0.8,
|
||||
0.0, 0.0, 1.0, 0.0); /* Transparent blue */
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_rectangle (cr, x, y, WIDTH, HEIGHT);
|
||||
cairo_fill_preserve (cr);
|
||||
cairo_clip (cr);
|
||||
|
||||
cairo_set_operator (cr, operators[i]);
|
||||
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
|
||||
|
||||
draw_funcs[j] (cr, x, y);
|
||||
if (cairo_status (cr))
|
||||
cairo_test_log ("%d %d HERE!\n", i, j);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
}
|
||||
|
||||
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
|
||||
cairo_test_log ("%d %d .HERE!\n", i, j);
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return cairo_test (&test, draw);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue