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
 * Copyright © 2013 Intel Corporation
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it either under the terms of the GNU Lesser General Public
9
 * License version 2.1 as published by the Free Software Foundation
10
 * (the "LGPL") or, at your option, under the terms of the Mozilla
11
 * Public License Version 1.1 (the "MPL"). If you do not alter this
12
 * notice, a recipient may use your version of this file under either
13
 * the MPL or the LGPL.
14
 *
15
 * You should have received a copy of the LGPL along with this library
16
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
 * You should have received a copy of the MPL along with this library
19
 * in the file COPYING-MPL-1.1
20
 *
21
 * The contents of this file are subject to the Mozilla Public License
22
 * Version 1.1 (the "License"); you may not use this file except in
23
 * compliance with the License. You may obtain a copy of the License at
24
 * http://www.mozilla.org/MPL/
25
 *
26
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28
 * the specific language governing rights and limitations.
29
 *
30
 * The Original Code is the cairo graphics library.
31
 *
32
 * The Initial Developer of the Original Code is University of Southern
33
 * California.
34
 *
35
 * Contributor(s):
36
 *	Carl D. Worth <cworth@cworth.org>
37
 *	Chris Wilson <chris@chris-wilson.co.uk>
38
 */
39

            
40
#include "cairoint.h"
41

            
42
#include "cairo-box-inline.h"
43
#include "cairo-path-fixed-private.h"
44
#include "cairo-slope-private.h"
45
#include "cairo-stroke-dash-private.h"
46
#include "cairo-traps-private.h"
47

            
48
#include <float.h>
49

            
50
struct stroker {
51
    const cairo_stroke_style_t	*style;
52

            
53
    const cairo_matrix_t *ctm;
54
    const cairo_matrix_t *ctm_inverse;
55
    double spline_cusp_tolerance;
56
    double half_line_width;
57
    double tolerance;
58
    double ctm_determinant;
59
    cairo_bool_t ctm_det_positive;
60
    cairo_line_join_t line_join;
61

            
62
    cairo_traps_t *traps;
63

            
64
    cairo_pen_t pen;
65

            
66
    cairo_point_t first_point;
67

            
68
    cairo_bool_t has_initial_sub_path;
69

            
70
    cairo_bool_t has_current_face;
71
    cairo_stroke_face_t current_face;
72

            
73
    cairo_bool_t has_first_face;
74
    cairo_stroke_face_t first_face;
75

            
76
    cairo_stroker_dash_t dash;
77

            
78
    cairo_bool_t has_bounds;
79
    cairo_box_t tight_bounds;
80
    cairo_box_t line_bounds;
81
    cairo_box_t join_bounds;
82
};
83

            
84
static cairo_status_t
85
6
stroker_init (struct stroker		*stroker,
86
	      const cairo_path_fixed_t	*path,
87
	      const cairo_stroke_style_t	*style,
88
	      const cairo_matrix_t	*ctm,
89
	      const cairo_matrix_t	*ctm_inverse,
90
	      double			 tolerance,
91
	      cairo_traps_t		*traps)
