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
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/*
3
 * Copyright © 2002 Keith Packard
4
 * Copyright © 2007 Red Hat, Inc.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Keith Packard
32
 *
33
 * Contributor(s):
34
 *	Keith R. Packard 
35
 *	Carl D. Worth 
36
 *
37
 * 2002-07-15: Converted from XRenderCompositeDoublePoly to #cairo_trap_t. Carl D. Worth
38
 */
39
 
40
#include "cairoint.h"
41
 
3959 Serge 42
#include "cairo-box-inline.h"
1892 serge 43
#include "cairo-boxes-private.h"
44
#include "cairo-error-private.h"
45
#include "cairo-region-private.h"
46
#include "cairo-slope-private.h"
3959 Serge 47
#include "cairo-traps-private.h"
48
#include "cairo-spans-private.h"
1892 serge 49
 
50
/* private functions */
51
 
52
void
53
_cairo_traps_init (cairo_traps_t *traps)
54
{
55
    VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
56
 
57
    traps->status = CAIRO_STATUS_SUCCESS;
58
 
59
    traps->maybe_region = 1;
60
    traps->is_rectilinear = 0;
61
    traps->is_rectangular = 0;
62
 
63
    traps->num_traps = 0;
64
 
65
    traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
66
    traps->traps = traps->traps_embedded;
67
 
68
    traps->num_limits = 0;
69
    traps->has_intersections = FALSE;
70
}
71
 
72
void
73
_cairo_traps_limit (cairo_traps_t	*traps,
74
		    const cairo_box_t	*limits,
75
		    int			 num_limits)
76
{
3959 Serge 77
    int i;
78
 
1892 serge 79
    traps->limits = limits;
80
    traps->num_limits = num_limits;
3959 Serge 81
 
82
    traps->bounds = limits[0];
83
    for (i = 1; i < num_limits; i++)
84
	_cairo_box_add_box (&traps->bounds, &limits[i]);
1892 serge 85
}
86
 
87
void
3959 Serge 88
_cairo_traps_init_with_clip (cairo_traps_t *traps,
89
			     const cairo_clip_t *clip)
90
{
91
    _cairo_traps_init (traps);
92
    if (clip)
93
	_cairo_traps_limit (traps, clip->boxes, clip->num_boxes);
94
}
95
 
96
void
1892 serge 97
_cairo_traps_clear (cairo_traps_t *traps)
98
{
99
    traps->status = CAIRO_STATUS_SUCCESS;
100
 
101
    traps->maybe_region = 1;
102
    traps->is_rectilinear = 0;
103
    traps->is_rectangular = 0;
104
 
105
    traps->num_traps = 0;
106
    traps->has_intersections = FALSE;
107
}
108
 
109
void
110
_cairo_traps_fini (cairo_traps_t *traps)
111
{
112
    if (traps->traps != traps->traps_embedded)
113
	free (traps->traps);
114
 
115
    VG (VALGRIND_MAKE_MEM_NOACCESS (traps, sizeof (cairo_traps_t)));
116
}
117
 
118
/* make room for at least one more trap */
119
static cairo_bool_t
120
_cairo_traps_grow (cairo_traps_t *traps)
121
{
122
    cairo_trapezoid_t *new_traps;
123
    int new_size = 4 * traps->traps_size;
124
 
125
    if (CAIRO_INJECT_FAULT ()) {
126
	traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
127
	return FALSE;
128
    }
129
 
130
    if (traps->traps == traps->traps_embedded) {
131
	new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
132
	if (new_traps != NULL)
133
	    memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
134
    } else {
135
	new_traps = _cairo_realloc_ab (traps->traps,
136
	                               new_size, sizeof (cairo_trapezoid_t));
137
    }
138
 
139
    if (unlikely (new_traps == NULL)) {
140
	traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
141
	return FALSE;
142
    }
143
 
144
    traps->traps = new_traps;
145
    traps->traps_size = new_size;
146
    return TRUE;
147
}
148
 
149
void
150
_cairo_traps_add_trap (cairo_traps_t *traps,
151
		       cairo_fixed_t top, cairo_fixed_t bottom,
152
		       cairo_line_t *left, cairo_line_t *right)
153
{
154
    cairo_trapezoid_t *trap;
155
 
156
    if (unlikely (traps->num_traps == traps->traps_size)) {
157
	if (unlikely (! _cairo_traps_grow (traps)))
158
	    return;
159
    }
160
 
161
    trap = &traps->traps[traps->num_traps++];
162
    trap->top = top;
163
    trap->bottom = bottom;
164
    trap->left = *left;
165
    trap->right = *right;
166
}
167
 
