1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright (c) 2008  M Joonas Pihlaja
5
 *
6
 * Permission is hereby granted, free of charge, to any person
7
 * obtaining a copy of this software and associated documentation
8
 * files (the "Software"), to deal in the Software without
9
 * restriction, including without limitation the rights to use,
10
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following
13
 * conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be
16
 * included in all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
 * OTHER DEALINGS IN THE SOFTWARE.
26
 */
27
#include "cairo-perf.h"
28
#include <assert.h>
29

            
30
#define MAX_SEGMENTS 2560
31

            
32
typedef enum {
33
    PIXALIGN,                   /* pixel aligned path */
34
    NONALIGN                    /* unaligned path. */
35
} align_t;
36

            
37
typedef enum {
38
    RECTCLOSE,                  /* keeps the path rectilinear */
39
    DIAGCLOSE                   /* forces a diagonal */
40
} close_t;
41

            
42
static cairo_time_t
43
draw_spiral (cairo_t *cr,
44
             cairo_fill_rule_t fill_rule,
45
             align_t align,
46
             close_t close,
47
             int width, int height, int loops)
48
{
49
    int i;
50
    int n=0;
51
    double x[MAX_SEGMENTS];
52
    double y[MAX_SEGMENTS];
53
    int step = 3;
54
    int side = width < height ? width : height;
55

            
56
    assert(5*(side/step/2+1)+2 < MAX_SEGMENTS);
57

            
58
#define L(x_,y_) (x[n] = (x_), y[n] = (y_), n++)
59
#define M(x_,y_) L(x_,y_)
60
#define v(t) L(x[n-1], y[n-1] + (t))
61
#define h(t) L(x[n-1] + (t), y[n-1])
62

            
63
    switch (align) {
64
    case PIXALIGN: M(0,0); break;
65
    case NONALIGN: M(0.1415926, 0.7182818); break;
66
    }
67

            
68
    while (side >= step && side >= 0) {
69
        v(side);
70
        h(side);
71
        v(-side);
72
        h(-side+step);
73
        v(step);
74
        side -= 2*step;
75
    }
76

            
77
    switch (close) {
78
    case RECTCLOSE: L(x[n-1],y[0]); break;
79
    case DIAGCLOSE: L(x[0],y[0]); break;
80
    }
81

            
82
    assert(n < MAX_SEGMENTS);
83

            
84
    cairo_save (cr);
85
    cairo_set_source_rgb (cr, 0, 0, 0);
86
    cairo_paint (cr);
87

            
88
    cairo_translate (cr, 1, 1);
89
    cairo_set_fill_rule (cr, fill_rule);
90
    cairo_set_source_rgb (cr, 1, 0, 0);
91

            
92
    cairo_new_path (cr);
93
    cairo_move_to (cr, x[0], y[0]);
94
    for (i = 1; i < n; i++) {
95
	cairo_line_to (cr, x[i], y[i]);
96
    }
97
    cairo_close_path (cr);
98

            
99
    cairo_perf_timer_start ();
100
    while (loops--)
101
        cairo_fill_preserve (cr);
102
    cairo_perf_timer_stop ();
103

            
104
    cairo_restore (cr);
105

            
106
    return cairo_perf_timer_elapsed ();
107
}
108

            
109
static cairo_time_t
110
draw_spiral_box (cairo_t *cr,
111
		 cairo_fill_rule_t fill_rule,
112
		 align_t align,
113
		 int width, int height, int loops)
114
{
115
    const int step = 3;
116
    int side = (width < height ? width : height) - 2;
117

            
118
    cairo_save (cr);
119
    cairo_set_source_rgb (cr, 0, 0, 0);
120
    cairo_paint (cr);
121

            
122
    cairo_set_source_rgb (cr, 1, 0, 0);
123
    cairo_set_fill_rule (cr, fill_rule);
124
    cairo_translate (cr, 1, 1);
125
    if (align == NONALIGN)
126
	cairo_translate (cr, 0.1415926, 0.7182818);
127

            
128
    cairo_new_path (cr);
129
    while (side >= step) {
130
	cairo_rectangle (cr, 0, 0, side, side);
131
	cairo_translate (cr, step, step);
132
	side -= 2*step;
133
    }
134

            
135
    cairo_perf_timer_start ();
136
    while (loops--)
137
        cairo_fill_preserve (cr);
138
    cairo_perf_timer_stop ();
139

            
140
    cairo_restore (cr);
141

            
142
    return cairo_perf_timer_elapsed ();
143
}
144

            
145
static cairo_time_t
146
draw_spiral_stroke (cairo_t *cr,
147
		    align_t align,
148
		    int width, int height, int loops)