92
{
93
    cairo_status_t status;
94

            
95
6
    stroker->style = style;
96
6
    stroker->ctm = ctm;
97
6
    stroker->ctm_inverse = NULL;
98
6
    if (! _cairo_matrix_is_identity (ctm_inverse))
99
6
	stroker->ctm_inverse = ctm_inverse;
100
6
    stroker->line_join = style->line_join;
101
6
    stroker->half_line_width = style->line_width / 2.0;
102
6
    stroker->tolerance = tolerance;
103
6
    stroker->traps = traps;
104

            
105
    /* If `CAIRO_LINE_JOIN_ROUND` is selected and a joint's `arc height`
106
     * is greater than `tolerance` then two segments are joined with
107
     * round-join, otherwise bevel-join is used.
108
     *
109
     * `Arc height` is the difference of the "half of a line width" and
110
     * the "half of a line width" times `cos(half the angle between segment vectors)`.
111
     *
112
     * See detailed description in the `_cairo_path_fixed_stroke_to_polygon()`
113
     * function in the `cairo-path-stroke-polygon.c` file or follow the
114
     * https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/372#note_1698225
115
     * link to see the detailed description with an illustration.
116
     */
117
6
    double scaled_hlw = hypot(stroker->half_line_width * ctm->xx,
118
6
			      stroker->half_line_width * ctm->yx);
119

            
120
6
    if (scaled_hlw <= tolerance) {
121
	stroker->spline_cusp_tolerance = -1.0;
122
    } else {
123
6
	stroker->spline_cusp_tolerance = 1 - tolerance / scaled_hlw;
124
6
	stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
125
6
	stroker->spline_cusp_tolerance *= 2;
126
6
	stroker->spline_cusp_tolerance -= 1;
127
    }
128

            
129
6
    stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
130
6
    stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
131

            
132
6
    status = _cairo_pen_init (&stroker->pen,
133
		              stroker->half_line_width,
134
			      tolerance, ctm);
135
6
    if (unlikely (status))
136
	return status;
137

            
138
6
    stroker->has_current_face = FALSE;
139
6
    stroker->has_first_face = FALSE;
140
6
    stroker->has_initial_sub_path = FALSE;
141

            
142
6
    _cairo_stroker_dash_init (&stroker->dash, style);
143

            
144
6
    stroker->has_bounds = traps->num_limits;
145
6
    if (stroker->has_bounds) {
146
	/* Extend the bounds in each direction to account for the maximum area
147
	 * we might generate trapezoids, to capture line segments that are outside
148
	 * of the bounds but which might generate rendering that's within bounds.
149
	 */
150
	double dx, dy;
151
	cairo_fixed_t fdx, fdy;
152

            
153
6
	stroker->tight_bounds = traps->bounds;
154

            
155
6
	_cairo_stroke_style_max_distance_from_path (stroker->style, path,
156
						    stroker->ctm, &dx, &dy);
157

            
158
6
	_cairo_stroke_style_max_line_distance_from_path (stroker->style, path,
159
							 stroker->ctm, &dx, &dy);
160

            
161
6
	fdx = _cairo_fixed_from_double (dx);
162
6
	fdy = _cairo_fixed_from_double (dy);
163

            
164
6
	stroker->line_bounds = stroker->tight_bounds;
165
6
	stroker->line_bounds.p1.x -= fdx;
166
6
	stroker->line_bounds.p2.x += fdx;
167
6
	stroker->line_bounds.p1.y -= fdy;
168
6
	stroker->line_bounds.p2.y += fdy;
169

            
170
6
	_cairo_stroke_style_max_join_distance_from_path (stroker->style, path,
171
							 stroker->ctm, &dx, &dy);
172

            
173
6
	fdx = _cairo_fixed_from_double (dx);
174
6
	fdy = _cairo_fixed_from_double (dy);
175

            
176
6
	stroker->join_bounds = stroker->tight_bounds;
177
6
	stroker->join_bounds.p1.x -= fdx;
178
6
	stroker->join_bounds.p2.x += fdx;
179
6
	stroker->join_bounds.p1.y -= fdy;
180
6
	stroker->join_bounds.p2.y += fdy;
181
    }
182

            
183
6
    return CAIRO_STATUS_SUCCESS;
184
}
185

            
186
static void
187
6
stroker_fini (struct stroker *stroker)
188
{
189
6
    _cairo_pen_fini (&stroker->pen);
190
6
}
191

            
192
static void
193
1032
translate_point (cairo_point_t *point, cairo_point_t *offset)
194
{
195
1032
    point->x += offset->x;
196
1032
    point->y += offset->y;
197
1032
}
198

            
199
static int
200
258
join_is_clockwise (const cairo_stroke_face_t *in,
201
		   const cairo_stroke_face_t *out)
202
{
203
258
    return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
204
}
205

            
206
static int
207
slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
208
{
209
    double c = dx1 * dy2 - dx2 * dy1;
210
    if (c > 0) return 1;
211
    if (c < 0) return -1;
212
    return 0;
213
}
214

            
215
static cairo_bool_t
216
240
stroker_intersects_join (const struct stroker *stroker,
217
			 const cairo_point_t *in,
218
			 const cairo_point_t *out)
219
{
220
    cairo_line_t segment;
221

            
222
240
    if (! stroker->has_bounds)
223
	return TRUE;
224

            
225
240
    segment.p1 = *in;
226
240
    segment.p2 = *out;
227
240
    return _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment);
228
}
229

            
230
static void
231
258
join (struct stroker *stroker,
232
      cairo_stroke_face_t *in,
233
      cairo_stroke_face_t *out)