3959 Serge 168
static void
169
_cairo_traps_add_clipped_trap (cairo_traps_t *traps,
170
			       cairo_fixed_t _top, cairo_fixed_t _bottom,
171
			       cairo_line_t *_left, cairo_line_t *_right)
172
{
173
    /* Note: With the goofy trapezoid specification, (where an
174
     * arbitrary two points on the lines can specified for the left
175
     * and right edges), these limit checks would not work in
176
     * general. For example, one can imagine a trapezoid entirely
177
     * within the limits, but with two points used to specify the left
178
     * edge entirely to the right of the limits.  Fortunately, for our
179
     * purposes, cairo will never generate such a crazy
180
     * trapezoid. Instead, cairo always uses for its points the
181
     * extreme positions of the edge that are visible on at least some
182
     * trapezoid. With this constraint, it's impossible for both
183
     * points to be outside the limits while the relevant edge is
184
     * entirely inside the limits.
185
     */
186
    if (traps->num_limits) {
187
	const cairo_box_t *b = &traps->bounds;
188
	cairo_fixed_t top = _top, bottom = _bottom;
189
	cairo_line_t left = *_left, right = *_right;
190
 
191
	/* Trivially reject if trapezoid is entirely to the right or
192
	 * to the left of the limits. */
193
	if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x)
194
	    return;
195
 
196
	if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x)
197
	    return;
198
 
199
	/* And reject if the trapezoid is entirely above or below */
200
	if (top >= b->p2.y || bottom <= b->p1.y)
201
	    return;
202
 
203
	/* Otherwise, clip the trapezoid to the limits. We only clip
204
	 * where an edge is entirely outside the limits. If we wanted
205
	 * to be more clever, we could handle cases where a trapezoid
206
	 * edge intersects the edge of the limits, but that would
207
	 * require slicing this trapezoid into multiple trapezoids,
208
	 * and I'm not sure the effort would be worth it. */
209
	if (top < b->p1.y)
210
	    top = b->p1.y;
211
 
212
	if (bottom > b->p2.y)
213
	    bottom = b->p2.y;
214
 
215
	if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x)
216
	    left.p1.x = left.p2.x = b->p1.x;
217
 
218
	if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x)
219
	    right.p1.x = right.p2.x = b->p2.x;
220
 
221
	/* Trivial discards for empty trapezoids that are likely to
222
	 * be produced by our tessellators (most notably convex_quad
223
	 * when given a simple rectangle).
224
	 */
225
	if (top >= bottom)
226
	    return;
227
 
228
	/* cheap colinearity check */
229
	if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y &&
230
	    right.p2.x <= left.p2.x && right.p2.y == left.p2.y)
231
	    return;
232
 
233
	_cairo_traps_add_trap (traps, top, bottom, &left, &right);
234
    } else
235
	_cairo_traps_add_trap (traps, _top, _bottom, _left, _right);
236
}
237
 
238
static int
239
_compare_point_fixed_by_y (const void *av, const void *bv)
240
{
241
    const cairo_point_t	*a = av, *b = bv;
242
    int ret = a->y - b->y;
243
    if (ret == 0)
244
	ret = a->x - b->x;
245
    return ret;
246
}
247
 
248
void
249
_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
250
				     const cairo_point_t q[4])
251
{
252
    int a, b, c, d;
253
    int i;
254
    cairo_slope_t ab, ad;
255
    cairo_bool_t b_left_of_d;
256
    cairo_line_t left;
257
    cairo_line_t right;
258
 
259
    /* Choose a as a point with minimal y */
260
    a = 0;
261
    for (i = 1; i < 4; i++)
262
	if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
263
	    a = i;
264
 
265
    /* b and d are adjacent to a, while c is opposite */
266
    b = (a + 1) % 4;
267
    c = (a + 2) % 4;
268
    d = (a + 3) % 4;
269
 
270
    /* Choose between b and d so that b.y is less than d.y */
271
    if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
272
	b = (a + 3) % 4;
273
	d = (a + 1) % 4;
274
    }
275
 
276
    /* Without freedom left to choose anything else, we have four
277
     * cases to tessellate.
278
     *
279
     * First, we have to determine the Y-axis sort of the four
280
     * vertices, (either abcd or abdc). After that we need to detemine
281
     * which edges will be "left" and which will be "right" in the
282
     * resulting trapezoids. This can be determined by computing a
283
     * slope comparison of ab and ad to determine if b is left of d or
284
     * not.
285
     *
286
     * Note that "left of" here is in the sense of which edges should
287
     * be the left vs. right edges of the trapezoid. In particular, b
288
     * left of d does *not* mean that b.x is less than d.x.
289
     *
290
     * This should hopefully be made clear in the lame ASCII art
291
     * below. Since the same slope comparison is used in all cases, we
292
     * compute it before testing for the Y-value sort. */
