1
/*
2
 * Copyright © 2016 Adrian Johnson
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
 * Authors:
25
 *	Adrian Johnson <ajohnson@redneon.com>
26
 */
27

            
28
#include "cairo-test.h"
29
#include <stdio.h>
30
#include <math.h>
31

            
32
#define PAT_SIZE  32
33
#define REPLAY_SIZE (PAT_SIZE*4)
34
#define PAD 10
35
#define WIDTH (REPLAY_SIZE*4 + PAD*5)
36
#define HEIGHT (REPLAY_SIZE + PAD*2)
37

            
38
/* Test replaying a recording surface pattern for each type of extend. */
39

            
40
static void
41
48
transform_extents(cairo_rectangle_t *extents, cairo_matrix_t *mat)
42
{
43
    double x1, y1, x2, y2, x, y;
44

            
45
#define UPDATE_BBOX \
46
    x1 = x < x1 ? x : x1; \
47
    y1 = y < y1 ? y : y1; \
48
    x2 = x > x2 ? x : x2; \
49
    y2 = y > y2 ? y : y2;
50

            
51
48
    x = extents->x;
52
48
    y = extents->y;
53
48
    cairo_matrix_transform_point (mat, &x, &y);
54
48
    x1 = x2 = x;
55
48
    y1 = y2 = y;
56

            
57
48
    x = extents->x + extents->width;
58
48
    y = extents->y;
59
48
    cairo_matrix_transform_point (mat, &x, &y);
60
48
    UPDATE_BBOX;
61

            
62
48
    x = extents->x;
63
48
    y = extents->y + extents->height;
64
48
    cairo_matrix_transform_point (mat, &x, &y);
65
48
    UPDATE_BBOX;
66

            
67
48
    x = extents->x + extents->width;
68
48
    y = extents->y + extents->height;
69
48
    cairo_matrix_transform_point (mat, &x, &y);
70
48
    UPDATE_BBOX;
71

            
72
48
    extents->x = x1;
73
48
    extents->y = y1;
74
48
    extents->width = x2 - extents->x;
75
48
    extents->height = y2 - extents->y;
76

            
77
#undef UPDATE_BBOX
78
48
}
79

            
80
static cairo_pattern_t *
81
48
create_pattern (cairo_matrix_t *mat, cairo_extend_t extend)
82
{
83
    cairo_surface_t *surf;
84
    cairo_pattern_t *pat;
85
    cairo_t *cr;
86
48
    cairo_rectangle_t extents = { 0, 0, PAT_SIZE, PAT_SIZE };
87

            
88
48
    transform_extents (&extents, mat);
89
48
    surf = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents);
90

            
91
48
    cr = cairo_create (surf);
92
48
    cairo_transform (cr, mat);
93

            
94
48
    cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2);
95
48
    cairo_set_source_rgb (cr, 1, 0, 0);
96
48
    cairo_fill (cr);
97

            
98
48
    cairo_translate (cr, PAT_SIZE/2, 0);
99
48
    cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2);
100
48
    cairo_set_source_rgb (cr, 0, 1, 0);
101
48
    cairo_fill (cr);
102

            
103
48
    cairo_translate (cr, 0, PAT_SIZE/2);
104
48
    cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2);
105
48
    cairo_set_source_rgb (cr, 0, 0, 1);
106
48
    cairo_fill (cr);
107

            
108
48
    cairo_translate (cr, -PAT_SIZE/2, 0);
109
48
    cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2);
110
48
    cairo_set_source_rgb (cr, 1, 1, 0);
111
48
    cairo_fill (cr);
112

            
113
48
    cairo_destroy (cr);
114

            
115
48
    pat = cairo_pattern_create_for_surface (surf);
116
48
    cairo_surface_destroy (surf);
117
48
    cairo_pattern_set_matrix (pat, mat);
118
48
    cairo_pattern_set_extend (pat, extend);
119
48
    cairo_pattern_set_filter (pat, CAIRO_FILTER_NEAREST);
120

            
121
48
    return pat;
122
}
123

            
124
static cairo_test_status_t
125
12
record_replay_extend (cairo_t *cr, int width, int height, cairo_extend_t extend)
126
{
127
    cairo_pattern_t *pat;
128
    cairo_matrix_t mat;
129

            
130
    /* record surface extents (-PAT_SIZE/2, -PAT_SIZE/2) to (PAT_SIZE/2, PAT_SIZE/2) */
131
12
    cairo_translate (cr, PAD, PAD);
132
12
    cairo_matrix_init_translate (&mat, -PAT_SIZE/2, -PAT_SIZE/2);
133
12
    pat = create_pattern (&mat, extend);
134

            
135
    /* test repeating patterns when the source is outside of the target clip */
136
12
    if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
137
6
	cairo_matrix_init_translate (&mat, 3*PAT_SIZE/2, 3*PAT_SIZE/2);
138
6
	cairo_pattern_set_matrix (pat, &mat);
139
    }