234
{
235
258
    int clockwise = join_is_clockwise (out, in);
236
    cairo_point_t *inpt, *outpt;
237

            
238
258
    if (in->cw.x == out->cw.x &&
239
18
	in->cw.y == out->cw.y &&
240
18
	in->ccw.x == out->ccw.x &&
241
18
	in->ccw.y == out->ccw.y)
242
    {
243
18
	return;
244
    }
245

            
246
240
    if (clockwise) {
247
	inpt = &in->ccw;
248
	outpt = &out->ccw;
249
    } else {
250
240
	inpt = &in->cw;
251
240
	outpt = &out->cw;
252
    }
253

            
254
240
    if (! stroker_intersects_join (stroker, inpt, outpt))
255
	    return;
256

            
257
240
    switch (stroker->line_join) {
258
240
    case CAIRO_LINE_JOIN_ROUND:
259
	/* construct a fan around the common midpoint */
260
240
	if ((in->dev_slope.x * out->dev_slope.x +
261
240
	     in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
262
	{
263
	    int start, stop;
264
	    cairo_point_t tri[3], edges[4];
265
	    cairo_pen_t *pen = &stroker->pen;
266

            
267
	    edges[0] = in->cw;
268
	    edges[1] = in->ccw;
269
	    tri[0] = in->point;
270
	    tri[1] = *inpt;
271
	    if (clockwise) {
272
		_cairo_pen_find_active_ccw_vertices (pen,
273
						     &in->dev_vector, &out->dev_vector,
274
						     &start, &stop);
275
		while (start != stop) {
276
		    tri[2] = in->point;
277
		    translate_point (&tri[2], &pen->vertices[start].point);
278
		    edges[2] = in->point;
279
		    edges[3] = tri[2];
280
		    _cairo_traps_tessellate_triangle_with_edges (stroker->traps,
281
								 tri, edges);
282
		    tri[1] = tri[2];
283
		    edges[0] = edges[2];
284
		    edges[1] = edges[3];
285

            
286
		    if (start-- == 0)
287
			start += pen->num_vertices;
288
		}
289
	    } else {
290
		_cairo_pen_find_active_cw_vertices (pen,
291
						    &in->dev_vector, &out->dev_vector,
292
						    &start, &stop);
293
		while (start != stop) {
294
		    tri[2] = in->point;
295
		    translate_point (&tri[2], &pen->vertices[start].point);
296
		    edges[2] = in->point;
297
		    edges[3] = tri[2];
298
		    _cairo_traps_tessellate_triangle_with_edges (stroker->traps,
299
								 tri, edges);
300
		    tri[1] = tri[2];
301
		    edges[0] = edges[2];
302
		    edges[1] = edges[3];
303

            
304
		    if (++start == pen->num_vertices)
305
			start = 0;
306
		}
307
	    }
308
	    tri[2] = *outpt;
309
	    edges[2] = out->cw;
310
	    edges[3] = out->ccw;
311
	    _cairo_traps_tessellate_triangle_with_edges (stroker->traps,
312
							 tri, edges);
313
	} else {
314
240
	    cairo_point_t t[] = { { in->point.x, in->point.y}, { inpt->x, inpt->y }, { outpt->x, outpt->y } };
315
240
	    cairo_point_t e[] = { { in->cw.x, in->cw.y}, { in->ccw.x, in->ccw.y },
316
240
				  { out->cw.x, out->cw.y}, { out->ccw.x, out->ccw.y } };
317
240
	    _cairo_traps_tessellate_triangle_with_edges (stroker->traps, t, e);
318
	}
319
240
	break;
320

            
321
    case CAIRO_LINE_JOIN_MITER:
322
    default: {
323
	/* dot product of incoming slope vector with outgoing slope vector */
324
	double in_dot_out = (-in->usr_vector.x * out->usr_vector.x +
325
			     -in->usr_vector.y * out->usr_vector.y);
326
	double ml = stroker->style->miter_limit;
327

            
328
	/* Check the miter limit -- lines meeting at an acute angle
329
	 * can generate long miters, the limit converts them to bevel
330
	 *
331
	 * Consider the miter join formed when two line segments
332
	 * meet at an angle psi:
333
	 *
334
	 *	   /.\
335
	 *	  /. .\
336
	 *	 /./ \.\
337
	 *	/./psi\.\
338
	 *
339
	 * We can zoom in on the right half of that to see:
340
	 *
341
	 *	    |\
342
	 *	    | \ psi/2
343
	 *	    |  \
344
	 *	    |   \
345
	 *	    |    \
346
	 *	    |     \
347
	 *	  miter    \
348
	 *	 length     \
349
	 *	    |        \
350
	 *	    |        .\
351
	 *	    |    .     \
352
	 *	    |.   line   \
353
	 *	     \    width  \
354
	 *	      \           \
355
	 *
356
	 *
357
	 * The right triangle in that figure, (the line-width side is
358
	 * shown faintly with three '.' characters), gives us the
359
	 * following expression relating miter length, angle and line
360
	 * width:
361
	 *
362
	 *	1 /sin (psi/2) = miter_length / line_width
363
	 *
364
	 * The right-hand side of this relationship is the same ratio
365
	 * in which the miter limit (ml) is expressed. We want to know
366
	 * when the miter length is within the miter limit. That is
367
	 * when the following condition holds:
368
	 *
369
	 *	1/sin(psi/2) <= ml
370
	 *	1 <= ml sin(psi/2)
371
	 *	1 <= ml² sin²(psi/2)
372
	 *	2 <= ml² 2 sin²(psi/2)
373
	 *				2·sin²(psi/2) = 1-cos(psi)
374
	 *	2 <= ml² (1-cos(psi))
375
	 *
376
	 *				in · out = |in| |out| cos (psi)
377
	 *
378
	 * in and out are both unit vectors, so:
379
	 *
380
	 *				in · out = cos (psi)
381
	 *
382
	 *	2 <= ml² (1 - in · out)
383
	 *
384
	 */
385
	if (2 <= ml * ml * (1 - in_dot_out)) {
386
	    double		x1, y1, x2, y2;
387
	    double		mx, my;
388
	    double		dx1, dx2, dy1, dy2;
389
	    cairo_point_t	outer;
390
	    cairo_point_t	quad[4];
391
	    double		ix, iy;
392
	    double		fdx1, fdy1, fdx2, fdy2;
393
	    double		mdx, mdy;
394

            
395
	    /*
396
	     * we've got the points already transformed to device
397
	     * space, but need to do some computation with them and
398
	     * also need to transform the slope from user space to
399
	     * device space
400
	     */
401
	    /* outer point of incoming line face */
402
	    x1 = _cairo_fixed_to_double (inpt->x);
403
	    y1 = _cairo_fixed_to_double (inpt->y);
404
	    dx1 = in->usr_vector.x;
405
	    dy1 = in->usr_vector.y;
406
	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
407

            
408
	    /* outer point of outgoing line face */
409
	    x2 = _cairo_fixed_to_double (outpt->x);
410
	    y2 = _cairo_fixed_to_double (outpt->y);
411
	    dx2 = out->usr_vector.x;
412
	    dy2 = out->usr_vector.y;
413
	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
414

            
415
	    /*
416
	     * Compute the location of the outer corner of the miter.
417
	     * That's pretty easy -- just the intersection of the two
418
	     * outer edges.  We've got slopes and points on each
419
	     * of those edges.  Compute my directly, then compute
420
	     * mx by using the edge with the larger dy; that avoids
421
	     * dividing by values close to zero.
422
	     */
423
	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
424
		  (dx1 * dy2 - dx2 * dy1));
425
	    if (fabs (dy1) >= fabs (dy2))
426
		mx = (my - y1) * dx1 / dy1 + x1;
427
	    else
428
		mx = (my - y2) * dx2 / dy2 + x2;
429

            
430
	    /*
431
	     * When the two outer edges are nearly parallel, slight
432
	     * perturbations in the position of the outer points of the lines
433
	     * caused by representing them in fixed point form can cause the
434
	     * intersection point of the miter to move a large amount. If
435
	     * that moves the miter intersection from between the two faces,
436
	     * then draw a bevel instead.
437
	     */
438

            
439
	    ix = _cairo_fixed_to_double (in->point.x);
440
	    iy = _cairo_fixed_to_double (in->point.y);
441

            
442
	    /* slope of one face */
443
	    fdx1 = x1 - ix; fdy1 = y1 - iy;
444

            
445
	    /* slope of the other face */
446
	    fdx2 = x2 - ix; fdy2 = y2 - iy;
447

            
448
	    /* slope from the intersection to the miter point */
449
	    mdx = mx - ix; mdy = my - iy;
450

            
451
	    /*
452
	     * Make sure the miter point line lies between the two
453
	     * faces by comparing the slopes
454
	     */
455
	    if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
456
		slope_compare_sgn (fdx2, fdy2, mdx, mdy))
457
	    {
458
		/*
459
		 * Draw the quadrilateral
460
		 */
461
		outer.x = _cairo_fixed_from_double (mx);
462
		outer.y = _cairo_fixed_from_double (my);
463

            
464
		quad[0] = in->point;
465
		quad[1] = *inpt;
466
		quad[2] = outer;
467
		quad[3] = *outpt;
468

            
469
		_cairo_traps_tessellate_convex_quad (stroker->traps, quad);
470
		break;
471
	    }
472
	}
473
    }
474
    /* fall through ... */
475
    case CAIRO_LINE_JOIN_BEVEL: {
476
	cairo_point_t t[] = { { in->point.x, in->point.y }, { inpt->x, inpt->y }, { outpt->x, outpt->y } };
477
	cairo_point_t e[] = { { in->cw.x, in->cw.y }, { in->ccw.x, in->ccw.y },
478
			      { out->cw.x, out->cw.y }, { out->ccw.x, out->ccw.y } };
479
	_cairo_traps_tessellate_triangle_with_edges (stroker->traps, t, e);
480
	break;
481
    }
482
    }
483
}
484

            
485
static void
486
24
add_cap (struct stroker *stroker, cairo_stroke_face_t *f)
487
{
488
24
    switch (stroker->style->line_cap) {
489
    case CAIRO_LINE_CAP_ROUND: {
490
	int start, stop;
491
	cairo_slope_t in_slope, out_slope;
492
	cairo_point_t tri[3], edges[4];
493
	cairo_pen_t *pen = &stroker->pen;
494

            
495
	in_slope = f->dev_vector;
496
	out_slope.dx = -in_slope.dx;
497
	out_slope.dy = -in_slope.dy;
498
	_cairo_pen_find_active_cw_vertices (pen, &in_slope, &out_slope,
499
					    &start, &stop);
500
	edges[0] = f->cw;
501
	edges[1] = f->ccw;
502
	tri[0] = f->point;
503
	tri[1] = f->cw;
504
	while (start != stop) {
505
	    tri[2] = f->point;
506
	    translate_point (&tri[2], &pen->vertices[start].point);
507
	    edges[2] = f->point;
508
	    edges[3] = tri[2];
509
	    _cairo_traps_tessellate_triangle_with_edges (stroker->traps,
510
							 tri, edges);
511

            
512
	    tri[1] = tri[2];
513
	    edges[0] = edges[2];
514
	    edges[1] = edges[3];
515
	    if (++start == pen->num_vertices)
516
		start = 0;
517
	}
518
	tri[2] = f->ccw;
519
	edges[2] = f->cw;
520
	edges[3] = f->ccw;
521
	_cairo_traps_tessellate_triangle_with_edges (stroker->traps,
522
						     tri, edges);
523
	break;
524
    }
525

            
526
    case CAIRO_LINE_CAP_SQUARE: {
527
	double dx, dy;
528
	cairo_slope_t fvector;
529
	cairo_point_t quad[4];
530

            
531
	dx = f->usr_vector.x;
532
	dy = f->usr_vector.y;
533
	dx *= stroker->half_line_width;
534
	dy *= stroker->half_line_width;
535
	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
536
	fvector.dx = _cairo_fixed_from_double (dx);
537
	fvector.dy = _cairo_fixed_from_double (dy);
538

            
539
	quad[0] = f->cw;
540
	quad[1].x = f->cw.x + fvector.dx;
541
	quad[1].y = f->cw.y + fvector.dy;
542
	quad[2].x = f->ccw.x + fvector.dx;
543
	quad[2].y = f->ccw.y + fvector.dy;
544
	quad[3] = f->ccw;
545

            
546
	_cairo_traps_tessellate_convex_quad (stroker->traps, quad);
547
	break;
548
    }
549

            
550
24
    case CAIRO_LINE_CAP_BUTT:
551
    default:
552
24
	break;
553
    }
554
24
}
555

            
556
static void
557
12
add_leading_cap (struct stroker     *stroker,
558
		 cairo_stroke_face_t *face)