293
 
294
    /* Note: If a == b then the ab slope doesn't give us any
295
     * information. In that case, we can replace it with the ac (or
296
     * equivalenly the bc) slope which gives us exactly the same
297
     * information we need. At worst the names of the identifiers ab
298
     * and b_left_of_d are inaccurate in this case, (would be ac, and
299
     * c_left_of_d). */
300
    if (q[a].x == q[b].x && q[a].y == q[b].y)
301
	_cairo_slope_init (&ab, &q[a], &q[c]);
302
    else
303
	_cairo_slope_init (&ab, &q[a], &q[b]);
304
 
305
    _cairo_slope_init (&ad, &q[a], &q[d]);
306
 
307
    b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;
308
 
309
    if (q[c].y <= q[d].y) {
310
	if (b_left_of_d) {
311
	    /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
312
	     *
313
	     *                      top bot left right
314
	     *        _a  a  a
315
	     *      / /  /|  |\      a.y b.y  ab   ad
316
	     *     b /  b |  b \
317
	     *    / /   | |   \ \    b.y c.y  bc   ad
318
	     *   c /    c |    c \
319
	     *  | /      \|     \ \  c.y d.y  cd   ad
320
	     *  d         d       d
321
	     */
322
	    left.p1  = q[a]; left.p2  = q[b];
323
	    right.p1 = q[a]; right.p2 = q[d];
324
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
325
	    left.p1  = q[b]; left.p2  = q[c];
326
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
327
	    left.p1  = q[c]; left.p2  = q[d];
328
	    _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
329
	} else {
330
	    /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
331
	     *
332
	     *       a  a  a_
333
	     *      /|  |\  \ \     a.y b.y  ad  ab
334
	     *     / b  | b  \ b
335
	     *    / /   | |   \ \   b.y c.y  ad  bc
336
	     *   / c    | c    \ c
337
	     *  / /     |/      \ | c.y d.y  ad  cd
338
	     *  d       d         d
339
	     */
340
	    left.p1  = q[a]; left.p2  = q[d];
341
	    right.p1 = q[a]; right.p2 = q[b];
342
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
343
	    right.p1 = q[b]; right.p2 = q[c];
344
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
345
	    right.p1 = q[c]; right.p2 = q[d];
346
	    _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
347
	}
348
    } else {
349
	if (b_left_of_d) {
350
	    /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
351
	     *
352
	     *        a   a     a
353
	     *       //  / \    |\     a.y b.y  ab  ad
354
	     *     /b/  b   \   b \
355
	     *    / /    \   \   \ \   b.y d.y  bc  ad
356
	     *   /d/      \   d   \ d
357
	     *  //         \ /     \|  d.y c.y  bc  dc
358
	     *  c           c       c
359
	     */
360
	    left.p1  = q[a]; left.p2  = q[b];
361
	    right.p1 = q[a]; right.p2 = q[d];
362
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
363
	    left.p1  = q[b]; left.p2  = q[c];
364
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
365
	    right.p1 = q[d]; right.p2 = q[c];
366
	    _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
367
	} else {
368
	    /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
369
	     *
370
	     *      a     a   a
371
	     *     /|    / \  \\       a.y b.y  ad  ab
372
	     *    / b   /   b  \b\
373
	     *   / /   /   /    \ \    b.y d.y  ad  bc
374
	     *  d /   d   /	 \d\
375
	     *  |/     \ /         \\  d.y c.y  dc  bc
376
	     *  c       c	   c
377
	     */
378
	    left.p1  = q[a]; left.p2  = q[d];
379
	    right.p1 = q[a]; right.p2 = q[b];
380
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
381
	    right.p1 = q[b]; right.p2 = q[c];
382
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
383
	    left.p1  = q[d]; left.p2  = q[c];
384
	    _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
385
	}
386
    }
387
}
388
 
389
/* A triangle is simply a degenerate case of a convex
390
 * quadrilateral. We would not benefit from having any distinct
391
 * implementation of triangle vs. quadrilateral tessellation here. */
392
void
393
_cairo_traps_tessellate_triangle (cairo_traps_t *traps,
394
				  const cairo_point_t t[3])
395
{
396
    cairo_point_t quad[4];
397
 
398
    quad[0] = t[0];
399
    quad[1] = t[0];
400
    quad[2] = t[1];
401
    quad[3] = t[2];
402
 
403
    _cairo_traps_tessellate_convex_quad (traps, quad);
404
}
405
 
406
 
1892 serge 407
/**
3959 Serge 408
 * _cairo_traps_init_boxes:
1892 serge 409
 * @traps: a #cairo_traps_t
410
 * @box: an array box that will each be converted to a single trapezoid
411
 *       to store in @traps.
412
 *
413
 * Initializes a #cairo_traps_t to contain an array of rectangular
414
 * trapezoids.
415
 **/
