#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#define CONST_CAST (pixman_region32_t *)
static const cairo_region_t _cairo_region_nil = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_NO_MEMORY,
};
cairo_region_t *
_cairo_region_create_in_error (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_region_t *) &_cairo_region_nil;
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_STATUS:
case CAIRO_STATUS_INVALID_CONTENT:
case CAIRO_STATUS_INVALID_FORMAT:
case CAIRO_STATUS_INVALID_VISUAL:
case CAIRO_STATUS_READ_ERROR:
case CAIRO_STATUS_WRITE_ERROR:
case CAIRO_STATUS_FILE_NOT_FOUND:
case CAIRO_STATUS_TEMP_FILE_ERROR:
case CAIRO_STATUS_INVALID_STRIDE:
case CAIRO_STATUS_INVALID_SIZE:
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
case CAIRO_STATUS_DEVICE_ERROR:
case CAIRO_STATUS_INVALID_RESTORE:
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
case CAIRO_STATUS_SURFACE_FINISHED:
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_DASH:
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
case CAIRO_STATUS_INVALID_SLANT:
case CAIRO_STATUS_INVALID_WEIGHT:
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
}
static cairo_status_t
_cairo_region_set_error (cairo_region_t *region,
cairo_status_t status)
{
if (! _cairo_status_is_error (status))
return status;
_cairo_status_set_error (®ion->status, status);
return _cairo_error (status);
}
void
_cairo_region_init (cairo_region_t *region)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0);
pixman_region32_init (®ion->rgn);
}
void
_cairo_region_init_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *rectangle)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0);
pixman_region32_init_rect (®ion->rgn,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
}
void
_cairo_region_fini (cairo_region_t *region)
{
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
pixman_region32_fini (®ion->rgn);
VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
}
cairo_region_t *
cairo_region_create (void)
{
cairo_region_t *region;
region = _cairo_malloc (sizeof (cairo_region_t));
if (region == NULL)
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1);
pixman_region32_init (®ion->rgn);
return region;
}
slim_hidden_def (cairo_region_create);
cairo_region_t *
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count)
{
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pboxes = stack_pboxes;
cairo_region_t *region;
int i;
region = _cairo_malloc (sizeof (cairo_region_t));
if (unlikely (region == NULL))
return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
if (count > ARRAY_LENGTH (stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
if (unlikely (pboxes == NULL)) {
free (region);
return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
for (i = 0; i < count; i++) {
pboxes[i].x1 = rects[i].x;
pboxes[i].y1 = rects[i].y;
pboxes[i].x2 = rects[i].x + rects[i].width;
pboxes[i].y2 = rects[i].y + rects[i].height;
}
i = pixman_region32_init_rects (®ion->rgn, pboxes, count);
if (pboxes != stack_pboxes)
free (pboxes);
if (unlikely (i == 0)) {
free (region);
return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1);
region->status = CAIRO_STATUS_SUCCESS;
return region;
}
slim_hidden_def (cairo_region_create_rectangles);
cairo_region_t *
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
{
cairo_region_t *region;
region = _cairo_malloc (sizeof (cairo_region_t));
if (unlikely (region == NULL))
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1);
pixman_region32_init_rect (®ion->rgn,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
return region;
}
slim_hidden_def (cairo_region_create_rectangle);
cairo_region_t *
cairo_region_copy (const cairo_region_t *original)
{
cairo_region_t *copy;
if (original != NULL && original->status)
return (cairo_region_t *) &_cairo_region_nil;
copy = cairo_region_create ();
if (unlikely (copy->status))
return copy;
if (original != NULL &&
! pixman_region32_copy (©->rgn, CONST_CAST &original->rgn))
{
cairo_region_destroy (copy);
return (cairo_region_t *) &_cairo_region_nil;
}
return copy;
}
slim_hidden_def (cairo_region_copy);
cairo_region_t *
cairo_region_reference (cairo_region_t *region)
{
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count))
return NULL;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
_cairo_reference_count_inc (®ion->ref_count);
return region;
}
slim_hidden_def (cairo_region_reference);
void
cairo_region_destroy (cairo_region_t *region)
{
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count))
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
if (! _cairo_reference_count_dec_and_test (®ion->ref_count))
return;
_cairo_region_fini (region);
free (region);
}
slim_hidden_def (cairo_region_destroy);
int
cairo_region_num_rectangles (const cairo_region_t *region)
{
if (region->status)
return 0;
return pixman_region32_n_rects (CONST_CAST ®ion->rgn);
}
slim_hidden_def (cairo_region_num_rectangles);
void
cairo_region_get_rectangle (const cairo_region_t *region,
int nth,
cairo_rectangle_int_t *rectangle)
{
pixman_box32_t *pbox;
if (region->status) {
rectangle->x = rectangle->y = 0;
rectangle->width = rectangle->height = 0;
return;
}
pbox = pixman_region32_rectangles (CONST_CAST ®ion->rgn, NULL) + nth;
rectangle->x = pbox->x1;
rectangle->y = pbox->y1;
rectangle->width = pbox->x2 - pbox->x1;
rectangle->height = pbox->y2 - pbox->y1;
}
slim_hidden_def (cairo_region_get_rectangle);
void
cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents)
{
pixman_box32_t *pextents;
if (region->status) {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
return;
}
pextents = pixman_region32_extents (CONST_CAST ®ion->rgn);
extents->x = pextents->x1;
extents->y = pextents->y1;
extents->width = pextents->x2 - pextents->x1;
extents->height = pextents->y2 - pextents->y1;
}
slim_hidden_def (cairo_region_get_extents);
cairo_status_t
cairo_region_status (const cairo_region_t *region)
{
return region->status;
}
slim_hidden_def (cairo_region_status);
cairo_status_t
cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
{
if (dst->status)
return dst->status;
if (other->status)
return _cairo_region_set_error (dst, other->status);
if (! pixman_region32_subtract (&dst->rgn,
&dst->rgn,
CONST_CAST &other->rgn))
{
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
}
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_region_subtract);
cairo_status_t
cairo_region_subtract_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region;
if (dst->status)
return dst->status;
pixman_region32_init_rect (®ion,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (®ion);
return status;
}
slim_hidden_def (cairo_region_subtract_rectangle);
cairo_status_t
cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
{
if (dst->status)
return dst->status;
if (other->status)
return _cairo_region_set_error (dst, other->status);
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_region_intersect);
cairo_status_t
cairo_region_intersect_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region;
if (dst->status)
return dst->status;
pixman_region32_init_rect (®ion,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, ®ion))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (®ion);
return status;
}
slim_hidden_def (cairo_region_intersect_rectangle);
cairo_status_t
cairo_region_union (cairo_region_t *dst,
const cairo_region_t *other)
{
if (dst->status)
return dst->status;
if (other->status)
return _cairo_region_set_error (dst, other->status);
if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_region_union);
cairo_status_t
cairo_region_union_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region;
if (dst->status)
return dst->status;
pixman_region32_init_rect (®ion,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
if (! pixman_region32_union (&dst->rgn, &dst->rgn, ®ion))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (®ion);
return status;
}
slim_hidden_def (cairo_region_union_rectangle);
cairo_status_t
cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t tmp;
if (dst->status)
return dst->status;
if (other->status)
return _cairo_region_set_error (dst, other->status);
pixman_region32_init (&tmp);
if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) ||
! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (&tmp);
return status;
}
slim_hidden_def (cairo_region_xor);
cairo_status_t
cairo_region_xor_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region, tmp;
if (dst->status)
return dst->status;
pixman_region32_init_rect (®ion,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
pixman_region32_init (&tmp);
if (! pixman_region32_subtract (&tmp, ®ion, &dst->rgn) ||
! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion) ||
! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (&tmp);
pixman_region32_fini (®ion);
return status;
}
slim_hidden_def (cairo_region_xor_rectangle);
cairo_bool_t
cairo_region_is_empty (const cairo_region_t *region)
{
if (region->status)
return TRUE;
return ! pixman_region32_not_empty (CONST_CAST ®ion->rgn);
}
slim_hidden_def (cairo_region_is_empty);
void
cairo_region_translate (cairo_region_t *region,
int dx, int dy)
{
if (region->status)
return;
pixman_region32_translate (®ion->rgn, dx, dy);
}
slim_hidden_def (cairo_region_translate);
cairo_region_overlap_t
cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle)
{
pixman_box32_t pbox;
pixman_region_overlap_t poverlap;
if (region->status)
return CAIRO_REGION_OVERLAP_OUT;
pbox.x1 = rectangle->x;
pbox.y1 = rectangle->y;
pbox.x2 = rectangle->x + rectangle->width;
pbox.y2 = rectangle->y + rectangle->height;
poverlap = pixman_region32_contains_rectangle (CONST_CAST ®ion->rgn,
&pbox);
switch (poverlap) {
default:
case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
case PIXMAN_REGION_IN: return CAIRO_REGION_OVERLAP_IN;
case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
}
}
slim_hidden_def (cairo_region_contains_rectangle);
cairo_bool_t
cairo_region_contains_point (const cairo_region_t *region,
int x, int y)
{
pixman_box32_t box;
if (region->status)
return FALSE;
return pixman_region32_contains_point (CONST_CAST ®ion->rgn, x, y, &box);
}
slim_hidden_def (cairo_region_contains_point);
cairo_bool_t
cairo_region_equal (const cairo_region_t *a,
const cairo_region_t *b)
{
if ((a != NULL && a->status) || (b != NULL && b->status))
return FALSE;
if (a == b)
return TRUE;
if (a == NULL || b == NULL)
return FALSE;
return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
}
slim_hidden_def (cairo_region_equal);