559
{
560
    cairo_stroke_face_t reversed;
561
    cairo_point_t t;
562

            
563
12
    reversed = *face;
564

            
565
    /* The initial cap needs an outward facing vector. Reverse everything */
566
12
    reversed.usr_vector.x = -reversed.usr_vector.x;
567
12
    reversed.usr_vector.y = -reversed.usr_vector.y;
568
12
    reversed.dev_vector.dx = -reversed.dev_vector.dx;
569
12
    reversed.dev_vector.dy = -reversed.dev_vector.dy;
570
12
    t = reversed.cw;
571
12
    reversed.cw = reversed.ccw;
572
12
    reversed.ccw = t;
573

            
574
12
    add_cap (stroker, &reversed);
575
12
}
576

            
577
static void
578
12
add_trailing_cap (struct stroker *stroker, cairo_stroke_face_t *face)
579
{
580
12
    add_cap (stroker, face);
581
12
}
582

            
583
static inline double
584
540
normalize_slope (double *dx, double *dy)
585
{
586
540
    double dx0 = *dx, dy0 = *dy;
587

            
588
540
    if (dx0 == 0.0 && dy0 == 0.0)
589
	return 0;
590

            
591
540
    if (dx0 == 0.0) {
592
48
	*dx = 0.0;
593
48
	if (dy0 > 0.0) {
594
24
	    *dy = 1.0;
595
24
	    return dy0;
596
	} else {
597
24
	    *dy = -1.0;
598
24
	    return -dy0;
599
	}
600
492
    } else if (dy0 == 0.0) {
601
48
	*dy = 0.0;
602
48
	if (dx0 > 0.0) {
603
24
	    *dx = 1.0;
604
24
	    return dx0;
605
	} else {
606
24
	    *dx = -1.0;
607
24
	    return -dx0;
608
	}
609
    } else {
610
444
	double mag = hypot (dx0, dy0);
611
444
	*dx = dx0 / mag;
612
444
	*dy = dy0 / mag;
613
444
	return mag;
614
    }
615
}
616

            
617
static void
618
270
compute_face (const cairo_point_t *point,
619
	      const cairo_slope_t *dev_slope,
620
	      struct stroker *stroker,
621
	      cairo_stroke_face_t *face)
