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
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
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 University of Southern
32
 * California.
33
 *
34
 * Contributor(s):
35
 *	Carl D. Worth 
36
 *	Chris Wilson 
37
 */
38
 
39
#define _BSD_SOURCE /* for hypot() */
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-path-fixed-private.h"
46
#include "cairo-slope-private.h"
3959 Serge 47
#include "cairo-stroke-dash-private.h"
48
#include "cairo-traps-private.h"
1892 serge 49
 
50
typedef struct cairo_stroker {
51
    cairo_stroke_style_t style;
52
 
53
    const cairo_matrix_t *ctm;
54
    const cairo_matrix_t *ctm_inverse;
3959 Serge 55
    double half_line_width;
1892 serge 56
    double tolerance;
3959 Serge 57
    double spline_cusp_tolerance;
1892 serge 58
    double ctm_determinant;
59
    cairo_bool_t ctm_det_positive;
60
 
61
    void *closure;
62
    cairo_status_t (*add_external_edge) (void *closure,
63
					 const cairo_point_t *p1,
64
					 const cairo_point_t *p2);
65
    cairo_status_t (*add_triangle) (void *closure,
66
				    const cairo_point_t triangle[3]);
67
    cairo_status_t (*add_triangle_fan) (void *closure,
68
					const cairo_point_t *midpt,
69
					const cairo_point_t *points,
70
					int npoints);
71
    cairo_status_t (*add_convex_quad) (void *closure,
72
				       const cairo_point_t quad[4]);
73
 
74
    cairo_pen_t	  pen;
75
 
76
    cairo_point_t current_point;
77
    cairo_point_t first_point;
78
 
79
    cairo_bool_t has_initial_sub_path;
80
 
81
    cairo_bool_t has_current_face;
82
    cairo_stroke_face_t current_face;
83
 
84
    cairo_bool_t has_first_face;
85
    cairo_stroke_face_t first_face;
86
 
87
    cairo_stroker_dash_t dash;
88
 
89
    cairo_bool_t has_bounds;
90
    cairo_box_t bounds;
91
} cairo_stroker_t;
92
 
93
static void
3959 Serge 94
_cairo_stroker_limit (cairo_stroker_t *stroker,
95
		      const cairo_path_fixed_t *path,
96
		      const cairo_box_t *boxes,
97
		      int num_boxes)
1892 serge 98
{
3959 Serge 99
    double dx, dy;
100
    cairo_fixed_t fdx, fdy;
1892 serge 101
 
3959 Serge 102
    stroker->has_bounds = TRUE;
103
    _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
1892 serge 104
 
3959 Serge 105
    /* Extend the bounds in each direction to account for the maximum area
106
     * we might generate trapezoids, to capture line segments that are outside
107
     * of the bounds but which might generate rendering that's within bounds.
108
     */
1892 serge 109
 
3959 Serge 110
    _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
111
						stroker->ctm, &dx, &dy);
1892 serge 112
 
3959 Serge 113
    fdx = _cairo_fixed_from_double (dx);
114
    fdy = _cairo_fixed_from_double (dy);
1892 serge 115
 
3959 Serge 116
    stroker->bounds.p1.x -= fdx;
117
    stroker->bounds.p2.x += fdx;
1892 serge 118
 
3959 Serge 119
    stroker->bounds.p1.y -= fdy;
120
    stroker->bounds.p2.y += fdy;
1892 serge 121
}
122
 
123
static cairo_status_t
124
_cairo_stroker_init (cairo_stroker_t		*stroker,
3959 Serge 125
		     const cairo_path_fixed_t	*path,
1892 serge 126
		     const cairo_stroke_style_t	*stroke_style,
127
		     const cairo_matrix_t	*ctm,
128
		     const cairo_matrix_t	*ctm_inverse,
3959 Serge 129
		     double			 tolerance,
130
		     const cairo_box_t		*limits,
131
		     int			 num_limits)
1892 serge 132
{
133
    cairo_status_t status;
134
 
135
    stroker->style = *stroke_style;
136
    stroker->ctm = ctm;
137
    stroker->ctm_inverse = ctm_inverse;
138
    stroker->tolerance = tolerance;
3959 Serge 139
    stroker->half_line_width = stroke_style->line_width / 2.0;
1892 serge 140
 
3959 Serge 141
    /* To test whether we need to join two segments of a spline using
142
     * a round-join or a bevel-join, we can inspect the angle between the
143
     * two segments. If the difference between the chord distance
144
     * (half-line-width times the cosine of the bisection angle) and the
145
     * half-line-width itself is greater than tolerance then we need to
146
     * inject a point.
147
     */
148
    stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
149
    stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
150
    stroker->spline_cusp_tolerance *= 2;
151
    stroker->spline_cusp_tolerance -= 1;
152
 
1892 serge 153
    stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
154
    stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
155
 
156
    status = _cairo_pen_init (&stroker->pen,
3959 Serge 157
			      stroker->half_line_width, tolerance, ctm);
1892 serge 158
    if (unlikely (status))
159
	return status;
160
 
161
    stroker->has_current_face = FALSE;
162
    stroker->has_first_face = FALSE;
163
    stroker->has_initial_sub_path = FALSE;
164
 
165
    _cairo_stroker_dash_init (&stroker->dash, stroke_style);
166
 
167
    stroker->add_external_edge = NULL;
168
 
3959 Serge 169
    stroker->has_bounds = FALSE;
170
    if (num_limits)
171
	_cairo_stroker_limit (stroker, path, limits, num_limits);
172
 
1892 serge 173
    return CAIRO_STATUS_SUCCESS;
174
}
175
 
176
static void
177
_cairo_stroker_fini (cairo_stroker_t *stroker)
178
{
179
    _cairo_pen_fini (&stroker->pen);
180
}
181
 
182
static void
183
_translate_point (cairo_point_t *point, const cairo_point_t *offset)
184
{
185
    point->x += offset->x;
186
    point->y += offset->y;
187
}
188
 
189
static int
190
_cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in,
191
				  const cairo_stroke_face_t *out)
192
{
193
    cairo_slope_t in_slope, out_slope;
194
 
195
    _cairo_slope_init (&in_slope, &in->point, &in->cw);
196
    _cairo_slope_init (&out_slope, &out->point, &out->cw);
197
 
198
    return _cairo_slope_compare (&in_slope, &out_slope) < 0;
199
}
200
 
201
/**
3959 Serge 202
 * _cairo_slope_compare_sgn:
1892 serge 203
 *
204
 * Return -1, 0 or 1 depending on the relative slopes of
205
 * two lines.
3959 Serge 206
 **/
