Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1892 serge 1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2009 Intel Corporation
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * Contributor(s):
31
 *	Chris Wilson 
32
 */
33
 
34
#include "cairoint.h"
35
 
3959 Serge 36
#include "cairo-box-inline.h"
1892 serge 37
#include "cairo-boxes-private.h"
38
#include "cairo-error-private.h"
39
 
40
void
41
_cairo_boxes_init (cairo_boxes_t *boxes)
42
{
43
    boxes->status = CAIRO_STATUS_SUCCESS;
44
    boxes->num_limits = 0;
45
    boxes->num_boxes = 0;
46
 
47
    boxes->tail = &boxes->chunks;
48
    boxes->chunks.next = NULL;
49
    boxes->chunks.base = boxes->boxes_embedded;
50
    boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
51
    boxes->chunks.count = 0;
52
 
53
    boxes->is_pixel_aligned = TRUE;
54
}
55
 
56
void
3959 Serge 57
_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
58
				  int x, int y, int w, int h)
59
{
60
    _cairo_boxes_init (boxes);
61
 
62
    _cairo_box_from_integers (&boxes->chunks.base[0], x, y, w, h);
63
    boxes->num_boxes = 1;
64
}
65
 
66
void
67
_cairo_boxes_init_with_clip (cairo_boxes_t *boxes,
68
			     cairo_clip_t *clip)
69
{
70
    _cairo_boxes_init (boxes);
71
    if (clip)
72
	_cairo_boxes_limit (boxes, clip->boxes, clip->num_boxes);
73
}
74
 
75
void
1892 serge 76
_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
77
			     cairo_box_t *array,
78
			     int num_boxes)
79
{
80
    int n;
81
 
82
    boxes->status = CAIRO_STATUS_SUCCESS;
83
    boxes->num_limits = 0;
84
    boxes->num_boxes = num_boxes;
85
 
86
    boxes->tail = &boxes->chunks;
87
    boxes->chunks.next = NULL;
88
    boxes->chunks.base = array;
89
    boxes->chunks.size = num_boxes;
90
    boxes->chunks.count = num_boxes;
91
 
92
    for (n = 0; n < num_boxes; n++) {
93
	if (! _cairo_fixed_is_integer (array[n].p1.x) ||
94
	    ! _cairo_fixed_is_integer (array[n].p1.y) ||
95
	    ! _cairo_fixed_is_integer (array[n].p2.x) ||
96
	    ! _cairo_fixed_is_integer (array[n].p2.y))
97
	{
98
	    break;
99
	}
100
    }
101
 
102
    boxes->is_pixel_aligned = n == num_boxes;
103
}
104
 
105
void
106
_cairo_boxes_limit (cairo_boxes_t	*boxes,
107
		    const cairo_box_t	*limits,
108
		    int			 num_limits)
109
{
110
    int n;
111
 
112
    boxes->limits = limits;
113
    boxes->num_limits = num_limits;
114
 
115
    if (boxes->num_limits) {
116
	boxes->limit = limits[0];
117
	for (n = 1; n < num_limits; n++) {
118
	    if (limits[n].p1.x < boxes->limit.p1.x)
119
		boxes->limit.p1.x = limits[n].p1.x;
120
 
121
	    if (limits[n].p1.y < boxes->limit.p1.y)
122
		boxes->limit.p1.y = limits[n].p1.y;
123
 
124
	    if (limits[n].p2.x > boxes->limit.p2.x)
125
		boxes->limit.p2.x = limits[n].p2.x;
126
 
127
	    if (limits[n].p2.y > boxes->limit.p2.y)
128
		boxes->limit.p2.y = limits[n].p2.y;
129
	}
130
    }
131
}
132
 
133
static void
134
_cairo_boxes_add_internal (cairo_boxes_t *boxes,
135
			   const cairo_box_t *box)