622
{
623
    double face_dx, face_dy;
624
    cairo_point_t offset_ccw, offset_cw;
625
    double slope_dx, slope_dy;
626

            
627
270
    slope_dx = _cairo_fixed_to_double (dev_slope->dx);
628
270
    slope_dy = _cairo_fixed_to_double (dev_slope->dy);
629
270
    face->length = normalize_slope (&slope_dx, &slope_dy);
630
270
    face->dev_slope.x = slope_dx;
631
270
    face->dev_slope.y = slope_dy;
632

            
633
    /*
634
     * rotate to get a line_width/2 vector along the face, note that
635
     * the vector must be rotated the right direction in device space,
636
     * but by 90° in user space. So, the rotation depends on
637
     * whether the ctm reflects or not, and that can be determined
638
     * by looking at the determinant of the matrix.
639
     */
640
270
    if (stroker->ctm_inverse) {
641
270
	cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
642
270
	normalize_slope (&slope_dx, &slope_dy);
643

            
644
270
	if (stroker->ctm_det_positive) {
645
270
	    face_dx = - slope_dy * stroker->half_line_width;
646
270
	    face_dy = slope_dx * stroker->half_line_width;
647
	} else {
648
	    face_dx = slope_dy * stroker->half_line_width;
649
	    face_dy = - slope_dx * stroker->half_line_width;
650
	}
651

            
652
	/* back to device space */
653
270
	cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
654
    } else {
655
	face_dx = - slope_dy * stroker->half_line_width;
656
	face_dy = slope_dx * stroker->half_line_width;
657
    }
658

            
659
270
    offset_ccw.x = _cairo_fixed_from_double (face_dx);
660
270
    offset_ccw.y = _cairo_fixed_from_double (face_dy);
661
270
    offset_cw.x = -offset_ccw.x;
662
270
    offset_cw.y = -offset_ccw.y;
663

            
664
270
    face->ccw = *point;
665
270
    translate_point (&face->ccw, &offset_ccw);
666

            
667
270
    face->point = *point;
668

            
669
270
    face->cw = *point;
670
270
    translate_point (&face->cw, &offset_cw);
671

            
672
270
    face->usr_vector.x = slope_dx;
673
270
    face->usr_vector.y = slope_dy;
674

            
675
270
    face->dev_vector = *dev_slope;
676
270
}
677

            
678
static void
679
18
add_caps (struct stroker *stroker)
680
{
681
    /* check for a degenerative sub_path */
682
18
    if (stroker->has_initial_sub_path &&
683
6
	!stroker->has_first_face &&
684
	!stroker->has_current_face &&
685
	stroker->style->line_cap == CAIRO_LINE_CAP_ROUND)
686
    {
687
	/* pick an arbitrary slope to use */
688
	cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
689
	cairo_stroke_face_t face;
690

            
691
	/* arbitrarily choose first_point
692
	 * first_point and current_point should be the same */
693
	compute_face (&stroker->first_point, &slope, stroker, &face);
694

            
695
	add_leading_cap (stroker, &face);
696
	add_trailing_cap (stroker, &face);
697
    }
698

            
699
18
    if (stroker->has_first_face)
700
12
	add_leading_cap (stroker, &stroker->first_face);
701

            
702
18
    if (stroker->has_current_face)
703
12
	add_trailing_cap (stroker, &stroker->current_face);
704
18
}
705

            
706
static cairo_bool_t
707
6
stroker_intersects_edge (const struct stroker *stroker,
708
			 const cairo_stroke_face_t *start,
709
			 const cairo_stroke_face_t *end)
