1
/*
2
 * Copyright © 2006 Novell, Inc.
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software
5
 * and its documentation for any purpose is hereby granted without
6
 * fee, provided that the above copyright notice appear in all copies
7
 * and that both that copyright notice and this permission notice
8
 * appear in supporting documentation, and that the name of
9
 * Novell, Inc. not be used in advertising or publicity pertaining to
10
 * distribution of the software without specific, written prior
11
 * permission. Novell, Inc. makes no representations about the
12
 * suitability of this software for any purpose.  It is provided "as
13
 * is" without express or implied warranty.
14
 *
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17
 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
18
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 *
23
 * Author: Robert O'Callahan <rocallahan@novell.com>
24
 */
25

            
26
#include "cairo-test.h"
27
#include <stddef.h>
28

            
29
static cairo_bool_t
30
7
check_count (const cairo_test_context_t *ctx,
31
	     const char *message,
32
             cairo_rectangle_list_t *list, int expected)
33
{
34
7
    if (list->status != CAIRO_STATUS_SUCCESS) {
35
        cairo_test_log (ctx, "Error: %s; cairo_copy_clip_rectangle_list failed with \"%s\"\n",
36
                        message, cairo_status_to_string(list->status));
37
        return 0;
38
    }
39

            
40
7
    if (list->num_rectangles == expected)
41
7
        return 1;
42
    cairo_test_log (ctx, "Error: %s; expected %d rectangles, got %d\n", message,
43
                    expected, list->num_rectangles);
44
    return 0;
45
}
46

            
47
static cairo_bool_t
48
2
check_unrepresentable (const cairo_test_context_t *ctx, const char *message, cairo_rectangle_list_t *list)
49
{
50
2
    if (list->status != CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) {
51
        cairo_test_log (ctx, "Error: %s; cairo_copy_clip_rectangle_list got unexpected result \"%s\"\n"
52
                        " (we expected CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)",
53
                        message, cairo_status_to_string(list->status));
54
        return 0;
55
    }
56
2
    return 1;
57
}
58

            
59
static cairo_bool_t
60
7
check_rectangles_contain (const cairo_test_context_t *ctx,
61
			  const char *message,
62
                          cairo_rectangle_list_t *list,
63
                          double x, double y, double width, double height)
64
{
65
    int i;
66

            
67
8
    for (i = 0; i < list->num_rectangles; ++i) {
68
8
        if (list->rectangles[i].x == x && list->rectangles[i].y == y &&
69
7
            list->rectangles[i].width == width && list->rectangles[i].height == height)
70
7
            return 1;
71
    }
72
    cairo_test_log (ctx, "Error: %s; rectangle list does not contain rectangle %f,%f,%f,%f\n",
73
                    message, x, y, width, height);
74
    return 0;
75
}
76

            
77
static cairo_bool_t
78
8
check_clip_extents (const cairo_test_context_t *ctx,
79
		    const char *message, cairo_t *cr,
80
                    double x, double y, double width, double height)
81
{
82
    double ext_x1, ext_y1, ext_x2, ext_y2;
83
8
    cairo_clip_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2);
84
8
    if (ext_x1 == x && ext_y1 == y && ext_x2 == x + width && ext_y2 == y + height)
85
8
        return 1;
86
    if (width == 0.0 && height == 0.0 && ext_x1 == ext_x2 && ext_y1 == ext_y2)
87
        return 1;
88
    cairo_test_log (ctx, "Error: %s; clip extents %f,%f,%f,%f should be %f,%f,%f,%f\n",
89
                    message, ext_x1, ext_y1, ext_x2 - ext_x1, ext_y2 - ext_y1,
90
                    x, y, width, height);
91
    return 0;
92
}
93

            
94
#define SIZE 100
95

            
96
static cairo_test_status_t
97
1
preamble (cairo_test_context_t *ctx)
98
{
99
    cairo_surface_t        *surface;
100
    cairo_t                *cr;
101
    cairo_rectangle_list_t *rectangle_list;
102
    const char             *phase;
103
1
    cairo_bool_t            completed = 0;
104
    cairo_status_t          status;
105

            
106
1
    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, SIZE, SIZE);
107
1
    cr = cairo_create (surface);
108
1
    cairo_surface_destroy (surface);
109

            
110

            
111
    /* first, test basic stuff. This should not be clipped, it should
112
       return the surface rectangle. */
113
1
    phase = "No clip set";
114
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
115
2
    if (! check_count (ctx, phase, rectangle_list, 1) ||
116
2
        ! check_clip_extents (ctx, phase, cr, 0, 0, SIZE, SIZE) ||
117
1
        ! check_rectangles_contain (ctx, phase, rectangle_list, 0, 0, SIZE, SIZE))
118
    {
119
	goto FAIL;
120
    }
121
1
    cairo_rectangle_list_destroy (rectangle_list);
122

            
123
    /* We should get the same results after applying a clip that contains the
124
       existing clip. */
125
1
    phase = "Clip beyond surface extents";
126
1
    cairo_save (cr);
127
1
    cairo_rectangle (cr, -10, -10, SIZE + 20 , SIZE + 20);
128
1
    cairo_clip (cr);
129
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
130
2
    if (! check_count (ctx, phase, rectangle_list, 1) ||
131
2
        ! check_clip_extents (ctx, phase, cr, 0, 0, SIZE, SIZE) ||
132
1
        ! check_rectangles_contain (ctx, phase, rectangle_list, 0, 0, SIZE, SIZE))
133
    {
134
	goto FAIL;
135
    }
136
1
    cairo_rectangle_list_destroy (rectangle_list);
137
1
    cairo_restore (cr);
138

            
139
    /* Test simple clip rect. */