136
{
137
    struct _cairo_boxes_chunk *chunk;
138
 
139
    if (unlikely (boxes->status))
140
	return;
141
 
142
    chunk = boxes->tail;
143
    if (unlikely (chunk->count == chunk->size)) {
144
	int size;
145
 
146
	size = chunk->size * 2;
147
	chunk->next = _cairo_malloc_ab_plus_c (size,
148
					       sizeof (cairo_box_t),
149
					       sizeof (struct _cairo_boxes_chunk));
150
 
151
	if (unlikely (chunk->next == NULL)) {
152
	    boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
153
	    return;
154
	}
155
 
156
	chunk = chunk->next;
157
	boxes->tail = chunk;
158
 
159
	chunk->next = NULL;
160
	chunk->count = 0;
161
	chunk->size = size;
162
	chunk->base = (cairo_box_t *) (chunk + 1);
163
    }
164
 
165
    chunk->base[chunk->count++] = *box;
166
    boxes->num_boxes++;
167
 
3959 Serge 168
    if (boxes->is_pixel_aligned)
169
	boxes->is_pixel_aligned = _cairo_box_is_pixel_aligned (box);
1892 serge 170
}
171
 
172
cairo_status_t
173
_cairo_boxes_add (cairo_boxes_t *boxes,
3959 Serge 174
		  cairo_antialias_t antialias,
1892 serge 175
		  const cairo_box_t *box)
176
{
3959 Serge 177
    cairo_box_t b;
178
 
179
    if (antialias == CAIRO_ANTIALIAS_NONE) {
180
	b.p1.x = _cairo_fixed_round_down (box->p1.x);
181
	b.p1.y = _cairo_fixed_round_down (box->p1.y);
182
	b.p2.x = _cairo_fixed_round_down (box->p2.x);
183
	b.p2.y = _cairo_fixed_round_down (box->p2.y);
184
	box = &b;
185
    }
186
 
1892 serge 187
    if (box->p1.y == box->p2.y)
188
	return CAIRO_STATUS_SUCCESS;
189
 
190
    if (box->p1.x == box->p2.x)
191
	return CAIRO_STATUS_SUCCESS;
192
 
193
    if (boxes->num_limits) {
194
	cairo_point_t p1, p2;
195
	cairo_bool_t reversed = FALSE;
196
	int n;
197
 
198
	/* support counter-clockwise winding for rectangular tessellation */
199
	if (box->p1.x < box->p2.x) {
200
	    p1.x = box->p1.x;
201
	    p2.x = box->p2.x;
202
	} else {
203
	    p2.x = box->p1.x;
204
	    p1.x = box->p2.x;
205
	    reversed = ! reversed;
206
	}
207
 
208
	if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x)
209
	    return CAIRO_STATUS_SUCCESS;
210
 
211
	if (box->p1.y < box->p2.y) {
212
	    p1.y = box->p1.y;
213
	    p2.y = box->p2.y;
214
	} else {
215
	    p2.y = box->p1.y;
216
	    p1.y = box->p2.y;
217
	    reversed = ! reversed;
218
	}
219
 
220
	if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y)
221
	    return CAIRO_STATUS_SUCCESS;
222
 
223
	for (n = 0; n < boxes->num_limits; n++) {
224
	    const cairo_box_t *limits = &boxes->limits[n];
225
	    cairo_box_t _box;
226
	    cairo_point_t _p1, _p2;
227
 
228
	    if (p1.x >= limits->p2.x || p2.x <= limits->p1.x)
229
		continue;
230
	    if (p1.y >= limits->p2.y || p2.y <= limits->p1.y)
231
		continue;
232
 
233
	    /* Otherwise, clip the box to the limits. */
234
	    _p1 = p1;
235
	    if (_p1.x < limits->p1.x)
236
		_p1.x = limits->p1.x;
237
	    if (_p1.y < limits->p1.y)
238
		_p1.y = limits->p1.y;
239
 
240
	    _p2 = p2;
241
	    if (_p2.x > limits->p2.x)
242
		_p2.x = limits->p2.x;
243
	    if (_p2.y > limits->p2.y)
244
		_p2.y = limits->p2.y;
245
 
246
	    if (_p2.y <= _p1.y || _p2.x <= _p1.x)
247
		continue;
248
 
249
	    _box.p1.y = _p1.y;
250
	    _box.p2.y = _p2.y;
251
	    if (reversed) {
252
		_box.p1.x = _p2.x;
253
		_box.p2.x = _p1.x;
254
	    } else {
255
		_box.p1.x = _p1.x;
256
		_box.p2.x = _p2.x;
257
	    }
258
 
259
	    _cairo_boxes_add_internal (boxes, &_box);
260
	}