1892 serge 207
static int
208
_cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
209
{
210
    double  c = (dx1 * dy2 - dx2 * dy1);
211
 
212
    if (c > 0) return 1;
213
    if (c < 0) return -1;
214
    return 0;
215
}
216
 
217
static inline int
218
_range_step (int i, int step, int max)
219
{
220
    i += step;
221
    if (i < 0)
222
	i = max - 1;
223
    if (i >= max)
224
	i = 0;
225
    return i;
226
}
227
 
228
/*
229
 * Construct a fan around the midpoint using the vertices from pen between
230
 * inpt and outpt.
231
 */
232
static cairo_status_t
233
_tessellate_fan (cairo_stroker_t *stroker,
234
		 const cairo_slope_t *in_vector,
235
		 const cairo_slope_t *out_vector,
236
		 const cairo_point_t *midpt,
237
		 const cairo_point_t *inpt,
238
		 const cairo_point_t *outpt,
239
		 cairo_bool_t clockwise)
240
{
241
    cairo_point_t stack_points[64], *points = stack_points;
3959 Serge 242
    cairo_pen_t *pen = &stroker->pen;
243
    int start, stop, num_points = 0;
1892 serge 244
    cairo_status_t status;
245
 
3959 Serge 246
    if (stroker->has_bounds &&
247
	! _cairo_box_contains_point (&stroker->bounds, midpt))
248
	goto BEVEL;
249
 
250
    assert (stroker->pen.num_vertices);
251
 
1892 serge 252
    if (clockwise) {
3959 Serge 253
	_cairo_pen_find_active_ccw_vertices (pen,
254
					     in_vector, out_vector,
255
					     &start, &stop);
256
	if (stroker->add_external_edge) {
257
	    cairo_point_t last;
258
	    last = *inpt;
259
	    while (start != stop) {
260
		cairo_point_t p = *midpt;
261
		_translate_point (&p, &pen->vertices[start].point);
1892 serge 262
 
3959 Serge 263
		status = stroker->add_external_edge (stroker->closure,
264
						     &last, &p);
265
		if (unlikely (status))
266
		    return status;
267
		last = p;
1892 serge 268
 
3959 Serge 269
		if (start-- == 0)
270
		    start += pen->num_vertices;
271
	    }
272
	    status = stroker->add_external_edge (stroker->closure,
273
						 &last, outpt);
274
	} else {
275
	    if (start == stop)
1892 serge 276
		goto BEVEL;
3959 Serge 277
 
278
	    num_points = stop - start;
279
	    if (num_points < 0)
280
		num_points += pen->num_vertices;
281
	    num_points += 2;
282
	    if (num_points > ARRAY_LENGTH(stack_points)) {
283
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
284
		if (unlikely (points == NULL))
285
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1892 serge 286
	    }
287
 
3959 Serge 288
	    points[0] = *inpt;
289
	    num_points = 1;
290
	    while (start != stop) {
291
		points[num_points] = *midpt;
292
		_translate_point (&points[num_points], &pen->vertices[start].point);
293
		num_points++;
1892 serge 294
 
3959 Serge 295
		if (start-- == 0)
296
		    start += pen->num_vertices;
1892 serge 297
	    }
3959 Serge 298
	    points[num_points++] = *outpt;
1892 serge 299
	}
3959 Serge 300
    } else {
301
	_cairo_pen_find_active_cw_vertices (pen,
302
					    in_vector, out_vector,
303
					    &start, &stop);
304
	if (stroker->add_external_edge) {
305
	    cairo_point_t last;
306
	    last = *inpt;
307
	    while (start != stop) {
308
		cairo_point_t p = *midpt;
309
		_translate_point (&p, &pen->vertices[start].point);
1892 serge 310
 
3959 Serge 311
		status = stroker->add_external_edge (stroker->closure,
312
						     &p, &last);
313
		if (unlikely (status))
314
		    return status;
315
		last = p;
1892 serge 316
 
3959 Serge 317
		if (++start == pen->num_vertices)
318
		    start = 0;
319
	    }
320
	    status = stroker->add_external_edge (stroker->closure,
321
						 outpt, &last);
322
	} else {
323
	    if (start == stop)
324
		goto BEVEL;
1892 serge 325
 
3959 Serge 326
	    num_points = stop - start;
327
	    if (num_points < 0)
328
		num_points += pen->num_vertices;
329
	    num_points += 2;
330
	    if (num_points > ARRAY_LENGTH(stack_points)) {
331
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
332
		if (unlikely (points == NULL))
333
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
334
	    }
1892 serge 335
 
3959 Serge 336
	    points[0] = *inpt;
337
	    num_points = 1;
338
	    while (start != stop) {
339
		points[num_points] = *midpt;
340
		_translate_point (&points[num_points], &pen->vertices[start].point);
341
		num_points++;
1892 serge 342
 
3959 Serge 343
		if (++start == pen->num_vertices)
344
		    start = 0;
345
	    }
346
	    points[num_points++] = *outpt;
347
	}
1892 serge 348
    }
349
 
3959 Serge 350
    if (num_points) {
1892 serge 351
	status = stroker->add_triangle_fan (stroker->closure,
3959 Serge 352
					    midpt, points, num_points);
1892 serge 353
    }
354
 
355
    if (points != stack_points)
356
	free (points);
357
 
358
    return status;
359
 
360
BEVEL:
361
    /* Ensure a leak free connection... */
362
    if (stroker->add_external_edge != NULL) {
363
	if (clockwise)
364
	    return stroker->add_external_edge (stroker->closure, inpt, outpt);
365
	else
366
	    return stroker->add_external_edge (stroker->closure, outpt, inpt);
367
    } else {
368
	stack_points[0] = *midpt;
369
	stack_points[1] = *inpt;
370
	stack_points[2] = *outpt;
371
	return stroker->add_triangle (stroker->closure, stack_points);
372
    }
373
}
374
 
375
static cairo_status_t
376
_cairo_stroker_join (cairo_stroker_t *stroker,
377
		     const cairo_stroke_face_t *in,
378
		     const cairo_stroke_face_t *out)