416
cairo_status_t
417
_cairo_traps_init_boxes (cairo_traps_t	    *traps,
418
		         const cairo_boxes_t *boxes)
419
{
420
    cairo_trapezoid_t *trap;
421
    const struct _cairo_boxes_chunk *chunk;
422
 
423
    _cairo_traps_init (traps);
424
 
425
    while (traps->traps_size < boxes->num_boxes) {
426
	if (unlikely (! _cairo_traps_grow (traps))) {
427
	    _cairo_traps_fini (traps);
428
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
429
	}
430
    }
431
 
432
    traps->num_traps = boxes->num_boxes;
433
    traps->is_rectilinear = TRUE;
434
    traps->is_rectangular = TRUE;
435
    traps->maybe_region = boxes->is_pixel_aligned;
436
 
437
    trap = &traps->traps[0];
438
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
439
	const cairo_box_t *box;
440
	int i;
441
 
442
	box = chunk->base;
443
	for (i = 0; i < chunk->count; i++) {
444
	    trap->top    = box->p1.y;
445
	    trap->bottom = box->p2.y;
446
 
447
	    trap->left.p1   = box->p1;
448
	    trap->left.p2.x = box->p1.x;
449
	    trap->left.p2.y = box->p2.y;
450
 
451
	    trap->right.p1.x = box->p2.x;
452
	    trap->right.p1.y = box->p1.y;
453
	    trap->right.p2   = box->p2;
454
 
455
	    box++, trap++;
456
	}
457
    }
458
 
459
    return CAIRO_STATUS_SUCCESS;
460
}
461
 
462
cairo_status_t
463
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
464
				   const cairo_point_t *top_left,
465
				   const cairo_point_t *bottom_right)
466
{
467
    cairo_line_t left;
468
    cairo_line_t right;
469
    cairo_fixed_t top, bottom;
470
 
471
    if (top_left->y == bottom_right->y)
472
	return CAIRO_STATUS_SUCCESS;
473
 
474
    if (top_left->x == bottom_right->x)
475
	return CAIRO_STATUS_SUCCESS;
476
 
477
     left.p1.x =  left.p2.x = top_left->x;
478
     left.p1.y = right.p1.y = top_left->y;
479
    right.p1.x = right.p2.x = bottom_right->x;
480
     left.p2.y = right.p2.y = bottom_right->y;
481
 
482
     top = top_left->y;
483
     bottom = bottom_right->y;
484
 
485
    if (traps->num_limits) {
486
	cairo_bool_t reversed;
487
	int n;
488
 
3959 Serge 489
	if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y)
490
	    return CAIRO_STATUS_SUCCESS;
491
 
1892 serge 492
	/* support counter-clockwise winding for rectangular tessellation */
493
	reversed = top_left->x > bottom_right->x;
494
	if (reversed) {
495
	    right.p1.x = right.p2.x = top_left->x;
496
	    left.p1.x = left.p2.x = bottom_right->x;
497
	}
498
 
3959 Serge 499
	if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x)
500
	    return CAIRO_STATUS_SUCCESS;
501
 
1892 serge 502
	for (n = 0; n < traps->num_limits; n++) {
503
	    const cairo_box_t *limits = &traps->limits[n];
504
	    cairo_line_t _left, _right;
505
	    cairo_fixed_t _top, _bottom;
506
 
507
	    if (top >= limits->p2.y)
508
		continue;
509
	    if (bottom <= limits->p1.y)
510
		continue;
511
 
512
	    /* Trivially reject if trapezoid is entirely to the right or
513
	     * to the left of the limits. */
514
	    if (left.p1.x >= limits->p2.x)
515
		continue;
516
	    if (right.p1.x <= limits->p1.x)
517
		continue;
518
 
519
	    /* Otherwise, clip the trapezoid to the limits. */
520
	    _top = top;
521
	    if (_top < limits->p1.y)
522
		_top = limits->p1.y;
523
 
524
	    _bottom = bottom;
525
	    if (_bottom > limits->p2.y)
526
		_bottom = limits->p2.y;
527
 
528
	    if (_bottom <= _top)
529
		continue;
530
 
531
	    _left = left;
532
	    if (_left.p1.x < limits->p1.x) {
533
		_left.p1.x = limits->p1.x;
534
		_left.p1.y = limits->p1.y;
535
		_left.p2.x = limits->p1.x;
536
		_left.p2.y = limits->p2.y;
537
	    }
538
 
539
	    _right = right;
540
	    if (_right.p1.x > limits->p2.x) {
541
		_right.p1.x = limits->p2.x;
542
		_right.p1.y = limits->p1.y;
543
		_right.p2.x = limits->p2.x;
544
		_right.p2.y = limits->p2.y;
545
	    }
546
 
547
	    if (left.p1.x >= right.p1.x)
548
		continue;
549
 
550
	    if (reversed)
551
		_cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
552
	    else
553
		_cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
554
	}
