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