379
{
380
    int	 clockwise = _cairo_stroker_join_is_clockwise (out, in);
381
    const cairo_point_t	*inpt, *outpt;
382
    cairo_point_t points[4];
383
    cairo_status_t status;
384
 
385
    if (in->cw.x  == out->cw.x  && in->cw.y  == out->cw.y &&
386
	in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
387
    {
388
	return CAIRO_STATUS_SUCCESS;
389
    }
390
 
391
    if (clockwise) {
392
	if (stroker->add_external_edge != NULL) {
393
	    status = stroker->add_external_edge (stroker->closure,
394
						 &out->cw, &in->point);
395
	    if (unlikely (status))
396
		return status;
397
 
398
	    status = stroker->add_external_edge (stroker->closure,
399
						 &in->point, &in->cw);
400
	    if (unlikely (status))
401
		return status;
402
	}
403
 
404
	inpt = &in->ccw;
405
	outpt = &out->ccw;
406
    } else {
407
	if (stroker->add_external_edge != NULL) {
408
	    status = stroker->add_external_edge (stroker->closure,
409
						 &in->ccw, &in->point);
410
	    if (unlikely (status))
411
		return status;
412
 
413
	    status = stroker->add_external_edge (stroker->closure,
414
						 &in->point, &out->ccw);
415
	    if (unlikely (status))
416
		return status;
417
	}
418
 
419
	inpt = &in->cw;
420
	outpt = &out->cw;
421
    }
422
 
423
    switch (stroker->style.line_join) {
424
    case CAIRO_LINE_JOIN_ROUND:
425
	/* construct a fan around the common midpoint */
426
	return _tessellate_fan (stroker,
427
				&in->dev_vector,
428
				&out->dev_vector,
429
				&in->point, inpt, outpt,
430
				clockwise);
431
 
432
    case CAIRO_LINE_JOIN_MITER:
433
    default: {
434
	/* dot product of incoming slope vector with outgoing slope vector */
435
	double	in_dot_out = -in->usr_vector.x * out->usr_vector.x +
436
			     -in->usr_vector.y * out->usr_vector.y;
437
	double	ml = stroker->style.miter_limit;
438
 
439
	/* Check the miter limit -- lines meeting at an acute angle
440
	 * can generate long miters, the limit converts them to bevel
441
	 *
442
	 * Consider the miter join formed when two line segments
443
	 * meet at an angle psi:
444
	 *
445
	 *	   /.\
446
	 *	  /. .\
447
	 *	 /./ \.\
448
	 *	/./psi\.\
449
	 *
450
	 * We can zoom in on the right half of that to see:
451
	 *
452
	 *	    |\
453
	 *	    | \ psi/2
454
	 *	    |  \
455
	 *	    |   \
456
	 *	    |    \
457
	 *	    |     \
458
	 *	  miter    \
459
	 *	 length     \
460
	 *	    |        \
461
	 *	    |        .\
462
	 *	    |    .     \
463
	 *	    |.   line   \
464
	 *	     \    width  \
465
	 *	      \           \
466
	 *
467
	 *
468
	 * The right triangle in that figure, (the line-width side is
469
	 * shown faintly with three '.' characters), gives us the
470
	 * following expression relating miter length, angle and line
471
	 * width:
472
	 *
473
	 *	1 /sin (psi/2) = miter_length / line_width
474
	 *
475
	 * The right-hand side of this relationship is the same ratio
476
	 * in which the miter limit (ml) is expressed. We want to know
477
	 * when the miter length is within the miter limit. That is
478
	 * when the following condition holds:
479
	 *
480
	 *	1/sin(psi/2) <= ml
481
	 *	1 <= ml sin(psi/2)
482
	 *	1 <= ml² sin²(psi/2)
483
	 *	2 <= ml² 2 sin²(psi/2)
484
	 *				2·sin²(psi/2) = 1-cos(psi)
485
	 *	2 <= ml² (1-cos(psi))
486
	 *
487
	 *				in · out = |in| |out| cos (psi)
488
	 *
489
	 * in and out are both unit vectors, so:
490
	 *
491
	 *				in · out = cos (psi)
492
	 *
493
	 *	2 <= ml² (1 - in · out)
494
	 *
495
	 */
496
	if (2 <= ml * ml * (1 - in_dot_out)) {
497
	    double		x1, y1, x2, y2;
498
	    double		mx, my;
499
	    double		dx1, dx2, dy1, dy2;
500
	    double		ix, iy;
501
	    double		fdx1, fdy1, fdx2, fdy2;
502
	    double		mdx, mdy;
503
 
504
	    /*
505
	     * we've got the points already transformed to device
506
	     * space, but need to do some computation with them and
507
	     * also need to transform the slope from user space to
508
	     * device space
509
	     */
510
	    /* outer point of incoming line face */
511
	    x1 = _cairo_fixed_to_double (inpt->x);
512
	    y1 = _cairo_fixed_to_double (inpt->y);
513
	    dx1 = in->usr_vector.x;
514
	    dy1 = in->usr_vector.y;
515
	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
516
 
517
	    /* outer point of outgoing line face */
518
	    x2 = _cairo_fixed_to_double (outpt->x);
519
	    y2 = _cairo_fixed_to_double (outpt->y);
520
	    dx2 = out->usr_vector.x;
521
	    dy2 = out->usr_vector.y;
522
	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
523
 
524
	    /*
525
	     * Compute the location of the outer corner of the miter.
526
	     * That's pretty easy -- just the intersection of the two
527
	     * outer edges.  We've got slopes and points on each
528
	     * of those edges.  Compute my directly, then compute
529
	     * mx by using the edge with the larger dy; that avoids
530
	     * dividing by values close to zero.
531
	     */
532
	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
533
		  (dx1 * dy2 - dx2 * dy1));
534
	    if (fabs (dy1) >= fabs (dy2))
535
		mx = (my - y1) * dx1 / dy1 + x1;
536
	    else
537
		mx = (my - y2) * dx2 / dy2 + x2;
538
 
539
	    /*
540
	     * When the two outer edges are nearly parallel, slight
541
	     * perturbations in the position of the outer points of the lines
542
	     * caused by representing them in fixed point form can cause the
543
	     * intersection point of the miter to move a large amount. If
544
	     * that moves the miter intersection from between the two faces,
545
	     * then draw a bevel instead.
546
	     */
547
 
548
	    ix = _cairo_fixed_to_double (in->point.x);
549
	    iy = _cairo_fixed_to_double (in->point.y);
550
 
551
	    /* slope of one face */
552
	    fdx1 = x1 - ix; fdy1 = y1 - iy;
553
 
554
	    /* slope of the other face */
555
	    fdx2 = x2 - ix; fdy2 = y2 - iy;
556
 
557
	    /* slope from the intersection to the miter point */
558
	    mdx = mx - ix; mdy = my - iy;
559
 
560
	    /*
561
	     * Make sure the miter point line lies between the two
562
	     * faces by comparing the slopes
563
	     */
564
	    if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
565
		_cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
566
	    {
567
		if (stroker->add_external_edge != NULL) {
568
		    points[0].x = _cairo_fixed_from_double (mx);
569
		    points[0].y = _cairo_fixed_from_double (my);
570
 
571
		    if (clockwise) {
572
			status = stroker->add_external_edge (stroker->closure,
573
							     inpt, &points[0]);
574
			if (unlikely (status))
575
			    return status;
576
 
577
			status = stroker->add_external_edge (stroker->closure,
578
							     &points[0], outpt);
579
			if (unlikely (status))
580
			    return status;
581
		    } else {
582
			status = stroker->add_external_edge (stroker->closure,
583
							     outpt, &points[0]);
584
			if (unlikely (status))
585
			    return status;
586
 
587
			status = stroker->add_external_edge (stroker->closure,
588
							     &points[0], inpt);
589
			if (unlikely (status))
590
			    return status;
591
		    }
592
 
593
		    return CAIRO_STATUS_SUCCESS;
594
		} else {
595
		    points[0] = in->point;
596
		    points[1] = *inpt;
597
		    points[2].x = _cairo_fixed_from_double (mx);
598
		    points[2].y = _cairo_fixed_from_double (my);
599
		    points[3] = *outpt;
600
 
601
		    return stroker->add_convex_quad (stroker->closure, points);
602
		}
603
	    }
604
	}
605
    }
606
 
607
    /* fall through ... */
608
 
609
    case CAIRO_LINE_JOIN_BEVEL:
610
	if (stroker->add_external_edge != NULL) {
611
	    if (clockwise) {
612
		return stroker->add_external_edge (stroker->closure,
613
						   inpt, outpt);
614
	    } else {
615
		return stroker->add_external_edge (stroker->closure,
616
						   outpt, inpt);
617
	    }
618
	} else {
619
	    points[0] = in->point;
620
	    points[1] = *inpt;
621
	    points[2] = *outpt;
622
 
623
	    return stroker->add_triangle (stroker->closure, points);
624
	}
625
    }
626
}
627
 