710
{
711
    cairo_box_t box;
712

            
713
6
    if (! stroker->has_bounds)
714
	return TRUE;
715

            
716
6
    if (_cairo_box_contains_point (&stroker->tight_bounds, &start->cw))
717
	return TRUE;
718
6
    box.p2 = box.p1 = start->cw;
719

            
720
6
    if (_cairo_box_contains_point (&stroker->tight_bounds, &start->ccw))
721
	return TRUE;
722
6
    _cairo_box_add_point (&box, &start->ccw);
723

            
724
6
    if (_cairo_box_contains_point (&stroker->tight_bounds, &end->cw))
725
	return TRUE;
726
6
    _cairo_box_add_point (&box, &end->cw);
727

            
728
6
    if (_cairo_box_contains_point (&stroker->tight_bounds, &end->ccw))
729
	return TRUE;
730
6
    _cairo_box_add_point (&box, &end->ccw);
731

            
732
12
    return (box.p2.x > stroker->tight_bounds.p1.x &&
733
6
	    box.p1.x < stroker->tight_bounds.p2.x &&
734
18
	    box.p2.y > stroker->tight_bounds.p1.y &&
735
6
	    box.p1.y < stroker->tight_bounds.p2.y);
736
}
737

            
738
static void
739
6
add_sub_edge (struct stroker *stroker,
740
	      const cairo_point_t *p1, const cairo_point_t *p2,
741
	      const cairo_slope_t *dev_slope,
742
	      cairo_stroke_face_t *start, cairo_stroke_face_t *end)
743
{
744
    cairo_point_t rectangle[4];
745

            
746
6
    compute_face (p1, dev_slope, stroker, start);
747

            
748
6
    *end = *start;
749
6
    end->point = *p2;
750
6
    rectangle[0].x = p2->x - p1->x;
751
6
    rectangle[0].y = p2->y - p1->y;
752
6
    translate_point (&end->ccw, &rectangle[0]);
753
6
    translate_point (&end->cw, &rectangle[0]);
754

            
755
6
    if (p1->x == p2->x && p1->y == p2->y)
756
	return;
757

            
758
6
    if (! stroker_intersects_edge (stroker, start, end))
759
	return;
760

            
761
6
    rectangle[0] = start->cw;
762
6
    rectangle[1] = start->ccw;
763
6
    rectangle[2] = end->ccw;
764
6
    rectangle[3] = end->cw;
765

            
766
6
    _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
767
}
768

            
769
static cairo_status_t
770
12
move_to (void *closure, const cairo_point_t *point)
771
{
772
12
    struct stroker *stroker = closure;
773

            
774
    /* Cap the start and end of the previous sub path as needed */
775
12
    add_caps (stroker);
776

            
777
12
    stroker->first_point = *point;
778
12
    stroker->current_face.point = *point;
779

            
780
12
    stroker->has_first_face = FALSE;
781
12
    stroker->has_current_face = FALSE;
782
12
    stroker->has_initial_sub_path = FALSE;
783

            
784
12
    return CAIRO_STATUS_SUCCESS;
785
}
786

            
787
static cairo_status_t
788
move_to_dashed (void *closure, const cairo_point_t *point)
789
{
790
    /* reset the dash pattern for new sub paths */
791
    struct stroker *stroker = closure;
792

            
793
    _cairo_stroker_dash_start (&stroker->dash);
794
    return move_to (closure, point);
795
}
796

            
797
static cairo_status_t
798
6
line_to (void *closure, const cairo_point_t *point)
799
{
800
6
    struct stroker *stroker = closure;
801
    cairo_stroke_face_t start, end;
802
6
    const cairo_point_t *p1 = &stroker->current_face.point;
803
6
    const cairo_point_t *p2 = point;
804
    cairo_slope_t dev_slope;
805

            
806
6
    stroker->has_initial_sub_path = TRUE;
807

            
808
6
    if (p1->x == p2->x && p1->y == p2->y)
809
	return CAIRO_STATUS_SUCCESS;
810

            
811
6
    _cairo_slope_init (&dev_slope, p1, p2);
812
6
    add_sub_edge (stroker, p1, p2, &dev_slope, &start, &end);
813

            
814
6
    if (stroker->has_current_face) {
815
	/* Join with final face from previous segment */
816
	join (stroker, &stroker->current_face, &start);
817
6
    } else if (!stroker->has_first_face) {
818
	/* Save sub path's first face in case needed for closing join */
819
6
	stroker->first_face = start;
820
6
	stroker->has_first_face = TRUE;
821
    }
822
6
    stroker->current_face = end;
823
6
    stroker->has_current_face = TRUE;
824

            
825
6
    return CAIRO_STATUS_SUCCESS;
826
}
827

            
828
/*
829
 * Dashed lines.  Cap each dash end, join around turns when on
830
 */