140
1
    phase = "Simple clip rect";
141
1
    cairo_save (cr);
142
1
    cairo_rectangle (cr, 10, 10, 80, 80);
143
1
    cairo_clip (cr);
144
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
145
2
    if (! check_count (ctx, phase, rectangle_list, 1) ||
146
2
        ! check_clip_extents (ctx, phase, cr, 10, 10, 80, 80) ||
147
1
        ! check_rectangles_contain (ctx, phase, rectangle_list, 10, 10, 80, 80))
148
    {
149
	goto FAIL;
150
    }
151
1
    cairo_rectangle_list_destroy (rectangle_list);
152
1
    cairo_restore (cr);
153

            
154
    /* Test everything clipped out. */
155
1
    phase = "All clipped out";
156
1
    cairo_save (cr);
157
1
    cairo_clip (cr);
158
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
159
2
    if (! check_count (ctx, phase, rectangle_list, 0) ||
160
1
        ! check_clip_extents (ctx, phase, cr, 0, 0, 0, 0))
161
    {
162
	goto FAIL;
163
    }
164
1
    cairo_rectangle_list_destroy (rectangle_list);
165
1
    cairo_restore (cr);
166

            
167
    /* test two clip rects */
168
1
    phase = "Two clip rects";
169
1
    cairo_save (cr);
170
1
    cairo_rectangle (cr, 10, 10, 10, 10);
171
1
    cairo_rectangle (cr, 20, 20, 10, 10);
172
1
    cairo_clip (cr);
173
1
    cairo_rectangle (cr, 15, 15, 10, 10);
174
1
    cairo_clip (cr);
175
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
176
2
    if (! check_count (ctx, phase, rectangle_list, 2) ||
177
2
        ! check_clip_extents (ctx, phase, cr, 15, 15, 10, 10) ||
178
2
        ! check_rectangles_contain (ctx, phase, rectangle_list, 15, 15, 5, 5) ||
179
1
        ! check_rectangles_contain (ctx, phase, rectangle_list, 20, 20, 5, 5))
180
    {
181
	goto FAIL;
182
    }
183
1
    cairo_rectangle_list_destroy (rectangle_list);
184
1
    cairo_restore (cr);
185

            
186
    /* test non-rectangular clip */
187
1
    phase = "Nonrectangular clip";
188
1
    cairo_save (cr);
189
1
    cairo_move_to (cr, 0, 0);
190
1
    cairo_line_to (cr, 100, 100);
191
1
    cairo_line_to (cr, 100, 0);
192
1
    cairo_close_path (cr);
193
1
    cairo_clip (cr);
194
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
195
     /* can't get this in one tight user-space rectangle */
196
2
    if (! check_unrepresentable (ctx, phase, rectangle_list) ||
197
1
        ! check_clip_extents (ctx, phase, cr, 0, 0, 100, 100))
198
    {
199
	goto FAIL;
200
    }
201
1
    cairo_rectangle_list_destroy (rectangle_list);
202
1
    cairo_restore (cr);
203

            
204
1
    phase = "User space, simple scale, getting clip with same transform";
205
1
    cairo_save (cr);
206
1
    cairo_scale (cr, 2, 2);
207
1
    cairo_rectangle (cr, 5, 5, 40, 40);
208
1
    cairo_clip (cr);
209
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
210
2
    if (! check_count (ctx, phase, rectangle_list, 1) ||
211
2
        ! check_clip_extents (ctx, phase, cr, 5, 5, 40, 40) ||
212
1
        ! check_rectangles_contain (ctx, phase, rectangle_list, 5, 5, 40, 40))
213
    {
214
	goto FAIL;
215
    }
216
1
    cairo_rectangle_list_destroy (rectangle_list);
217
1
    cairo_restore (cr);
218

            
219
1
    phase = "User space, simple scale, getting clip with no transform";
220
1
    cairo_save (cr);
221
1
    cairo_save (cr);
222
1
    cairo_scale (cr, 2, 2);
223
1
    cairo_rectangle (cr, 5, 5, 40, 40);
224
1
    cairo_restore (cr);
225
1
    cairo_clip (cr);
226
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
227
2
    if (! check_count (ctx, phase, rectangle_list, 1) ||
228
2
        ! check_clip_extents (ctx, phase, cr, 10, 10, 80, 80) ||
229
1
        ! check_rectangles_contain (ctx, phase, rectangle_list, 10, 10, 80, 80))
230
    {
231
	goto FAIL;
232
    }
233
1
    cairo_rectangle_list_destroy (rectangle_list);
234
1
    cairo_restore (cr);
235

            
236
1
    phase = "User space, rotation, getting clip with no transform";
237
1
    cairo_save (cr);
238
1
    cairo_save (cr);
239
1
    cairo_rotate (cr, 12);
240
1
    cairo_rectangle (cr, 5, 5, 40, 40);
241
1
    cairo_restore (cr);
242
1
    cairo_clip (cr);
243
1
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
244
1
    if (! check_unrepresentable (ctx, phase, rectangle_list))
245
	goto FAIL;
246

            
247
1
    completed = 1;
248
1
FAIL:
249
1
    cairo_rectangle_list_destroy (rectangle_list);
250
1
    status = cairo_status (cr);
251
1
    cairo_destroy (cr);
252

            
253
1
    if (!completed)
254
        return CAIRO_TEST_FAILURE;
255

            
256
1
    return cairo_test_status_from_status (ctx, status);
257
}
258

            
259
1
CAIRO_TEST (get_clip,
260
	    "Test cairo_copy_clip_rectangle_list and cairo_clip_extents",
261
	    "clip, extents", /* keywords */
262
	    NULL, /* requirements */
263
	    0, 0,
264
	    preamble, NULL)