628
static cairo_status_t
629
_cairo_stroker_add_cap (cairo_stroker_t *stroker,
630
			const cairo_stroke_face_t *f)
631
{
632
    switch (stroker->style.line_cap) {
633
    case CAIRO_LINE_CAP_ROUND: {
634
	cairo_slope_t slope;
635
 
636
	slope.dx = -f->dev_vector.dx;
637
	slope.dy = -f->dev_vector.dy;
638
 
639
	return _tessellate_fan (stroker,
640
				&f->dev_vector,
641
				&slope,
642
				&f->point, &f->cw, &f->ccw,
643
				FALSE);
644
 
645
    }
646
 
647
    case CAIRO_LINE_CAP_SQUARE: {
648
	double dx, dy;
649
	cairo_slope_t	fvector;
650
	cairo_point_t	quad[4];
651
 
652
	dx = f->usr_vector.x;
653
	dy = f->usr_vector.y;
3959 Serge 654
	dx *= stroker->half_line_width;
655
	dy *= stroker->half_line_width;
1892 serge 656
	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
657
	fvector.dx = _cairo_fixed_from_double (dx);
658
	fvector.dy = _cairo_fixed_from_double (dy);
659
 
660
	quad[0] = f->ccw;
661
	quad[1].x = f->ccw.x + fvector.dx;
662
	quad[1].y = f->ccw.y + fvector.dy;
663
	quad[2].x = f->cw.x + fvector.dx;
664
	quad[2].y = f->cw.y + fvector.dy;
665
	quad[3] = f->cw;
666
 
667
	if (stroker->add_external_edge != NULL) {
668
	    cairo_status_t status;
669
 
670
	    status = stroker->add_external_edge (stroker->closure,
671
						 &quad[0], &quad[1]);
672
	    if (unlikely (status))
673
		return status;
674
 
675
	    status = stroker->add_external_edge (stroker->closure,
676
						 &quad[1], &quad[2]);
677
	    if (unlikely (status))
678
		return status;
679
 
680
	    status = stroker->add_external_edge (stroker->closure,
681
						 &quad[2], &quad[3]);
682
	    if (unlikely (status))
683
		return status;
684
 
685
	    return CAIRO_STATUS_SUCCESS;
686
	} else {
687
	    return stroker->add_convex_quad (stroker->closure, quad);
688
	}
689
    }
690
 
691
    case CAIRO_LINE_CAP_BUTT:
692
    default:
693
	if (stroker->add_external_edge != NULL) {
694
	    return stroker->add_external_edge (stroker->closure,
695
					       &f->ccw, &f->cw);
696
	} else {
697
	    return CAIRO_STATUS_SUCCESS;
698
	}
699
    }
700
}
701
 
702
static cairo_status_t
703
_cairo_stroker_add_leading_cap (cairo_stroker_t     *stroker,
704
				const cairo_stroke_face_t *face)
705
{
706
    cairo_stroke_face_t reversed;
707
    cairo_point_t t;
708
 
709
    reversed = *face;
710
 
711
    /* The initial cap needs an outward facing vector. Reverse everything */
712
    reversed.usr_vector.x = -reversed.usr_vector.x;
713
    reversed.usr_vector.y = -reversed.usr_vector.y;
714
    reversed.dev_vector.dx = -reversed.dev_vector.dx;
715
    reversed.dev_vector.dy = -reversed.dev_vector.dy;
716
    t = reversed.cw;
717
    reversed.cw = reversed.ccw;
718
    reversed.ccw = t;
719
 
720
    return _cairo_stroker_add_cap (stroker, &reversed);
721
}
722
 
723
static cairo_status_t
724
_cairo_stroker_add_trailing_cap (cairo_stroker_t     *stroker,
725
				 const cairo_stroke_face_t *face)
726
{
727
    return _cairo_stroker_add_cap (stroker, face);
728
}
729
 
730
static inline cairo_bool_t
731
_compute_normalized_device_slope (double *dx, double *dy,
732
				  const cairo_matrix_t *ctm_inverse,
733
				  double *mag_out)
734
{
735
    double dx0 = *dx, dy0 = *dy;
736
    double mag;
737
 
738
    cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0);
739
 
740
    if (dx0 == 0.0 && dy0 == 0.0) {
741
	if (mag_out)
742
	    *mag_out = 0.0;
743
	return FALSE;
744
    }
745
 
746
    if (dx0 == 0.0) {
747
	*dx = 0.0;
748
	if (dy0 > 0.0) {
749
	    mag = dy0;
750
	    *dy = 1.0;
751
	} else {
752
	    mag = -dy0;
753
	    *dy = -1.0;
754
	}
755
    } else if (dy0 == 0.0) {
756
	*dy = 0.0;
757
	if (dx0 > 0.0) {
758
	    mag = dx0;
759
	    *dx = 1.0;
760
	} else {
761
	    mag = -dx0;
762
	    *dx = -1.0;
763
	}
764
    } else {
765
	mag = hypot (dx0, dy0);
766
	*dx = dx0 / mag;
767
	*dy = dy0 / mag;
768
    }
