beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-path-stroke.c
blob4d4ede8136190c0dd06cad89afe6cefa7abcddf6
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
4 * Copyright © 2002 University of Southern California
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.
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
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/
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.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is University of Southern
32 * California.
34 * Contributor(s):
35 * Carl D. Worth <cworth@cworth.org>
36 * Chris Wilson <chris@chris-wilson.co.uk>
39 #define _BSD_SOURCE /* for hypot() */
40 #include "cairoint.h"
42 #include "cairo-box-inline.h"
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"
47 #include "cairo-stroke-dash-private.h"
48 #include "cairo-traps-private.h"
50 typedef struct cairo_stroker {
51 cairo_stroke_style_t style;
53 const cairo_matrix_t *ctm;
54 const cairo_matrix_t *ctm_inverse;
55 double half_line_width;
56 double tolerance;
57 double spline_cusp_tolerance;
58 double ctm_determinant;
59 cairo_bool_t ctm_det_positive;
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]);
74 cairo_pen_t pen;
76 cairo_point_t current_point;
77 cairo_point_t first_point;
79 cairo_bool_t has_initial_sub_path;
81 cairo_bool_t has_current_face;
82 cairo_stroke_face_t current_face;
84 cairo_bool_t has_first_face;
85 cairo_stroke_face_t first_face;
87 cairo_stroker_dash_t dash;
89 cairo_bool_t has_bounds;
90 cairo_box_t bounds;
91 } cairo_stroker_t;
93 static void
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)
99 double dx, dy;
100 cairo_fixed_t fdx, fdy;
102 stroker->has_bounds = TRUE;
103 _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
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.
110 _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
111 stroker->ctm, &dx, &dy);
113 fdx = _cairo_fixed_from_double (dx);
114 fdy = _cairo_fixed_from_double (dy);
116 stroker->bounds.p1.x -= fdx;
117 stroker->bounds.p2.x += fdx;
119 stroker->bounds.p1.y -= fdy;
120 stroker->bounds.p2.y += fdy;
123 static cairo_status_t
124 _cairo_stroker_init (cairo_stroker_t *stroker,
125 const cairo_path_fixed_t *path,
126 const cairo_stroke_style_t *stroke_style,
127 const cairo_matrix_t *ctm,
128 const cairo_matrix_t *ctm_inverse,
129 double tolerance,
130 const cairo_box_t *limits,
131 int num_limits)
133 cairo_status_t status;
135 stroker->style = *stroke_style;
136 stroker->ctm = ctm;
137 stroker->ctm_inverse = ctm_inverse;
138 stroker->tolerance = tolerance;
139 stroker->half_line_width = stroke_style->line_width / 2.0;
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.
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;
153 stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
154 stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
156 status = _cairo_pen_init (&stroker->pen,
157 stroker->half_line_width, tolerance, ctm);
158 if (unlikely (status))
159 return status;
161 stroker->has_current_face = FALSE;
162 stroker->has_first_face = FALSE;
163 stroker->has_initial_sub_path = FALSE;
165 _cairo_stroker_dash_init (&stroker->dash, stroke_style);
167 stroker->add_external_edge = NULL;
169 stroker->has_bounds = FALSE;
170 if (num_limits)
171 _cairo_stroker_limit (stroker, path, limits, num_limits);
173 return CAIRO_STATUS_SUCCESS;
176 static void
177 _cairo_stroker_fini (cairo_stroker_t *stroker)
179 _cairo_pen_fini (&stroker->pen);
182 static void
183 _translate_point (cairo_point_t *point, const cairo_point_t *offset)
185 point->x += offset->x;
186 point->y += offset->y;
189 static int
190 _cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in,
191 const cairo_stroke_face_t *out)
193 cairo_slope_t in_slope, out_slope;
195 _cairo_slope_init (&in_slope, &in->point, &in->cw);
196 _cairo_slope_init (&out_slope, &out->point, &out->cw);
198 return _cairo_slope_compare (&in_slope, &out_slope) < 0;
202 * _cairo_slope_compare_sgn:
204 * Return -1, 0 or 1 depending on the relative slopes of
205 * two lines.
207 static int
208 _cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
210 double c = (dx1 * dy2 - dx2 * dy1);
212 if (c > 0) return 1;
213 if (c < 0) return -1;
214 return 0;
217 static inline int
218 _range_step (int i, int step, int max)
220 i += step;
221 if (i < 0)
222 i = max - 1;
223 if (i >= max)
224 i = 0;
225 return i;
229 * Construct a fan around the midpoint using the vertices from pen between
230 * inpt and outpt.
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)
241 cairo_point_t stack_points[64], *points = stack_points;
242 cairo_pen_t *pen = &stroker->pen;
243 int start, stop, num_points = 0;
244 cairo_status_t status;
246 if (stroker->has_bounds &&
247 ! _cairo_box_contains_point (&stroker->bounds, midpt))
248 goto BEVEL;
250 assert (stroker->pen.num_vertices);
252 if (clockwise) {
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);
263 status = stroker->add_external_edge (stroker->closure,
264 &last, &p);
265 if (unlikely (status))
266 return status;
267 last = p;
269 if (start-- == 0)
270 start += pen->num_vertices;
272 status = stroker->add_external_edge (stroker->closure,
273 &last, outpt);
274 } else {
275 if (start == stop)
276 goto BEVEL;
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);
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++;
295 if (start-- == 0)
296 start += pen->num_vertices;
298 points[num_points++] = *outpt;
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);
311 status = stroker->add_external_edge (stroker->closure,
312 &p, &last);
313 if (unlikely (status))
314 return status;
315 last = p;
317 if (++start == pen->num_vertices)
318 start = 0;
320 status = stroker->add_external_edge (stroker->closure,
321 outpt, &last);
322 } else {
323 if (start == stop)
324 goto BEVEL;
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);
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++;
343 if (++start == pen->num_vertices)
344 start = 0;
346 points[num_points++] = *outpt;
350 if (num_points) {
351 status = stroker->add_triangle_fan (stroker->closure,
352 midpt, points, num_points);
355 if (points != stack_points)
356 free (points);
358 return status;
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);
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)
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;
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)
388 return CAIRO_STATUS_SUCCESS;
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;
398 status = stroker->add_external_edge (stroker->closure,
399 &in->point, &in->cw);
400 if (unlikely (status))
401 return status;
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;
413 status = stroker->add_external_edge (stroker->closure,
414 &in->point, &out->ccw);
415 if (unlikely (status))
416 return status;
419 inpt = &in->cw;
420 outpt = &out->cw;
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);
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;
439 /* Check the miter limit -- lines meeting at an acute angle
440 * can generate long miters, the limit converts them to bevel
442 * Consider the miter join formed when two line segments
443 * meet at an angle psi:
445 * /.\
446 * /. .\
447 * /./ \.\
448 * /./psi\.\
450 * We can zoom in on the right half of that to see:
452 * |\
453 * | \ psi/2
454 * | \
455 * | \
456 * | \
457 * | \
458 * miter \
459 * length \
460 * | \
461 * | .\
462 * | . \
463 * |. line \
464 * \ width \
465 * \ \
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:
473 * 1 /sin (psi/2) = miter_length / line_width
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:
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))
487 * in · out = |in| |out| cos (psi)
489 * in and out are both unit vectors, so:
491 * in · out = cos (psi)
493 * 2 <= ml² (1 - in · out)
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;
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
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);
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);
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.
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;
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.
548 ix = _cairo_fixed_to_double (in->point.x);
549 iy = _cairo_fixed_to_double (in->point.y);
551 /* slope of one face */
552 fdx1 = x1 - ix; fdy1 = y1 - iy;
554 /* slope of the other face */
555 fdx2 = x2 - ix; fdy2 = y2 - iy;
557 /* slope from the intersection to the miter point */
558 mdx = mx - ix; mdy = my - iy;
561 * Make sure the miter point line lies between the two
562 * faces by comparing the slopes
564 if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
565 _cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
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);
571 if (clockwise) {
572 status = stroker->add_external_edge (stroker->closure,
573 inpt, &points[0]);
574 if (unlikely (status))
575 return status;
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;
587 status = stroker->add_external_edge (stroker->closure,
588 &points[0], inpt);
589 if (unlikely (status))
590 return status;
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;
601 return stroker->add_convex_quad (stroker->closure, points);
607 /* fall through ... */
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);
618 } else {
619 points[0] = in->point;
620 points[1] = *inpt;
621 points[2] = *outpt;
623 return stroker->add_triangle (stroker->closure, points);
628 static cairo_status_t
629 _cairo_stroker_add_cap (cairo_stroker_t *stroker,
630 const cairo_stroke_face_t *f)
632 switch (stroker->style.line_cap) {
633 case CAIRO_LINE_CAP_ROUND: {
634 cairo_slope_t slope;
636 slope.dx = -f->dev_vector.dx;
637 slope.dy = -f->dev_vector.dy;
639 return _tessellate_fan (stroker,
640 &f->dev_vector,
641 &slope,
642 &f->point, &f->cw, &f->ccw,
643 FALSE);
647 case CAIRO_LINE_CAP_SQUARE: {
648 double dx, dy;
649 cairo_slope_t fvector;
650 cairo_point_t quad[4];
652 dx = f->usr_vector.x;
653 dy = f->usr_vector.y;
654 dx *= stroker->half_line_width;
655 dy *= stroker->half_line_width;
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);
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;
667 if (stroker->add_external_edge != NULL) {
668 cairo_status_t status;
670 status = stroker->add_external_edge (stroker->closure,
671 &quad[0], &quad[1]);
672 if (unlikely (status))
673 return status;
675 status = stroker->add_external_edge (stroker->closure,
676 &quad[1], &quad[2]);
677 if (unlikely (status))
678 return status;
680 status = stroker->add_external_edge (stroker->closure,
681 &quad[2], &quad[3]);
682 if (unlikely (status))
683 return status;
685 return CAIRO_STATUS_SUCCESS;
686 } else {
687 return stroker->add_convex_quad (stroker->closure, quad);
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;
702 static cairo_status_t
703 _cairo_stroker_add_leading_cap (cairo_stroker_t *stroker,
704 const cairo_stroke_face_t *face)
706 cairo_stroke_face_t reversed;
707 cairo_point_t t;
709 reversed = *face;
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;
720 return _cairo_stroker_add_cap (stroker, &reversed);
723 static cairo_status_t
724 _cairo_stroker_add_trailing_cap (cairo_stroker_t *stroker,
725 const cairo_stroke_face_t *face)
727 return _cairo_stroker_add_cap (stroker, face);
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)
735 double dx0 = *dx, dy0 = *dy;
736 double mag;
738 cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0);
740 if (dx0 == 0.0 && dy0 == 0.0) {
741 if (mag_out)
742 *mag_out = 0.0;
743 return FALSE;
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;
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;
764 } else {
765 mag = hypot (dx0, dy0);
766 *dx = dx0 / mag;
767 *dy = dy0 / mag;
770 if (mag_out)
771 *mag_out = mag;
773 return TRUE;
776 static void
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)
784 double face_dx, face_dy;
785 cairo_point_t offset_ccw, offset_cw;
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.
794 if (stroker->ctm_det_positive)
796 face_dx = - slope_dy * stroker->half_line_width;
797 face_dy = slope_dx * stroker->half_line_width;
799 else
801 face_dx = slope_dy * stroker->half_line_width;
802 face_dy = - slope_dx * stroker->half_line_width;
805 /* back to device space */
806 cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
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;
813 face->ccw = *point;
814 _translate_point (&face->ccw, &offset_ccw);
816 face->point = *point;
818 face->cw = *point;
819 _translate_point (&face->cw, &offset_cw);
821 face->usr_vector.x = slope_dx;
822 face->usr_vector.y = slope_dy;
824 face->dev_vector = *dev_slope;
827 static cairo_status_t
828 _cairo_stroker_add_caps (cairo_stroker_t *stroker)
830 cairo_status_t status;
832 /* check for a degenerative sub_path */
833 if (stroker->has_initial_sub_path
834 && ! stroker->has_first_face
835 && ! stroker->has_current_face
836 && stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
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;
843 _compute_normalized_device_slope (&dx, &dy,
844 stroker->ctm_inverse, NULL);
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);
850 status = _cairo_stroker_add_leading_cap (stroker, &face);
851 if (unlikely (status))
852 return status;
854 status = _cairo_stroker_add_trailing_cap (stroker, &face);
855 if (unlikely (status))
856 return status;
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;
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;
873 return CAIRO_STATUS_SUCCESS;
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)
885 _compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start);
886 *end = *start;
888 if (p1->x == p2->x && p1->y == p2->y)
889 return CAIRO_STATUS_SUCCESS;
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;
897 if (stroker->add_external_edge != NULL) {
898 cairo_status_t status;
900 status = stroker->add_external_edge (stroker->closure,
901 &end->cw, &start->cw);
902 if (unlikely (status))
903 return status;
905 status = stroker->add_external_edge (stroker->closure,
906 &start->ccw, &end->ccw);
907 if (unlikely (status))
908 return status;
910 return CAIRO_STATUS_SUCCESS;
911 } else {
912 cairo_point_t quad[4];
914 quad[0] = start->cw;
915 quad[1] = end->cw;
916 quad[2] = end->ccw;
917 quad[3] = start->ccw;
919 return stroker->add_convex_quad (stroker->closure, quad);
923 static cairo_status_t
924 _cairo_stroker_move_to (void *closure,
925 const cairo_point_t *point)
927 cairo_stroker_t *stroker = closure;
928 cairo_status_t status;
930 /* reset the dash pattern for new sub paths */
931 _cairo_stroker_dash_start (&stroker->dash);
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;
938 stroker->first_point = *point;
939 stroker->current_point = *point;
941 stroker->has_first_face = FALSE;
942 stroker->has_current_face = FALSE;
943 stroker->has_initial_sub_path = FALSE;
945 return CAIRO_STATUS_SUCCESS;
948 static cairo_status_t
949 _cairo_stroker_line_to (void *closure,
950 const cairo_point_t *point)
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;
959 stroker->has_initial_sub_path = TRUE;
961 if (p1->x == point->x && p1->y == point->y)
962 return CAIRO_STATUS_SUCCESS;
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);
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;
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;
990 stroker->current_face = end;
991 stroker->has_current_face = TRUE;
993 stroker->current_point = *point;
995 return CAIRO_STATUS_SUCCESS;
998 static cairo_status_t
999 _cairo_stroker_spline_to (void *closure,
1000 const cairo_point_t *point,
1001 const cairo_slope_t *tangent)
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;
1009 stroker->has_initial_sub_path = TRUE;
1011 if (stroker->current_point.x == point->x &&
1012 stroker->current_point.y == point->y)
1013 return CAIRO_STATUS_SUCCESS;
1015 slope_dx = _cairo_fixed_to_double (tangent->dx);
1016 slope_dy = _cairo_fixed_to_double (tangent->dy);
1018 if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
1019 stroker->ctm_inverse, NULL))
1020 return CAIRO_STATUS_SUCCESS;
1022 _compute_face (point, tangent,
1023 slope_dx, slope_dy,
1024 stroker, &new_face);
1026 assert (stroker->has_current_face);
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) {
1031 const cairo_point_t *inpt, *outpt;
1032 int clockwise = _cairo_stroker_join_is_clockwise (&new_face,
1033 &stroker->current_face);
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;
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);
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);
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);
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);
1076 stroker->current_face = new_face;
1077 stroker->has_current_face = TRUE;
1078 stroker->current_point = *point;
1080 return CAIRO_STATUS_SUCCESS;
1084 * Dashed lines. Cap each dash end, join around turns when on
1086 static cairo_status_t
1087 _cairo_stroker_line_to_dashed (void *closure,
1088 const cairo_point_t *p2)
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;
1101 stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
1103 if (p1->x == p2->x && p1->y == p2->y)
1104 return CAIRO_STATUS_SUCCESS;
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)))
1111 fully_in_bounds = FALSE;
1114 _cairo_slope_init (&dev_slope, p1, p2);
1116 slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
1117 slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
1119 if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
1120 stroker->ctm_inverse, &mag))
1122 return CAIRO_STATUS_SUCCESS;
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;
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)))
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;
1149 if (stroker->has_current_face)
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;
1158 stroker->has_current_face = FALSE;
1160 else if (! stroker->has_first_face &&
1161 stroker->dash.dash_starts_on)
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;
1167 else
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;
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;
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;
1192 stroker->has_current_face = FALSE;
1196 _cairo_stroker_dash_step (&stroker->dash, step_length);
1197 segment.p1 = segment.p2;
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.
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.
1210 _compute_face (p2, &dev_slope,
1211 slope_dx, slope_dy,
1212 stroker,
1213 &stroker->current_face);
1215 status = _cairo_stroker_add_leading_cap (stroker,
1216 &stroker->current_face);
1217 if (unlikely (status))
1218 return status;
1220 stroker->has_current_face = TRUE;
1223 stroker->current_point = *p2;
1225 return CAIRO_STATUS_SUCCESS;
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)
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;
1239 cairo_spline_add_point_func_t line_to;
1240 cairo_spline_add_point_func_t spline_to;
1241 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1243 line_to = stroker->dash.dashed ?
1244 (cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
1245 (cairo_spline_add_point_func_t) _cairo_stroker_line_to;
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;
1252 if (! _cairo_spline_init (&spline,
1253 spline_to,
1254 stroker,
1255 &stroker->current_point, b, c, d))
1257 cairo_slope_t fallback_slope;
1258 _cairo_slope_init (&fallback_slope, &stroker->current_point, d);
1259 return line_to (closure, d, &fallback_slope);
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;
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))
1274 _compute_face (&stroker->current_point,
1275 &spline.initial_slope,
1276 slope_dx, slope_dy,
1277 stroker, &face);
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;
1289 stroker->current_face = face;
1290 stroker->has_current_face = TRUE;
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;
1298 status = _cairo_spline_decompose (&spline, stroker->tolerance);
1299 if (unlikely (status))
1300 return status;
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))
1309 _compute_face (&stroker->current_point,
1310 &spline.final_slope,
1311 slope_dx, slope_dy,
1312 stroker, &face);
1315 status = _cairo_stroker_join (stroker, &stroker->current_face, &face);
1316 if (unlikely (status))
1317 return status;
1319 stroker->current_face = face;
1322 stroker->style.line_join = line_join_save;
1324 return CAIRO_STATUS_SUCCESS;
1327 static cairo_status_t
1328 _cairo_stroker_close_path (void *closure)
1330 cairo_stroker_t *stroker = closure;
1331 cairo_status_t status;
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;
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;
1354 stroker->has_initial_sub_path = FALSE;
1355 stroker->has_first_face = FALSE;
1356 stroker->has_current_face = FALSE;
1358 return CAIRO_STATUS_SUCCESS;
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)
1377 cairo_stroker_t stroker;
1378 cairo_status_t status;
1380 status = _cairo_stroker_init (&stroker, path, stroke_style,
1381 ctm, ctm_inverse, tolerance,
1382 NULL, 0);
1383 if (unlikely (status))
1384 return status;
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;
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);
1400 if (unlikely (status))
1401 goto BAIL;
1403 /* Cap the start and end of the final sub path as needed */
1404 status = _cairo_stroker_add_caps (&stroker);
1406 BAIL:
1407 _cairo_stroker_fini (&stroker);
1409 return status;
1412 cairo_status_t
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)
1420 cairo_stroker_t stroker;
1421 cairo_status_t status;
1423 status = _cairo_stroker_init (&stroker, path, stroke_style,
1424 ctm, ctm_inverse, tolerance,
1425 polygon->limits, polygon->num_limits);
1426 if (unlikely (status))
1427 return status;
1429 stroker.add_external_edge = _cairo_polygon_add_external_edge,
1430 stroker.closure = polygon;
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);
1441 if (unlikely (status))
1442 goto BAIL;
1444 /* Cap the start and end of the final sub path as needed */
1445 status = _cairo_stroker_add_caps (&stroker);
1447 BAIL:
1448 _cairo_stroker_fini (&stroker);
1450 return status;
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)
1461 cairo_int_status_t status;
1462 cairo_polygon_t polygon;
1464 _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
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;
1474 status = _cairo_polygon_status (&polygon);
1475 if (unlikely (status))
1476 goto BAIL;
1478 status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
1479 CAIRO_FILL_RULE_WINDING);
1481 BAIL:
1482 _cairo_polygon_fini (&polygon);
1484 return status;