261
    } else {
262
	_cairo_boxes_add_internal (boxes, box);
263
    }
264
 
265
    return boxes->status;
266
}
267
 
268
void
269
_cairo_boxes_extents (const cairo_boxes_t *boxes,
3959 Serge 270
		      cairo_box_t *box)
1892 serge 271
{
272
    const struct _cairo_boxes_chunk *chunk;
3959 Serge 273
    cairo_box_t b;
1892 serge 274
    int i;
275
 
3959 Serge 276
    if (boxes->num_boxes == 0) {
277
	box->p1.x = box->p1.y = box->p2.x = box->p2.y = 0;
278
	return;
279
    }
1892 serge 280
 
3959 Serge 281
    b = boxes->chunks.base[0];
1892 serge 282
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
283
	for (i = 0; i < chunk->count; i++) {
3959 Serge 284
	    if (chunk->base[i].p1.x < b.p1.x)
285
		b.p1.x = chunk->base[i].p1.x;
1892 serge 286
 
3959 Serge 287
	    if (chunk->base[i].p1.y < b.p1.y)
288
		b.p1.y = chunk->base[i].p1.y;
1892 serge 289
 
3959 Serge 290
	    if (chunk->base[i].p2.x > b.p2.x)
291
		b.p2.x = chunk->base[i].p2.x;
1892 serge 292
 
3959 Serge 293
	    if (chunk->base[i].p2.y > b.p2.y)
294
		b.p2.y = chunk->base[i].p2.y;
1892 serge 295
	}
296
    }
3959 Serge 297
    *box = b;
1892 serge 298
}
299
 
300
void
301
_cairo_boxes_clear (cairo_boxes_t *boxes)
302
{
303
    struct _cairo_boxes_chunk *chunk, *next;
304
 
305
    for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
306
	next = chunk->next;
307
	free (chunk);
308
    }
309
 
310
    boxes->tail = &boxes->chunks;
311
    boxes->chunks.next = 0;
312
    boxes->chunks.count = 0;
3959 Serge 313
    boxes->chunks.base = boxes->boxes_embedded;
314
    boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
1892 serge 315
    boxes->num_boxes = 0;
316
 
317
    boxes->is_pixel_aligned = TRUE;
318
}
319
 
3959 Serge 320
cairo_box_t *
321
_cairo_boxes_to_array (const cairo_boxes_t *boxes,
322
		       int *num_boxes,
323
		       cairo_bool_t force_allocation)
324
{
325
    const struct _cairo_boxes_chunk *chunk;
326
    cairo_box_t *box;
327
    int i, j;
328
 
329
    *num_boxes = boxes->num_boxes;
330
    if (boxes->chunks.next == NULL && ! force_allocation)
331
	    return boxes->chunks.base;
332
 
333
    box = _cairo_malloc_ab (boxes->num_boxes, sizeof (cairo_box_t));
334
    if (box == NULL) {
335
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
336
	return NULL;
337
    }
338
 
339
    j = 0;
340
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
341
	for (i = 0; i < chunk->count; i++)
342
	    box[j++] = chunk->base[i];
343
    }
344
 
345
    return box;
346
}
347
 
1892 serge 348
void
349
_cairo_boxes_fini (cairo_boxes_t *boxes)
350
{
351
    struct _cairo_boxes_chunk *chunk, *next;
352
 
353
    for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
354
	next = chunk->next;
355
	free (chunk);
356
    }
