1
/*
2
 * Copyright © 2007 Red Hat, Inc.
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use, copy,
8
 * modify, merge, publish, distribute, sublicense, and/or sell copies
9
 * of the Software, and to permit persons to whom the Software is
10
 * furnished to do so, subject to the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 *
24
 * Author: Carl Worth <cworth@cworth.org>
25
 */
26

            
27
#define _ISOC99_SOURCE	/* for INFINITY */
28

            
29
#include "config.h"
30
#include "cairo-test.h"
31

            
32
#if !defined(INFINITY)
33
#define INFINITY HUGE_VAL
34
#endif
35

            
36
static cairo_test_status_t
37
3
draw (cairo_t *cr, int width, int height)
38
{
39
3
    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
40
    cairo_status_t status;
41
    cairo_surface_t *target;
42
    cairo_font_face_t *font_face;
43
    cairo_font_options_t *font_options;
44
    cairo_scaled_font_t *scaled_font;
45
    cairo_pattern_t *pattern;
46
    cairo_t *cr2;
47
3
    cairo_matrix_t identity, bogus, inf, invalid = {
48
	4.0, 4.0,
49
	4.0, 4.0,
50
	4.0, 4.0
51
    };
52

            
53
#define CHECK_STATUS(status, function_name)						\
54
if ((status) == CAIRO_STATUS_SUCCESS) {							\
55
    cairo_test_log (ctx, "Error: %s with invalid matrix passed\n",				\
56
		    (function_name));							\
57
    return CAIRO_TEST_FAILURE;								\
58
} else if ((status) != CAIRO_STATUS_INVALID_MATRIX) {					\
59
    cairo_test_log (ctx, "Error: %s with invalid matrix returned unexpected status "	\
60
		    "(%d): %s\n",							\
61
		    (function_name),							\
62
		    status,								\
63
		    cairo_status_to_string (status));					\
64
    return CAIRO_TEST_FAILURE;								\
65
}
66

            
67
    /* clear floating point exceptions (added by cairo_test_init()) */
68
#if HAVE_FEDISABLEEXCEPT
69
3
    fedisableexcept (FE_INVALID);
70
#endif
71

            
72
    /* create a bogus matrix and check results of attempted inversion */
73
3
    bogus.x0 = bogus.xy = bogus.xx = cairo_test_NaN ();
74
3
    bogus.y0 = bogus.yx = bogus.yy = bogus.xx;
75
3
    status = cairo_matrix_invert (&bogus);
76
3
    CHECK_STATUS (status, "cairo_matrix_invert(NaN)");
77

            
78
3
    inf.x0 = inf.xy = inf.xx = INFINITY;
79
3
    inf.y0 = inf.yx = inf.yy = inf.xx;
80
3
    status = cairo_matrix_invert (&inf);
81
3
    CHECK_STATUS (status, "cairo_matrix_invert(infinity)");
82

            
83
    /* test cairo_matrix_invert with invalid matrix */
84
3
    status = cairo_matrix_invert (&invalid);
85
3
    CHECK_STATUS (status, "cairo_matrix_invert(invalid)");
86

            
87

            
88
3
    cairo_matrix_init_identity (&identity);
89

            
90
3
    target = cairo_get_group_target (cr);
91

            
92
    /* test cairo_transform with invalid matrix */
93
3
    cr2 = cairo_create (target);
94
3
    cairo_transform (cr2, &invalid);
95

            
96
3
    status = cairo_status (cr2);
97
3
    cairo_destroy (cr2);
98
3
    CHECK_STATUS (status, "cairo_transform(invalid)");
99

            
100
    /* test cairo_transform with bogus matrix */
101
3
    cr2 = cairo_create (target);
102
3
    cairo_transform (cr2, &bogus);
103

            
104
3
    status = cairo_status (cr2);
105
3
    cairo_destroy (cr2);
106
3
    CHECK_STATUS (status, "cairo_transform(NaN)");
107

            
108
    /* test cairo_transform with ∞ matrix */
109
3
    cr2 = cairo_create (target);
110
3
    cairo_transform (cr2, &inf);
111

            
112
3
    status = cairo_status (cr2);
113
3
    cairo_destroy (cr2);
114
3
    CHECK_STATUS (status, "cairo_transform(infinity)");
115

            
116

            
117
    /* test cairo_set_matrix with invalid matrix */
118
3
    cr2 = cairo_create (target);
119
3
    cairo_set_matrix (cr2, &invalid);
120

            
121
3
    status = cairo_status (cr2);
122
3
    cairo_destroy (cr2);
123
3
    CHECK_STATUS (status, "cairo_set_matrix(invalid)");
124

            
125
    /* test cairo_set_matrix with bogus matrix */
126
3
    cr2 = cairo_create (target);
127
3
    cairo_set_matrix (cr2, &bogus);
128

            
129
3
    status = cairo_status (cr2);
130
3
    cairo_destroy (cr2);
131
3
    CHECK_STATUS (status, "cairo_set_matrix(NaN)");
132

            
133
    /* test cairo_set_matrix with ∞ matrix */
134
3
    cr2 = cairo_create (target);
135
3
    cairo_set_matrix (cr2, &inf);
136

            
137
3
    status = cairo_status (cr2);
138
3
    cairo_destroy (cr2);
139
3
    CHECK_STATUS (status, "cairo_set_matrix(infinity)");
140

            
141

            
142
    /* test cairo_set_font_matrix with invalid matrix */
143
3
    cr2 = cairo_create (target);
144
3
    cairo_set_font_matrix (cr2, &invalid);
145

            
146
    /* draw some text to force the font to be resolved */
147
3
    cairo_show_text (cr2, "hello");
148

            
149
3
    status = cairo_status (cr2);
150
3
    cairo_destroy (cr2);
151
3
    CHECK_STATUS (status, "cairo_set_font_matrix(invalid)");
152

            
153
    /* test cairo_set_font_matrix with bogus matrix */
154
3
    cr2 = cairo_create (target);
155
3
    cairo_set_font_matrix (cr2, &bogus);
156

            
157
    /* draw some text to force the font to be resolved */
158
3
    cairo_show_text (cr2, "hello");
159

            
160
3
    status = cairo_status (cr2);
161
3
    cairo_destroy (cr2);
162
3
    CHECK_STATUS (status, "cairo_set_font_matrix(NaN)");
163

            
164
    /* test cairo_set_font_matrix with ∞ matrix */
165
3
    cr2 = cairo_create (target);
166
3
    cairo_set_font_matrix (cr2, &inf);
167

            
168
    /* draw some text to force the font to be resolved */
169
3
    cairo_show_text (cr2, "hello");
170

            
171
3
    status = cairo_status (cr2);
172
3
    cairo_destroy (cr2);
173
3
    CHECK_STATUS (status, "cairo_set_font_matrix(infinity)");
174

            
175

            
176
    /* test cairo_scaled_font_create with invalid matrix */
177
3
    cr2 = cairo_create (target);
178
3
    font_face = cairo_get_font_face (cr2);
179
3
    font_options = cairo_font_options_create ();
180
3
    cairo_get_font_options (cr, font_options);
181
3
    scaled_font = cairo_scaled_font_create (font_face,
182
					    &invalid,
183
					    &identity,
184
					    font_options);
185
3
    status = cairo_scaled_font_status (scaled_font);
186
3
    CHECK_STATUS (status, "cairo_scaled_font_create(invalid)");
187

            
188
3
    cairo_scaled_font_destroy (scaled_font);
189

            
190
3
    scaled_font = cairo_scaled_font_create (font_face,
191
					    &identity,
192
					    &invalid,
193
					    font_options);
194
3
    status = cairo_scaled_font_status (scaled_font);
195
3
    CHECK_STATUS (status, "cairo_scaled_font_create(invalid)");
196

            
197
3
    cairo_scaled_font_destroy (scaled_font);
198
3
    cairo_font_options_destroy (font_options);
199
3
    cairo_destroy (cr2);
200

            
201
    /* test cairo_scaled_font_create with bogus matrix */
202
3
    cr2 = cairo_create (target);
203
3
    font_face = cairo_get_font_face (cr2);
204
3
    font_options = cairo_font_options_create ();
205
3
    cairo_get_font_options (cr, font_options);
206
3
    scaled_font = cairo_scaled_font_create (font_face,
207
					    &bogus,
208
					    &identity,
209
					    font_options);
210
3
    status = cairo_scaled_font_status (scaled_font);
211
3
    CHECK_STATUS (status, "cairo_scaled_font_create(NaN)");
212

            
213
3
    cairo_scaled_font_destroy (scaled_font);
214

            
215
3
    scaled_font = cairo_scaled_font_create (font_face,
216
					    &identity,
217
					    &bogus,
218
					    font_options);
219
3
    status = cairo_scaled_font_status (scaled_font);
220
3
    CHECK_STATUS (status, "cairo_scaled_font_create(NaN)");
221

            
222
3
    cairo_scaled_font_destroy (scaled_font);
223
3
    cairo_font_options_destroy (font_options);
224
3
    cairo_destroy (cr2);
225

            
226
    /* test cairo_scaled_font_create with ∞ matrix */
227
3
    cr2 = cairo_create (target);
228
3
    font_face = cairo_get_font_face (cr2);
229
3
    font_options = cairo_font_options_create ();
230
3
    cairo_get_font_options (cr, font_options);
231
3
    scaled_font = cairo_scaled_font_create (font_face,
232
					    &inf,
233
					    &identity,
234
					    font_options);
235
3
    status = cairo_scaled_font_status (scaled_font);
236
3
    CHECK_STATUS (status, "cairo_scaled_font_create(infinity)");
237

            
238
3
    cairo_scaled_font_destroy (scaled_font);
239

            
240
3
    scaled_font = cairo_scaled_font_create (font_face,
241
					    &identity,
242
					    &inf,
243
					    font_options);
244
3
    status = cairo_scaled_font_status (scaled_font);
245
3
    CHECK_STATUS (status, "cairo_scaled_font_create(infinity)");
246

            
247
3
    cairo_scaled_font_destroy (scaled_font);
248
3
    cairo_font_options_destroy (font_options);
249
3
    cairo_destroy (cr2);
250

            
251

            
252
    /* test cairo_pattern_set_matrix with invalid matrix */
253
3
    pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
254
3
    cairo_pattern_set_matrix (pattern, &invalid);
255
3
    status = cairo_pattern_status (pattern);
256
3
    CHECK_STATUS (status, "cairo_pattern_set_matrix(invalid)");
257
3
    cairo_pattern_destroy (pattern);
258

            
259
    /* test cairo_pattern_set_matrix with bogus matrix */
260
3
    pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
261
3
    cairo_pattern_set_matrix (pattern, &bogus);
262
3
    status = cairo_pattern_status (pattern);
263
3
    CHECK_STATUS (status, "cairo_pattern_set_matrix(NaN)");
264
3
    cairo_pattern_destroy (pattern);
265

            
266
    /* test cairo_pattern_set_matrix with ∞ matrix */
267
3
    pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
268
3
    cairo_pattern_set_matrix (pattern, &inf);
269
3
    status = cairo_pattern_status (pattern);
270
3
    CHECK_STATUS (status, "cairo_pattern_set_matrix(infinity)");
271
3
    cairo_pattern_destroy (pattern);
272

            
273

            
274
    /* test invalid transformations */
275
3
    cr2 = cairo_create (target);
276
3
    cairo_translate (cr2, bogus.xx, bogus.yy);
277
3
    CHECK_STATUS (status, "cairo_translate(NaN, NaN)");
278
3
    cairo_destroy (cr2);
279

            
280
3
    cr2 = cairo_create (target);
281
3
    cairo_translate (cr2, 0, bogus.yy);
282
3
    CHECK_STATUS (status, "cairo_translate(0, NaN)");
283
3
    cairo_destroy (cr2);
284

            
285
3
    cr2 = cairo_create (target);
286
3
    cairo_translate (cr2, bogus.xx, 0);
287
3
    CHECK_STATUS (status, "cairo_translate(NaN, 0)");
288
3
    cairo_destroy (cr2);
289

            
290
3
    cr2 = cairo_create (target);
291
3
    cairo_translate (cr2, inf.xx, inf.yy);
292
3
    CHECK_STATUS (status, "cairo_translate(∞, ∞)");
293
3
    cairo_destroy (cr2);
294

            
295
3
    cr2 = cairo_create (target);
296
3
    cairo_translate (cr2, 0, inf.yy);
297
3
    CHECK_STATUS (status, "cairo_translate(0, ∞)");
298
3
    cairo_destroy (cr2);
299

            
300
3
    cr2 = cairo_create (target);
301
3
    cairo_translate (cr2, inf.xx, 0);
302
3
    CHECK_STATUS (status, "cairo_translate(∞, 0)");
303
3
    cairo_destroy (cr2);
304

            
305

            
306
3
    cr2 = cairo_create (target);
307
3
    cairo_scale (cr2, bogus.xx, bogus.yy);
308
3
    CHECK_STATUS (status, "cairo_scale(NaN, NaN)");
309
3
    cairo_destroy (cr2);
310

            
311
3
    cr2 = cairo_create (target);
312
3
    cairo_scale (cr2, 1, bogus.yy);
313
3
    CHECK_STATUS (status, "cairo_scale(1, NaN)");
314
3
    cairo_destroy (cr2);
315

            
316
3
    cr2 = cairo_create (target);
317
3
    cairo_scale (cr2, bogus.xx, 1);
318
3
    CHECK_STATUS (status, "cairo_scale(NaN, 1)");
319
3
    cairo_destroy (cr2);
320

            
321
3
    cr2 = cairo_create (target);
322
3
    cairo_scale (cr2, inf.xx, inf.yy);
323
3
    CHECK_STATUS (status, "cairo_scale(∞, ∞)");
324
3
    cairo_destroy (cr2);
325

            
326
3
    cr2 = cairo_create (target);
327
3
    cairo_scale (cr2, 1, inf.yy);
328
3
    CHECK_STATUS (status, "cairo_scale(1, ∞)");
329
3
    cairo_destroy (cr2);
330

            
331
3
    cr2 = cairo_create (target);
332
3
    cairo_scale (cr2, inf.xx, 1);
333
3
    CHECK_STATUS (status, "cairo_scale(∞, 1)");
334
3
    cairo_destroy (cr2);
335

            
336
3
    cr2 = cairo_create (target);
337
3
    cairo_scale (cr2, bogus.xx, bogus.yy);
338
3
    CHECK_STATUS (status, "cairo_scale(0, 0)");
339
3
    cairo_destroy (cr2);
340

            
341
3
    cr2 = cairo_create (target);
342
3
    cairo_scale (cr2, 1, bogus.yy);
343
3
    CHECK_STATUS (status, "cairo_scale(1, 0)");
344
3
    cairo_destroy (cr2);
345

            
346
3
    cr2 = cairo_create (target);
347
3
    cairo_scale (cr2, bogus.xx, 1);
348
3
    CHECK_STATUS (status, "cairo_scale(0, 1)");
349
3
    cairo_destroy (cr2);
350

            
351

            
352
3
    cr2 = cairo_create (target);
353
3
    cairo_rotate (cr2, bogus.xx);
354
3
    CHECK_STATUS (status, "cairo_rotate(NaN)");
355
3
    cairo_destroy (cr2);
356

            
357
3
    cr2 = cairo_create (target);
358
3
    cairo_rotate (cr2, inf.xx);
359
3
    CHECK_STATUS (status, "cairo_rotate(∞)");
360
3
    cairo_destroy (cr2);
361

            
362
#if HAVE_FECLEAREXCEPT
363
3
    feclearexcept (FE_INVALID);
364
#endif
365

            
366
3
    return CAIRO_TEST_SUCCESS;
367
}
368

            
369
1
CAIRO_TEST (invalid_matrix,
370
	    "Test that all relevant public functions return CAIRO_STATUS_INVALID_MATRIX as appropriate",
371
	    "api, matrix", /* keywords */
372
	    NULL, /* requirements */
373
	    0, 0,
374
	    NULL, draw)