555
    } else {
556
	_cairo_traps_add_trap (traps, top, bottom, &left, &right);
557
    }
558
 
559
    return traps->status;
560
}
561
 
562
void
563
_cairo_traps_translate (cairo_traps_t *traps, int x, int y)
564
{
565
    cairo_fixed_t xoff, yoff;
566
    cairo_trapezoid_t *t;
567
    int i;
568
 
569
    /* Ugh. The cairo_composite/(Render) interface doesn't allow
570
       an offset for the trapezoids. Need to manually shift all
571
       the coordinates to align with the offset origin of the
572
       intermediate surface. */
573
 
574
    xoff = _cairo_fixed_from_int (x);
575
    yoff = _cairo_fixed_from_int (y);
576
 
577
    for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
578
	t->top += yoff;
579
	t->bottom += yoff;
580
	t->left.p1.x += xoff;
581
	t->left.p1.y += yoff;
582
	t->left.p2.x += xoff;
583
	t->left.p2.y += yoff;
584
	t->right.p1.x += xoff;
585
	t->right.p1.y += yoff;
586
	t->right.p2.x += xoff;
587
	t->right.p2.y += yoff;
588
    }
589
}
590
 
591
void
592
_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
593
                                            cairo_trapezoid_t *src_traps,
594
                                            int num_traps,
595
                                            double tx, double ty,
596
                                            double sx, double sy)
597
{
598
    int i;
599
    cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
600
    cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
601
 
602
    if (sx == 1.0 && sy == 1.0) {
603
        for (i = 0; i < num_traps; i++) {
604
            offset_traps[i].top = src_traps[i].top + yoff;
605
            offset_traps[i].bottom = src_traps[i].bottom + yoff;
606
            offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
607
            offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
608
            offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
609
            offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
610
            offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
611
            offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
612
            offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
613
            offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
614
        }
615
    } else {
616
        cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
617
        cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
618
 
619
        for (i = 0; i < num_traps; i++) {
620
            offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc);
621
            offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc);
622
            offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc);
623
            offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc);
624
            offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc);
625
            offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc);
626
            offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc);
627
            offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc);
628
            offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc);
629
            offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc);
630
        }
631
    }
632
}
633
 
634
static cairo_bool_t
635
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
636
{
637
    cairo_slope_t slope_left, slope_pt, slope_right;
638
 
639
    if (t->top > pt->y)
640
	return FALSE;
641
    if (t->bottom < pt->y)
642
	return FALSE;
643
 
644
    _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
645
    _cairo_slope_init (&slope_pt, &t->left.p1, pt);
646
 
647
    if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
648
	return FALSE;
649
 
650
    _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
651
    _cairo_slope_init (&slope_pt, &t->right.p1, pt);
652
 
653
    if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
654
	return FALSE;
655
 
656
    return TRUE;
657
}
658
 
659
cairo_bool_t
660
_cairo_traps_contain (const cairo_traps_t *traps,
661
		      double x, double y)
662
{
663
    int i;
664
    cairo_point_t point;
665
 
666
    point.x = _cairo_fixed_from_double (x);
667
    point.y = _cairo_fixed_from_double (y);
668
 
669
    for (i = 0; i < traps->num_traps; i++) {
670
	if (_cairo_trap_contains (&traps->traps[i], &point))
671
	    return TRUE;
672
    }
673
 
674
    return FALSE;
675
}
676
 
677
static cairo_fixed_t
678
_line_compute_intersection_x_for_y (const cairo_line_t *line,
679
				    cairo_fixed_t y)
680
{
681
    return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
682
}
683
 
684
void
685
_cairo_traps_extents (const cairo_traps_t *traps,
686
		      cairo_box_t *extents)