357
}
3959 Serge 358
 
359
cairo_bool_t
360
_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
361
			   cairo_bool_t (*func) (cairo_box_t *box, void *data),
362
			   void *data)
363
{
364
    struct _cairo_boxes_chunk *chunk;
365
    int i;
366
 
367
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
368
	for (i = 0; i < chunk->count; i++)
369
	    if (! func (&chunk->base[i], data))
370
		return FALSE;
371
    }
372
 
373
    return TRUE;
374
}
375
 
376
struct cairo_box_renderer {
377
    cairo_span_renderer_t base;
378
    cairo_boxes_t *boxes;
379
};
380
 
381
static cairo_status_t
382
span_to_boxes (void *abstract_renderer, int y, int h,
383
	       const cairo_half_open_span_t *spans, unsigned num_spans)
384
{
385
    struct cairo_box_renderer *r = abstract_renderer;
386
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
387
    cairo_box_t box;
388
 
389
    if (num_spans == 0)
390
	return CAIRO_STATUS_SUCCESS;
391
 
392
    box.p1.y = _cairo_fixed_from_int (y);
393
    box.p2.y = _cairo_fixed_from_int (y + h);
394
    do {
395
	if (spans[0].coverage) {
396
	    box.p1.x = _cairo_fixed_from_int(spans[0].x);
397
	    box.p2.x = _cairo_fixed_from_int(spans[1].x);
398
	    status = _cairo_boxes_add (r->boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
399
	}
400
	spans++;
401
    } while (--num_spans > 1 && status == CAIRO_STATUS_SUCCESS);
402
 
403
    return status;
404
}
405
 
406
cairo_status_t
407
_cairo_rasterise_polygon_to_boxes (cairo_polygon_t			*polygon,
408
				   cairo_fill_rule_t			 fill_rule,
409
				   cairo_boxes_t *boxes)
410
{
411
    struct cairo_box_renderer renderer;
412
    cairo_scan_converter_t *converter;
413
    cairo_int_status_t status;
414
    cairo_rectangle_int_t r;
415
 
416
    TRACE ((stderr, "%s: fill_rule=%d\n", __FUNCTION__, fill_rule));
417
 
418
    _cairo_box_round_to_rectangle (&polygon->extents, &r);
419
    converter = _cairo_mono_scan_converter_create (r.x, r.y,
420
						   r.x + r.width,
421
						   r.y + r.height,
422
						   fill_rule);
423
    status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
424
    if (unlikely (status))
425
	goto cleanup_converter;
426
 
427
    renderer.boxes = boxes;
428
    renderer.base.render_rows = span_to_boxes;
429
 
430
    status = converter->generate (converter, &renderer.base);
431
cleanup_converter:
432
    converter->destroy (converter);
433
    return status;
434
}
435
 
436
void
437
_cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes)
438
{
439
    const struct _cairo_boxes_chunk *chunk;
440
    cairo_box_t extents;
441
    int i;
442
 
443
    _cairo_boxes_extents (boxes, &extents);
444
    fprintf (stream, "boxes x %d: (%f, %f) x (%f, %f)\n",
445
	     boxes->num_boxes,
446
	     _cairo_fixed_to_double (extents.p1.x),
447
	     _cairo_fixed_to_double (extents.p1.y),
448
	     _cairo_fixed_to_double (extents.p2.x),
449
	     _cairo_fixed_to_double (extents.p2.y));
450
 
451
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
452
	for (i = 0; i < chunk->count; i++) {
453
	    fprintf (stderr, "  box[%d]: (%f, %f), (%f, %f)\n", i,
454
		     _cairo_fixed_to_double (chunk->base[i].p1.x),
455
		     _cairo_fixed_to_double (chunk->base[i].p1.y),
456
		     _cairo_fixed_to_double (chunk->base[i].p2.x),
457
		     _cairo_fixed_to_double (chunk->base[i].p2.y));
458
	}
459
    }
460
}