149
{
150
    const int step = 3;
151
    int side = width < height ? width : height;
152

            
153
    cairo_save (cr);
154
    cairo_set_source_rgb (cr, 0, 0, 0);
155
    cairo_paint (cr);
156

            
157
    cairo_translate (cr, 1, 1);
158
    cairo_set_source_rgb (cr, 1, 0, 0);
159
    cairo_set_line_width (cr, 4.);
160
    cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
161
    cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
162

            
163
    cairo_new_path (cr);
164
    switch (align) {
165
    case PIXALIGN: cairo_move_to (cr, 0,0); break;
166
    case NONALIGN: cairo_move_to (cr, 0.1415926, 0.7182818); break;
167
    }
168
    while (side >= step) {
169
	cairo_rel_line_to (cr, 0, side);
170
        side -= step;
171
	if (side <= 0)
172
	    break;
173

            
174
	cairo_rel_line_to (cr, side, 0);
175
        side -= step;
176
	if (side <= 0)
177
	    break;
178

            
179
	cairo_rel_line_to (cr, 0, -side);
180
        side -= step;
181
	if (side <= 0)
182
	    break;
183

            
184
	cairo_rel_line_to (cr, -side, 0);
185
        side -= step;
186
	if (side <= 0)
187
	    break;
188
    }
189

            
190
    cairo_perf_timer_start ();
191
    while (loops--)
192
        cairo_stroke_preserve (cr);
193
    cairo_perf_timer_stop ();
194

            
195
    cairo_restore (cr);
196

            
197
    return cairo_perf_timer_elapsed ();
198
}
199

            
200
static cairo_time_t
201
draw_spiral_eo_pa_re (cairo_t *cr, int width, int height, int loops)
202
{
203
    return draw_spiral (cr,
204
                        CAIRO_FILL_RULE_EVEN_ODD,
205
                        PIXALIGN,
206
                        RECTCLOSE,
207
                        width, height, loops);
208
}
209

            
210
static cairo_time_t
211
draw_spiral_nz_pa_re (cairo_t *cr, int width, int height, int loops)
212
{
213
    return draw_spiral (cr,
214
                        CAIRO_FILL_RULE_WINDING,
215
                        PIXALIGN,
216
                        RECTCLOSE,
217
                        width, height, loops);
218
}
219

            
220
static cairo_time_t
221
draw_spiral_eo_na_re (cairo_t *cr, int width, int height, int loops)
222
{
223
    return draw_spiral (cr,
224
                        CAIRO_FILL_RULE_EVEN_ODD,
225
                        NONALIGN,
226
                        RECTCLOSE,
227
                        width, height, loops);
228
}
229

            
230
static cairo_time_t
231
draw_spiral_nz_na_re (cairo_t *cr, int width, int height, int loops)
232
{
233
    return draw_spiral (cr,
234
                        CAIRO_FILL_RULE_WINDING,
235
                        NONALIGN,
236
                        RECTCLOSE,
237
                        width, height, loops);
238
}
239

            
240
static cairo_time_t
241
draw_spiral_eo_pa_di (cairo_t *cr, int width, int height, int loops)
242
{
243
    return draw_spiral (cr,
244
                        CAIRO_FILL_RULE_EVEN_ODD,
245
                        PIXALIGN,
246
                        DIAGCLOSE,
247
                        width, height, loops);
248
}
249

            
250
static cairo_time_t
251
draw_spiral_nz_pa_di (cairo_t *cr, int width, int height, int loops)
252
{
253
    return draw_spiral (cr,
254
                        CAIRO_FILL_RULE_WINDING,
255
                        PIXALIGN,
256
                        DIAGCLOSE,
257
                        width, height, loops);
258
}
259

            
260
static cairo_time_t
261
draw_spiral_eo_na_di (cairo_t *cr, int width, int height, int loops)
262
{
263
    return draw_spiral (cr,
264
                        CAIRO_FILL_RULE_EVEN_ODD,
265
                        NONALIGN,
266
                        DIAGCLOSE,
267
                        width, height, loops);
268
}
269

            
270
static cairo_time_t
271
draw_spiral_nz_na_di (cairo_t *cr, int width, int height, int loops)
272
{
273
    return draw_spiral (cr,
274
                        CAIRO_FILL_RULE_WINDING,
275
                        NONALIGN,
276
                        DIAGCLOSE,
277
                        width, height, loops);
278
}
279

            
280
static cairo_time_t
281
draw_spiral_nz_pa_box (cairo_t *cr, int width, int height, int loops)
282
{
283
    return draw_spiral_box (cr,
284
			    CAIRO_FILL_RULE_WINDING, PIXALIGN,
285
			    width, height, loops);
286
}
287

            
288
static cairo_time_t
289
draw_spiral_nz_na_box (cairo_t *cr, int width, int height, int loops)
290
{
291
    return draw_spiral_box (cr,
292
			    CAIRO_FILL_RULE_WINDING, NONALIGN,
293
			    width, height, loops);
294
}
295

            
296

            
297
static cairo_time_t
298
draw_spiral_eo_pa_box (cairo_t *cr, int width, int height, int loops)
299
{
300
    return draw_spiral_box (cr,
301
			    CAIRO_FILL_RULE_EVEN_ODD, PIXALIGN,
302
			    width, height, loops);
303
}
304

            
305
static cairo_time_t
306
draw_spiral_eo_na_box (cairo_t *cr, int width, int height, int loops)
307
{
308
    return draw_spiral_box (cr,
309
			    CAIRO_FILL_RULE_EVEN_ODD, NONALIGN,
310
			    width, height, loops);
311
}
312

            
313
static cairo_time_t
314
draw_spiral_stroke_pa (cairo_t *cr, int width, int height, int loops)
315
{
316
    return draw_spiral_stroke (cr,
317
			       PIXALIGN,
318
			       width, height, loops);
319
}
320

            
321
static cairo_time_t
322
draw_spiral_stroke_na (cairo_t *cr, int width, int height, int loops)
323
{
324
    return draw_spiral_stroke (cr,
325
			       NONALIGN,
326
			       width, height, loops);
327
}
328

            
329
cairo_bool_t
330
spiral_enabled (cairo_perf_t *perf)
331
{
332
    return cairo_perf_can_run (perf, "spiral", NULL);
333
}
334

            
335
void
336
spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height)
337
{
338
    cairo_perf_run (perf, "spiral-box-nonalign-evenodd-fill", draw_spiral_eo_na_box, NULL);
339
    cairo_perf_run (perf, "spiral-box-nonalign-nonzero-fill", draw_spiral_nz_na_box, NULL);
340
    cairo_perf_run (perf, "spiral-box-pixalign-evenodd-fill", draw_spiral_eo_pa_box, NULL);
341
    cairo_perf_run (perf, "spiral-box-pixalign-nonzero-fill", draw_spiral_nz_pa_box, NULL);
342
    cairo_perf_run (perf, "spiral-diag-nonalign-evenodd-fill", draw_spiral_eo_na_di, NULL);
343
    cairo_perf_run (perf, "spiral-diag-nonalign-nonzero-fill", draw_spiral_nz_na_di, NULL);
344
    cairo_perf_run (perf, "spiral-diag-pixalign-evenodd-fill", draw_spiral_eo_pa_di, NULL);
345
    cairo_perf_run (perf, "spiral-diag-pixalign-nonzero-fill", draw_spiral_nz_pa_di, NULL);
346
    cairo_perf_run (perf, "spiral-rect-nonalign-evenodd-fill", draw_spiral_eo_na_re, NULL);
347
    cairo_perf_run (perf, "spiral-rect-nonalign-nonzero-fill", draw_spiral_nz_na_re, NULL);
348
    cairo_perf_run (perf, "spiral-rect-pixalign-evenodd-fill", draw_spiral_eo_pa_re, NULL);
349
    cairo_perf_run (perf, "spiral-rect-pixalign-nonzero-fill", draw_spiral_nz_pa_re, NULL);
350
    cairo_perf_run (perf, "spiral-nonalign-stroke", draw_spiral_stroke_na, NULL);
351
    cairo_perf_run (perf, "spiral-pixalign-stroke", draw_spiral_stroke_pa, NULL);
352
}