687
{
688
    int i;
689
 
690
    if (traps->num_traps == 0) {
691
	extents->p1.x = extents->p1.y = 0;
692
	extents->p2.x = extents->p2.y = 0;
693
	return;
694
    }
695
 
696
    extents->p1.x = extents->p1.y = INT32_MAX;
697
    extents->p2.x = extents->p2.y = INT32_MIN;
698
 
699
    for (i = 0; i < traps->num_traps; i++) {
700
	const cairo_trapezoid_t *trap =  &traps->traps[i];
701
 
702
	if (trap->top < extents->p1.y)
703
	    extents->p1.y = trap->top;
704
	if (trap->bottom > extents->p2.y)
705
	    extents->p2.y = trap->bottom;
706
 
707
	if (trap->left.p1.x < extents->p1.x) {
708
	    cairo_fixed_t x = trap->left.p1.x;
709
	    if (trap->top != trap->left.p1.y) {
710
		x = _line_compute_intersection_x_for_y (&trap->left,
711
							trap->top);
712
		if (x < extents->p1.x)
713
		    extents->p1.x = x;
714
	    } else
715
		extents->p1.x = x;
716
	}
717
	if (trap->left.p2.x < extents->p1.x) {
718
	    cairo_fixed_t x = trap->left.p2.x;
719
	    if (trap->bottom != trap->left.p2.y) {
720
		x = _line_compute_intersection_x_for_y (&trap->left,
721
							trap->bottom);
722
		if (x < extents->p1.x)
723
		    extents->p1.x = x;
724
	    } else
725
		extents->p1.x = x;
726
	}
727
 
728
	if (trap->right.p1.x > extents->p2.x) {
729
	    cairo_fixed_t x = trap->right.p1.x;
730
	    if (trap->top != trap->right.p1.y) {
731
		x = _line_compute_intersection_x_for_y (&trap->right,
732
							trap->top);
733
		if (x > extents->p2.x)
734
		    extents->p2.x = x;
735
	    } else
736
		extents->p2.x = x;
737
	}
738
	if (trap->right.p2.x > extents->p2.x) {
739
	    cairo_fixed_t x = trap->right.p2.x;
740
	    if (trap->bottom != trap->right.p2.y) {
741
		x = _line_compute_intersection_x_for_y (&trap->right,
742
							trap->bottom);
743
		if (x > extents->p2.x)
744
		    extents->p2.x = x;
745
	    } else
746
		extents->p2.x = x;
747
	}
748
    }
749
}
750
 
3959 Serge 751
static cairo_bool_t
752
_mono_edge_is_vertical (const cairo_line_t *line)
753
{
754
    return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
755
}
1892 serge 756
 
3959 Serge 757
static cairo_bool_t
758
_traps_are_pixel_aligned (cairo_traps_t *traps,
759
			  cairo_antialias_t antialias)
760
{
761
    int i;
762
 
763
    if (antialias == CAIRO_ANTIALIAS_NONE) {
764
	for (i = 0; i < traps->num_traps; i++) {
765
	    if (! _mono_edge_is_vertical (&traps->traps[i].left)   ||
766
		! _mono_edge_is_vertical (&traps->traps[i].right))
767
	    {
768
		traps->maybe_region = FALSE;
769
		return FALSE;
770
	    }
771
	}
772
    } else {
773
	for (i = 0; i < traps->num_traps; i++) {
774
	    if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
775
		traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
776
		! _cairo_fixed_is_integer (traps->traps[i].top)          ||
777
		! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
778
		! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
779
		! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
780
	    {
781
		traps->maybe_region = FALSE;
782
		return FALSE;
783
	    }
784
	}
785
    }
786
 
787
    return TRUE;
788
}
789
 
1892 serge 790
/**
791
 * _cairo_traps_extract_region:
792
 * @traps: a #cairo_traps_t
793
 * @region: a #cairo_region_t
794
 *
795
 * Determines if a set of trapezoids are exactly representable as a
796
 * cairo region.  If so, the passed-in region is initialized to
797
 * the area representing the given traps.  It should be finalized
798
 * with cairo_region_fini().  If not, %CAIRO_INT_STATUS_UNSUPPORTED
799
 * is returned.
800
 *
801
 * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
802
 * or %CAIRO_STATUS_NO_MEMORY
803
 **/
804
cairo_int_status_t
805
_cairo_traps_extract_region (cairo_traps_t   *traps,
3959 Serge 806
			     cairo_antialias_t antialias,
1892 serge 807
			     cairo_region_t **region)
808
{
809
    cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
810
    cairo_rectangle_int_t *rects = stack_rects;
811
    cairo_int_status_t status;
812
    int i, rect_count;
813
 
814
    /* we only treat this a hint... */
3959 Serge 815
    if (antialias != CAIRO_ANTIALIAS_NONE && ! traps->maybe_region)
1892 serge 816
	return CAIRO_INT_STATUS_UNSUPPORTED;
817
 
3959 Serge 818
    if (! _traps_are_pixel_aligned (traps, antialias)) {
819
	traps->maybe_region = FALSE;
820
	return CAIRO_INT_STATUS_UNSUPPORTED;
1892 serge 821
    }
822
 
823
    if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
824
	rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t));
825
 
826
	if (unlikely (rects == NULL))
827
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
828
    }
829
 
830
    rect_count = 0;