831
static cairo_status_t
832
line_to_dashed (void *closure, const cairo_point_t *point)
833
{
834
    struct stroker *stroker = closure;
835
    double mag, remain, step_length = 0;
836
    double slope_dx, slope_dy;
837
    double dx2, dy2;
838
    cairo_stroke_face_t sub_start, sub_end;
839
    const cairo_point_t *p1 = &stroker->current_face.point;
840
    const cairo_point_t *p2 = point;
841
    cairo_slope_t dev_slope;
842
    cairo_line_t segment;
843
    cairo_bool_t fully_in_bounds;
844

            
845
    stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
846

            
847
    if (p1->x == p2->x && p1->y == p2->y)
848
	return CAIRO_STATUS_SUCCESS;
849

            
850
    fully_in_bounds = TRUE;
851
    if (stroker->has_bounds &&
852
	(! _cairo_box_contains_point (&stroker->join_bounds, p1) ||
853
	 ! _cairo_box_contains_point (&stroker->join_bounds, p2)))
854
    {
855
	fully_in_bounds = FALSE;
856
    }
857

            
858
    _cairo_slope_init (&dev_slope, p1, p2);
859

            
860
    slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
861
    slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
862

            
863
    if (stroker->ctm_inverse)
864
	cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
865
    mag = normalize_slope (&slope_dx, &slope_dy);
866
    if (mag <= DBL_EPSILON)
867
	return CAIRO_STATUS_SUCCESS;
868

            
869
    remain = mag;
870
    segment.p1 = *p1;
871
    while (remain) {
872
	step_length = MIN (stroker->dash.dash_remain, remain);
873
	remain -= step_length;
874
	dx2 = slope_dx * (mag - remain);
875
	dy2 = slope_dy * (mag - remain);
876
	cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
877
	segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
878
	segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
879

            
880
	if (stroker->dash.dash_on &&
881
	    (fully_in_bounds ||
882
	     (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
883
	     _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment)))
884
	{
885
	    add_sub_edge (stroker,
886
			  &segment.p1, &segment.p2,
887
			  &dev_slope,
888
			  &sub_start, &sub_end);
889

            
890
	    if (stroker->has_current_face) {
891
		/* Join with final face from previous segment */
892
		join (stroker, &stroker->current_face, &sub_start);
893

            
894
		stroker->has_current_face = FALSE;
895
	    } else if (! stroker->has_first_face && stroker->dash.dash_starts_on) {
896
		/* Save sub path's first face in case needed for closing join */
897
		stroker->first_face = sub_start;
898
		stroker->has_first_face = TRUE;
899
	    } else {
900
		/* Cap dash start if not connecting to a previous segment */
901
		add_leading_cap (stroker, &sub_start);
902
	    }
903

            
904
	    if (remain) {
905
		/* Cap dash end if not at end of segment */
906
		add_trailing_cap (stroker, &sub_end);
907
	    } else {
908
		stroker->current_face = sub_end;
909
		stroker->has_current_face = TRUE;
910
	    }
911
	} else {
912
	    if (stroker->has_current_face) {
913
		/* Cap final face from previous segment */
914
		add_trailing_cap (stroker, &stroker->current_face);
915

            
916
		stroker->has_current_face = FALSE;
917
	    }
918
	}
919

            
920
	_cairo_stroker_dash_step (&stroker->dash, step_length);
921
	segment.p1 = segment.p2;
922
    }
923

            
924
    if (stroker->dash.dash_on && ! stroker->has_current_face) {
925
	/* This segment ends on a transition to dash_on, compute a new face
926
	 * and add cap for the beginning of the next dash_on step.
927
	 *
928
	 * Note: this will create a degenerate cap if this is not the last line
929
	 * in the path. Whether this behaviour is desirable or not is debatable.
930
	 * On one side these degenerate caps can not be reproduced with regular
931
	 * path stroking.
932
	 * On the other hand, Acroread 7 also produces the degenerate caps.
933
	 */
934
	compute_face (point, &dev_slope, stroker, &stroker->current_face);
935

            
936
	add_leading_cap (stroker, &stroker->current_face);
937

            
938
	stroker->has_current_face = TRUE;
939
    } else
940
	stroker->current_face.point = *point;
941

            
942
    return CAIRO_STATUS_SUCCESS;
943
}
944

            
945
static cairo_status_t
946
add_point (void *closure,
947
	   const cairo_point_t *point,
948
	   const cairo_slope_t *tangent)
949
{
950
    return line_to_dashed (closure, point);
951
};
952

            
953
static cairo_status_t
954
240
spline_to (void *closure,
955
	   const cairo_point_t *point,
956
	   const cairo_slope_t *tangent)