769
 
770
    if (mag_out)
771
	*mag_out = mag;
772
 
773
    return TRUE;
774
}
775
 
776
static void
3959 Serge 777
_compute_face (const cairo_point_t *point,
778
	       const cairo_slope_t *dev_slope,
779
	       double slope_dx,
780
	       double slope_dy,
781
	       cairo_stroker_t *stroker,
782
	       cairo_stroke_face_t *face)
1892 serge 783
{
784
    double face_dx, face_dy;
785
    cairo_point_t offset_ccw, offset_cw;
786
 
787
    /*
788
     * rotate to get a line_width/2 vector along the face, note that
789
     * the vector must be rotated the right direction in device space,
790
     * but by 90° in user space. So, the rotation depends on
791
     * whether the ctm reflects or not, and that can be determined
792
     * by looking at the determinant of the matrix.
793
     */
794
    if (stroker->ctm_det_positive)
795
    {
3959 Serge 796
	face_dx = - slope_dy * stroker->half_line_width;
797
	face_dy = slope_dx * stroker->half_line_width;
1892 serge 798
    }
799
    else
800
    {
3959 Serge 801
	face_dx = slope_dy * stroker->half_line_width;
802
	face_dy = - slope_dx * stroker->half_line_width;
1892 serge 803
    }
804
 
805
    /* back to device space */
806
    cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
807
 
808
    offset_ccw.x = _cairo_fixed_from_double (face_dx);
809
    offset_ccw.y = _cairo_fixed_from_double (face_dy);
810
    offset_cw.x = -offset_ccw.x;
811
    offset_cw.y = -offset_ccw.y;
812
 
813
    face->ccw = *point;
814
    _translate_point (&face->ccw, &offset_ccw);
815
 
816
    face->point = *point;
817
 
818
    face->cw = *point;
819
    _translate_point (&face->cw, &offset_cw);
820
 
821
    face->usr_vector.x = slope_dx;
822
    face->usr_vector.y = slope_dy;
823
 
824
    face->dev_vector = *dev_slope;
825
}
826
 
827
static cairo_status_t
828
_cairo_stroker_add_caps (cairo_stroker_t *stroker)
829
{
830
    cairo_status_t status;
831
 
832
    /* check for a degenerative sub_path */
833
    if (stroker->has_initial_sub_path
834
	&& ! stroker->has_first_face
835
	&& ! stroker->has_current_face
3959 Serge 836
	&& stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
1892 serge 837
    {
838
	/* pick an arbitrary slope to use */
839
	double dx = 1.0, dy = 0.0;
840
	cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
841
	cairo_stroke_face_t face;
842
 
843
	_compute_normalized_device_slope (&dx, &dy,
844
					  stroker->ctm_inverse, NULL);
845
 
846
	/* arbitrarily choose first_point
847
	 * first_point and current_point should be the same */
848
	_compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face);
849
 
850
	status = _cairo_stroker_add_leading_cap (stroker, &face);
851
	if (unlikely (status))
852
	    return status;
853
 
854
	status = _cairo_stroker_add_trailing_cap (stroker, &face);
855
	if (unlikely (status))
856
	    return status;
857
    }
858
 
859
    if (stroker->has_first_face) {
860
	status = _cairo_stroker_add_leading_cap (stroker,
861
						 &stroker->first_face);
862
	if (unlikely (status))
863
	    return status;
864
    }
865
 
866
    if (stroker->has_current_face) {
867
	status = _cairo_stroker_add_trailing_cap (stroker,
868
						  &stroker->current_face);
869
	if (unlikely (status))
870
	    return status;
871
    }
872
 
873
    return CAIRO_STATUS_SUCCESS;
874
}
875
 
876
static cairo_status_t
877
_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker,
878
			     const cairo_point_t *p1,
879
			     const cairo_point_t *p2,
880
			     cairo_slope_t *dev_slope,
881
			     double slope_dx, double slope_dy,
882
			     cairo_stroke_face_t *start,
883
			     cairo_stroke_face_t *end)
884
{
885
    _compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start);
886
    *end = *start;
887
 
888
    if (p1->x == p2->x && p1->y == p2->y)
889
	return CAIRO_STATUS_SUCCESS;
890
 
891
    end->point = *p2;
892
    end->ccw.x += p2->x - p1->x;
893
    end->ccw.y += p2->y - p1->y;
894
    end->cw.x += p2->x - p1->x;
895
    end->cw.y += p2->y - p1->y;
896
 
897
    if (stroker->add_external_edge != NULL) {
898
	cairo_status_t status;
899
 
900
	status = stroker->add_external_edge (stroker->closure,
901
					     &end->cw, &start->cw);
902
	if (unlikely (status))
903
	    return status;
904
 
905
	status = stroker->add_external_edge (stroker->closure,
906
					     &start->ccw, &end->ccw);
907
	if (unlikely (status))
908
	    return status;
909
 
910
	return CAIRO_STATUS_SUCCESS;
911
    } else {
912
	cairo_point_t quad[4];
913
 
914
	quad[0] = start->cw;
915
	quad[1] = end->cw;
916
	quad[2] = end->ccw;
917
	quad[3] = start->ccw;
918
 
919
	return stroker->add_convex_quad (stroker->closure, quad);
920
    }
921
}
922
 
923
static cairo_status_t
924
_cairo_stroker_move_to (void *closure,
925
			const cairo_point_t *point)
926
{
927
    cairo_stroker_t *stroker = closure;
928
    cairo_status_t status;
929
 
930
    /* reset the dash pattern for new sub paths */
931
    _cairo_stroker_dash_start (&stroker->dash);
932
 
933
    /* Cap the start and end of the previous sub path as needed */
934
    status = _cairo_stroker_add_caps (stroker);
935
    if (unlikely (status))
936
	return status;
937
 
938
    stroker->first_point = *point;
939
    stroker->current_point = *point;
940
 
941
    stroker->has_first_face = FALSE;
942
    stroker->has_current_face = FALSE;
943
    stroker->has_initial_sub_path = FALSE;
944
 
945
    return CAIRO_STATUS_SUCCESS;
946
}
947
 
948
static cairo_status_t
949
_cairo_stroker_line_to (void *closure,
950
			const cairo_point_t *point)