831
    for (i = 0; i < traps->num_traps; i++) {
3959 Serge 832
	int x1, y1, x2, y2;
1892 serge 833
 
3959 Serge 834
	if (antialias == CAIRO_ANTIALIAS_NONE) {
835
	    x1 = _cairo_fixed_integer_round_down (traps->traps[i].left.p1.x);
836
	    y1 = _cairo_fixed_integer_round_down (traps->traps[i].top);
837
	    x2 = _cairo_fixed_integer_round_down (traps->traps[i].right.p1.x);
838
	    y2 = _cairo_fixed_integer_round_down (traps->traps[i].bottom);
839
	} else {
840
	    x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
841
	    y1 = _cairo_fixed_integer_part (traps->traps[i].top);
842
	    x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
843
	    y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
844
	}
1892 serge 845
 
3959 Serge 846
	if (x2 > x1 && y2 > y1) {
847
	    rects[rect_count].x = x1;
848
	    rects[rect_count].y = y1;
849
	    rects[rect_count].width  = x2 - x1;
850
	    rects[rect_count].height = y2 - y1;
851
	    rect_count++;
852
	}
1892 serge 853
    }
854
 
3959 Serge 855
 
1892 serge 856
    *region = cairo_region_create_rectangles (rects, rect_count);
857
    status = (*region)->status;
858
 
859
    if (rects != stack_rects)
860
	free (rects);
861
 
862
    return status;
863
}
864
 
3959 Serge 865
cairo_bool_t
866
_cairo_traps_to_boxes (cairo_traps_t *traps,
867
		       cairo_antialias_t antialias,
868
		       cairo_boxes_t *boxes)
869
{
870
    int i;
871
 
872
    for (i = 0; i < traps->num_traps; i++) {
873
	if (traps->traps[i].left.p1.x  != traps->traps[i].left.p2.x ||
874
	    traps->traps[i].right.p1.x != traps->traps[i].right.p2.x)
875
	    return FALSE;
876
    }
877
 
878
    _cairo_boxes_init (boxes);
879
 
880
    boxes->num_boxes    = traps->num_traps;
881
    boxes->chunks.base  = (cairo_box_t *) traps->traps;
882
    boxes->chunks.count = traps->num_traps;
883
    boxes->chunks.size  = traps->num_traps;
884
 
885
    if (antialias != CAIRO_ANTIALIAS_NONE) {
886
	for (i = 0; i < traps->num_traps; i++) {
887
	    /* Note the traps and boxes alias so we need to take the local copies first. */
888
	    cairo_fixed_t x1 = traps->traps[i].left.p1.x;
889
	    cairo_fixed_t x2 = traps->traps[i].right.p1.x;
890
	    cairo_fixed_t y1 = traps->traps[i].top;
891
	    cairo_fixed_t y2 = traps->traps[i].bottom;
892
 
893
	    boxes->chunks.base[i].p1.x = x1;
894
	    boxes->chunks.base[i].p1.y = y1;
895
	    boxes->chunks.base[i].p2.x = x2;
896
	    boxes->chunks.base[i].p2.y = y2;
897
 
898
	    if (boxes->is_pixel_aligned) {
899
		boxes->is_pixel_aligned =
900
		    _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
901
		    _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
902
	    }
903
	}
904
    } else {
905
	boxes->is_pixel_aligned = TRUE;
906
 
907
	for (i = 0; i < traps->num_traps; i++) {
908
	    /* Note the traps and boxes alias so we need to take the local copies first. */
909
	    cairo_fixed_t x1 = traps->traps[i].left.p1.x;
910
	    cairo_fixed_t x2 = traps->traps[i].right.p1.x;
911
	    cairo_fixed_t y1 = traps->traps[i].top;
912
	    cairo_fixed_t y2 = traps->traps[i].bottom;
913
 
914
	    /* round down here to match Pixman's behavior when using traps. */
915
	    boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
916
	    boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
917
	    boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
918
	    boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
919
	}
920
    }
921
 
922
    return TRUE;
923
}
924
 
1892 serge 925
/* moves trap points such that they become the actual corners of the trapezoid */
926
static void
927
_sanitize_trap (cairo_trapezoid_t *t)
928
{
929
    cairo_trapezoid_t s = *t;
930
 
931
#define FIX(lr, tb, p) \
932
    if (t->lr.p.y != t->tb) { \
933
        t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div_floor (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \
934
        t->lr.p.y = s.tb; \
935
    }
936
    FIX (left,  top,    p1);
937
    FIX (left,  bottom, p2);
938
    FIX (right, top,    p1);
939
    FIX (right, bottom, p2);
940
}
941
 
942
cairo_private cairo_status_t
943
_cairo_traps_path (const cairo_traps_t *traps,
944
		   cairo_path_fixed_t  *path)
945
{
946
    int i;
947
 
948
    for (i = 0; i < traps->num_traps; i++) {
949
	cairo_status_t status;
950
	cairo_trapezoid_t trap = traps->traps[i];
951
 
952
	if (trap.top == trap.bottom)
953
	    continue;
954
 
955
	_sanitize_trap (&trap);
956
 
957
	status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
958
	if (unlikely (status)) return status;
959
	status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
960
	if (unlikely (status)) return status;
961
	status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
962
	if (unlikely (status)) return status;
963
	status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
964
	if (unlikely (status)) return status;
965
	status = _cairo_path_fixed_close_path (path);
966
	if (unlikely (status)) return status;
967
    }
968
 
969
    return CAIRO_STATUS_SUCCESS;
970
}
3959 Serge 971
 
972
void
973
_cairo_debug_print_traps (FILE *file, const cairo_traps_t *traps)
974
{
975
    cairo_box_t extents;
976
    int n;
977
 
978
#if 0
979
    if (traps->has_limits) {
980
	printf ("%s: limits=(%d, %d, %d, %d)\n",
981
		filename,
982
		traps->limits.p1.x, traps->limits.p1.y,
983
		traps->limits.p2.x, traps->limits.p2.y);
984
    }
985
#endif
986
 
987
    _cairo_traps_extents (traps, &extents);
988
    fprintf (file, "extents=(%d, %d, %d, %d)\n",
989
	     extents.p1.x, extents.p1.y,
990
	     extents.p2.x, extents.p2.y);
991
 
992
    for (n = 0; n < traps->num_traps; n++) {
993
	fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
994
		 traps->traps[n].top,
995
		 traps->traps[n].bottom,
996
		 traps->traps[n].left.p1.x,
997
		 traps->traps[n].left.p1.y,
998
		 traps->traps[n].left.p2.x,
999
		 traps->traps[n].left.p2.y,
1000
		 traps->traps[n].right.p1.x,
1001
		 traps->traps[n].right.p1.y,
1002
		 traps->traps[n].right.p2.x,
1003
		 traps->traps[n].right.p2.y);
1004
    }
1005
}
1006
 
1007
struct cairo_trap_renderer {
1008
    cairo_span_renderer_t base;
1009
    cairo_traps_t *traps;
1010
};
1011
 
1012
static cairo_status_t
1013
span_to_traps (void *abstract_renderer, int y, int h,
1014
	       const cairo_half_open_span_t *spans, unsigned num_spans)
1015
{
1016
    struct cairo_trap_renderer *r = abstract_renderer;
1017
    cairo_fixed_t top, bot;
1018
 
1019
    if (num_spans == 0)
1020
	return CAIRO_STATUS_SUCCESS;
1021
 
1022
    top = _cairo_fixed_from_int (y);
1023
    bot = _cairo_fixed_from_int (y + h);
1024
    do {
1025
	if (spans[0].coverage) {
1026
	    cairo_fixed_t x0 = _cairo_fixed_from_int(spans[0].x);
1027
	    cairo_fixed_t x1 = _cairo_fixed_from_int(spans[1].x);
1028
	    cairo_line_t left = { { x0, top }, { x0, bot } },
1029
			 right = { { x1, top }, { x1, bot } };
1030
	    _cairo_traps_add_trap (r->traps, top, bot, &left, &right);
1031
	}
1032
	spans++;
1033
    } while (--num_spans > 1);
1034
 
1035
    return CAIRO_STATUS_SUCCESS;
1036
}
1037
 
1038
cairo_int_status_t
1039
_cairo_rasterise_polygon_to_traps (cairo_polygon_t			*polygon,
1040
				   cairo_fill_rule_t			 fill_rule,
1041
				   cairo_antialias_t			 antialias,
1042
				   cairo_traps_t *traps)
1043
{
1044
    struct cairo_trap_renderer renderer;
1045
    cairo_scan_converter_t *converter;
1046
    cairo_int_status_t status;
1047
    cairo_rectangle_int_t r;
1048
 
1049
    TRACE ((stderr, "%s: fill_rule=%d, antialias=%d\n",
1050
	    __FUNCTION__, fill_rule, antialias));
1051
    assert(antialias == CAIRO_ANTIALIAS_NONE);
1052
 
1053
    renderer.traps = traps;
1054
    renderer.base.render_rows = span_to_traps;
1055
 
1056
    _cairo_box_round_to_rectangle (&polygon->extents, &r);
1057
    converter = _cairo_mono_scan_converter_create (r.x, r.y,
1058
						   r.x + r.width,
1059
						   r.y + r.height,
1060
						   fill_rule);
1061
    status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
1062
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1063
	status = converter->generate (converter, &renderer.base);
1064
    converter->destroy (converter);
1065
    return status;
1066
}