140

            
141
12
    cairo_set_source (cr, pat);
142
12
    cairo_pattern_destroy (pat);
143
12
    cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE);
144
12
    cairo_fill (cr);
145

            
146
    /* record surface extents (-2*PAT_SIZE/2, -2*PAT_SIZE/2) to (2*PAT_SIZE/2, 2*PAT_SIZE/2) */
147
12
    cairo_translate (cr, REPLAY_SIZE + PAD, 0);
148
12
    cairo_matrix_init_translate (&mat, -2.0*PAT_SIZE/2, -2.0*PAT_SIZE/2);
149
12
    cairo_matrix_scale (&mat, 2, 2);
150
12
    pat = create_pattern (&mat, extend);
151
12
    cairo_set_source (cr, pat);
152
12
    cairo_pattern_destroy (pat);
153
12
    cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE);
154
12
    cairo_fill (cr);
155

            
156
    /* record surface extents (-0.5*PAT_SIZE/2, -0.5*PAT_SIZE/2) to (0.5*PAT_SIZE/2, 0.5*PAT_SIZE/2) */
157
12
    cairo_translate (cr, REPLAY_SIZE + PAD, 0);
158
12
    cairo_matrix_init_translate (&mat, -0.5*PAT_SIZE/2, -0.5*PAT_SIZE/2);
159
12
    cairo_matrix_scale (&mat, 0.5, 0.5);
160
12
    pat = create_pattern (&mat, extend);
161
12
    cairo_set_source (cr, pat);
162
12
    cairo_pattern_destroy (pat);
163
12
    cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE);
164
12
    cairo_fill (cr);
165

            
166
    /* record surface centered on (0,0) and rotated 45 deg */
167
12
    cairo_translate (cr, REPLAY_SIZE + PAD, 0);
168
12
    cairo_matrix_init_translate (&mat, -PAT_SIZE/sqrt(2), -PAT_SIZE/sqrt(2));
169
12
    cairo_matrix_rotate (&mat, M_PI/4.0);
170
12
    cairo_matrix_translate (&mat, PAT_SIZE/2, -PAT_SIZE/2);
171
12
    pat = create_pattern (&mat, extend);
172
12
    cairo_set_source (cr, pat);
173
12
    cairo_pattern_destroy (pat);
174
12
    cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE);
175
12
    cairo_fill (cr);
176

            
177
12
    return CAIRO_TEST_SUCCESS;
178
}
179

            
180
static cairo_test_status_t
181
3
record_replay_extend_none (cairo_t *cr, int width, int height)
182
{
183
3
    return record_replay_extend (cr, width, height, CAIRO_EXTEND_NONE);
184
}
185

            
186
static cairo_test_status_t
187
3
record_replay_extend_repeat (cairo_t *cr, int width, int height)
188
{
189
3
    return record_replay_extend (cr, width, height, CAIRO_EXTEND_REPEAT);
190
}
191

            
192
static cairo_test_status_t
193
3
record_replay_extend_reflect (cairo_t *cr, int width, int height)
194
{
195
3
    return record_replay_extend (cr, width, height, CAIRO_EXTEND_REFLECT);
196
}
197

            
198
static cairo_test_status_t
199
3
record_replay_extend_pad (cairo_t *cr, int width, int height)
200
{
201
3
    return record_replay_extend (cr, width, height, CAIRO_EXTEND_PAD);
202
}
203

            
204
1
CAIRO_TEST (record_replay_extend_none,
205
	    "Paint recording pattern with CAIRO_EXTEND_NONE",
206
	    "record,pattern,extend", /* keywords */
207
	    NULL, /* requirements */
208
	    WIDTH, HEIGHT,
209
	    NULL, record_replay_extend_none)
210
1
CAIRO_TEST (record_replay_extend_repeat,
211
	    "Paint recording pattern with CAIRO_EXTEND_REPEAT",
212
	    "record,pattern,extend", /* keywords */
213
	    NULL, /* requirements */
214
	    WIDTH, HEIGHT,
215
	    NULL, record_replay_extend_repeat)
216
1
CAIRO_TEST (record_replay_extend_reflect,
217
	    "Paint recording pattern with CAIRO_EXTEND_REFLECT",
218
	    "record,pattern,extend", /* keywords */
219
	    NULL, /* requirements */
220
	    WIDTH, HEIGHT,
221
	    NULL, record_replay_extend_reflect)
222
1
CAIRO_TEST (record_replay_extend_pad,
223
	    "Paint recording pattern with CAIRO_EXTEND_PAD",
224
	    "record,pattern,extend", /* keywords */
225
	    NULL, /* requirements */
226
	    WIDTH, HEIGHT,
227
	    NULL, record_replay_extend_pad)