/work/workdir/UnpackedTarball/cairo/src/cairo-stroke-style.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* cairo - a vector graphics library with display and print output |
2 | | * |
3 | | * Copyright © 2005 Red Hat, Inc |
4 | | * |
5 | | * This library is free software; you can redistribute it and/or |
6 | | * modify it either under the terms of the GNU Lesser General Public |
7 | | * License version 2.1 as published by the Free Software Foundation |
8 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
9 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
10 | | * notice, a recipient may use your version of this file under either |
11 | | * the MPL or the LGPL. |
12 | | * |
13 | | * You should have received a copy of the LGPL along with this library |
14 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
15 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
16 | | * You should have received a copy of the MPL along with this library |
17 | | * in the file COPYING-MPL-1.1 |
18 | | * |
19 | | * The contents of this file are subject to the Mozilla Public License |
20 | | * Version 1.1 (the "License"); you may not use this file except in |
21 | | * compliance with the License. You may obtain a copy of the License at |
22 | | * http://www.mozilla.org/MPL/ |
23 | | * |
24 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
25 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
26 | | * the specific language governing rights and limitations. |
27 | | * |
28 | | * The Original Code is the cairo graphics library. |
29 | | * |
30 | | * The Initial Developer of the Original Code is Red Hat, Inc. |
31 | | * |
32 | | * Contributor(s): |
33 | | * Carl Worth <cworth@cworth.org> |
34 | | */ |
35 | | |
36 | | #include "cairoint.h" |
37 | | #include "cairo-error-private.h" |
38 | | |
39 | | void |
40 | | _cairo_stroke_style_init (cairo_stroke_style_t *style) |
41 | 8.13M | { |
42 | 8.13M | VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t))); |
43 | | |
44 | 8.13M | style->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT; |
45 | 8.13M | style->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT; |
46 | 8.13M | style->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT; |
47 | 8.13M | style->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT; |
48 | | |
49 | 8.13M | style->dash = NULL; |
50 | 8.13M | style->num_dashes = 0; |
51 | 8.13M | style->dash_offset = 0.0; |
52 | | |
53 | 8.13M | style->is_hairline = FALSE; |
54 | 8.13M | } |
55 | | |
56 | | cairo_status_t |
57 | | _cairo_stroke_style_init_copy (cairo_stroke_style_t *style, |
58 | | const cairo_stroke_style_t *other) |
59 | 19.4k | { |
60 | 19.4k | if (CAIRO_INJECT_FAULT ()) |
61 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
62 | | |
63 | 19.4k | VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t))); |
64 | | |
65 | 19.4k | style->line_width = other->line_width; |
66 | 19.4k | style->line_cap = other->line_cap; |
67 | 19.4k | style->line_join = other->line_join; |
68 | 19.4k | style->miter_limit = other->miter_limit; |
69 | | |
70 | 19.4k | style->num_dashes = other->num_dashes; |
71 | | |
72 | 19.4k | if (other->dash == NULL) { |
73 | 19.4k | style->dash = NULL; |
74 | 19.4k | } else { |
75 | 0 | style->dash = _cairo_malloc_ab (style->num_dashes, sizeof (double)); |
76 | 0 | if (unlikely (style->dash == NULL)) |
77 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
78 | | |
79 | 0 | memcpy (style->dash, other->dash, |
80 | 0 | style->num_dashes * sizeof (double)); |
81 | 0 | } |
82 | | |
83 | 19.4k | style->dash_offset = other->dash_offset; |
84 | | |
85 | 19.4k | style->is_hairline = other->is_hairline; |
86 | | |
87 | 19.4k | return CAIRO_STATUS_SUCCESS; |
88 | 19.4k | } |
89 | | |
90 | | void |
91 | | _cairo_stroke_style_fini (cairo_stroke_style_t *style) |
92 | 8.15M | { |
93 | 8.15M | free (style->dash); |
94 | 8.15M | style->dash = NULL; |
95 | | |
96 | 8.15M | style->num_dashes = 0; |
97 | | |
98 | 8.15M | VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t))); |
99 | 8.15M | } |
100 | | |
101 | | /* |
102 | | * For a stroke in the given style, compute the maximum distance |
103 | | * from the path that vertices could be generated. In the case |
104 | | * of rotation in the ctm, the distance will not be exact. |
105 | | */ |
106 | | void |
107 | | _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style, |
108 | | const cairo_path_fixed_t *path, |
109 | | const cairo_matrix_t *ctm, |
110 | | double *dx, double *dy) |
111 | 838k | { |
112 | 838k | double style_expansion = 0.5; |
113 | | |
114 | 838k | if (style->line_cap == CAIRO_LINE_CAP_SQUARE) |
115 | 0 | style_expansion = M_SQRT1_2; |
116 | | |
117 | 838k | if (style->line_join == CAIRO_LINE_JOIN_MITER && |
118 | 838k | ! path->stroke_is_rectilinear && |
119 | 838k | style_expansion < M_SQRT2 * style->miter_limit) |
120 | 14.8k | { |
121 | 14.8k | style_expansion = M_SQRT2 * style->miter_limit; |
122 | 14.8k | } |
123 | | |
124 | 838k | style_expansion *= style->line_width; |
125 | | |
126 | 838k | if (_cairo_matrix_has_unity_scale (ctm)) { |
127 | 834k | *dx = *dy = style_expansion; |
128 | 834k | } else { |
129 | 3.80k | *dx = style_expansion * hypot (ctm->xx, ctm->xy); |
130 | 3.80k | *dy = style_expansion * hypot (ctm->yy, ctm->yx); |
131 | 3.80k | } |
132 | 838k | } |
133 | | |
134 | | void |
135 | | _cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style, |
136 | | const cairo_path_fixed_t *path, |
137 | | const cairo_matrix_t *ctm, |
138 | | double *dx, double *dy) |
139 | 0 | { |
140 | 0 | double style_expansion = 0.5 * style->line_width; |
141 | 0 | if (_cairo_matrix_has_unity_scale (ctm)) { |
142 | 0 | *dx = *dy = style_expansion; |
143 | 0 | } else { |
144 | 0 | *dx = style_expansion * hypot (ctm->xx, ctm->xy); |
145 | 0 | *dy = style_expansion * hypot (ctm->yy, ctm->yx); |
146 | 0 | } |
147 | 0 | } |
148 | | |
149 | | void |
150 | | _cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style, |
151 | | const cairo_path_fixed_t *path, |
152 | | const cairo_matrix_t *ctm, |
153 | | double *dx, double *dy) |
154 | 0 | { |
155 | 0 | double style_expansion = 0.5; |
156 | |
|
157 | 0 | if (style->line_join == CAIRO_LINE_JOIN_MITER && |
158 | 0 | ! path->stroke_is_rectilinear && |
159 | 0 | style_expansion < M_SQRT2 * style->miter_limit) |
160 | 0 | { |
161 | 0 | style_expansion = M_SQRT2 * style->miter_limit; |
162 | 0 | } |
163 | |
|
164 | 0 | style_expansion *= style->line_width; |
165 | |
|
166 | 0 | if (_cairo_matrix_has_unity_scale (ctm)) { |
167 | 0 | *dx = *dy = style_expansion; |
168 | 0 | } else { |
169 | 0 | *dx = style_expansion * hypot (ctm->xx, ctm->xy); |
170 | 0 | *dy = style_expansion * hypot (ctm->yy, ctm->yx); |
171 | 0 | } |
172 | 0 | } |
173 | | /* |
174 | | * Computes the period of a dashed stroke style. |
175 | | * Returns 0 for non-dashed styles. |
176 | | */ |
177 | | double |
178 | | _cairo_stroke_style_dash_period (const cairo_stroke_style_t *style) |
179 | 0 | { |
180 | 0 | double period; |
181 | 0 | unsigned int i; |
182 | |
|
183 | 0 | period = 0.0; |
184 | 0 | for (i = 0; i < style->num_dashes; i++) |
185 | 0 | period += style->dash[i]; |
186 | |
|
187 | 0 | if (style->num_dashes & 1) |
188 | 0 | period *= 2.0; |
189 | |
|
190 | 0 | return period; |
191 | 0 | } |
192 | | |
193 | | /* |
194 | | * Coefficient of the linear approximation (minimizing square difference) |
195 | | * of the surface covered by round caps |
196 | | * |
197 | | * This can be computed in the following way: |
198 | | * the area inside the circle with radius w/2 and the region -d/2 <= x <= d/2 is: |
199 | | * f(w,d) = 2 * integrate (sqrt (w*w/4 - x*x), x, -d/2, d/2) |
200 | | * The square difference to a generic linear approximation (c*d) in the range (0,w) would be: |
201 | | * integrate ((f(w,d) - c*d)^2, d, 0, w) |
202 | | * To minimize this difference it is sufficient to find a solution of the differential with |
203 | | * respect to c: |
204 | | * solve ( diff (integrate ((f(w,d) - c*d)^2, d, 0, w), c), c) |
205 | | * Which leads to c = 9/32*pi*w |
206 | | * Since we're not interested in the true area, but just in a coverage extimate, |
207 | | * we always divide the real area by the line width (w). |
208 | | * The same computation for square caps would be |
209 | | * f(w,d) = 2 * integrate(w/2, x, -d/2, d/2) |
210 | | * c = 1*w |
211 | | * but in this case it would not be an approximation, since f is already linear in d. |
212 | | */ |
213 | 0 | #define ROUND_MINSQ_APPROXIMATION (9*M_PI/32) |
214 | | |
215 | | /* |
216 | | * Computes the length of the "on" part of a dashed stroke style, |
217 | | * taking into account also line caps. |
218 | | * Returns 0 for non-dashed styles. |
219 | | */ |
220 | | double |
221 | | _cairo_stroke_style_dash_stroked (const cairo_stroke_style_t *style) |
222 | 0 | { |
223 | 0 | double stroked, cap_scale; |
224 | 0 | unsigned int i; |
225 | |
|
226 | 0 | switch (style->line_cap) { |
227 | 0 | default: ASSERT_NOT_REACHED; |
228 | 0 | case CAIRO_LINE_CAP_BUTT: cap_scale = 0.0; break; |
229 | 0 | case CAIRO_LINE_CAP_ROUND: cap_scale = ROUND_MINSQ_APPROXIMATION; break; |
230 | 0 | case CAIRO_LINE_CAP_SQUARE: cap_scale = 1.0; break; |
231 | 0 | } |
232 | | |
233 | 0 | stroked = 0.0; |
234 | 0 | if (style->num_dashes & 1) { |
235 | | /* Each dash element is used both as on and as off. The order in which they are summed is |
236 | | * irrelevant, so sum the coverage of one dash element, taken both on and off at each iteration */ |
237 | 0 | for (i = 0; i < style->num_dashes; i++) |
238 | 0 | stroked += style->dash[i] + cap_scale * MIN (style->dash[i], style->line_width); |
239 | 0 | } else { |
240 | | /* Even (0, 2, ...) dashes are on and simply counted for the coverage, odd dashes are off, thus |
241 | | * their coverage is approximated based on the area covered by the caps of adjacent on dases. */ |
242 | 0 | for (i = 0; i + 1 < style->num_dashes; i += 2) |
243 | 0 | stroked += style->dash[i] + cap_scale * MIN (style->dash[i+1], style->line_width); |
244 | 0 | } |
245 | |
|
246 | 0 | return stroked; |
247 | 0 | } |
248 | | |
249 | | /* |
250 | | * Verifies if _cairo_stroke_style_dash_approximate should be used to generate |
251 | | * an approximation of the dash pattern in the specified style, when used for |
252 | | * stroking a path with the given CTM and tolerance. |
253 | | * Always %FALSE for non-dashed styles. |
254 | | */ |
255 | | cairo_bool_t |
256 | | _cairo_stroke_style_dash_can_approximate (const cairo_stroke_style_t *style, |
257 | | const cairo_matrix_t *ctm, |
258 | | double tolerance) |
259 | 834k | { |
260 | 834k | double period; |
261 | | |
262 | 834k | if (! style->num_dashes) |
263 | 834k | return FALSE; |
264 | | |
265 | 0 | period = _cairo_stroke_style_dash_period (style); |
266 | 0 | return _cairo_matrix_transformed_circle_major_axis (ctm, period) < tolerance; |
267 | 834k | } |
268 | | |
269 | | /* |
270 | | * Create a 2-dashes approximation of a dashed style, by making the "on" and "off" |
271 | | * parts respect the original ratio. |
272 | | */ |
273 | | void |
274 | | _cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style, |
275 | | const cairo_matrix_t *ctm, |
276 | | double tolerance, |
277 | | double *dash_offset, |
278 | | double *dashes, |
279 | | unsigned int *num_dashes) |
280 | 0 | { |
281 | 0 | double coverage, scale, offset; |
282 | 0 | cairo_bool_t on = TRUE; |
283 | 0 | unsigned int i = 0; |
284 | |
|
285 | 0 | coverage = _cairo_stroke_style_dash_stroked (style) / _cairo_stroke_style_dash_period (style); |
286 | 0 | coverage = MIN (coverage, 1.0); |
287 | 0 | scale = tolerance / _cairo_matrix_transformed_circle_major_axis (ctm, 1.0); |
288 | | |
289 | | /* We stop searching for a starting point as soon as the |
290 | | * offset reaches zero. Otherwise when an initial dash |
291 | | * segment shrinks to zero it will be skipped over. */ |
292 | 0 | offset = style->dash_offset; |
293 | 0 | while (offset > 0.0 && offset >= style->dash[i]) { |
294 | 0 | offset -= style->dash[i]; |
295 | 0 | on = !on; |
296 | 0 | if (++i == style->num_dashes) |
297 | 0 | i = 0; |
298 | 0 | } |
299 | |
|
300 | 0 | *num_dashes = 2; |
301 | | |
302 | | /* |
303 | | * We want to create a new dash pattern with the same relative coverage, |
304 | | * but composed of just 2 elements with total length equal to scale. |
305 | | * Based on the formula in _cairo_stroke_style_dash_stroked: |
306 | | * scale * coverage = dashes[0] + cap_scale * MIN (dashes[1], line_width) |
307 | | * = MIN (dashes[0] + cap_scale * (scale - dashes[0]), |
308 | | * dashes[0] + cap_scale * line_width) = |
309 | | * = MIN (dashes[0] * (1 - cap_scale) + cap_scale * scale, |
310 | | * dashes[0] + cap_scale * line_width) |
311 | | * |
312 | | * Solving both cases we get: |
313 | | * dashes[0] = scale * (coverage - cap_scale) / (1 - cap_scale) |
314 | | * when scale - dashes[0] <= line_width |
315 | | * dashes[0] = scale * coverage - cap_scale * line_width |
316 | | * when scale - dashes[0] > line_width. |
317 | | * |
318 | | * Comparing the two cases we get: |
319 | | * second > first |
320 | | * second > scale * (coverage - cap_scale) / (1 - cap_scale) |
321 | | * second - cap_scale * second - scale * coverage + scale * cap_scale > 0 |
322 | | * (scale * coverage - cap_scale * line_width) - cap_scale * second - scale * coverage + scale * cap_scale > 0 |
323 | | * - line_width - second + scale > 0 |
324 | | * scale - second > line_width |
325 | | * which is the condition for the second solution to be the valid one. |
326 | | * So when second > first, the second solution is the correct one (i.e. |
327 | | * the solution is always MAX (first, second). |
328 | | */ |
329 | 0 | switch (style->line_cap) { |
330 | 0 | default: |
331 | 0 | ASSERT_NOT_REACHED; |
332 | 0 | dashes[0] = 0.0; |
333 | 0 | break; |
334 | | |
335 | 0 | case CAIRO_LINE_CAP_BUTT: |
336 | | /* Simplified formula (substituting 0 for cap_scale): */ |
337 | 0 | dashes[0] = scale * coverage; |
338 | 0 | break; |
339 | | |
340 | 0 | case CAIRO_LINE_CAP_ROUND: |
341 | 0 | dashes[0] = MAX(scale * (coverage - ROUND_MINSQ_APPROXIMATION) / (1.0 - ROUND_MINSQ_APPROXIMATION), |
342 | 0 | scale * coverage - ROUND_MINSQ_APPROXIMATION * style->line_width); |
343 | 0 | break; |
344 | | |
345 | 0 | case CAIRO_LINE_CAP_SQUARE: |
346 | | /* |
347 | | * Special attention is needed to handle the case cap_scale == 1 (since the first solution |
348 | | * is either indeterminate or -inf in this case). Since dash lengths are always >=0, using |
349 | | * 0 as first solution always leads to the correct solution. |
350 | | */ |
351 | 0 | dashes[0] = MAX(0.0, scale * coverage - style->line_width); |
352 | 0 | break; |
353 | 0 | } |
354 | | |
355 | 0 | dashes[1] = scale - dashes[0]; |
356 | |
|
357 | 0 | *dash_offset = on ? 0.0 : dashes[0]; |
358 | 0 | } |