951
{
952
    cairo_stroker_t *stroker = closure;
953
    cairo_stroke_face_t start, end;
954
    cairo_point_t *p1 = &stroker->current_point;
955
    cairo_slope_t dev_slope;
956
    double slope_dx, slope_dy;
957
    cairo_status_t status;
958
 
959
    stroker->has_initial_sub_path = TRUE;
960
 
961
    if (p1->x == point->x && p1->y == point->y)
962
	return CAIRO_STATUS_SUCCESS;
963
 
964
    _cairo_slope_init (&dev_slope, p1, point);
965
    slope_dx = _cairo_fixed_to_double (point->x - p1->x);
966
    slope_dy = _cairo_fixed_to_double (point->y - p1->y);
967
    _compute_normalized_device_slope (&slope_dx, &slope_dy,
968
				      stroker->ctm_inverse, NULL);
969
 
970
    status = _cairo_stroker_add_sub_edge (stroker,
971
					  p1, point,
972
					  &dev_slope,
973
					  slope_dx, slope_dy,
974
					  &start, &end);
975
    if (unlikely (status))
976
	return status;
977
 
978
    if (stroker->has_current_face) {
979
	/* Join with final face from previous segment */
980
	status = _cairo_stroker_join (stroker,
981
				      &stroker->current_face,
982
				      &start);
983
	if (unlikely (status))
984
	    return status;
985
    } else if (! stroker->has_first_face) {
986
	/* Save sub path's first face in case needed for closing join */
987
	stroker->first_face = start;
988
	stroker->has_first_face = TRUE;
989
    }
990
    stroker->current_face = end;
991
    stroker->has_current_face = TRUE;
992
 
993
    stroker->current_point = *point;
994
 
995
    return CAIRO_STATUS_SUCCESS;
996
}
997
 
3959 Serge 998
static cairo_status_t
999
_cairo_stroker_spline_to (void *closure,
1000
			  const cairo_point_t *point,
1001
			  const cairo_slope_t *tangent)
1002
{
1003
    cairo_stroker_t *stroker = closure;
1004
    cairo_stroke_face_t new_face;
1005
    double slope_dx, slope_dy;
1006
    cairo_point_t points[3];
1007
    cairo_point_t intersect_point;
1008
 
1009
    stroker->has_initial_sub_path = TRUE;
1010
 
1011
    if (stroker->current_point.x == point->x &&
1012
	stroker->current_point.y == point->y)
1013
	return CAIRO_STATUS_SUCCESS;
1014
 
1015
    slope_dx = _cairo_fixed_to_double (tangent->dx);
1016
    slope_dy = _cairo_fixed_to_double (tangent->dy);
1017
 
1018
    if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
1019
					    stroker->ctm_inverse, NULL))
1020
	return CAIRO_STATUS_SUCCESS;
1021
 
1022
    _compute_face (point, tangent,
1023
		   slope_dx, slope_dy,
1024
		   stroker, &new_face);
1025
 
1026
    assert (stroker->has_current_face);
1027
 
1028
    if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x +
1029
         new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) {
1030
 
1031
	const cairo_point_t *inpt, *outpt;
1032
	int clockwise = _cairo_stroker_join_is_clockwise (&new_face,
1033
							  &stroker->current_face);
1034
 
1035
	if (clockwise) {
1036
	    inpt = &stroker->current_face.cw;
1037
	    outpt = &new_face.cw;
1038
	} else {
1039
	    inpt = &stroker->current_face.ccw;
1040
	    outpt = &new_face.ccw;
1041
	}
1042
 
1043
	_tessellate_fan (stroker,
1044
			 &stroker->current_face.dev_vector,
1045
			 &new_face.dev_vector,
1046
			 &stroker->current_face.point,
1047
			 inpt, outpt,
1048
			 clockwise);
1049
    }
1050
 
1051
    if (_slow_segment_intersection (&stroker->current_face.cw,
1052
				    &stroker->current_face.ccw,
1053
				    &new_face.cw,
1054
				    &new_face.ccw,
1055
				    &intersect_point)) {
1056
	points[0] = stroker->current_face.ccw;
1057
	points[1] = new_face.ccw;
1058
	points[2] = intersect_point;
1059
	stroker->add_triangle (stroker->closure, points);
1060
 
1061
	points[0] = stroker->current_face.cw;
1062
	points[1] = new_face.cw;
1063
	stroker->add_triangle (stroker->closure, points);
1064
    } else {
1065
	points[0] = stroker->current_face.ccw;
1066
	points[1] = stroker->current_face.cw;
1067
	points[2] = new_face.cw;
1068
	stroker->add_triangle (stroker->closure, points);
1069
 
1070
	points[0] = stroker->current_face.ccw;
1071
	points[1] = new_face.cw;
1072
	points[2] = new_face.ccw;
1073
	stroker->add_triangle (stroker->closure, points);
1074
    }
1075
 
1076
    stroker->current_face = new_face;
1077
    stroker->has_current_face = TRUE;
1078
    stroker->current_point = *point;
1079
 
1080
    return CAIRO_STATUS_SUCCESS;
1081
}
1082
 
1892 serge 1083
/*
1084
 * Dashed lines.  Cap each dash end, join around turns when on
1085
 */
1086
static cairo_status_t
1087
_cairo_stroker_line_to_dashed (void *closure,
1088
			       const cairo_point_t *p2)
1089
{
1090
    cairo_stroker_t *stroker = closure;
1091
    double mag, remain, step_length = 0;
1092
    double slope_dx, slope_dy;
1093
    double dx2, dy2;
1094
    cairo_stroke_face_t sub_start, sub_end;
1095
    cairo_point_t *p1 = &stroker->current_point;
1096
    cairo_slope_t dev_slope;
1097
    cairo_line_t segment;
1098
    cairo_bool_t fully_in_bounds;
1099
    cairo_status_t status;
1100
 
1101
    stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
1102
 
1103
    if (p1->x == p2->x && p1->y == p2->y)
1104
	return CAIRO_STATUS_SUCCESS;
1105
 
1106
    fully_in_bounds = TRUE;
1107
    if (stroker->has_bounds &&
1108
	(! _cairo_box_contains_point (&stroker->bounds, p1) ||
1109
	 ! _cairo_box_contains_point (&stroker->bounds, p2)))
1110
    {
1111
	fully_in_bounds = FALSE;
1112
    }
1113
 
1114
    _cairo_slope_init (&dev_slope, p1, p2);
1115
 
1116
    slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
1117
    slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
1118
 
1119
    if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
1120
					    stroker->ctm_inverse, &mag))
1121
    {
1122
	return CAIRO_STATUS_SUCCESS;
1123
    }
1124
 
1125
    remain = mag;
1126
    segment.p1 = *p1;
1127
    while (remain) {
1128
	step_length = MIN (stroker->dash.dash_remain, remain);
1129
	remain -= step_length;
1130
	dx2 = slope_dx * (mag - remain);
1131
	dy2 = slope_dy * (mag - remain);
1132
	cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
1133
	segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
1134
	segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
1135
 
1136
	if (stroker->dash.dash_on &&
1137
	    (fully_in_bounds ||
1138
	     (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
1139
	     _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
1140
	{
1141
	    status = _cairo_stroker_add_sub_edge (stroker,
1142
						  &segment.p1, &segment.p2,
1143
						  &dev_slope,
1144
						  slope_dx, slope_dy,
1145
						  &sub_start, &sub_end);
1146
	    if (unlikely (status))
1147
		return status;
1148
 
1149
	    if (stroker->has_current_face)
1150
	    {
1151
		/* Join with final face from previous segment */
1152
		status = _cairo_stroker_join (stroker,
1153
					      &stroker->current_face,
1154
					      &sub_start);
1155
		if (unlikely (status))
1156
		    return status;
1157
 
1158
		stroker->has_current_face = FALSE;
1159
	    }
1160
	    else if (! stroker->has_first_face &&
1161
		       stroker->dash.dash_starts_on)
1162
	    {
1163
		/* Save sub path's first face in case needed for closing join */
1164
		stroker->first_face = sub_start;
1165
		stroker->has_first_face = TRUE;
1166
	    }
1167
	    else
1168
	    {
1169
		/* Cap dash start if not connecting to a previous segment */
1170
		status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
1171
		if (unlikely (status))
1172
		    return status;
1173
	    }
1174
 
1175
	    if (remain) {
1176
		/* Cap dash end if not at end of segment */
1177
		status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
1178
		if (unlikely (status))
1179
		    return status;
1180
	    } else {
1181
		stroker->current_face = sub_end;
1182
		stroker->has_current_face = TRUE;
1183
	    }
1184
	} else {
1185
	    if (stroker->has_current_face) {
1186
		/* Cap final face from previous segment */
1187
		status = _cairo_stroker_add_trailing_cap (stroker,
1188
							  &stroker->current_face);
1189
		if (unlikely (status))
1190
		    return status;
1191
 
1192
		stroker->has_current_face = FALSE;
1193
	    }
1194
	}
1195
 
1196
	_cairo_stroker_dash_step (&stroker->dash, step_length);
1197
	segment.p1 = segment.p2;
1198
    }
1199
 
1200
    if (stroker->dash.dash_on && ! stroker->has_current_face) {
1201
	/* This segment ends on a transition to dash_on, compute a new face
1202
	 * and add cap for the beginning of the next dash_on step.
1203
	 *
1204
	 * Note: this will create a degenerate cap if this is not the last line
1205
	 * in the path. Whether this behaviour is desirable or not is debatable.
1206
	 * On one side these degenerate caps can not be reproduced with regular
1207
	 * path stroking.
1208
	 * On the other hand, Acroread 7 also produces the degenerate caps.
1209
	 */
1210
	_compute_face (p2, &dev_slope,
1211
		       slope_dx, slope_dy,
1212
		       stroker,
1213
		       &stroker->current_face);
1214
 
1215
	status = _cairo_stroker_add_leading_cap (stroker,
1216
						 &stroker->current_face);
1217
	if (unlikely (status))
1218
	    return status;
1219
 
1220
	stroker->has_current_face = TRUE;
1221
    }
1222
 
1223
    stroker->current_point = *p2;
1224
 
1225
    return CAIRO_STATUS_SUCCESS;
1226
}
1227
 
1228
static cairo_status_t
1229
_cairo_stroker_curve_to (void *closure,
1230
			 const cairo_point_t *b,
1231
			 const cairo_point_t *c,
1232
			 const cairo_point_t *d)
1233
{
1234
    cairo_stroker_t *stroker = closure;
1235
    cairo_spline_t spline;
1236
    cairo_line_join_t line_join_save;
1237
    cairo_stroke_face_t face;
1238
    double slope_dx, slope_dy;
3959 Serge 1239
    cairo_spline_add_point_func_t line_to;
1240
    cairo_spline_add_point_func_t spline_to;
1892 serge 1241
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1242
 
1243
    line_to = stroker->dash.dashed ?
3959 Serge 1244
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
1245
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to;
1892 serge 1246
 
3959 Serge 1247
    /* spline_to is only capable of rendering non-degenerate splines. */
1248
    spline_to = stroker->dash.dashed ?
1249
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
1250
	(cairo_spline_add_point_func_t) _cairo_stroker_spline_to;
1251
 
1892 serge 1252
    if (! _cairo_spline_init (&spline,
3959 Serge 1253
			      spline_to,
1254
			      stroker,
1892 serge 1255
			      &stroker->current_point, b, c, d))
1256
    {
3959 Serge 1257
	cairo_slope_t fallback_slope;
1258
	_cairo_slope_init (&fallback_slope, &stroker->current_point, d);
1259
	return line_to (closure, d, &fallback_slope);
1892 serge 1260
    }
1261
 
1262
    /* If the line width is so small that the pen is reduced to a
1263
       single point, then we have nothing to do. */
1264
    if (stroker->pen.num_vertices <= 1)
1265
	return CAIRO_STATUS_SUCCESS;
1266
 
1267
    /* Compute the initial face */
1268
    if (! stroker->dash.dashed || stroker->dash.dash_on) {
1269
	slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx);
1270
	slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy);
1271
	if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
1272
					      stroker->ctm_inverse, NULL))
1273
	{
1274
	    _compute_face (&stroker->current_point,
1275
			   &spline.initial_slope,
1276
			   slope_dx, slope_dy,
1277
			   stroker, &face);
1278
	}
1279
	if (stroker->has_current_face) {
1280
	    status = _cairo_stroker_join (stroker,
1281
					  &stroker->current_face, &face);
1282
	    if (unlikely (status))
1283
		return status;
1284
	} else if (! stroker->has_first_face) {
1285
	    stroker->first_face = face;
1286
	    stroker->has_first_face = TRUE;
1287
	}
1288
 
1289
	stroker->current_face = face;
1290
	stroker->has_current_face = TRUE;
1291
    }
1292
 
1293
    /* Temporarily modify the stroker to use round joins to guarantee
1294
     * smooth stroked curves. */
1295
    line_join_save = stroker->style.line_join;
1296
    stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
1297
 
1298
    status = _cairo_spline_decompose (&spline, stroker->tolerance);
1299
    if (unlikely (status))
1300
	return status;
1301
 
1302
    /* And join the final face */
1303
    if (! stroker->dash.dashed || stroker->dash.dash_on) {
1304
	slope_dx = _cairo_fixed_to_double (spline.final_slope.dx);
1305
	slope_dy = _cairo_fixed_to_double (spline.final_slope.dy);
1306
	if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
1307
					      stroker->ctm_inverse, NULL))
1308
	{
1309
	    _compute_face (&stroker->current_point,
1310
			   &spline.final_slope,
1311
			   slope_dx, slope_dy,
1312
			   stroker, &face);
1313
	}
1314
 
1315
	status = _cairo_stroker_join (stroker, &stroker->current_face, &face);
1316
	if (unlikely (status))
1317
	    return status;
1318
 
1319
	stroker->current_face = face;
1320
    }
1321
 
1322
    stroker->style.line_join = line_join_save;
1323
 
1324
    return CAIRO_STATUS_SUCCESS;
1325
}
1326
 
1327
static cairo_status_t
1328
_cairo_stroker_close_path (void *closure)
1329
{
1330
    cairo_stroker_t *stroker = closure;
1331
    cairo_status_t status;
1332
 
1333
    if (stroker->dash.dashed)
1334
	status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
1335
    else
1336
	status = _cairo_stroker_line_to (stroker, &stroker->first_point);
1337
    if (unlikely (status))
1338
	return status;
1339
 
1340
    if (stroker->has_first_face && stroker->has_current_face) {
1341
	/* Join first and final faces of sub path */
1342
	status = _cairo_stroker_join (stroker,
1343
				      &stroker->current_face,
1344
				      &stroker->first_face);
1345
	if (unlikely (status))
1346
	    return status;
1347
    } else {
1348
	/* Cap the start and end of the sub path as needed */
1349
	status = _cairo_stroker_add_caps (stroker);
1350
	if (unlikely (status))
1351
	    return status;
1352
    }
1353
 
1354
    stroker->has_initial_sub_path = FALSE;
1355
    stroker->has_first_face = FALSE;
1356
    stroker->has_current_face = FALSE;
1357
 
1358
    return CAIRO_STATUS_SUCCESS;
1359
}
1360
 
1361
cairo_status_t
1362
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t	*path,
1363
				    const cairo_stroke_style_t	*stroke_style,
1364
				    const cairo_matrix_t	*ctm,
1365
				    const cairo_matrix_t	*ctm_inverse,
1366
				    double		 tolerance,
1367
				    cairo_status_t (*add_triangle) (void *closure,
1368
								    const cairo_point_t triangle[3]),
1369
				    cairo_status_t (*add_triangle_fan) (void *closure,
1370
									const cairo_point_t *midpt,
1371
									const cairo_point_t *points,
1372
									int npoints),
1373
				    cairo_status_t (*add_convex_quad) (void *closure,
1374
								       const cairo_point_t quad[4]),
1375
				    void *closure)
1376
{
1377
    cairo_stroker_t stroker;
1378
    cairo_status_t status;
1379
 
3959 Serge 1380
    status = _cairo_stroker_init (&stroker, path, stroke_style,
1381
			          ctm, ctm_inverse, tolerance,
1382
				  NULL, 0);
1892 serge 1383
    if (unlikely (status))
1384
	return status;
1385
 
1386
    stroker.add_triangle = add_triangle;
1387
    stroker.add_triangle_fan = add_triangle_fan;
1388
    stroker.add_convex_quad = add_convex_quad;
1389
    stroker.closure = closure;
1390
 
1391
    status = _cairo_path_fixed_interpret (path,
1392
					  _cairo_stroker_move_to,
1393
					  stroker.dash.dashed ?
1394
					  _cairo_stroker_line_to_dashed :
1395
					  _cairo_stroker_line_to,
1396
					  _cairo_stroker_curve_to,
1397
					  _cairo_stroker_close_path,
1398
					  &stroker);
1399
 
1400
    if (unlikely (status))
1401
	goto BAIL;
1402
 
1403
    /* Cap the start and end of the final sub path as needed */
1404
    status = _cairo_stroker_add_caps (&stroker);
1405
 
1406
BAIL:
1407
    _cairo_stroker_fini (&stroker);
1408
 
1409
    return status;
1410
}
1411
 
1412
cairo_status_t
3959 Serge 1413
_cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t	*path,
1414
					    const cairo_stroke_style_t	*stroke_style,
1415
					    const cairo_matrix_t	*ctm,
1416
					    const cairo_matrix_t	*ctm_inverse,
1417
					    double		 tolerance,
1418
					    cairo_polygon_t *polygon)
1892 serge 1419
{
1420
    cairo_stroker_t stroker;
1421
    cairo_status_t status;
1422
 
3959 Serge 1423
    status = _cairo_stroker_init (&stroker, path, stroke_style,
1424
			          ctm, ctm_inverse, tolerance,
1425
				  polygon->limits, polygon->num_limits);
1892 serge 1426
    if (unlikely (status))
1427
	return status;
1428
 
1429
    stroker.add_external_edge = _cairo_polygon_add_external_edge,
1430
    stroker.closure = polygon;
1431
 
1432
    status = _cairo_path_fixed_interpret (path,
1433
					  _cairo_stroker_move_to,
1434
					  stroker.dash.dashed ?
1435
					  _cairo_stroker_line_to_dashed :
1436
					  _cairo_stroker_line_to,
1437
					  _cairo_stroker_curve_to,
1438
					  _cairo_stroker_close_path,
1439
					  &stroker);
1440
 
1441
    if (unlikely (status))
1442
	goto BAIL;
1443
 
1444
    /* Cap the start and end of the final sub path as needed */
1445
    status = _cairo_stroker_add_caps (&stroker);
1446
 
1447
BAIL:
1448
    _cairo_stroker_fini (&stroker);
1449
 
1450
    return status;
1451
}
1452
 
3959 Serge 1453
cairo_int_status_t
1454
_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t	*path,
1455
                                           const cairo_stroke_style_t	*stroke_style,
1456
                                           const cairo_matrix_t	*ctm,
1457
                                           const cairo_matrix_t	*ctm_inverse,
1458
                                           double		 tolerance,
1459
                                           cairo_traps_t	*traps)
1892 serge 1460
{
3959 Serge 1461
    cairo_int_status_t status;
1892 serge 1462
    cairo_polygon_t polygon;
1463
 
3959 Serge 1464
    _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
1892 serge 1465
    status = _cairo_path_fixed_stroke_to_polygon (path,
1466
						  stroke_style,
1467
						  ctm,
1468
						  ctm_inverse,
1469
						  tolerance,
1470
						  &polygon);
1471
    if (unlikely (status))
1472
	goto BAIL;
1473
 
1474
    status = _cairo_polygon_status (&polygon);
1475
    if (unlikely (status))
1476
	goto BAIL;
1477
 
1478
    status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
1479
							CAIRO_FILL_RULE_WINDING);
1480
 
1481
BAIL:
1482
    _cairo_polygon_fini (&polygon);
1483
 
1484
    return status;
1485
}