957
{
958
240
    struct stroker *stroker = closure;
959
    cairo_stroke_face_t face;
960

            
961
240
    if ((tangent->dx | tangent->dy) == 0) {
962
	cairo_point_t t;
963

            
964
	face = stroker->current_face;
965

            
966
	face.usr_vector.x = -face.usr_vector.x;
967
	face.usr_vector.y = -face.usr_vector.y;
968
	face.dev_slope.x = -face.dev_slope.x;
969
	face.dev_slope.y = -face.dev_slope.y;
970
	face.dev_vector.dx = -face.dev_vector.dx;
971
	face.dev_vector.dy = -face.dev_vector.dy;
972

            
973
	t = face.cw;
974
	face.cw = face.ccw;
975
	face.ccw = t;
976

            
977
	join (stroker, &stroker->current_face, &face);
978
    } else {
979
	cairo_point_t rectangle[4];
980

            
981
240
	compute_face (&stroker->current_face.point, tangent, stroker, &face);
982
240
	join (stroker, &stroker->current_face, &face);
983

            
984
240
	rectangle[0] = face.cw;
985
240
	rectangle[1] = face.ccw;
986

            
987
240
	rectangle[2].x = point->x - face.point.x;
988
240
	rectangle[2].y = point->y - face.point.y;
989
240
	face.point = *point;
990
240
	translate_point (&face.ccw, &rectangle[2]);
991
240
	translate_point (&face.cw, &rectangle[2]);
992

            
993
240
	rectangle[2] = face.ccw;
994
240
	rectangle[3] = face.cw;
995

            
996
240
	_cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
997
    }
998

            
999
240
    stroker->current_face = face;
240
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
24
curve_to (void *closure,
	  const cairo_point_t *b,
	  const cairo_point_t *c,
	  const cairo_point_t *d)
{
24
    struct stroker *stroker = closure;
    cairo_line_join_t line_join_save;
    cairo_spline_t spline;
    cairo_stroke_face_t face;
    cairo_status_t status;
24
    if (stroker->has_bounds &&
24
	! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
24
				    &stroker->line_bounds))
	return line_to (closure, d);
24
    if (! _cairo_spline_init (&spline, spline_to, stroker,
24
			      &stroker->current_face.point, b, c, d))
	return line_to (closure, d);
24
    compute_face (&stroker->current_face.point, &spline.initial_slope,
		  stroker, &face);
24
    if (stroker->has_current_face) {
	/* Join with final face from previous segment */
18
	join (stroker, &stroker->current_face, &face);
    } else {
6
	if (! stroker->has_first_face) {
	    /* Save sub path's first face in case needed for closing join */
6
	    stroker->first_face = face;
6
	    stroker->has_first_face = TRUE;
	}
6
	stroker->has_current_face = TRUE;
    }
24
    stroker->current_face = face;
    /* Temporarily modify the stroker to use round joins to guarantee
     * smooth stroked curves. */
24
    line_join_save = stroker->line_join;
24
    stroker->line_join = CAIRO_LINE_JOIN_ROUND;
24
    status = _cairo_spline_decompose (&spline, stroker->tolerance);
24
    stroker->line_join = line_join_save;
24
    return status;
}
static cairo_status_t
curve_to_dashed (void *closure,
		 const cairo_point_t *b,
		 const cairo_point_t *c,
		 const cairo_point_t *d)
{
    struct stroker *stroker = closure;
    cairo_spline_t spline;
    cairo_line_join_t line_join_save;
    cairo_spline_add_point_func_t func;
    cairo_status_t status;
    func = add_point;
    if (stroker->has_bounds &&
	! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
				    &stroker->line_bounds))
	return func (closure, d, NULL);
    if (! _cairo_spline_init (&spline, func, stroker,
			      &stroker->current_face.point, b, c, d))
	return func (closure, d, NULL);
    /* Temporarily modify the stroker to use round joins to guarantee
     * smooth stroked curves. */
    line_join_save = stroker->line_join;
    stroker->line_join = CAIRO_LINE_JOIN_ROUND;
    status = _cairo_spline_decompose (&spline, stroker->tolerance);
    stroker->line_join = line_join_save;
    return status;
}
static cairo_status_t
_close_path (struct stroker *stroker)
{
    if (stroker->has_first_face && stroker->has_current_face) {
	/* Join first and final faces of sub path */
	join (stroker, &stroker->current_face, &stroker->first_face);
    } else {
	/* Cap the start and end of the sub path as needed */
	add_caps (stroker);
    }
    stroker->has_initial_sub_path = FALSE;
    stroker->has_first_face = FALSE;
    stroker->has_current_face = FALSE;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
close_path (void *closure)
{
    struct stroker *stroker = closure;
    cairo_status_t status;
    status = line_to (stroker, &stroker->first_point);
    if (unlikely (status))
	return status;
    return _close_path (stroker);
}
static cairo_status_t
close_path_dashed (void *closure)
{
    struct stroker *stroker = closure;
    cairo_status_t status;
    status = line_to_dashed (stroker, &stroker->first_point);
    if (unlikely (status))
	return status;
    return _close_path (stroker);
}
cairo_int_status_t
6
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t	*path,
				   const cairo_stroke_style_t	*style,
				   const cairo_matrix_t		*ctm,
				   const cairo_matrix_t		*ctm_inverse,
				   double			 tolerance,
				   cairo_traps_t		*traps)
{
    struct stroker stroker;
    cairo_status_t status;
6
    status = stroker_init (&stroker, path, style,
			   ctm, ctm_inverse, tolerance,
			   traps);
6
    if (unlikely (status))
	return status;
6
    if (stroker.dash.dashed)
	status = _cairo_path_fixed_interpret (path,
					      move_to_dashed,
					      line_to_dashed,
					      curve_to_dashed,
					      close_path_dashed,
					      &stroker);
    else
6
	status = _cairo_path_fixed_interpret (path,
					      move_to,
					      line_to,
					      curve_to,
					      close_path,
					      &stroker);
6
    assert(status == CAIRO_STATUS_SUCCESS);
6
    add_caps (&stroker);
6
    stroker_fini (&stroker);
6
    return traps->status;
}