mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 02:58:02 +02:00
Add clip getters API + tests
Add new public API methods:
void cairo_clip_extents (cairo_t *cr, double *x1, double *y1,
double *x2, double *y2);
cairo_rectangle_list_t *cairo_copy_clip_rectangles (cairo_t *);
void cairo_rectangle_list_destroy (cairo_rectangle_list_t *);
Also add 'get-clip' and 'get-path-extents' tests.
This commit is contained in:
parent
a8ca155f83
commit
191e108b93
10 changed files with 753 additions and 2 deletions
|
|
@ -38,6 +38,8 @@
|
|||
|
||||
#include "cairo-path-fixed-private.h"
|
||||
|
||||
extern cairo_private const cairo_rectangle_list_t _cairo_rectangles_nil;
|
||||
|
||||
struct _cairo_clip_path {
|
||||
unsigned int ref_count;
|
||||
cairo_path_fixed_t path;
|
||||
|
|
@ -124,4 +126,7 @@ _cairo_clip_translate (cairo_clip_t *clip,
|
|||
cairo_fixed_t tx,
|
||||
cairo_fixed_t ty);
|
||||
|
||||
cairo_private cairo_rectangle_list_t*
|
||||
_cairo_clip_copy_rectangles (cairo_clip_t *clip, cairo_gstate_t *gstate);
|
||||
|
||||
#endif /* CAIRO_CLIP_PRIVATE_H */
|
||||
|
|
|
|||
127
src/cairo-clip.c
127
src/cairo-clip.c
|
|
@ -118,6 +118,39 @@ _cairo_clip_reset (cairo_clip_t *clip)
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
|
||||
cairo_rectangle_int16_t *rectangle)
|
||||
{
|
||||
while (clip_path) {
|
||||
cairo_status_t status;
|
||||
cairo_traps_t traps;
|
||||
cairo_box_t extents;
|
||||
cairo_rectangle_int16_t extents_rect;
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
|
||||
status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
|
||||
clip_path->fill_rule,
|
||||
clip_path->tolerance,
|
||||
&traps);
|
||||
if (status) {
|
||||
_cairo_traps_fini (&traps);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_traps_extents (&traps, &extents);
|
||||
_cairo_box_round_to_rectangle (&extents, &extents_rect);
|
||||
_cairo_rectangle_intersect (rectangle, &extents_rect);
|
||||
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
clip_path = clip_path->prev;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
|
||||
cairo_rectangle_int16_t *rectangle)
|
||||
|
|
@ -126,7 +159,12 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (clip->path) {
|
||||
/* Intersect path extents here. */
|
||||
cairo_status_t status;
|
||||
|
||||
status = _cairo_clip_path_intersect_to_rectangle (clip->path,
|
||||
rectangle);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (clip->region) {
|
||||
|
|
@ -534,3 +572,90 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const cairo_rectangle_list_t _cairo_rectangles_nil =
|
||||
{ CAIRO_STATUS_NO_MEMORY, NULL, 0 };
|
||||
static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
|
||||
{ CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_clip_rect_to_user (cairo_gstate_t *gstate,
|
||||
double x, double y, double width, double height,
|
||||
cairo_rectangle_t *rectangle)
|
||||
{
|
||||
double x2 = x + width;
|
||||
double y2 = y + height;
|
||||
cairo_bool_t is_tight;
|
||||
|
||||
_cairo_gstate_backend_to_user_rectangle (gstate, &x, &y, &x2, &y2, &is_tight);
|
||||
rectangle->x = x;
|
||||
rectangle->y = y;
|
||||
rectangle->width = x2 - x;
|
||||
rectangle->height = y2 - y;
|
||||
return is_tight;
|
||||
}
|
||||
|
||||
cairo_private cairo_rectangle_list_t*
|
||||
_cairo_clip_copy_rectangles (cairo_clip_t *clip, cairo_gstate_t *gstate)
|
||||
{
|
||||
cairo_rectangle_list_t *list;
|
||||
cairo_rectangle_t *rectangles;
|
||||
int n_boxes;
|
||||
|
||||
if (clip->path || clip->surface)
|
||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
|
||||
|
||||
n_boxes = clip->region ? pixman_region_num_rects (clip->region) : 1;
|
||||
rectangles = malloc (sizeof (cairo_rectangle_t)*n_boxes);
|
||||
if (rectangles == NULL)
|
||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
|
||||
|
||||
if (clip->region) {
|
||||
pixman_box16_t *boxes;
|
||||
int i;
|
||||
|
||||
boxes = pixman_region_rects (clip->region);
|
||||
for (i = 0; i < n_boxes; ++i) {
|
||||
if (!_cairo_clip_rect_to_user(gstate, boxes[i].x1, boxes[i].y1,
|
||||
boxes[i].x2 - boxes[i].x1,
|
||||
boxes[i].y2 - boxes[i].y1,
|
||||
&rectangles[i])) {
|
||||
free (rectangles);
|
||||
return (cairo_rectangle_list_t*)
|
||||
&_cairo_rectangles_not_representable;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cairo_rectangle_int16_t extents;
|
||||
_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents);
|
||||
if (!_cairo_clip_rect_to_user(gstate, extents.x, extents.y,
|
||||
extents.width, extents.height,
|
||||
rectangles)) {
|
||||
free (rectangles);
|
||||
return (cairo_rectangle_list_t*)
|
||||
&_cairo_rectangles_not_representable;
|
||||
}
|
||||
}
|
||||
|
||||
list = malloc (sizeof (cairo_rectangle_list_t));
|
||||
if (list == NULL) {
|
||||
free (rectangles);
|
||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
|
||||
}
|
||||
|
||||
list->status = CAIRO_STATUS_SUCCESS;
|
||||
list->rectangles = rectangles;
|
||||
list->num_rectangles = n_boxes;
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
|
||||
{
|
||||
if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
|
||||
rectangle_list == &_cairo_rectangles_not_representable)
|
||||
return;
|
||||
|
||||
free (rectangle_list->rectangles);
|
||||
free (rectangle_list);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1148,6 +1148,40 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
|||
gstate->antialias, gstate->target);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
|
||||
double *x1,
|
||||
double *y1,
|
||||
double *x2,
|
||||
double *y2)
|
||||
{
|
||||
cairo_rectangle_int16_t extents;
|
||||
cairo_status_t status;
|
||||
|
||||
status = _cairo_surface_get_extents (gstate->target, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*x1 = extents.x;
|
||||
*y1 = extents.y;
|
||||
*x2 = extents.x + extents.width;
|
||||
*y2 = extents.y + extents.height;
|
||||
|
||||
_cairo_gstate_backend_to_user_rectangle (gstate, x1, y1, x2, y2, NULL);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_rectangle_list_t*
|
||||
_cairo_gstate_copy_clip_rectangles (cairo_gstate_t *gstate)
|
||||
{
|
||||
return _cairo_clip_copy_rectangles (&gstate->clip, gstate);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
|
||||
{
|
||||
|
|
|
|||
63
src/cairo.c
63
src/cairo.c
|
|
@ -2208,6 +2208,67 @@ cairo_reset_clip (cairo_t *cr)
|
|||
_cairo_set_error (cr, cr->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_clip_extents:
|
||||
* @cr: a cairo context
|
||||
* @x1: left of the resulting extents
|
||||
* @y1: top of the resulting extents
|
||||
* @x2: right of the resulting extents
|
||||
* @y2: bottom of the resulting extents
|
||||
*
|
||||
* Computes a bounding box in user coordinates covering the area inside the
|
||||
* current clip.
|
||||
**/
|
||||
void
|
||||
cairo_clip_extents (cairo_t *cr,
|
||||
double *x1, double *y1,
|
||||
double *x2, double *y2)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2);
|
||||
if (cr->status)
|
||||
_cairo_set_error (cr, cr->status);
|
||||
}
|
||||
|
||||
static cairo_rectangle_list_t *
|
||||
_cairo_rectangle_list_create_for_status (cairo_status_t status)
|
||||
{
|
||||
cairo_rectangle_list_t *list;
|
||||
|
||||
list = malloc (sizeof (cairo_rectangle_list_t));
|
||||
if (list == NULL)
|
||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
|
||||
list->status = status;
|
||||
list->rectangles = NULL;
|
||||
list->num_rectangles = 0;
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_copy_clip_rectangles:
|
||||
*
|
||||
* Returns the current clip region as a list of rectangles in user coordinates.
|
||||
* Never returns %NULL.
|
||||
*
|
||||
* The status in the list may be CAIRO_STATUS_CLIP_NOT_REPRESENTABLE to
|
||||
* indicate that the clip region cannot be represented as a list of
|
||||
* user-space rectangles. The status may have other values to indicate
|
||||
* other errors.
|
||||
*
|
||||
* The caller must always call cairo_rectangle_list_destroy on the result of
|
||||
* this function.
|
||||
**/
|
||||
cairo_rectangle_list_t *
|
||||
cairo_copy_clip_rectangles (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return _cairo_rectangle_list_create_for_status (cr->status);
|
||||
|
||||
return _cairo_gstate_copy_clip_rectangles (cr->gstate);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_select_font_face:
|
||||
* @cr: a #cairo_t
|
||||
|
|
@ -3097,6 +3158,8 @@ cairo_status_to_string (cairo_status_t status)
|
|||
return "invalid value for a DSC comment";
|
||||
case CAIRO_STATUS_INVALID_INDEX:
|
||||
return "invalid index passed to getter";
|
||||
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
|
||||
return "clip region not representable in desired format";
|
||||
}
|
||||
|
||||
return "<unknown error status>";
|
||||
|
|
|
|||
36
src/cairo.h
36
src/cairo.h
|
|
@ -170,6 +170,7 @@ typedef struct _cairo_user_data_key {
|
|||
* @CAIRO_STATUS_INVALID_DASH: invalid value for a dash setting
|
||||
* @CAIRO_STATUS_INVALID_DSC_COMMENT: invalid value for a DSC comment (Since 1.2)
|
||||
* @CAIRO_STATUS_INVALID_INDEX: invalid index passed to getter
|
||||
* @CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: clip region not representable in desired format (Since 1.4)
|
||||
*
|
||||
* #cairo_status_t is used to indicate errors that can occur when
|
||||
* using Cairo. In some cases it is returned directly by functions.
|
||||
|
|
@ -201,7 +202,8 @@ typedef enum _cairo_status {
|
|||
CAIRO_STATUS_FILE_NOT_FOUND,
|
||||
CAIRO_STATUS_INVALID_DASH,
|
||||
CAIRO_STATUS_INVALID_DSC_COMMENT,
|
||||
CAIRO_STATUS_INVALID_INDEX
|
||||
CAIRO_STATUS_INVALID_INDEX,
|
||||
CAIRO_STATUS_CLIP_NOT_REPRESENTABLE
|
||||
} cairo_status_t;
|
||||
|
||||
/**
|
||||
|
|
@ -589,6 +591,38 @@ cairo_clip (cairo_t *cr);
|
|||
cairo_public void
|
||||
cairo_clip_preserve (cairo_t *cr);
|
||||
|
||||
cairo_public void
|
||||
cairo_clip_extents (cairo_t *cr,
|
||||
double *x1, double *y1,
|
||||
double *x2, double *y2);
|
||||
|
||||
/**
|
||||
* cairo_rectangle_t:
|
||||
*
|
||||
* A data structure for holding a rectangle.
|
||||
*/
|
||||
typedef struct _cairo_rectangle {
|
||||
double x, y, width, height;
|
||||
} cairo_rectangle_t;
|
||||
|
||||
/**
|
||||
* cairo_rectangle_list_t:
|
||||
*
|
||||
* A data structure for holding a dynamically allocated
|
||||
* array of rectangles.
|
||||
*/
|
||||
typedef struct _cairo_rectangle_list {
|
||||
cairo_status_t status;
|
||||
cairo_rectangle_t *rectangles;
|
||||
int num_rectangles;
|
||||
} cairo_rectangle_list_t;
|
||||
|
||||
cairo_public cairo_rectangle_list_t *
|
||||
cairo_copy_clip_rectangles (cairo_t *cr);
|
||||
|
||||
cairo_public void
|
||||
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list);
|
||||
|
||||
/* Font/Text functions */
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1338,6 +1338,16 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
|
|||
cairo_private cairo_status_t
|
||||
_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
|
||||
double *x1,
|
||||
double *y1,
|
||||
double *x2,
|
||||
double *y2);
|
||||
|
||||
cairo_private cairo_rectangle_list_t*
|
||||
_cairo_gstate_copy_clip_rectangles (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_gstate_show_surface (cairo_gstate_t *gstate,
|
||||
cairo_surface_t *surface,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ font-face-get-type \
|
|||
font-matrix-translation \
|
||||
glyph-cache-pressure \
|
||||
get-and-set \
|
||||
get-clip \
|
||||
get-group-target \
|
||||
get-path-extents \
|
||||
gradient-alpha \
|
||||
leaky-dash \
|
||||
leaky-polygon \
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ font-face-get-type \
|
|||
font-matrix-translation \
|
||||
glyph-cache-pressure \
|
||||
get-and-set \
|
||||
get-clip \
|
||||
get-group-target \
|
||||
get-path-extents \
|
||||
gradient-alpha \
|
||||
leaky-dash \
|
||||
leaky-polygon \
|
||||
|
|
|
|||
277
test/get-clip.c
Normal file
277
test/get-clip.c
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Copyright © 2006 Novell, 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
|
||||
* Novell, Inc. not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Novell, Inc. makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* NOVELL, 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: Robert O'Callahan <rocallahan@novell.com>
|
||||
*/
|
||||
|
||||
#include "cairo-test.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static cairo_test_draw_function_t draw;
|
||||
|
||||
cairo_test_t test = {
|
||||
"get-clip",
|
||||
"Test cairo_copy_clip_rectangles and cairo_clip_extents",
|
||||
0, 0,
|
||||
draw
|
||||
};
|
||||
|
||||
static cairo_bool_t
|
||||
check_count (const char *message, cairo_bool_t uses_clip_rects,
|
||||
cairo_rectangle_list_t *list, int expected)
|
||||
{
|
||||
if (!uses_clip_rects) {
|
||||
if (expected == 0 && list->num_rectangles == 0)
|
||||
return 1;
|
||||
cairo_test_log ("Error: %s; cairo_copy_clip_rectangles unexpectedly got %d rectangles\n",
|
||||
message, list->num_rectangles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list->status != CAIRO_STATUS_SUCCESS) {
|
||||
cairo_test_log ("Error: %s; cairo_copy_clip_rectangles failed with \"%s\"\n",
|
||||
message, cairo_status_to_string(list->status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list->num_rectangles == expected)
|
||||
return 1;
|
||||
cairo_test_log ("Error: %s; expected %d rectangles, got %d\n", message,
|
||||
expected, list->num_rectangles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
check_unrepresentable (const char *message, cairo_rectangle_list_t *list)
|
||||
{
|
||||
if (list->status != CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) {
|
||||
cairo_test_log ("Error: %s; cairo_copy_clip_rectangles got unexpected result \"%s\"\n"
|
||||
" (we expected CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)",
|
||||
message, cairo_status_to_string(list->status));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
check_rectangles_contain (const char *message, cairo_bool_t uses_clip_rects,
|
||||
cairo_rectangle_list_t *list,
|
||||
double x, double y, double width, double height)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!uses_clip_rects)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < list->num_rectangles; ++i) {
|
||||
if (list->rectangles[i].x == x && list->rectangles[i].y == y &&
|
||||
list->rectangles[i].width == width && list->rectangles[i].height == height)
|
||||
return 1;
|
||||
}
|
||||
cairo_test_log ("Error: %s; rectangle list does not contain rectangle %f,%f,%f,%f\n",
|
||||
message, x, y, width, height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
check_clip_extents (const char *message, cairo_t *cr,
|
||||
double x, double y, double width, double height)
|
||||
{
|
||||
double ext_x1, ext_y1, ext_x2, ext_y2;
|
||||
cairo_clip_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2);
|
||||
if (ext_x1 == x && ext_y1 == y && ext_x2 == x + width && ext_y2 == y + height)
|
||||
return 1;
|
||||
cairo_test_log ("Error: %s; clip extents %f,%f,%f,%f should be %f,%f,%f,%f\n",
|
||||
message, ext_x1, ext_y1, ext_x2 - ext_x1, ext_y2 - ext_y1,
|
||||
x, y, width, height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
draw (cairo_t *cr, int width, int height)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr2;
|
||||
cairo_rectangle_list_t *rectangle_list;
|
||||
const char *phase;
|
||||
cairo_bool_t uses_clip_rects;
|
||||
|
||||
surface = cairo_surface_create_similar (cairo_get_target (cr),
|
||||
CAIRO_CONTENT_COLOR, 100, 100);
|
||||
/* don't use cr accidentally */
|
||||
cr = NULL;
|
||||
cr2 = cairo_create (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
/* check the surface type so we ignore cairo_copy_clip_rectangles failures
|
||||
on surface types that don't use rectangle lists for clipping */
|
||||
switch (cairo_surface_get_type (surface)) {
|
||||
case CAIRO_SURFACE_TYPE_PDF:
|
||||
case CAIRO_SURFACE_TYPE_PS:
|
||||
case CAIRO_SURFACE_TYPE_SVG:
|
||||
uses_clip_rects = 0;
|
||||
break;
|
||||
case CAIRO_SURFACE_TYPE_IMAGE:
|
||||
case CAIRO_SURFACE_TYPE_XLIB:
|
||||
case CAIRO_SURFACE_TYPE_XCB:
|
||||
case CAIRO_SURFACE_TYPE_GLITZ:
|
||||
case CAIRO_SURFACE_TYPE_QUARTZ:
|
||||
case CAIRO_SURFACE_TYPE_WIN32:
|
||||
case CAIRO_SURFACE_TYPE_BEOS:
|
||||
case CAIRO_SURFACE_TYPE_DIRECTFB:
|
||||
default:
|
||||
uses_clip_rects = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* first, test basic stuff. This should not be clipped, it should
|
||||
return the surface rectangle. */
|
||||
phase = "No clip set";
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
if (!check_count (phase, uses_clip_rects, rectangle_list, 1) ||
|
||||
!check_clip_extents (phase, cr2, 0, 0, 100, 100) ||
|
||||
!check_rectangles_contain(phase, uses_clip_rects, rectangle_list, 0, 0, 100, 100)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
|
||||
/* Test simple clip rect. */
|
||||
phase = "Simple clip rect";
|
||||
cairo_save (cr2);
|
||||
cairo_rectangle (cr2, 10, 10, 80, 80);
|
||||
cairo_clip (cr2);
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
if (!check_count (phase, uses_clip_rects, rectangle_list, 1) ||
|
||||
!check_clip_extents (phase, cr2, 10, 10, 80, 80) ||
|
||||
!check_rectangles_contain(phase, uses_clip_rects, rectangle_list, 10, 10, 80, 80)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
cairo_restore (cr2);
|
||||
|
||||
/* Test everything clipped out. */
|
||||
phase = "All clipped out";
|
||||
cairo_save (cr2);
|
||||
cairo_clip (cr2);
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
if (!check_count (phase, uses_clip_rects, rectangle_list, 0)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
cairo_restore (cr2);
|
||||
|
||||
/* test two clip rects */
|
||||
phase = "Two clip rects";
|
||||
cairo_save (cr2);
|
||||
cairo_rectangle (cr2, 10, 10, 10, 10);
|
||||
cairo_rectangle (cr2, 20, 20, 10, 10);
|
||||
cairo_clip (cr2);
|
||||
cairo_rectangle (cr2, 15, 15, 10, 10);
|
||||
cairo_clip (cr2);
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
if (!check_count (phase, uses_clip_rects, rectangle_list, 2) ||
|
||||
!check_clip_extents (phase, cr2, 15, 15, 10, 10) ||
|
||||
!check_rectangles_contain(phase, uses_clip_rects, rectangle_list, 15, 15, 5, 5) ||
|
||||
!check_rectangles_contain(phase, uses_clip_rects, rectangle_list, 20, 20, 5, 5)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
cairo_restore (cr2);
|
||||
|
||||
/* test non-rectangular clip */
|
||||
phase = "Nonrectangular clip";
|
||||
cairo_save (cr2);
|
||||
cairo_move_to (cr2, 0, 0);
|
||||
cairo_line_to (cr2, 100, 100);
|
||||
cairo_line_to (cr2, 100, 0);
|
||||
cairo_close_path (cr2);
|
||||
cairo_clip (cr2);
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
/* can't get this in one tight user-space rectangle */
|
||||
if (!check_unrepresentable (phase, rectangle_list) ||
|
||||
!check_clip_extents (phase, cr2, 0, 0, 100, 100)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "User space, simple scale, getting clip with same transform";
|
||||
cairo_save (cr2);
|
||||
cairo_scale (cr2, 2, 2);
|
||||
cairo_rectangle (cr2, 5, 5, 40, 40);
|
||||
cairo_clip (cr2);
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
if (!check_count (phase, uses_clip_rects, rectangle_list, 1) ||
|
||||
!check_clip_extents (phase, cr2, 5, 5, 40, 40) ||
|
||||
!check_rectangles_contain(phase, uses_clip_rects, rectangle_list, 5, 5, 40, 40)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "User space, simple scale, getting clip with no transform";
|
||||
cairo_save (cr2);
|
||||
cairo_save (cr2);
|
||||
cairo_scale (cr2, 2, 2);
|
||||
cairo_rectangle (cr2, 5, 5, 40, 40);
|
||||
cairo_restore (cr2);
|
||||
cairo_clip (cr2);
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
if (!check_count (phase, uses_clip_rects, rectangle_list, 1) ||
|
||||
!check_clip_extents (phase, cr2, 10, 10, 80, 80) ||
|
||||
!check_rectangles_contain(phase, uses_clip_rects, rectangle_list, 10, 10, 80, 80)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "User space, rotation, getting clip with no transform";
|
||||
cairo_save (cr2);
|
||||
cairo_save (cr2);
|
||||
cairo_rotate (cr2, 12);
|
||||
cairo_rectangle (cr2, 5, 5, 40, 40);
|
||||
cairo_restore (cr2);
|
||||
cairo_clip (cr2);
|
||||
rectangle_list = cairo_copy_clip_rectangles (cr2);
|
||||
if (!check_unrepresentable (phase, rectangle_list)) {
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
cairo_rectangle_list_destroy (rectangle_list);
|
||||
cairo_restore (cr2);
|
||||
|
||||
cairo_destroy (cr2);
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return cairo_test (&test);
|
||||
}
|
||||
199
test/get-path-extents.c
Normal file
199
test/get-path-extents.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright © 2006 Novell, 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
|
||||
* Novell, Inc. not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Novell, Inc. makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* NOVELL, 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: Robert O'Callahan <rocallahan@novell.com>
|
||||
*/
|
||||
|
||||
#include "cairo-test.h"
|
||||
#include <stddef.h>
|
||||
#include <math.h>
|
||||
|
||||
static cairo_test_draw_function_t draw;
|
||||
|
||||
cairo_test_t test = {
|
||||
"get-path-extents",
|
||||
"Test cairo_fill_extents and cairo_stroke_extents",
|
||||
0, 0,
|
||||
draw
|
||||
};
|
||||
|
||||
enum ExtentsType { FILL, STROKE };
|
||||
|
||||
enum Relation { EQUALS, CONTAINS };
|
||||
|
||||
static cairo_bool_t
|
||||
check_extents (const char *message, cairo_t *cr, enum ExtentsType type,
|
||||
enum Relation relation,
|
||||
double x, double y, double width, double height)
|
||||
{
|
||||
double ext_x1, ext_y1, ext_x2, ext_y2;
|
||||
const char *type_string;
|
||||
const char *relation_string;
|
||||
|
||||
switch (type) {
|
||||
default:
|
||||
case FILL:
|
||||
type_string = "fill";
|
||||
cairo_fill_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2);
|
||||
break;
|
||||
case STROKE:
|
||||
type_string = "stroke";
|
||||
cairo_stroke_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2);
|
||||
break;
|
||||
}
|
||||
|
||||
/* let empty rects match */
|
||||
if ((ext_x1 == ext_x2 || ext_y1 == ext_y2) && (width == 0 || height == 0))
|
||||
return 1;
|
||||
|
||||
switch (relation) {
|
||||
default:
|
||||
case EQUALS:
|
||||
relation_string = "equal";
|
||||
if (ext_x1 == x && ext_y1 == y && ext_x2 == x + width && ext_y2 == y + height)
|
||||
return 1;
|
||||
break;
|
||||
case CONTAINS:
|
||||
relation_string = "contain";
|
||||
if (width == 0 || height == 0) {
|
||||
/* odd test that doesn't really test anything... */
|
||||
return 1;
|
||||
}
|
||||
if (ext_x1 <= x && ext_y1 <= y && ext_x2 >= x + width && ext_y2 >= y + height)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_test_log ("Error: %s; %s extents %f,%f,%f,%f should %s %f,%f,%f,%f\n",
|
||||
message, type_string,
|
||||
ext_x1, ext_y1, ext_x2 - ext_x1, ext_y2 - ext_y1,
|
||||
relation_string,
|
||||
x, y, width, height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
draw (cairo_t *cr, int width, int height)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr2;
|
||||
const char *phase;
|
||||
|
||||
surface = cairo_surface_create_similar (cairo_get_target (cr),
|
||||
CAIRO_CONTENT_COLOR, 100, 100);
|
||||
/* don't use cr accidentally */
|
||||
cr = NULL;
|
||||
cr2 = cairo_create (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
cairo_set_line_width (cr2, 10);
|
||||
cairo_set_line_join (cr2, CAIRO_LINE_JOIN_MITER);
|
||||
cairo_set_miter_limit (cr2, 100);
|
||||
|
||||
phase = "No path";
|
||||
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
|
||||
!check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0))
|
||||
return CAIRO_TEST_FAILURE;
|
||||
|
||||
phase = "Simple rect";
|
||||
cairo_save (cr2);
|
||||
cairo_rectangle (cr2, 10, 10, 80, 80);
|
||||
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 80, 80) ||
|
||||
!check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 90, 90))
|
||||
return CAIRO_TEST_FAILURE;
|
||||
cairo_new_path (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "Two rects";
|
||||
cairo_save (cr2);
|
||||
cairo_rectangle (cr2, 10, 10, 10, 10);
|
||||
cairo_rectangle (cr2, 20, 20, 10, 10);
|
||||
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 20, 20) ||
|
||||
!check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 30, 30))
|
||||
return CAIRO_TEST_FAILURE;
|
||||
cairo_new_path (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "Triangle";
|
||||
cairo_save (cr2);
|
||||
cairo_move_to (cr2, 10, 10);
|
||||
cairo_line_to (cr2, 90, 90);
|
||||
cairo_line_to (cr2, 90, 10);
|
||||
cairo_close_path (cr2);
|
||||
/* miter joins protrude 5*(1+sqrt(2)) above the top-left corner and to
|
||||
the right of the bottom-right corner */
|
||||
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 80, 80) ||
|
||||
!check_extents (phase, cr2, STROKE, CONTAINS, 0, 5, 95, 95))
|
||||
return CAIRO_TEST_FAILURE;
|
||||
cairo_new_path (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "User space, simple scale, getting extents with same transform";
|
||||
cairo_save (cr2);
|
||||
cairo_scale (cr2, 2, 2);
|
||||
cairo_rectangle (cr2, 5, 5, 40, 40);
|
||||
if (!check_extents (phase, cr2, FILL, EQUALS, 5, 5, 40, 40) ||
|
||||
!check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 50, 50))
|
||||
return CAIRO_TEST_FAILURE;
|
||||
cairo_new_path (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "User space, simple scale, getting extents with no transform";
|
||||
cairo_save (cr2);
|
||||
cairo_save (cr2);
|
||||
cairo_scale (cr2, 2, 2);
|
||||
cairo_rectangle (cr2, 5, 5, 40, 40);
|
||||
cairo_restore (cr2);
|
||||
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 80, 80) ||
|
||||
!check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 90, 90))
|
||||
return CAIRO_TEST_FAILURE;
|
||||
cairo_new_path (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
phase = "User space, rotation, getting extents with transform";
|
||||
cairo_save (cr2);
|
||||
cairo_rectangle (cr2, -50, -50, 50, 50);
|
||||
cairo_rotate (cr2, -M_PI/4);
|
||||
/* the path in user space is now (nearly) the square rotated by
|
||||
45 degrees about the origin. Thus its x1 and x2 are both nearly 0.
|
||||
This should show any bugs where we just transform device-space
|
||||
x1,y1 and x2,y2 to get the extents. */
|
||||
/* The largest axis-aligned square inside the rotated path has
|
||||
side lengths 50*sqrt(2), so a bit over 35 on either side of
|
||||
the axes. With the stroke width added to the rotated path,
|
||||
the largest axis-aligned square is a bit over 38 on either side of
|
||||
the axes. */
|
||||
if (!check_extents (phase, cr2, FILL, CONTAINS, -35, -35, 35, 35) ||
|
||||
!check_extents (phase, cr2, STROKE, CONTAINS, -38, -38, 38, 38))
|
||||
return CAIRO_TEST_FAILURE;
|
||||
cairo_new_path (cr2);
|
||||
cairo_restore (cr2);
|
||||
|
||||
cairo_destroy (cr2);
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return cairo_test (&test);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue