Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1892 Rev 3959
Line 36... Line 36...
36
 *	Carl D. Worth 
36
 *	Carl D. Worth 
37
 */
37
 */
Line 38... Line 38...
38
 
38
 
Line -... Line 39...
-
 
39
#include "cairoint.h"
39
#include "cairoint.h"
40
 
-
 
41
#include "cairo-box-inline.h"
40
 
42
#include "cairo-error-private.h"
41
#include "cairo-error-private.h"
43
#include "cairo-list-inline.h"
Line 42... Line 44...
42
#include "cairo-path-fixed-private.h"
44
#include "cairo-path-fixed-private.h"
43
#include "cairo-slope-private.h"
45
#include "cairo-slope-private.h"
Line 65... Line 67...
65
static void
67
static void
66
_cairo_path_buf_add_points (cairo_path_buf_t       *buf,
68
_cairo_path_buf_add_points (cairo_path_buf_t       *buf,
67
			    const cairo_point_t    *points,
69
			    const cairo_point_t    *points,
68
			    int		            num_points);
70
			    int		            num_points);
Line 69... Line -...
69
 
-
 
70
#define cairo_path_head(path__) (&(path__)->buf.base)
-
 
71
#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
-
 
72
 
-
 
73
#define cairo_path_buf_next(pos__) \
-
 
74
    cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
-
 
75
#define cairo_path_buf_prev(pos__) \
-
 
76
    cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
-
 
77
 
-
 
78
#define cairo_path_foreach_buf_start(pos__, path__) \
-
 
79
    pos__ = cairo_path_head (path__); do
-
 
80
#define cairo_path_foreach_buf_end(pos__, path__) \
-
 
81
    while ((pos__ = cairo_path_buf_next (pos__)) !=  cairo_path_head (path__))
-
 
82
 
71
 
83
void
72
void
84
_cairo_path_fixed_init (cairo_path_fixed_t *path)
73
_cairo_path_fixed_init (cairo_path_fixed_t *path)
85
{
74
{
Line 95... Line 84...
95
    path->buf.base.points = path->buf.points;
84
    path->buf.base.points = path->buf.points;
Line 96... Line 85...
96
 
85
 
97
    path->current_point.x = 0;
86
    path->current_point.x = 0;
98
    path->current_point.y = 0;
87
    path->current_point.y = 0;
99
    path->last_move_point = path->current_point;
-
 
-
 
88
    path->last_move_point = path->current_point;
100
    path->has_last_move_point = FALSE;
89
 
-
 
90
    path->has_current_point = FALSE;
-
 
91
    path->needs_move_to = TRUE;
101
    path->has_current_point = FALSE;
92
    path->has_extents = FALSE;
-
 
93
    path->has_curve_to = FALSE;
102
    path->has_curve_to = FALSE;
94
    path->stroke_is_rectilinear = TRUE;
103
    path->is_rectilinear = TRUE;
95
    path->fill_is_rectilinear = TRUE;
104
    path->maybe_fill_region = TRUE;
96
    path->fill_maybe_region = TRUE;
Line 105... Line 97...
105
    path->is_empty_fill = TRUE;
97
    path->fill_is_empty = TRUE;
106
 
98
 
107
    path->extents.p1.x = path->extents.p1.y = INT_MAX;
99
    path->extents.p1.x = path->extents.p1.y = 0;
Line 108... Line 100...
108
    path->extents.p2.x = path->extents.p2.y = INT_MIN;
100
    path->extents.p2.x = path->extents.p2.y = 0;
109
}
101
}
110
 
102
 
Line 124... Line 116...
124
    path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
116
    path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
125
    path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
117
    path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
Line 126... Line 118...
126
 
118
 
127
    path->current_point = other->current_point;
119
    path->current_point = other->current_point;
128
    path->last_move_point = other->last_move_point;
-
 
-
 
120
    path->last_move_point = other->last_move_point;
129
    path->has_last_move_point = other->has_last_move_point;
121
 
-
 
122
    path->has_current_point = other->has_current_point;
-
 
123
    path->needs_move_to = other->needs_move_to;
130
    path->has_current_point = other->has_current_point;
124
    path->has_extents = other->has_extents;
-
 
125
    path->has_curve_to = other->has_curve_to;
131
    path->has_curve_to = other->has_curve_to;
126
    path->stroke_is_rectilinear = other->stroke_is_rectilinear;
132
    path->is_rectilinear = other->is_rectilinear;
127
    path->fill_is_rectilinear = other->fill_is_rectilinear;
133
    path->maybe_fill_region = other->maybe_fill_region;
128
    path->fill_maybe_region = other->fill_maybe_region;
Line 134... Line 129...
134
    path->is_empty_fill = other->is_empty_fill;
129
    path->fill_is_empty = other->fill_is_empty;
Line 135... Line 130...
135
 
130
 
136
    path->extents = other->extents;
131
    path->extents = other->extents;
Line 180... Line 175...
180
unsigned long
175
unsigned long
181
_cairo_path_fixed_hash (const cairo_path_fixed_t *path)
176
_cairo_path_fixed_hash (const cairo_path_fixed_t *path)
182
{
177
{
183
    unsigned long hash = _CAIRO_HASH_INIT_VALUE;
178
    unsigned long hash = _CAIRO_HASH_INIT_VALUE;
184
    const cairo_path_buf_t *buf;
179
    const cairo_path_buf_t *buf;
185
    int num_points, num_ops;
180
    unsigned int count;
Line 186... Line -...
186
 
-
 
187
    hash = _cairo_hash_bytes (hash, &path->extents, sizeof (path->extents));
-
 
188
 
181
 
189
    num_ops = num_points = 0;
182
    count = 0;
190
    cairo_path_foreach_buf_start (buf, path) {
183
    cairo_path_foreach_buf_start (buf, path) {
191
	hash = _cairo_hash_bytes (hash, buf->op,
184
	hash = _cairo_hash_bytes (hash, buf->op,
-
 
185
			          buf->num_ops * sizeof (buf->op[0]));
-
 
186
	count += buf->num_ops;
-
 
187
    } cairo_path_foreach_buf_end (buf, path);
-
 
188
    hash = _cairo_hash_bytes (hash, &count, sizeof (count));
-
 
189
 
-
 
190
    count = 0;
192
			          buf->num_ops * sizeof (buf->op[0]));
191
    cairo_path_foreach_buf_start (buf, path) {
193
	hash = _cairo_hash_bytes (hash, buf->points,
192
	hash = _cairo_hash_bytes (hash, buf->points,
194
			          buf->num_points * sizeof (buf->points[0]));
-
 
195
 
-
 
196
	num_ops    += buf->num_ops;
193
			          buf->num_points * sizeof (buf->points[0]));
197
	num_points += buf->num_points;
194
	count += buf->num_points;
198
    } cairo_path_foreach_buf_end (buf, path);
-
 
199
 
-
 
200
    hash = _cairo_hash_bytes (hash, &num_ops, sizeof (num_ops));
195
    } cairo_path_foreach_buf_end (buf, path);
Line 201... Line 196...
201
    hash = _cairo_hash_bytes (hash, &num_points, sizeof (num_points));
196
    hash = _cairo_hash_bytes (hash, &count, sizeof (count));
202
 
197
 
Line 203... Line 198...
203
    return hash;
198
    return hash;
Line 231... Line 226...
231
 
226
 
232
    if (a == b)
227
    if (a == b)
Line 233... Line 228...
233
	return TRUE;
228
	return TRUE;
234
 
-
 
235
    /* use the flags to quickly differentiate based on contents */
229
 
236
    if (a->is_empty_fill != b->is_empty_fill ||
-
 
237
	a->has_curve_to != b->has_curve_to ||
-
 
238
	a->maybe_fill_region != b->maybe_fill_region ||
230
    /* use the flags to quickly differentiate based on contents */
239
	a->is_rectilinear != b->is_rectilinear)
231
    if (a->has_curve_to != b->has_curve_to)
240
    {
232
    {
Line 241... Line 233...
241
	return FALSE;
233
	return FALSE;
Line 364... Line 356...
364
    _cairo_path_fixed_fini (path);
356
    _cairo_path_fixed_fini (path);
365
    free (path);
357
    free (path);
366
}
358
}
Line 367... Line 359...
367
 
359
 
368
static cairo_path_op_t
360
static cairo_path_op_t
369
_cairo_path_last_op (cairo_path_fixed_t *path)
361
_cairo_path_fixed_last_op (cairo_path_fixed_t *path)
370
{
362
{
Line 371... Line 363...
371
    cairo_path_buf_t *buf;
363
    cairo_path_buf_t *buf;
372
 
364
 
373
    buf = cairo_path_tail (path);
-
 
Line 374... Line 365...
374
    if (buf->num_ops == 0)
365
    buf = cairo_path_tail (path);
375
	return -1;
366
    assert (buf->num_ops != 0);
Line 376... Line 367...
376
 
367
 
377
    return buf->op[buf->num_ops - 1];
368
    return buf->op[buf->num_ops - 1];
378
}
-
 
379
 
369
}
380
static inline void
370
 
-
 
371
static inline const cairo_point_t *
381
_cairo_path_fixed_extents_add (cairo_path_fixed_t *path,
372
_cairo_path_fixed_penultimate_point (cairo_path_fixed_t *path)
382
			       const cairo_point_t *point)
373
{
383
{
374
    cairo_path_buf_t *buf;
-
 
375
 
-
 
376
    buf = cairo_path_tail (path);
-
 
377
    if (likely (buf->num_points >= 2)) {
-
 
378
	return &buf->points[buf->num_points - 2];
-
 
379
    } else {
-
 
380
	cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
-
 
381
 
384
    if (point->x < path->extents.p1.x)
382
	assert (prev_buf->num_points >= 2 - buf->num_points);
-
 
383
	return &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
385
	path->extents.p1.x = point->x;
384
    }
-
 
385
}
386
    if (point->y < path->extents.p1.y)
386
 
-
 
387
static void
-
 
388
_cairo_path_fixed_drop_line_to (cairo_path_fixed_t *path)
-
 
389
{
387
	path->extents.p1.y = point->y;
390
    cairo_path_buf_t *buf;
388
 
391
 
-
 
392
    assert (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO);
389
    if (point->x > path->extents.p2.x)
393
 
Line 390... Line 394...
390
	path->extents.p2.x = point->x;
394
    buf = cairo_path_tail (path);
391
    if (point->y > path->extents.p2.y)
395
    buf->num_points--;
392
	path->extents.p2.y = point->y;
396
    buf->num_ops--;
393
}
397
}
394
 
398
 
395
cairo_status_t
399
cairo_status_t
396
_cairo_path_fixed_move_to (cairo_path_fixed_t  *path,
-
 
Line -... Line 400...
-
 
400
_cairo_path_fixed_move_to (cairo_path_fixed_t  *path,
397
			   cairo_fixed_t	x,
401
			   cairo_fixed_t	x,
398
			   cairo_fixed_t	y)
402
			   cairo_fixed_t	y)
-
 
403
{
Line 399... Line -...
399
{
-
 
400
    cairo_status_t status;
404
    _cairo_path_fixed_new_sub_path (path);
401
    cairo_point_t point;
-
 
402
 
-
 
-
 
405
 
Line 403... Line 406...
403
    point.x = x;
406
    path->has_current_point = TRUE;
404
    point.y = y;
407
    path->current_point.x = x;
405
 
408
    path->current_point.y = y;
406
    /* If the previous op was also a MOVE_TO, then just change its
-
 
407
     * point rather than adding a new op. */
409
    path->last_move_point = path->current_point;
408
    if (_cairo_path_last_op (path) == CAIRO_PATH_OP_MOVE_TO) {
410
 
Line 409... Line -...
409
	cairo_path_buf_t *buf;
-
 
410
 
-
 
411
	buf = cairo_path_tail (path);
-
 
412
	buf->points[buf->num_points - 1] = point;
-
 
413
    } else {
411
    return CAIRO_STATUS_SUCCESS;
414
	status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
412
}
415
	if (unlikely (status))
413
 
-
 
414
static cairo_status_t
416
	    return status;
415
_cairo_path_fixed_move_to_apply (cairo_path_fixed_t  *path)
417
 
416
{
418
	if (path->has_current_point && path->is_rectilinear) {
417
    if (likely (! path->needs_move_to))
419
	    /* a move-to is first an implicit close */
418
	return CAIRO_STATUS_SUCCESS;
-
 
419
 
-
 
420
    path->needs_move_to = FALSE;
-
 
421
 
-
 
422
    if (path->has_extents) {
420
	    path->is_rectilinear = path->current_point.x == path->last_move_point.x ||
423
	_cairo_box_add_point (&path->extents, &path->current_point);
Line 421... Line -...
421
				   path->current_point.y == path->last_move_point.y;
-
 
422
	    path->maybe_fill_region &= path->is_rectilinear;
424
    } else {
423
	}
-
 
424
	if (path->maybe_fill_region) {
-
 
Line 425... Line 425...
425
	    path->maybe_fill_region =
425
	_cairo_box_set (&path->extents, &path->current_point, &path->current_point);
426
		_cairo_fixed_is_integer (path->last_move_point.x) &&
426
	path->has_extents = TRUE;
Line 427... Line 427...
427
		_cairo_fixed_is_integer (path->last_move_point.y);
427
    }
428
	}
428
 
429
    }
429
    if (path->fill_maybe_region) {
-
 
430
	path->fill_maybe_region = _cairo_fixed_is_integer (path->current_point.x) &&
-
 
431
				  _cairo_fixed_is_integer (path->current_point.y);
-
 
432
    }
-
 
433
 
-
 
434
    path->last_move_point = path->current_point;
-
 
435
 
-
 
436
    return _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &path->current_point, 1);
-
 
437
}
-
 
438
 
-
 
439
void
-
 
440
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
430
 
441
{
431
    path->current_point = point;
442
    if (! path->needs_move_to) {
Line 432... Line 443...
432
    path->last_move_point = point;
443
	/* If the current subpath doesn't need_move_to, it contains at least one command */
433
    path->has_last_move_point = TRUE;
444
	if (path->fill_is_rectilinear) {
Line 473... Line 484...
473
     * that the last_move_point state is updated properly.
484
     * that the last_move_point state is updated properly.
474
     */
485
     */
475
    if (! path->has_current_point)
486
    if (! path->has_current_point)
476
	return _cairo_path_fixed_move_to (path, point.x, point.y);
487
	return _cairo_path_fixed_move_to (path, point.x, point.y);
Line -... Line 488...
-
 
488
 
-
 
489
    status = _cairo_path_fixed_move_to_apply (path);
-
 
490
    if (unlikely (status))
-
 
491
	return status;
477
 
492
 
478
    /* If the previous op was but the initial MOVE_TO and this segment
493
    /* If the previous op was but the initial MOVE_TO and this segment
479
     * is degenerate, then we can simply skip this point. Note that
494
     * is degenerate, then we can simply skip this point. Note that
480
     * a move-to followed by a degenerate line-to is a valid path for
495
     * a move-to followed by a degenerate line-to is a valid path for
481
     * stroking, but at all other times is simply a degenerate segment.
496
     * stroking, but at all other times is simply a degenerate segment.
482
     */
497
     */
483
    if (_cairo_path_last_op (path) != CAIRO_PATH_OP_MOVE_TO) {
498
    if (_cairo_path_fixed_last_op (path) != CAIRO_PATH_OP_MOVE_TO) {
484
	if (x == path->current_point.x && y == path->current_point.y)
499
	if (x == path->current_point.x && y == path->current_point.y)
485
	    return CAIRO_STATUS_SUCCESS;
500
	    return CAIRO_STATUS_SUCCESS;
Line 486... Line 501...
486
    }
501
    }
487
 
502
 
488
    /* If the previous op was also a LINE_TO with the same gradient,
503
    /* If the previous op was also a LINE_TO with the same gradient,
489
     * then just change its end-point rather than adding a new op.
504
     * then just change its end-point rather than adding a new op.
490
     */
-
 
491
    if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
505
     */
Line 492... Line 506...
492
	cairo_path_buf_t *buf;
506
    if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
493
	const cairo_point_t *p;
-
 
494
 
-
 
495
	buf = cairo_path_tail (path);
-
 
496
	if (likely (buf->num_points >= 2)) {
-
 
497
	    p = &buf->points[buf->num_points-2];
-
 
498
	} else {
-
 
499
	    cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
-
 
500
	    p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
507
	const cairo_point_t *p;
501
	}
508
 
502
 
509
	p = _cairo_path_fixed_penultimate_point (path);
503
	if (p->x == path->current_point.x && p->y == path->current_point.y) {
-
 
504
	    /* previous line element was degenerate, replace */
510
	if (p->x == path->current_point.x && p->y == path->current_point.y) {
505
	    buf->points[buf->num_points - 1] = point;
511
	    /* previous line element was degenerate, replace */
Line 506... Line 512...
506
	    goto FLAGS;
512
	    _cairo_path_fixed_drop_line_to (path);
507
	} else {
513
	} else {
508
	    cairo_slope_t prev, self;
514
	    cairo_slope_t prev, self;
509
 
515
 
510
	    _cairo_slope_init (&prev, p, &path->current_point);
516
	    _cairo_slope_init (&prev, p, &path->current_point);
511
	    _cairo_slope_init (&self, &path->current_point, &point);
517
	    _cairo_slope_init (&self, &path->current_point, &point);
-
 
518
	    if (_cairo_slope_equal (&prev, &self) &&
-
 
519
		/* cannot trim anti-parallel segments whilst stroking */
-
 
520
		! _cairo_slope_backwards (&prev, &self))
-
 
521
	    {
512
	    if (_cairo_slope_equal (&prev, &self) &&
522
		_cairo_path_fixed_drop_line_to (path);
513
		/* cannot trim anti-parallel segments whilst stroking */
523
		/* In this case the flags might be more restrictive than
514
		! _cairo_slope_backwards (&prev, &self))
524
		 * what we actually need.
515
	    {
525
		 * When changing the flags definition we should check if
516
		buf->points[buf->num_points - 1] = point;
526
		 * changing the line_to point can affect them.
Line 517... Line -...
517
		goto FLAGS;
-
 
518
	    }
-
 
519
	}
-
 
520
    }
-
 
521
 
-
 
522
    status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
527
		*/
523
    if (unlikely (status))
528
	    }
524
	return status;
529
	}
-
 
530
    }
525
 
531
 
526
  FLAGS:
-
 
527
    if (path->is_rectilinear) {
532
    if (path->stroke_is_rectilinear) {
528
	path->is_rectilinear = path->current_point.x == x ||
533
	path->stroke_is_rectilinear = path->current_point.x == x ||
529
			       path->current_point.y == y;
534
				      path->current_point.y == y;
530
	path->maybe_fill_region &= path->is_rectilinear;
535
	path->fill_is_rectilinear &= path->stroke_is_rectilinear;
531
    }
536
	path->fill_maybe_region &= path->fill_is_rectilinear;
532
    if (path->maybe_fill_region) {
537
	if (path->fill_maybe_region) {
533
	path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
538
	    path->fill_maybe_region = _cairo_fixed_is_integer (x) &&
534
				  _cairo_fixed_is_integer (y);
539
				      _cairo_fixed_is_integer (y);
-
 
540
	}
Line 535... Line 541...
535
    }
541
	if (path->fill_is_empty) {
536
    if (path->is_empty_fill) {
-
 
-
 
542
	    path->fill_is_empty = path->current_point.x == x &&
537
	path->is_empty_fill = path->current_point.x == x &&
543
				  path->current_point.y == y;
538
			      path->current_point.y == y;
-
 
539
    }
544
	}
540
 
545
    }
541
    path->current_point = point;
-
 
542
    if (path->has_last_move_point) {
546
 
Line 543... Line 547...
543
	_cairo_path_fixed_extents_add (path, &path->last_move_point);
547
    path->current_point = point;
544
	path->has_last_move_point = FALSE;
548
 
545
    }
549
    _cairo_box_add_point (&path->extents, &point);
Line 567... Line 571...
567
			    cairo_fixed_t x2, cairo_fixed_t y2)
571
			    cairo_fixed_t x2, cairo_fixed_t y2)
568
{
572
{
569
    cairo_status_t status;
573
    cairo_status_t status;
570
    cairo_point_t point[3];
574
    cairo_point_t point[3];
Line -... Line 575...
-
 
575
 
-
 
576
    /* If this curves does not move, replace it with a line-to.
-
 
577
     * This frequently happens with rounded-rectangles and r==0.
-
 
578
    */
-
 
579
    if (path->current_point.x == x2 && path->current_point.y == y2) {
-
 
580
	if (x1 == x2 && x0 == x2 && y1 == y2 && y0 == y2)
-
 
581
	    return _cairo_path_fixed_line_to (path, x2, y2);
-
 
582
 
-
 
583
	/* We may want to check for the absence of a cusp, in which case
-
 
584
	 * we can also replace the curve-to with a line-to.
-
 
585
	 */
-
 
586
    }
571
 
587
 
572
    /* make sure subpaths are started properly */
588
    /* make sure subpaths are started properly */
573
    if (! path->has_current_point) {
589
    if (! path->has_current_point) {
-
 
590
	status = _cairo_path_fixed_move_to (path, x0, y0);
-
 
591
	assert (status == CAIRO_STATUS_SUCCESS);
-
 
592
    }
-
 
593
 
574
	status = _cairo_path_fixed_move_to (path, x0, y0);
594
    status = _cairo_path_fixed_move_to_apply (path);
575
	if (unlikely (status))
595
    if (unlikely (status))
-
 
596
	return status;
-
 
597
 
-
 
598
    /* If the previous op was a degenerate LINE_TO, drop it. */
-
 
599
    if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
-
 
600
	const cairo_point_t *p;
-
 
601
 
-
 
602
	p = _cairo_path_fixed_penultimate_point (path);
-
 
603
	if (p->x == path->current_point.x && p->y == path->current_point.y) {
-
 
604
	    /* previous line element was degenerate, replace */
-
 
605
	    _cairo_path_fixed_drop_line_to (path);
576
	    return status;
606
	}
Line 577... Line 607...
577
    }
607
    }
578
 
608
 
579
    point[0].x = x0; point[0].y = y0;
609
    point[0].x = x0; point[0].y = y0;
-
 
610
    point[1].x = x1; point[1].y = y1;
580
    point[1].x = x1; point[1].y = y1;
611
    point[2].x = x2; point[2].y = y2;
581
    point[2].x = x2; point[2].y = y2;
612
 
582
    status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
-
 
Line 583... Line 613...
583
    if (unlikely (status))
613
    _cairo_box_add_curve_to (&path->extents, &path->current_point,
584
	return status;
-
 
585
 
-
 
586
    path->current_point = point[2];
614
			     &point[0], &point[1], &point[2]);
587
    path->has_current_point = TRUE;
615
 
588
    path->is_empty_fill = FALSE;
616
    path->current_point = point[2];
589
    path->has_curve_to = TRUE;
-
 
590
    path->is_rectilinear = FALSE;
-
 
591
    path->maybe_fill_region = FALSE;
617
    path->has_curve_to = TRUE;
592
 
-
 
593
    /* coarse bounds */
618
    path->stroke_is_rectilinear = FALSE;
594
    if (path->has_last_move_point) {
-
 
595
	_cairo_path_fixed_extents_add (path, &path->last_move_point);
-
 
596
	path->has_last_move_point = FALSE;
-
 
597
    }
-
 
Line 598... Line 619...
598
    _cairo_path_fixed_extents_add (path, &point[0]);
619
    path->fill_is_rectilinear = FALSE;
599
    _cairo_path_fixed_extents_add (path, &point[1]);
620
    path->fill_maybe_region = FALSE;
Line 600... Line 621...
600
    _cairo_path_fixed_extents_add (path, &point[2]);
621
    path->fill_is_empty = FALSE;
601
 
622
 
602
    return CAIRO_STATUS_SUCCESS;
623
    return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
Line 628... Line 649...
628
    cairo_status_t status;
649
    cairo_status_t status;
Line 629... Line 650...
629
 
650
 
630
    if (! path->has_current_point)
651
    if (! path->has_current_point)
Line 631... Line -...
631
	return CAIRO_STATUS_SUCCESS;
-
 
632
 
-
 
633
    /* If the previous op was also a LINE_TO back to the start, discard it */
-
 
634
    if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
-
 
635
	if (path->current_point.x == path->last_move_point.x &&
-
 
636
	    path->current_point.y == path->last_move_point.y)
-
 
637
	{
-
 
638
	    cairo_path_buf_t *buf;
-
 
639
	    cairo_point_t *p;
-
 
640
 
-
 
641
	    buf = cairo_path_tail (path);
-
 
642
	    if (likely (buf->num_points >= 2)) {
652
	return CAIRO_STATUS_SUCCESS;
643
		p = &buf->points[buf->num_points-2];
653
 
644
	    } else {
654
    /*
645
		cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
655
     * Add a line_to, to compute flags and solve any degeneracy.
646
		p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
-
 
647
	    }
656
     * It will be removed later (if it was actually added).
648
 
657
     */
649
	    path->current_point = *p;
658
    status = _cairo_path_fixed_line_to (path,
650
	    buf->num_ops--;
-
 
651
	    buf->num_points--;
-
 
652
	}
-
 
653
    }
-
 
654
 
659
					path->last_move_point.x,
655
    status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
660
					path->last_move_point.y);
Line -... Line 661...
-
 
661
    if (unlikely (status))
656
    if (unlikely (status))
662
	return status;
657
	return status;
663
 
-
 
664
    /*
-
 
665
     * If the command used to close the path is a line_to, drop it.
-
 
666
     * We must check that last command is actually a line_to,
-
 
667
     * because the path could have been closed with a curve_to (and
658
 
668
     * the previous line_to not added as it would be degenerate).
-
 
669
     */
-
 
670
    if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO)
-
 
671
	    _cairo_path_fixed_drop_line_to (path);
-
 
672
 
659
    return _cairo_path_fixed_move_to (path,
673
    path->needs_move_to = TRUE; /* After close_path, add an implicit move_to */
Line 660... Line 674...
660
				      path->last_move_point.x,
674
 
661
				      path->last_move_point.y);
675
    return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
662
}
676
}
Line 712... Line 726...
712
			     _cairo_fixed_to_double (points[i].x),
726
			     _cairo_fixed_to_double (points[i].x),
713
			     _cairo_fixed_to_double (points[i].y));
727
			     _cairo_fixed_to_double (points[i].y));
714
	}
728
	}
715
	len += snprintf (buf + len, sizeof (buf), "]");
729
	len += snprintf (buf + len, sizeof (buf), "]");
Line -... Line 730...
-
 
730
 
716
 
731
#define STRINGIFYFLAG(x)  (path->x ? #x " " : "")
717
	fprintf (stderr,
732
	fprintf (stderr,
718
		 "_cairo_path_fixed_add (%s, %s)\n",
733
		 "_cairo_path_fixed_add (%s, %s) [%s%s%s%s%s%s%s%s]\n",
-
 
734
		 op_str[(int) op], buf,
-
 
735
		 STRINGIFYFLAG(has_current_point),
-
 
736
		 STRINGIFYFLAG(needs_move_to),
-
 
737
		 STRINGIFYFLAG(has_extents),
-
 
738
		 STRINGIFYFLAG(has_curve_to),
-
 
739
		 STRINGIFYFLAG(stroke_is_rectilinear),
-
 
740
		 STRINGIFYFLAG(fill_is_rectilinear),
-
 
741
		 STRINGIFYFLAG(fill_is_empty),
-
 
742
		 STRINGIFYFLAG(fill_maybe_region)
-
 
743
		 );
719
		 op_str[(int) op], buf);
744
#undef STRINGIFYFLAG
Line 720... Line 745...
720
    }
745
    }
721
 
746
 
Line 770... Line 795...
770
static void
795
static void
771
_cairo_path_buf_add_points (cairo_path_buf_t       *buf,
796
_cairo_path_buf_add_points (cairo_path_buf_t       *buf,
772
			    const cairo_point_t    *points,
797
			    const cairo_point_t    *points,
773
			    int		            num_points)
798
			    int		            num_points)
774
{
799
{
-
 
800
    if (num_points == 0)
-
 
801
	return;
-
 
802
 
775
    memcpy (buf->points + buf->num_points,
803
    memcpy (buf->points + buf->num_points,
776
	    points,
804
	    points,
777
	    sizeof (points[0]) * num_points);
805
	    sizeof (points[0]) * num_points);
778
    buf->num_points += num_points;
806
    buf->num_points += num_points;
779
}
807
}
Line 780... Line 808...
780
 
808
 
781
cairo_status_t
809
cairo_status_t
782
_cairo_path_fixed_interpret (const cairo_path_fixed_t		*path,
-
 
783
			     cairo_direction_t			 dir,
810
_cairo_path_fixed_interpret (const cairo_path_fixed_t		*path,
784
			     cairo_path_fixed_move_to_func_t	*move_to,
811
			     cairo_path_fixed_move_to_func_t	*move_to,
785
			     cairo_path_fixed_line_to_func_t	*line_to,
812
			     cairo_path_fixed_line_to_func_t	*line_to,
786
			     cairo_path_fixed_curve_to_func_t	*curve_to,
813
			     cairo_path_fixed_curve_to_func_t	*curve_to,
787
			     cairo_path_fixed_close_path_func_t	*close_path,
814
			     cairo_path_fixed_close_path_func_t	*close_path,
788
			     void				*closure)
815
			     void				*closure)
789
{
-
 
790
    const uint8_t num_args[] = {
816
{
791
	1, /* cairo_path_move_to */
-
 
792
	1, /* cairo_path_op_line_to */
-
 
793
	3, /* cairo_path_op_curve_to */
-
 
794
	0, /* cairo_path_op_close_path */
-
 
795
    };
817
    const cairo_path_buf_t *buf;
796
    cairo_status_t status;
-
 
797
    const cairo_path_buf_t *buf, *first;
-
 
798
    cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
-
 
799
    int step = forward ? 1 : -1;
-
 
800
 
-
 
801
    buf = first = forward ? cairo_path_head (path) : cairo_path_tail (path);
-
 
802
    do {
-
 
803
	cairo_point_t *points;
-
 
804
	int start, stop, i;
-
 
805
 
-
 
806
	if (forward) {
-
 
807
	    start = 0;
-
 
808
	    stop = buf->num_ops;
-
 
809
	    points = buf->points;
-
 
810
	} else {
-
 
811
	    start = buf->num_ops - 1;
-
 
812
	    stop = -1;
-
 
813
	    points = buf->points + buf->num_points;
-
 
814
	}
-
 
815
 
-
 
816
	for (i = start; i != stop; i += step) {
-
 
Line 817... Line 818...
817
	    cairo_path_op_t op = buf->op[i];
818
    cairo_status_t status;
-
 
819
 
818
 
820
    cairo_path_foreach_buf_start (buf, path) {
Line -... Line 821...
-
 
821
	const cairo_point_t *points = buf->points;
819
	    if (! forward)
822
	unsigned int i;
820
		points -= num_args[(int) op];
823
 
821
 
824
	for (i = 0; i < buf->num_ops; i++) {
-
 
825
	    switch (buf->op[i]) {
822
	    switch (op) {
826
	    case CAIRO_PATH_OP_MOVE_TO:
823
	    case CAIRO_PATH_OP_MOVE_TO:
827
		status = (*move_to) (closure, &points[0]);
824
		status = (*move_to) (closure, &points[0]);
828
		points += 1;
-
 
829
		break;
825
		break;
830
	    case CAIRO_PATH_OP_LINE_TO:
826
	    case CAIRO_PATH_OP_LINE_TO:
831
		status = (*line_to) (closure, &points[0]);
827
		status = (*line_to) (closure, &points[0]);
832
		points += 1;
-
 
833
		break;
828
		break;
834
	    case CAIRO_PATH_OP_CURVE_TO:
829
	    case CAIRO_PATH_OP_CURVE_TO:
835
		status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
830
		status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
836
		points += 3;
831
		break;
837
		break;
832
	    default:
838
	    default:
833
		ASSERT_NOT_REACHED;
839
		ASSERT_NOT_REACHED;
834
	    case CAIRO_PATH_OP_CLOSE_PATH:
840
	    case CAIRO_PATH_OP_CLOSE_PATH:
-
 
841
		status = (*close_path) (closure);
835
		status = (*close_path) (closure);
842
		break;
836
		break;
843
	    }
837
	    }
-
 
838
	    if (unlikely (status))
-
 
839
		return status;
-
 
840
 
844
 
841
	    if (forward)
845
	    if (unlikely (status))
Line 842... Line 846...
842
		points += num_args[(int) op];
846
		return status;
843
	}
847
	}
Line 844... Line 848...
844
    } while ((buf = forward ? cairo_path_buf_next (buf) : cairo_path_buf_prev (buf)) != first);
848
    } cairo_path_foreach_buf_end (buf, path);
Line 899... Line 903...
899
}
903
}
Line 900... Line 904...
900
 
904
 
901
cairo_status_t
905
cairo_status_t
902
_cairo_path_fixed_append (cairo_path_fixed_t		    *path,
906
_cairo_path_fixed_append (cairo_path_fixed_t		    *path,
903
			  const cairo_path_fixed_t	    *other,
-
 
904
			  cairo_direction_t		     dir,
907
			  const cairo_path_fixed_t	    *other,
905
			  cairo_fixed_t			     tx,
908
			  cairo_fixed_t			     tx,
906
			  cairo_fixed_t			     ty)
909
			  cairo_fixed_t			     ty)
907
{
910
{
Line 908... Line 911...
908
    cairo_path_fixed_append_closure_t closure;
911
    cairo_path_fixed_append_closure_t closure;
909
 
912
 
910
    closure.path = path;
913
    closure.path = path;
Line 911... Line 914...
911
    closure.offset.x = tx;
914
    closure.offset.x = tx;
912
    closure.offset.y = ty;
915
    closure.offset.y = ty;
913
 
916
 
914
    return _cairo_path_fixed_interpret (other, dir,
917
    return _cairo_path_fixed_interpret (other,
915
					_append_move_to,
918
					_append_move_to,
916
					_append_line_to,
919
					_append_line_to,
Line 927... Line 930...
927
				    cairo_fixed_t scaley)
930
				    cairo_fixed_t scaley)
928
{
931
{
929
    cairo_path_buf_t *buf;
932
    cairo_path_buf_t *buf;
930
    unsigned int i;
933
    unsigned int i;
Line 931... Line -...
931
 
-
 
932
    if (path->maybe_fill_region) {
-
 
933
	path->maybe_fill_region = _cairo_fixed_is_integer (offx) &&
934
 
934
	                          _cairo_fixed_is_integer (offy) &&
935
    if (scalex == CAIRO_FIXED_ONE && scaley == CAIRO_FIXED_ONE) {
935
			          _cairo_fixed_is_integer (scalex) &&
936
	_cairo_path_fixed_translate (path, offx, offy);
936
			          _cairo_fixed_is_integer (scaley);
937
	return;
Line -... Line 938...
-
 
938
    }
-
 
939
 
-
 
940
    path->last_move_point.x = _cairo_fixed_mul (scalex, path->last_move_point.x) + offx;
-
 
941
    path->last_move_point.y = _cairo_fixed_mul (scaley, path->last_move_point.y) + offy;
-
 
942
    path->current_point.x   = _cairo_fixed_mul (scalex, path->current_point.x) + offx;
-
 
943
    path->current_point.y   = _cairo_fixed_mul (scaley, path->current_point.y) + offy;
-
 
944
 
937
    }
945
    path->fill_maybe_region = TRUE;
938
 
946
 
939
    cairo_path_foreach_buf_start (buf, path) {
947
    cairo_path_foreach_buf_start (buf, path) {
940
	 for (i = 0; i < buf->num_points; i++) {
948
	 for (i = 0; i < buf->num_points; i++) {
941
	     if (scalex != CAIRO_FIXED_ONE)
949
	     if (scalex != CAIRO_FIXED_ONE)
Line 942... Line 950...
942
		 buf->points[i].x = _cairo_fixed_mul (buf->points[i].x, scalex);
950
		 buf->points[i].x = _cairo_fixed_mul (buf->points[i].x, scalex);
943
	     buf->points[i].x += offx;
951
	     buf->points[i].x += offx;
944
 
952
 
-
 
953
	     if (scaley != CAIRO_FIXED_ONE)
-
 
954
		 buf->points[i].y = _cairo_fixed_mul (buf->points[i].y, scaley);
-
 
955
	     buf->points[i].y += offy;
-
 
956
 
-
 
957
	    if (path->fill_maybe_region) {
945
	     if (scaley != CAIRO_FIXED_ONE)
958
		path->fill_maybe_region = _cairo_fixed_is_integer (buf->points[i].x) &&
946
		 buf->points[i].y = _cairo_fixed_mul (buf->points[i].y, scaley);
959
					  _cairo_fixed_is_integer (buf->points[i].y);
Line -... Line 960...
-
 
960
	    }
-
 
961
	 }
947
	     buf->points[i].y += offy;
962
    } cairo_path_foreach_buf_end (buf, path);
948
	 }
963
 
-
 
964
    path->fill_maybe_region &= path->fill_is_rectilinear;
-
 
965
 
-
 
966
    path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx;
-
 
967
    path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx;
-
 
968
    if (scalex < 0) {
Line 949... Line 969...
949
    } cairo_path_foreach_buf_end (buf, path);
969
	cairo_fixed_t t = path->extents.p1.x;
950
 
970
	path->extents.p1.x = path->extents.p2.x;
-
 
971
	path->extents.p2.x = t;
-
 
972
    }
-
 
973
 
-
 
974
    path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy;
-
 
975
    path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy;
951
    path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx;
976
    if (scaley < 0) {
Line 952... Line 977...
952
    path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx;
977
	cairo_fixed_t t = path->extents.p1.y;
953
 
978
	path->extents.p1.y = path->extents.p2.y;
954
    path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy;
979
	path->extents.p2.y = t;
Line 964... Line 989...
964
    unsigned int i;
989
    unsigned int i;
Line 965... Line 990...
965
 
990
 
966
    if (offx == 0 && offy == 0)
991
    if (offx == 0 && offy == 0)
Line 967... Line -...
967
	return;
-
 
968
 
-
 
969
    if (path->maybe_fill_region &&
-
 
970
	! (_cairo_fixed_is_integer (offx) && _cairo_fixed_is_integer (offy)))
-
 
971
    {
-
 
972
	path->maybe_fill_region = FALSE;
-
 
973
    }
992
	return;
974
 
993
 
975
    path->last_move_point.x += offx;
994
    path->last_move_point.x += offx;
976
    path->last_move_point.y += offy;
995
    path->last_move_point.y += offy;
Line -... Line 996...
-
 
996
    path->current_point.x += offx;
-
 
997
    path->current_point.y += offy;
977
    path->current_point.x += offx;
998
 
978
    path->current_point.y += offy;
999
    path->fill_maybe_region = TRUE;
979
 
1000
 
980
    cairo_path_foreach_buf_start (buf, path) {
1001
    cairo_path_foreach_buf_start (buf, path) {
-
 
1002
	for (i = 0; i < buf->num_points; i++) {
-
 
1003
	    buf->points[i].x += offx;
-
 
1004
	    buf->points[i].y += offy;
-
 
1005
 
-
 
1006
	    if (path->fill_maybe_region) {
981
	 for (i = 0; i < buf->num_points; i++) {
1007
		path->fill_maybe_region = _cairo_fixed_is_integer (buf->points[i].x) &&
982
	     buf->points[i].x += offx;
1008
					  _cairo_fixed_is_integer (buf->points[i].y);
Line -... Line 1009...
-
 
1009
	    }
-
 
1010
	 }
983
	     buf->points[i].y += offy;
1011
    } cairo_path_foreach_buf_end (buf, path);
984
	 }
1012
 
985
    } cairo_path_foreach_buf_end (buf, path);
1013
    path->fill_maybe_region &= path->fill_is_rectilinear;
986
 
1014
 
987
    path->extents.p1.x += offx;
1015
    path->extents.p1.x += offx;
Line -... Line 1016...
-
 
1016
    path->extents.p1.y += offy;
-
 
1017
    path->extents.p2.x += offx;
-
 
1018
    path->extents.p2.y += offy;
-
 
1019
}
-
 
1020
 
-
 
1021
 
-
 
1022
static inline void
-
 
1023
_cairo_path_fixed_transform_point (cairo_point_t *p,
-
 
1024
				   const cairo_matrix_t *matrix)
-
 
1025
{
-
 
1026
    double dx, dy;
-
 
1027
 
-
 
1028
    dx = _cairo_fixed_to_double (p->x);
-
 
1029
    dy = _cairo_fixed_to_double (p->y);
988
    path->extents.p1.y += offy;
1030
    cairo_matrix_transform_point (matrix, &dx, &dy);
989
    path->extents.p2.x += offx;
1031
    p->x = _cairo_fixed_from_double (dx);
990
    path->extents.p2.y += offy;
1032
    p->y = _cairo_fixed_from_double (dy);
991
}
1033
}
992
 
1034
 
Line 1001... Line 1043...
1001
 **/
1043
 **/
1002
void
1044
void
1003
_cairo_path_fixed_transform (cairo_path_fixed_t	*path,
1045
_cairo_path_fixed_transform (cairo_path_fixed_t	*path,
1004
			     const cairo_matrix_t     *matrix)
1046
			     const cairo_matrix_t     *matrix)
1005
{
1047
{
-
 
1048
    cairo_box_t extents;
-
 
1049
    cairo_point_t point;
1006
    cairo_path_buf_t *buf;
1050
    cairo_path_buf_t *buf;
1007
    unsigned int i;
1051
    unsigned int i;
1008
    double dx, dy;
-
 
1009
 
-
 
1010
    /* XXX current_point, last_move_to */
-
 
Line 1011... Line 1052...
1011
 
1052
 
1012
    if (matrix->yx == 0.0 && matrix->xy == 0.0) {
1053
    if (matrix->yx == 0.0 && matrix->xy == 0.0) {
1013
	/* Fast path for the common case of scale+transform */
-
 
1014
	 if (matrix->xx == 1. && matrix->yy == 1.) {
-
 
1015
	     _cairo_path_fixed_translate (path,
-
 
1016
					  _cairo_fixed_from_double (matrix->x0),
-
 
1017
					  _cairo_fixed_from_double (matrix->y0));
-
 
1018
	 } else {
1054
	/* Fast path for the common case of scale+transform */
1019
	     _cairo_path_fixed_offset_and_scale (path,
1055
	_cairo_path_fixed_offset_and_scale (path,
1020
						 _cairo_fixed_from_double (matrix->x0),
1056
					    _cairo_fixed_from_double (matrix->x0),
1021
						 _cairo_fixed_from_double (matrix->y0),
1057
					    _cairo_fixed_from_double (matrix->y0),
1022
						 _cairo_fixed_from_double (matrix->xx),
1058
					    _cairo_fixed_from_double (matrix->xx),
1023
						 _cairo_fixed_from_double (matrix->yy));
-
 
1024
	 }
1059
					    _cairo_fixed_from_double (matrix->yy));
1025
	return;
1060
	return;
Line 1026... Line -...
1026
    }
-
 
1027
 
-
 
1028
    path->extents.p1.x = path->extents.p1.y = INT_MAX;
-
 
1029
    path->extents.p2.x = path->extents.p2.y = INT_MIN;
-
 
1030
    path->maybe_fill_region = FALSE;
-
 
1031
    cairo_path_foreach_buf_start (buf, path) {
1061
    }
1032
	 for (i = 0; i < buf->num_points; i++) {
1062
 
Line 1033... Line 1063...
1033
	    dx = _cairo_fixed_to_double (buf->points[i].x);
1063
    _cairo_path_fixed_transform_point (&path->last_move_point, matrix);
-
 
1064
    _cairo_path_fixed_transform_point (&path->current_point, matrix);
-
 
1065
 
Line -... Line 1066...
-
 
1066
    buf = cairo_path_head (path);
-
 
1067
    if (buf->num_points == 0)
1034
	    dy = _cairo_fixed_to_double (buf->points[i].y);
1068
	return;
1035
 
1069
 
Line 1036... Line 1070...
1036
	    cairo_matrix_transform_point (matrix, &dx, &dy);
1070
    extents = path->extents;
-
 
1071
    point = buf->points[0];
1037
 
1072
    _cairo_path_fixed_transform_point (&point, matrix);
-
 
1073
    _cairo_box_set (&path->extents, &point, &point);
1038
	    buf->points[i].x = _cairo_fixed_from_double (dx);
1074
 
1039
	    buf->points[i].y = _cairo_fixed_from_double (dy);
1075
    cairo_path_foreach_buf_start (buf, path) {
1040
 
-
 
Line 1041... Line -...
1041
	    /* XXX need to eliminate surplus move-to's? */
-
 
1042
	    _cairo_path_fixed_extents_add (path, &buf->points[i]);
-
 
1043
	 }
1076
	for (i = 0; i < buf->num_points; i++) {
1044
    } cairo_path_foreach_buf_end (buf, path);
-
 
1045
}
1077
	    _cairo_path_fixed_transform_point (&buf->points[i], matrix);
Line 1046... Line 1078...
1046
 
1078
	    _cairo_box_add_point (&path->extents, &buf->points[i]);
1047
cairo_bool_t
-
 
1048
_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
-
 
1049
			    const cairo_path_fixed_t *other)
-
 
1050
{
1079
	}
1051
    const cairo_path_buf_t *path_buf, *other_buf;
-
 
1052
 
-
 
1053
    if (path->current_point.x != other->current_point.x ||
1080
    } cairo_path_foreach_buf_end (buf, path);
1054
	path->current_point.y != other->current_point.y ||
-
 
1055
	path->has_current_point != other->has_current_point ||
-
 
1056
	path->has_curve_to != other->has_curve_to ||
-
 
Line 1057... Line 1081...
1057
	path->is_rectilinear != other->is_rectilinear ||
1081
 
1058
	path->maybe_fill_region != other->maybe_fill_region ||
-
 
1059
	path->last_move_point.x != other->last_move_point.x ||
-
 
1060
	path->last_move_point.y != other->last_move_point.y)
-
 
1061
    {
1082
    if (path->has_curve_to) {
1062
	return FALSE;
-
 
1063
    }
-
 
1064
 
-
 
1065
    other_buf = cairo_path_head (other);
1083
	cairo_bool_t is_tight;
1066
    cairo_path_foreach_buf_start (path_buf, path) {
1084
 
1067
	if (path_buf->num_ops != other_buf->num_ops ||
1085
	_cairo_matrix_transform_bounding_box_fixed (matrix, &extents, &is_tight);
1068
	    path_buf->num_points != other_buf->num_points ||
-
 
1069
	    memcmp (path_buf->op, other_buf->op,
-
 
Line -... Line 1086...
-
 
1086
	if (!is_tight) {
-
 
1087
	    cairo_bool_t has_extents;
-
 
1088
 
1070
		    sizeof (cairo_path_op_t) * path_buf->num_ops) != 0 ||
1089
	    has_extents = _cairo_path_bounder_extents (path, &extents);
-
 
1090
	    assert (has_extents);
1071
	    memcmp (path_buf->points, other_buf->points,
1091
	}
Line 1072... Line 1092...
1072
		    sizeof (cairo_point_t) * path_buf->num_points) != 0)
1092
	path->extents = extents;
1073
	{
1093
    }
1074
	    return FALSE;
1094
 
Line 1121... Line 1141...
1121
    cairo_spline_t spline;
1141
    cairo_spline_t spline;
Line 1122... Line 1142...
1122
 
1142
 
Line 1123... Line 1143...
1123
    cairo_point_t *p0 = &cpf->current_point;
1143
    cairo_point_t *p0 = &cpf->current_point;
1124
 
1144
 
1125
    if (! _cairo_spline_init (&spline,
1145
    if (! _cairo_spline_init (&spline,
1126
			      cpf->line_to,
1146
			      (cairo_spline_add_point_func_t)cpf->line_to,
1127
			      cpf->closure,
1147
			      cpf->closure,
1128
			      p0, p1, p2, p3))
1148
			      p0, p1, p2, p3))
1129
    {
1149
    {
Line 1143... Line 1163...
1143
    return cpf->close_path (cpf->closure);
1163
    return cpf->close_path (cpf->closure);
1144
}
1164
}
Line 1145... Line 1165...
1145
 
1165
 
1146
cairo_status_t
1166
cairo_status_t
1147
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t		*path,
-
 
1148
				  cairo_direction_t			dir,
1167
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t		*path,
1149
				  cairo_path_fixed_move_to_func_t	*move_to,
1168
				  cairo_path_fixed_move_to_func_t	*move_to,
1150
				  cairo_path_fixed_line_to_func_t	*line_to,
1169
				  cairo_path_fixed_line_to_func_t	*line_to,
1151
				  cairo_path_fixed_close_path_func_t	*close_path,
1170
				  cairo_path_fixed_close_path_func_t	*close_path,
1152
				  void					*closure,
1171
				  void					*closure,
1153
				  double				tolerance)
1172
				  double				tolerance)
1154
{
1173
{
Line 1155... Line 1174...
1155
    cpf_t flattener;
1174
    cpf_t flattener;
1156
 
1175
 
1157
    if (! path->has_curve_to) {
1176
    if (! path->has_curve_to) {
1158
	return _cairo_path_fixed_interpret (path, dir,
1177
	return _cairo_path_fixed_interpret (path,
1159
					    move_to,
1178
					    move_to,
1160
					    line_to,
1179
					    line_to,
1161
					    NULL,
1180
					    NULL,
Line 1166... Line 1185...
1166
    flattener.tolerance = tolerance;
1185
    flattener.tolerance = tolerance;
1167
    flattener.move_to = move_to;
1186
    flattener.move_to = move_to;
1168
    flattener.line_to = line_to;
1187
    flattener.line_to = line_to;
1169
    flattener.close_path = close_path;
1188
    flattener.close_path = close_path;
1170
    flattener.closure = closure;
1189
    flattener.closure = closure;
1171
    return _cairo_path_fixed_interpret (path, dir,
1190
    return _cairo_path_fixed_interpret (path,
1172
					_cpf_move_to,
1191
					_cpf_move_to,
1173
					_cpf_line_to,
1192
					_cpf_line_to,
1174
					_cpf_curve_to,
1193
					_cpf_curve_to,
1175
					_cpf_close_path,
1194
					_cpf_close_path,
1176
					&flattener);
1195
					&flattener);
Line 1196... Line 1215...
1196
	box->p1.y = p2->y;
1215
	box->p1.y = p2->y;
1197
	box->p2.y = p1->y;
1216
	box->p2.y = p1->y;
1198
    }
1217
    }
1199
}
1218
}
Line 1200... Line -...
1200
 
-
 
1201
/*
-
 
1202
 * Check whether the given path contains a single rectangle.
-
 
1203
 */
1219
 
1204
cairo_bool_t
1220
static inline cairo_bool_t
1205
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
-
 
1206
			  cairo_box_t *box)
1221
_path_is_quad (const cairo_path_fixed_t *path)
1207
{
1222
{
Line 1208... Line -...
1208
    const cairo_path_buf_t *buf = cairo_path_head (path);
-
 
1209
 
-
 
1210
    if (! path->is_rectilinear)
-
 
1211
	return FALSE;
1223
    const cairo_path_buf_t *buf = cairo_path_head (path);
1212
 
1224
 
1213
    /* Do we have the right number of ops? */
1225
    /* Do we have the right number of ops? */
Line 1214... Line 1226...
1214
    if (buf->num_ops < 4 || buf->num_ops > 6)
1226
    if (buf->num_ops < 4 || buf->num_ops > 6)
Line 1242... Line 1254...
1242
		buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
1254
		buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
1243
		return FALSE;
1255
		return FALSE;
1244
	}
1256
	}
1245
    }
1257
    }
Line -... Line 1258...
-
 
1258
 
-
 
1259
    return TRUE;
-
 
1260
}
-
 
1261
 
-
 
1262
static inline cairo_bool_t
-
 
1263
_points_form_rect (const cairo_point_t *points)
-
 
1264
{
-
 
1265
    if (points[0].y == points[1].y &&
-
 
1266
	points[1].x == points[2].x &&
-
 
1267
	points[2].y == points[3].y &&
-
 
1268
	points[3].x == points[0].x)
-
 
1269
	return TRUE;
-
 
1270
    if (points[0].x == points[1].x &&
-
 
1271
	points[1].y == points[2].y &&
-
 
1272
	points[2].x == points[3].x &&
-
 
1273
	points[3].y == points[0].y)
-
 
1274
	return TRUE;
-
 
1275
    return FALSE;
-
 
1276
}
-
 
1277
 
-
 
1278
/*
-
 
1279
 * Check whether the given path contains a single rectangle.
-
 
1280
 */
-
 
1281
cairo_bool_t
-
 
1282
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
-
 
1283
			  cairo_box_t *box)
-
 
1284
{
-
 
1285
    const cairo_path_buf_t *buf;
-
 
1286
 
-
 
1287
    if (! path->fill_is_rectilinear)
-
 
1288
	return FALSE;
-
 
1289
 
-
 
1290
    if (! _path_is_quad (path))
-
 
1291
	return FALSE;
-
 
1292
 
-
 
1293
    buf = cairo_path_head (path);
-
 
1294
    if (_points_form_rect (buf->points)) {
-
 
1295
	_canonical_box (box, &buf->points[0], &buf->points[2]);
-
 
1296
	return TRUE;
-
 
1297
    }
-
 
1298
 
-
 
1299
    return FALSE;
-
 
1300
}
-
 
1301
 
-
 
1302
/* Determine whether two lines A->B and C->D intersect based on the 
-
 
1303
 * algorithm described here: http://paulbourke.net/geometry/pointlineplane/ */
-
 
1304
static inline cairo_bool_t
-
 
1305
_lines_intersect_or_are_coincident (cairo_point_t a,
-
 
1306
				    cairo_point_t b,
-
 
1307
				    cairo_point_t c,
-
 
1308
				    cairo_point_t d)
-
 
1309
{
-
 
1310
    cairo_int64_t numerator_a, numerator_b, denominator;
-
 
1311
    cairo_bool_t denominator_negative;
-
 
1312
 
-
 
1313
    denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x),
-
 
1314
				    _cairo_int32x32_64_mul (d.x - c.x, b.y - a.y));
-
 
1315
    numerator_a = _cairo_int64_sub (_cairo_int32x32_64_mul (d.x - c.x, a.y - c.y),
-
 
1316
				    _cairo_int32x32_64_mul (d.y - c.y, a.x - c.x));
-
 
1317
    numerator_b = _cairo_int64_sub (_cairo_int32x32_64_mul (b.x - a.x, a.y - c.y),
-
 
1318
				    _cairo_int32x32_64_mul (b.y - a.y, a.x - c.x));
-
 
1319
 
-
 
1320
    if (_cairo_int64_is_zero (denominator)) {
-
 
1321
	/* If the denominator and numerators are both zero,
-
 
1322
	 * the lines are coincident. */
-
 
1323
	if (_cairo_int64_is_zero (numerator_a) && _cairo_int64_is_zero (numerator_b))
-
 
1324
	    return TRUE;
-
 
1325
 
-
 
1326
	/* Otherwise, a zero denominator indicates the lines are
-
 
1327
	*  parallel and never intersect. */
-
 
1328
	return FALSE;
-
 
1329
    }
-
 
1330
 
-
 
1331
    /* The lines intersect if both quotients are between 0 and 1 (exclusive). */
-
 
1332
 
-
 
1333
     /* We first test whether either quotient is a negative number. */
-
 
1334
    denominator_negative = _cairo_int64_negative (denominator);
-
 
1335
    if (_cairo_int64_negative (numerator_a) ^ denominator_negative)
-
 
1336
	return FALSE;
-
 
1337
    if (_cairo_int64_negative (numerator_b) ^ denominator_negative)
-
 
1338
	return FALSE;
-
 
1339
 
-
 
1340
    /* A zero quotient indicates an "intersection" at an endpoint, which
-
 
1341
     * we aren't considering a true intersection. */
-
 
1342
    if (_cairo_int64_is_zero (numerator_a) || _cairo_int64_is_zero (numerator_b))
-
 
1343
	return FALSE;
-
 
1344
 
-
 
1345
    /* If the absolute value of the numerator is larger than or equal to the
-
 
1346
     * denominator the result of the division would be greater than or equal
-
 
1347
     * to one. */
-
 
1348
    if (! denominator_negative) {
-
 
1349
        if (! _cairo_int64_lt (numerator_a, denominator) ||
-
 
1350
	    ! _cairo_int64_lt (numerator_b, denominator))
-
 
1351
	    return FALSE;
-
 
1352
    } else {
-
 
1353
        if (! _cairo_int64_lt (denominator, numerator_a) ||
-
 
1354
	    ! _cairo_int64_lt (denominator, numerator_b))
-
 
1355
	    return FALSE;
-
 
1356
    }
-
 
1357
 
-
 
1358
    return TRUE;
-
 
1359
}
-
 
1360
 
-
 
1361
cairo_bool_t
-
 
1362
_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path)
-
 
1363
{
-
 
1364
    const cairo_point_t *points;
-
 
1365
 
-
 
1366
    if (! _path_is_quad (path))
-
 
1367
	return FALSE;
-
 
1368
 
-
 
1369
    points = cairo_path_head (path)->points;
-
 
1370
    if (_points_form_rect (points))
-
 
1371
	return TRUE;
-
 
1372
 
-
 
1373
    if (_lines_intersect_or_are_coincident (points[0], points[1],
-
 
1374
					    points[3], points[2]))
-
 
1375
	return FALSE;
-
 
1376
 
-
 
1377
    if (_lines_intersect_or_are_coincident (points[0], points[3],
-
 
1378
					    points[1], points[2]))
-
 
1379
	return FALSE;
-
 
1380
 
-
 
1381
    return TRUE;
-
 
1382
}
-
 
1383
 
-
 
1384
cairo_bool_t
-
 
1385
_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
-
 
1386
				 cairo_box_t *box)
-
 
1387
{
-
 
1388
    const cairo_path_buf_t *buf = cairo_path_head (path);
-
 
1389
 
-
 
1390
    if (! path->fill_is_rectilinear)
-
 
1391
	return FALSE;
-
 
1392
 
-
 
1393
    /* Do we have the right number of ops? */
-
 
1394
    if (buf->num_ops != 5)
-
 
1395
	return FALSE;
-
 
1396
 
-
 
1397
    /* Check whether the ops are those that would be used for a rectangle */
-
 
1398
    if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
-
 
1399
	buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
-
 
1400
	buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
-
 
1401
	buf->op[3] != CAIRO_PATH_OP_LINE_TO ||
-
 
1402
	buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH)
-
 
1403
    {
-
 
1404
	return FALSE;
-
 
1405
    }
1246
 
1406
 
1247
    /* Ok, we may have a box, if the points line up */
1407
    /* Ok, we may have a box, if the points line up */
1248
    if (buf->points[0].y == buf->points[1].y &&
1408
    if (buf->points[0].y == buf->points[1].y &&
1249
	buf->points[1].x == buf->points[2].x &&
1409
	buf->points[1].x == buf->points[2].x &&
1250
	buf->points[2].y == buf->points[3].y &&
1410
	buf->points[2].y == buf->points[3].y &&
Line 1284... Line 1444...
1284
    const cairo_path_buf_t *buf;
1444
    const cairo_path_buf_t *buf;
Line 1285... Line 1445...
1285
 
1445
 
1286
    if (! _cairo_path_fixed_is_box (path, box))
1446
    if (! _cairo_path_fixed_is_box (path, box))
Line -... Line 1447...
-
 
1447
	return FALSE;
-
 
1448
 
-
 
1449
    /* This check is valid because the current implementation of
1287
	return FALSE;
1450
     * _cairo_path_fixed_is_box () only accepts rectangles like:
1288
 
1451
     * move,line,line,line[,line|close[,close|move]]. */
1289
    buf = cairo_path_head (path);
1452
    buf = cairo_path_head (path);
Line 1290... Line 1453...
1290
    if (buf->points[0].y == buf->points[1].y)
1453
    if (buf->num_ops > 4)
1291
	return TRUE;
1454
	return TRUE;
Line 1329... Line 1492...
1329
    if (_iter->buf == NULL)
1492
    if (_iter->buf == NULL)
1330
	return FALSE;
1493
	return FALSE;
Line 1331... Line 1494...
1331
 
1494
 
Line 1332... Line -...
1332
    iter = *_iter;
-
 
1333
 
1495
    iter = *_iter;
1334
    if (iter.n_op == iter.buf->num_ops &&
-
 
1335
	! _cairo_path_fixed_iter_next_op (&iter))
1496
 
1336
    {
-
 
Line 1337... Line 1497...
1337
	return FALSE;
1497
    if (iter.n_op == iter.buf->num_ops && ! _cairo_path_fixed_iter_next_op (&iter))
1338
    }
1498
	return FALSE;
1339
 
1499
 
1340
    /* Check whether the ops are those that would be used for a rectangle */
1500
    /* Check whether the ops are those that would be used for a rectangle */
Line 1348... Line 1508...
1348
	return FALSE;
1508
	return FALSE;
1349
    points[1] = iter.buf->points[iter.n_point++];
1509
    points[1] = iter.buf->points[iter.n_point++];
1350
    if (! _cairo_path_fixed_iter_next_op (&iter))
1510
    if (! _cairo_path_fixed_iter_next_op (&iter))
1351
	return FALSE;
1511
	return FALSE;
Line -... Line 1512...
-
 
1512
 
1352
 
1513
    /* a horizontal/vertical closed line is also a degenerate rectangle */
-
 
1514
    switch (iter.buf->op[iter.n_op]) {
-
 
1515
    case CAIRO_PATH_OP_CLOSE_PATH:
-
 
1516
	_cairo_path_fixed_iter_next_op (&iter);
-
 
1517
    case CAIRO_PATH_OP_MOVE_TO: /* implicit close */
-
 
1518
	box->p1 = box->p2 = points[0];
-
 
1519
	*_iter = iter;
-
 
1520
	return TRUE;
1353
    if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
1521
    default:
-
 
1522
	return FALSE;
-
 
1523
    case CAIRO_PATH_OP_LINE_TO:
-
 
1524
	break;
-
 
1525
    }
1354
	return FALSE;
1526
 
1355
    points[2] = iter.buf->points[iter.n_point++];
1527
    points[2] = iter.buf->points[iter.n_point++];
1356
    if (! _cairo_path_fixed_iter_next_op (&iter))
1528
    if (! _cairo_path_fixed_iter_next_op (&iter))
Line 1357... Line 1529...
1357
	return FALSE;
1529
	return FALSE;
1358
 
1530
 
1359
    if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
1531
    if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
1360
	return FALSE;
-
 
1361
    points[3] = iter.buf->points[iter.n_point++];
-
 
Line 1362... Line 1532...
1362
    if (! _cairo_path_fixed_iter_next_op (&iter))
1532
	return FALSE;
1363
	return FALSE;
1533
    points[3] = iter.buf->points[iter.n_point++];
1364
 
1534
 
-
 
1535
    /* Now, there are choices. The rectangle might end with a LINE_TO
-
 
1536
     * (to the original point), but this isn't required. If it
1365
    /* Now, there are choices. The rectangle might end with a LINE_TO
1537
     * doesn't, then it must end with a CLOSE_PATH (which may be implicit). */
1366
     * (to the original point), but this isn't required. If it
-
 
1367
     * doesn't, then it must end with a CLOSE_PATH (which may be implicit). */
1538
    if (! _cairo_path_fixed_iter_next_op (&iter)) {
1368
    if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO)
1539
	/* implicit close due to fill */
1369
    {
1540
    } else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) {
1370
	points[4] = iter.buf->points[iter.n_point++];
1541
	points[4] = iter.buf->points[iter.n_point++];
1371
	if (points[4].x != points[0].x || points[4].y != points[0].y)
1542
	if (points[4].x != points[0].x || points[4].y != points[0].y)
-
 
1543
	    return FALSE;
1372
	    return FALSE;
1544
	_cairo_path_fixed_iter_next_op (&iter);
-
 
1545
    } else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH) {
1373
    }
1546
	_cairo_path_fixed_iter_next_op (&iter);
1374
    else if (! (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH ||
1547
    } else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO) {
1375
		iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO))
1548
	/* implicit close-path due to new-sub-path */
1376
    {
-
 
1377
	return FALSE;
-
 
Line 1378... Line 1549...
1378
    }
1549
    } else {
1379
    if (! _cairo_path_fixed_iter_next_op (&iter))
1550
	return FALSE;
1380
	return FALSE;
1551
    }
1381
 
1552
 
Line 1409... Line 1580...
1409
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
1580
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
1410
{
1581
{
1411
    if (iter->buf == NULL)
1582
    if (iter->buf == NULL)
1412
	return TRUE;
1583
	return TRUE;
Line 1413... Line 1584...
1413
 
1584
 
1414
    if (iter->n_op == iter->buf->num_ops)
-
 
1415
	return TRUE;
-
 
1416
 
-
 
1417
    if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO &&
-
 
1418
	iter->buf->num_ops == iter->n_op + 1)
-
 
1419
    {
-
 
1420
	return TRUE;
-
 
1421
    }
-
 
1422
 
-
 
1423
    return FALSE;
1585
    return iter->n_op == iter->buf->num_ops;