surface-fallback: Convert to composite rectangles

This commit is contained in:
Chris Wilson 2010-01-22 17:56:26 +00:00
parent 498c10032e
commit b713510f21
4 changed files with 155 additions and 288 deletions

View file

@ -40,12 +40,13 @@
#include "cairoint.h"
#include "cairo-surface-fallback-private.h"
#include "cairo-boxes-private.h"
#include "cairo-clip-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-spans-private.h"
#include "cairo-surface-fallback-private.h"
typedef struct {
cairo_surface_t *dst;
@ -894,85 +895,51 @@ _composite_spans_draw_func (void *closure,
clip_region);
}
static cairo_status_t
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
{
if (clip != NULL) {
if (! _cairo_rectangle_intersect (extents,
_cairo_clip_get_extents (clip)))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
return _cairo_clip_rectangle (clip, extents);
} else if (_cairo_rectangle_empty (extents))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
_clip_contains_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect)
box_is_aligned (const cairo_box_t *box)
{
cairo_clip_path_t *clip_path;
clip_path = clip->path;
if (clip_path->extents.x > rect->x ||
clip_path->extents.y > rect->y ||
clip_path->extents.x + clip_path->extents.width < rect->x + rect->width ||
clip_path->extents.y + clip_path->extents.height < rect->y + rect->height)
{
return FALSE;
}
do {
cairo_box_t box;
if (! _cairo_path_fixed_is_box (&clip_path->path, &box))
return FALSE;
if (box.p1.x > _cairo_fixed_from_int (rect->x) ||
box.p1.y > _cairo_fixed_from_int (rect->y) ||
box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) ||
box.p2.y < _cairo_fixed_from_int (rect->y + rect->height))
{
return FALSE;
}
} while ((clip_path = clip_path->prev) != NULL);
return TRUE;
return
_cairo_fixed_is_integer (box->p1.x) &&
_cairo_fixed_is_integer (box->p1.y) &&
_cairo_fixed_is_integer (box->p2.x) &&
_cairo_fixed_is_integer (box->p2.y);
}
static inline cairo_status_t
_clip_to_boxes (cairo_clip_t **clip,
const cairo_rectangle_int_t *extents,
cairo_bool_t is_bounded,
const cairo_composite_rectangles_t *extents,
cairo_box_t **boxes,
int *num_boxes)
{
cairo_status_t status;
const cairo_rectangle_int_t *rect;
if (*clip == NULL) {
status = CAIRO_STATUS_SUCCESS;
rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
if (*clip == NULL)
goto EXTENTS;
}
status = _cairo_clip_rectangle (*clip, rect);
if (unlikely (status))
return status;
status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
switch ((int) status) {
case CAIRO_STATUS_SUCCESS:
if (is_bounded)
if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
*clip = NULL;
goto DONE;
case CAIRO_INT_STATUS_UNSUPPORTED:
status = CAIRO_STATUS_SUCCESS;
case CAIRO_INT_STATUS_UNSUPPORTED:
goto EXTENTS;
default:
return status;
}
EXTENTS:
_cairo_box_from_rectangle (&(*boxes)[0], extents);
status = CAIRO_STATUS_SUCCESS;
_cairo_box_from_rectangle (&(*boxes)[0], rect);
*num_boxes = 1;
DONE:
return status;
@ -984,44 +951,32 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_clip_path_t *clip_path = clip ? clip->path : NULL;
cairo_box_t boxes_stack[32], *boxes = boxes_stack;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
cairo_boxes_t boxes;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_status_t status;
cairo_traps_t traps;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded || clip);
extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
assert (extents.is_bounded || clip);
is_bounded = FALSE;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_composite_rectangles_init_for_paint (&extents,
rect.width,
rect.height,
op, source,
clip);
if (unlikely (status))
return status;
_cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
status = _rectangle_intersect_clip (&extents, clip);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status))
return status;
}
status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
return status;
}
/* If the clip cannot be reduced to a set of boxes, we will need to
* use a clipmask. Paint is special as it is the only operation that
@ -1039,18 +994,20 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface,
NULL);
}
status = _cairo_traps_init_boxes (&traps, boxes, num_boxes);
/* meh, surface-fallback is dying anyway... */
_cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
status = _cairo_traps_init_boxes (&traps, &boxes);
if (unlikely (status))
goto CLEANUP_BOXES;
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, CAIRO_ANTIALIAS_DEFAULT,
clip, &extents);
clip, &extents.bounded);
_cairo_traps_fini (&traps);
CLEANUP_BOXES:
if (boxes != boxes_stack)
free (boxes);
if (clip_boxes != boxes_stack)
free (clip_boxes);
return status;
}
@ -1093,48 +1050,32 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded || clip);
extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
assert (extents.is_bounded || clip);
is_bounded = FALSE;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_composite_rectangles_init_for_mask (&extents,
rect.width, rect.height,
op, source, mask, clip);
if (unlikely (status))
return status;
_cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
_cairo_pattern_get_extents (mask, &mask_extents);
if (! _cairo_rectangle_intersect (&extents, &mask_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
status = _rectangle_intersect_clip (&extents, clip);
if (status) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
return status;
if (clip != NULL && extents.is_bounded) {
status = _cairo_clip_rectangle (clip, &extents.bounded);
if (unlikely (status))
return status;
}
return _clip_and_composite (clip, op, source,
_cairo_surface_mask_draw_func,
(void *) mask,
surface, &extents);
surface, &extents.bounded);
}
cairo_status_t
@ -1151,60 +1092,36 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
{
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_box_t boxes_stack[32], *boxes = boxes_stack;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded || clip);
extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
assert (extents.is_bounded || clip);
is_bounded = FALSE;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_composite_rectangles_init_for_stroke (&extents,
rect.width,
rect.height,
op, source,
path, stroke_style, ctm,
clip);
if (unlikely (status))
return status;
_cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t path_extents;
_cairo_path_fixed_approximate_stroke_extents (path,
stroke_style, ctm,
&path_extents);
if (! _cairo_rectangle_intersect (&extents, &path_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
status = _rectangle_intersect_clip (&extents, clip);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status))
return status;
}
status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
return status;
}
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, boxes, num_boxes);
_cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, boxes, num_boxes);
_cairo_traps_limit (&traps, clip_boxes, num_boxes);
if (path->is_rectilinear) {
status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
@ -1230,10 +1147,8 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
goto DO_TRAPS;
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t polygon_extents;
_cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents);
if (! _cairo_rectangle_intersect (&extents, &polygon_extents))
_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
goto CLEANUP;
}
@ -1246,7 +1161,7 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
status = _clip_and_composite (clip, op, source,
_composite_spans_draw_func,
&info, surface, &extents);
&info, surface, &extents.bounded);
goto CLEANUP;
}
@ -1260,12 +1175,12 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
DO_TRAPS:
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, antialias,
clip, &extents);
clip, &extents.bounded);
CLEANUP:
_cairo_traps_fini (&traps);
_cairo_polygon_fini (&polygon);
if (boxes != boxes_stack)
free (boxes);
if (clip_boxes != boxes_stack)
free (clip_boxes);
return status;
}
@ -1282,67 +1197,36 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
{
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_box_t boxes_stack[32], *boxes = boxes_stack;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
cairo_bool_t is_rectilinear;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded || clip);
extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
assert (extents.is_bounded || clip);
is_bounded = FALSE;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
_cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t path_extents;
_cairo_path_fixed_approximate_fill_extents (path, &path_extents);
if (! _cairo_rectangle_intersect (&extents, &path_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (is_bounded) {
if (clip != NULL && _clip_contains_rectangle (clip, &extents))
clip = NULL;
if (clip != NULL && clip->path->prev == NULL &&
_cairo_path_fixed_equal (&clip->path->path, path))
{
clip = NULL;
}
}
status = _rectangle_intersect_clip (&extents, clip);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
status = _cairo_composite_rectangles_init_for_fill (&extents,
rect.width,
rect.height,
op, source, path,
clip);
if (unlikely (status))
return status;
}
status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status))
return status;
}
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, boxes, num_boxes);
_cairo_traps_limit (&traps, clip_boxes, num_boxes);
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, boxes, num_boxes);
_cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
if (path->is_empty_fill)
goto DO_TRAPS;
@ -1367,10 +1251,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
goto DO_TRAPS;
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t polygon_extents;
_cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents);
if (! _cairo_rectangle_intersect (&extents, &polygon_extents))
_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
goto CLEANUP;
}
@ -1395,7 +1277,7 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
status = _clip_and_composite (clip, op, source,
_composite_spans_draw_func,
&info, surface, &extents);
&info, surface, &extents.bounded);
goto CLEANUP;
}
@ -1409,12 +1291,12 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
DO_TRAPS:
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, antialias,
clip, &extents);
clip, &extents.bounded);
CLEANUP:
_cairo_traps_fini (&traps);
_cairo_polygon_fini (&polygon);
if (boxes != boxes_stack)
free (boxes);
if (clip_boxes != boxes_stack)
free (clip_boxes);
return status;
}
@ -1485,50 +1367,32 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_show_glyphs_info_t glyph_info;
cairo_bool_t is_bounded;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded || clip);
extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
assert (extents.is_bounded || clip);
is_bounded = FALSE;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
_cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t glyph_extents;
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents,
status = _cairo_composite_rectangles_init_for_glyphs (&extents,
rect.width,
rect.height,
op, source,
scaled_font,
glyphs, num_glyphs,
clip,
NULL);
if (unlikely (status))
return status;
if (unlikely (status))
return status;
if (! _cairo_rectangle_intersect (&extents, &glyph_extents))
return CAIRO_STATUS_SUCCESS;
is_bounded = TRUE;
}
if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
status = _rectangle_intersect_clip (&extents, clip);
if (status) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
return status;
if (clip != NULL && extents.is_bounded) {
status = _cairo_clip_rectangle (clip, &extents.bounded);
if (unlikely (status))
return status;
}
glyph_info.font = scaled_font;
@ -1539,7 +1403,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
_cairo_surface_old_show_glyphs_draw_func,
&glyph_info,
surface,
&extents);
&extents.bounded);
}
cairo_surface_t *

View file

@ -121,6 +121,9 @@ cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status)
{
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
return status;

View file

@ -39,6 +39,7 @@
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-slope-private.h"
@ -157,45 +158,45 @@ _cairo_traps_add_trap (cairo_traps_t *traps,
**/
cairo_status_t
_cairo_traps_init_boxes (cairo_traps_t *traps,
const cairo_box_t *boxes,
int num_boxes)
const cairo_boxes_t *boxes)
{
cairo_trapezoid_t *trap;
const struct _cairo_boxes_chunk *chunk;
_cairo_traps_init (traps);
while (traps->traps_size < num_boxes) {
while (traps->traps_size < boxes->num_boxes) {
if (unlikely (! _cairo_traps_grow (traps))) {
_cairo_traps_fini (traps);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
}
traps->num_traps = num_boxes;
traps->num_traps = boxes->num_boxes;
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
traps->maybe_region = boxes->is_pixel_aligned;
trap = &traps->traps[0];
while (num_boxes--) {
trap->top = boxes->p1.y;
trap->bottom = boxes->p2.y;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box;
int i;
trap->left.p1 = boxes->p1;
trap->left.p2.x = boxes->p1.x;
trap->left.p2.y = boxes->p2.y;
box = chunk->base;
for (i = 0; i < chunk->count; i++) {
trap->top = box->p1.y;
trap->bottom = box->p2.y;
trap->right.p1.x = boxes->p2.x;
trap->right.p1.y = boxes->p1.y;
trap->right.p2 = boxes->p2;
trap->left.p1 = box->p1;
trap->left.p2.x = box->p1.x;
trap->left.p2.y = box->p2.y;
if (traps->maybe_region) {
traps->maybe_region = _cairo_fixed_is_integer (boxes->p1.x) &&
_cairo_fixed_is_integer (boxes->p1.y) &&
_cairo_fixed_is_integer (boxes->p2.x) &&
_cairo_fixed_is_integer (boxes->p2.y);
trap->right.p1.x = box->p2.x;
trap->right.p1.y = box->p1.y;
trap->right.p2 = box->p2;
box++, trap++;
}
trap++, boxes++;
}
return CAIRO_STATUS_SUCCESS;

View file

@ -2377,8 +2377,7 @@ _cairo_traps_limit (cairo_traps_t *traps,
cairo_private cairo_status_t
_cairo_traps_init_boxes (cairo_traps_t *traps,
const cairo_box_t *boxes,
int num_boxes);
const cairo_boxes_t *boxes);
cairo_private void
_cairo_traps_clear (cairo_traps_t *traps);