/src/ghostpdl/base/gxhintn1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* A stuff for reconnizing and fixing wrong contour signs. */ |
18 | | |
19 | | #include "memory_.h" |
20 | | #include "math_.h" |
21 | | #include "gx.h" |
22 | | #include "gxfixed.h" |
23 | | #include "gxarith.h" |
24 | | #include "gstypes.h" |
25 | | #include "gxmatrix.h" |
26 | | #include "gxhintn.h" |
27 | | #include "gzpath.h" |
28 | | |
29 | 0 | #define CURVE_FLATTENING (fixed_1) /* Design units in 'fixed'. */ |
30 | | |
31 | | static double inline line_area_2(fixed p0x, fixed p0y, fixed p1x, fixed p1y) |
32 | 0 | { /* Returns area * 2.*/ |
33 | 0 | return ((double)p0x*p1y - (double)p0y*p1x); |
34 | 0 | } |
35 | | |
36 | | static double inline bezier_area_2(fixed p0x, fixed p0y, fixed p1x, fixed p1y, |
37 | | fixed p2x, fixed p2y, fixed p3x, fixed p3y) |
38 | 0 | { /* Returns area * 2.*/ |
39 | 0 | return (-(p0y*(6.0*p1x + 3.0*p2x + p3x)) + p0x*(6.0*p1y + 3.0*p2y + p3y) - |
40 | 0 | 3*((double)p1y*p2x + (double)p1y*p3x + 2.0*p2y*p3x - 2.0*p2x*p3y - (double)p1x*(p2y + p3y)))/10; |
41 | 0 | } |
42 | | |
43 | | static void t1_hinter__reverse_contour(t1_hinter * self, int c) |
44 | 0 | { |
45 | 0 | int b = self->contour[c]; |
46 | 0 | int e = self->contour[c + 1] - 1; /* Skip 'close'. */ |
47 | 0 | int e2 = (b + e + 1) / 2; |
48 | 0 | int i; |
49 | 0 | t1_pole p; |
50 | | |
51 | | /* Reverse all except endpoint ('close') : */ |
52 | 0 | for (i = b + 1; i < e2; i++) { |
53 | 0 | int j = e - (i - b); |
54 | |
|
55 | 0 | p = self->pole[i]; |
56 | 0 | self->pole[i] = self->pole[j]; |
57 | 0 | self->pole[j] = p; |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | 0 | #define CONTACT_SIGNAL -100000.0 |
62 | | |
63 | | static double inline bar_winding_angle(fixed x0, fixed y0, fixed x1, fixed y1) |
64 | 0 | { |
65 | 0 | double vp = (double)x0 * y1 - (double)y0 * x1; |
66 | 0 | double sp = (double)x0 * x1 + (double)y0 * y1; |
67 | 0 | double A; |
68 | |
|
69 | 0 | if (sp == 0) { |
70 | 0 | if (vp == 0) |
71 | 0 | return CONTACT_SIGNAL; /* Contours contact. */ |
72 | 0 | A = 1.57079632679489661923; /* pi/2. */ |
73 | 0 | if (vp < 0) |
74 | 0 | A = -A; |
75 | 0 | } else |
76 | 0 | A = atan2(vp, sp); |
77 | 0 | return A; |
78 | 0 | } |
79 | | |
80 | | static double |
81 | | curve_winding_angle_rec(int k, fixed x0, fixed y0, fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3) |
82 | 0 | { |
83 | 0 | if (k <= 1) |
84 | 0 | return bar_winding_angle(x0, y0, x3, y3); |
85 | 0 | else { |
86 | | /* Assuming the trapezoid is not self-intersecting and |
87 | | the curve is inside the trapezoid |
88 | | due to Type 1 constraints. */ |
89 | 0 | double a0 = bar_winding_angle(x0, y0, x1, y1); |
90 | 0 | double a1 = bar_winding_angle(x1, y1, x2, y2); |
91 | 0 | double a2 = bar_winding_angle(x2, y2, x3, y3); |
92 | 0 | double a3 = bar_winding_angle(x3, y3, x0, y0); |
93 | 0 | double a = a0 + a1 + a2 + a3; |
94 | |
|
95 | 0 | if (any_abs(a) < 0.1 && a0 != CONTACT_SIGNAL && |
96 | 0 | a1 != CONTACT_SIGNAL && |
97 | 0 | a2 != CONTACT_SIGNAL && |
98 | 0 | a3 != CONTACT_SIGNAL) { |
99 | | /* The center is outside the trapezoid. */ |
100 | 0 | return -a3; |
101 | 0 | } else { |
102 | 0 | fixed x01 = (x0 + x1) / 2, y01 = (y0 + y1) / 2; |
103 | 0 | fixed x12 = (x1 + x2) / 2, y12 = (y1 + y2) / 2; |
104 | 0 | fixed x23 = (x2 + x3) / 2, y23 = (y2 + y3) / 2; |
105 | 0 | fixed x012 = (x01 + x12) / 2, y012 = (y01 + y12) / 2; |
106 | 0 | fixed x123 = (x12 + x23) / 2, y123 = (y12 + y23) / 2; |
107 | 0 | fixed x0123 = (x012 + x123) / 2, y0123 = (y012 + y123) / 2; |
108 | 0 | double A0, A1; |
109 | |
|
110 | 0 | A0 = curve_winding_angle_rec(k - 1, x0, y0, x01, y01, x012, y012, x0123, y0123); |
111 | 0 | if (A0 == CONTACT_SIGNAL) |
112 | 0 | return CONTACT_SIGNAL; |
113 | 0 | A1 = curve_winding_angle_rec(k - 1, x0123, y0123, x123, y123, x23, y23, x3, y3); |
114 | 0 | if (A1 == CONTACT_SIGNAL) |
115 | 0 | return CONTACT_SIGNAL; |
116 | 0 | return A0 + A1; |
117 | 0 | } |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | | static int curve_log2_samples(fixed x0, fixed y0, fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3) |
122 | 0 | { |
123 | 0 | curve_segment s; |
124 | |
|
125 | 0 | s.p1.x = x1; |
126 | 0 | s.p1.y = y1; |
127 | 0 | s.p2.x = x2; |
128 | 0 | s.p2.y = y2; |
129 | 0 | s.pt.x = x3; |
130 | 0 | s.pt.y = y3; |
131 | 0 | return gx_curve_log2_samples(x0, y0, &s, (fixed)CURVE_FLATTENING); |
132 | 0 | } |
133 | | |
134 | | static double curve_winding_angle(fixed x0, fixed y0, fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3) |
135 | 0 | { |
136 | 0 | int k = curve_log2_samples(x0, y0, x1, y1, x2, y2, x3, y3); |
137 | |
|
138 | 0 | return curve_winding_angle_rec(k, x0, y0, x1, y1, x2, y2, x3, y3); |
139 | 0 | } |
140 | | |
141 | | static int t1_hinter__is_inside(t1_hinter * self, t1_glyph_space_coord gx, t1_glyph_space_coord gy, int c) |
142 | 0 | { |
143 | 0 | int b = self->contour[c]; |
144 | 0 | int e = self->contour[c + 1] - 1; |
145 | 0 | double a = 0, A; |
146 | 0 | int i; |
147 | |
|
148 | 0 | for (i = b; i < e;) { |
149 | 0 | if (self->pole[i + 1].type != offcurve) { /* line or close. */ |
150 | 0 | A = bar_winding_angle(self->pole[i + 0].gx - gx, self->pole[i + 0].gy - gy, |
151 | 0 | self->pole[i + 1].gx - gx, self->pole[i + 1].gy - gy); |
152 | 0 | i++; |
153 | 0 | } else { |
154 | 0 | A = curve_winding_angle(self->pole[i + 0].gx - gx, self->pole[i + 0].gy - gy, |
155 | 0 | self->pole[i + 1].gx - gx, self->pole[i + 1].gy - gy, |
156 | 0 | self->pole[i + 2].gx - gx, self->pole[i + 2].gy - gy, |
157 | 0 | self->pole[i + 3].gx - gx, self->pole[i + 3].gy - gy); |
158 | 0 | i += 3; |
159 | 0 | } |
160 | 0 | if (A == CONTACT_SIGNAL) |
161 | 0 | return -1; |
162 | 0 | a += A; |
163 | 0 | } |
164 | 0 | if (any_abs(a) < 0.1) |
165 | 0 | return 0; |
166 | 0 | return 1; |
167 | 0 | } |
168 | | |
169 | | static inline bool |
170 | | intersect_bar_bar(fixed q0x, fixed q0y, fixed q1x, fixed q1y, fixed q2x, fixed q2y, fixed q3x, fixed q3y) |
171 | 0 | { |
172 | 0 | if (q1x == q0x && q1y == q0y) |
173 | 0 | return false; |
174 | 0 | if (q1x == q2x && q1y == q2y) |
175 | 0 | return false; |
176 | 0 | if (q0x == q2x && q0y == q2y) |
177 | 0 | return true; |
178 | 0 | if (q0x == q3x && q0y == q3y) |
179 | 0 | return true; |
180 | 0 | if (q1x == q2x && q1y == q2y) |
181 | 0 | return true; |
182 | 0 | if (q1x == q3x && q1y == q3y) |
183 | 0 | return true; |
184 | 0 | else { |
185 | 0 | fixed dx1 = q1x - q0x; |
186 | 0 | fixed dy1 = q1y - q0y; |
187 | 0 | fixed dx2 = q2x - q0x; |
188 | 0 | fixed dy2 = q2y - q0y; |
189 | 0 | fixed dx3 = q3x - q0x; |
190 | 0 | fixed dy3 = q3y - q0y; |
191 | 0 | fixed dx1a = any_abs(dx1); |
192 | 0 | fixed dy1a = any_abs(dy1); |
193 | 0 | fixed dx2a = any_abs(dx2); |
194 | 0 | fixed dy2a = any_abs(dy2); |
195 | 0 | fixed dx3a = any_abs(dx3); |
196 | 0 | fixed dy3a = any_abs(dy3); |
197 | 0 | fixed d = dx1a | dy1a | dx2a | dy2a | dx3a | dy3a; |
198 | 0 | fixed ry, ey; /* stubs only - don't use them, they are whong here. */ |
199 | | |
200 | | /* gx_intersect_small_bars needs cubes of distances to fit into 62 bits, |
201 | | Drop extra bits here. |
202 | | We don't need ry, so don't bother with absolute coordinates. */ |
203 | 0 | while (d >= (1 << (60 / 3))) { |
204 | 0 | d >>= 1; |
205 | 0 | dx1 = (dx1 + 1) / 2; |
206 | 0 | dy1 = (dy1 + 1) / 2; |
207 | 0 | dx2 = (dy2 + 1) / 2; |
208 | 0 | dy2 = (dy2 + 1) / 2; |
209 | 0 | dx3 = (dy3 + 1) / 2; |
210 | 0 | dy3 = (dy3 + 1) / 2; |
211 | 0 | } |
212 | | /* Well, when we drop bits, the intersection isn't precise. |
213 | | But it happens with big characters only, |
214 | | which unlikely have close oncurve poles |
215 | | which belong to different contours. |
216 | | Due to that we believe the boolean result is precise |
217 | | with a very high probablility. */ |
218 | 0 | return gx_intersect_small_bars(0, 0, dx1, dy1, dx2, dy2, dx3, dy3, &ry, &ey); |
219 | 0 | } |
220 | 0 | } |
221 | | |
222 | | static inline bool |
223 | | t1_hinter__intersect_bar_bar(t1_hinter * self, int i, int j) |
224 | 0 | { |
225 | 0 | fixed q0x = self->pole[i + 0].gx; |
226 | 0 | fixed q0y = self->pole[i + 0].gy; |
227 | 0 | fixed q1x = self->pole[i + 1].gx; |
228 | 0 | fixed q1y = self->pole[i + 1].gy; |
229 | 0 | fixed q2x = self->pole[j + 0].gx; |
230 | 0 | fixed q2y = self->pole[j + 0].gy; |
231 | 0 | fixed q3x = self->pole[j + 1].gx; |
232 | 0 | fixed q3y = self->pole[j + 1].gy; |
233 | |
|
234 | 0 | return intersect_bar_bar(q0x, q0y, q1x, q1y, q2x, q2y, q3x, q3y); |
235 | 0 | } |
236 | | |
237 | | static bool intersect_curve_bar_rec(int m, int k, fixed X1, fixed Y1, |
238 | | fixed x0, fixed y0, fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3) |
239 | 0 | { |
240 | 0 | if (m <= 1) |
241 | 0 | return intersect_bar_bar(0, 0, X1, Y1, x0, y0, x3, y3); |
242 | 0 | else { |
243 | 0 | gs_rect box0, box1; |
244 | |
|
245 | 0 | if (X1 < 0) |
246 | 0 | box0.p.x = X1, box0.q.x = 0; |
247 | 0 | else |
248 | 0 | box0.p.x = 0, box0.q.x = X1; |
249 | 0 | if (Y1 < 0) |
250 | 0 | box0.p.y = Y1, box0.q.y = 0; |
251 | 0 | else |
252 | 0 | box0.p.y = 0, box0.q.y = Y1; |
253 | |
|
254 | 0 | box1.p.x = box1.q.x = x0; |
255 | 0 | box1.p.y = box1.q.y = y0; |
256 | 0 | if (box1.p.x > x1) |
257 | 0 | box1.p.x = x1; |
258 | 0 | if (box1.q.x < x1) |
259 | 0 | box1.q.x = x1; |
260 | 0 | if (box1.p.y > y1) |
261 | 0 | box1.p.y = y1; |
262 | 0 | if (box1.q.y < y1) |
263 | 0 | box1.q.y = y1; |
264 | 0 | if (box1.p.x > x2) |
265 | 0 | box1.p.x = x2; |
266 | 0 | if (box1.q.x < x2) |
267 | 0 | box1.q.x = x2; |
268 | 0 | if (box1.p.y > y2) |
269 | 0 | box1.p.y = y2; |
270 | 0 | if (box1.q.y < y2) |
271 | 0 | box1.q.y = y2; |
272 | 0 | if (box1.p.x > x3) |
273 | 0 | box1.p.x = x3; |
274 | 0 | if (box1.q.x < x3) |
275 | 0 | box1.q.x = x3; |
276 | 0 | if (box1.p.y > y3) |
277 | 0 | box1.p.y = y3; |
278 | 0 | if (box1.q.y < y3) |
279 | 0 | box1.q.y = y3; |
280 | 0 | if (box0.p.x > box1.q.x) |
281 | 0 | return false; |
282 | 0 | if (box0.q.x < box1.p.x) |
283 | 0 | return false; |
284 | 0 | if (box0.p.y > box1.q.y) |
285 | 0 | return false; |
286 | 0 | if (box0.q.y < box1.p.y) |
287 | 0 | return false; |
288 | 0 | } |
289 | 0 | { fixed x01 = (x0 + x1) / 2, y01 = (y0 + y1) / 2; |
290 | 0 | fixed x12 = (x1 + x2) / 2, y12 = (y1 + y2) / 2; |
291 | 0 | fixed x23 = (x2 + x3) / 2, y23 = (y2 + y3) / 2; |
292 | 0 | fixed x012 = (x01 + x12) / 2, y012 = (y01 + y12) / 2; |
293 | 0 | fixed x123 = (x12 + x23) / 2, y123 = (y12 + y23) / 2; |
294 | 0 | fixed x0123 = (x012 + x123) / 2, y0123 = (y012 + y123) / 2; |
295 | |
|
296 | 0 | if (k <= 1) { |
297 | 0 | if (intersect_curve_bar_rec(m - 1, k, X1, Y1, x0, y0, x01, y01, x012, y012, x0123, y0123)) |
298 | 0 | return true; |
299 | 0 | if (intersect_curve_bar_rec(m - 1, k, X1, Y1, x0123, y0123, x123, y123, x23, y23, x3, y3)) |
300 | 0 | return true; |
301 | 0 | } else { |
302 | 0 | fixed X01 = X1 / 2; |
303 | 0 | fixed Y01 = Y1 / 2; |
304 | |
|
305 | 0 | if (intersect_curve_bar_rec(m - 1, k - 1, X01, Y01, x0, y0, x01, y01, x012, y012, x0123, y0123)) |
306 | 0 | return true; |
307 | 0 | if (intersect_curve_bar_rec(m - 1, k - 1, X01, Y01, x0123, y0123, x123, y123, x23, y23, x3, y3)) |
308 | 0 | return true; |
309 | 0 | if (intersect_curve_bar_rec(m - 1, k - 1, X1 - X01, Y1 - Y01, x0 - X01, y0 - Y01, x01 - X01, y01 - Y01, |
310 | 0 | x012 - X01, y012 - Y01, x0123 - X01, y0123 - Y01)) |
311 | 0 | return true; |
312 | 0 | if (intersect_curve_bar_rec(m - 1, k - 1, X1 - X01, Y1 - Y01, x0123 - X01, y0123 - Y01, |
313 | 0 | x123 - X01, y123 - Y01, x23 - X01, y23 - Y01, x3 - X01, y3 - Y01)) |
314 | 0 | return true; |
315 | 0 | } |
316 | 0 | } |
317 | 0 | return false; |
318 | 0 | } |
319 | | |
320 | | static int bar_samples(fixed dx, fixed dy) |
321 | 0 | { |
322 | 0 | int l = (any_abs(dx) | any_abs(dy)) / CURVE_FLATTENING, m = 0; |
323 | 0 | while (l) { |
324 | 0 | l >>= 1; |
325 | 0 | m++; |
326 | 0 | } |
327 | 0 | return m; |
328 | 0 | } |
329 | | |
330 | | static bool t1_hinter__intersect_curve_bar(t1_hinter * self, int i, int j) |
331 | 0 | { |
332 | 0 | fixed X0 = self->pole[j].gx; |
333 | 0 | fixed Y0 = self->pole[j].gy; |
334 | 0 | fixed X1 = self->pole[j + 1].gx - X0; |
335 | 0 | fixed Y1 = self->pole[j + 1].gy - Y0; |
336 | 0 | fixed x0 = self->pole[i].gx - X0; |
337 | 0 | fixed y0 = self->pole[i].gy - Y0; |
338 | 0 | fixed x1 = self->pole[i + 1].gx - X0; |
339 | 0 | fixed y1 = self->pole[i + 1].gy - Y0; |
340 | 0 | fixed x2 = self->pole[i + 2].gx - X0; |
341 | 0 | fixed y2 = self->pole[i + 2].gy - Y0; |
342 | 0 | fixed x3 = self->pole[i + 3].gx - X0; |
343 | 0 | fixed y3 = self->pole[i + 3].gy - Y0; |
344 | 0 | int k = curve_log2_samples(0, 0, x1, y1, x2, y2, x3, y3); |
345 | 0 | int m = bar_samples(X1, Y1); |
346 | |
|
347 | 0 | return intersect_curve_bar_rec(m, k, X1, Y1, x0, y0, x1, y1, x2, y2, x3, y3); |
348 | 0 | } |
349 | | |
350 | | static bool intersect_curve_curve_rec(int ka, int kb, |
351 | | fixed ax0, fixed ay0, fixed ax1, fixed ay1, fixed ax2, fixed ay2, fixed ax3, fixed ay3, |
352 | | fixed bx0, fixed by0, fixed bx1, fixed by1, fixed bx2, fixed by2, fixed bx3, fixed by3) |
353 | 0 | { |
354 | 0 | if (ka <= 1 && kb <= 1) |
355 | 0 | return intersect_bar_bar(ax0, ay0, ax3, ay3, bx0, by0, bx3, by3); |
356 | 0 | else if (ka <= 1) { |
357 | 0 | int m = bar_samples(ax3 - ax0, ay3 - ay0); |
358 | |
|
359 | 0 | return intersect_curve_bar_rec(m, kb, ax3 - ax0, ay3 - ay0, |
360 | 0 | bx0 - ax0, by0 - ay0, bx1 - ax0, by1 - ay0, bx2 - ax0, by2 - ay0, bx3 - ax0, by3 - ay0); |
361 | 0 | } else if (kb <= 1) { |
362 | 0 | int m = bar_samples(bx3 - bx0, by3 - by0); |
363 | |
|
364 | 0 | return intersect_curve_bar_rec(m, ka, bx3 - bx0, by3 - by0, |
365 | 0 | ax0 - bx0, ay0 - by0, ax1 - bx0, ay1 - by0, ax2 - bx0, ay2 - by0, ax3 - bx0, ay3 - by0); |
366 | 0 | } else { |
367 | 0 | gs_rect box0, box1; |
368 | |
|
369 | 0 | box0.p.x = box0.q.x = ax0; |
370 | 0 | box0.p.y = box0.q.y = ay0; |
371 | 0 | if (box0.p.x > ax1) |
372 | 0 | box0.p.x = ax1; |
373 | 0 | if (box0.q.x < ax1) |
374 | 0 | box0.q.x = ax1; |
375 | 0 | if (box0.p.y > ay1) |
376 | 0 | box0.p.y = ay1; |
377 | 0 | if (box0.q.y < ay1) |
378 | 0 | box0.q.y = ay1; |
379 | 0 | if (box0.p.x > ax2) |
380 | 0 | box0.p.x = ax2; |
381 | 0 | if (box0.q.x < ax2) |
382 | 0 | box0.q.x = ax2; |
383 | 0 | if (box0.p.y > ay2) |
384 | 0 | box0.p.y = ay2; |
385 | 0 | if (box0.q.y < ay2) |
386 | 0 | box0.q.y = ay2; |
387 | 0 | if (box0.p.x > ax3) |
388 | 0 | box0.p.x = ax3; |
389 | 0 | if (box0.q.x < ax3) |
390 | 0 | box0.q.x = ax3; |
391 | 0 | if (box0.p.y > ay3) |
392 | 0 | box0.p.y = ay3; |
393 | 0 | if (box0.q.y < ay3) |
394 | 0 | box0.q.y = ay3; |
395 | 0 | box1.p.x = box1.q.x = bx0; |
396 | 0 | box1.p.y = box1.q.y = by0; |
397 | 0 | if (box1.p.x > bx1) |
398 | 0 | box1.p.x = bx1; |
399 | 0 | if (box1.q.x < bx1) |
400 | 0 | box1.q.x = bx1; |
401 | 0 | if (box1.p.y > by1) |
402 | 0 | box1.p.y = by1; |
403 | 0 | if (box1.q.y < by1) |
404 | 0 | box1.q.y = by1; |
405 | 0 | if (box1.p.x > bx2) |
406 | 0 | box1.p.x = bx2; |
407 | 0 | if (box1.q.x < bx2) |
408 | 0 | box1.q.x = bx2; |
409 | 0 | if (box1.p.y > by2) |
410 | 0 | box1.p.y = by2; |
411 | 0 | if (box1.q.y < by2) |
412 | 0 | box1.q.y = by2; |
413 | 0 | if (box1.p.x > bx3) |
414 | 0 | box1.p.x = bx3; |
415 | 0 | if (box1.q.x < bx3) |
416 | 0 | box1.q.x = bx3; |
417 | 0 | if (box1.p.y > by3) |
418 | 0 | box1.p.y = by3; |
419 | 0 | if (box1.q.y < by3) |
420 | 0 | box1.q.y = by3; |
421 | 0 | if (box0.p.x > box1.q.x) |
422 | 0 | return false; |
423 | 0 | if (box0.q.x < box1.p.x) |
424 | 0 | return false; |
425 | 0 | if (box0.p.y > box1.q.y) |
426 | 0 | return false; |
427 | 0 | if (box0.q.y < box1.p.y) |
428 | 0 | return false; |
429 | 0 | } |
430 | 0 | { fixed ax01 = (ax0 + ax1) / 2, ay01 = (ay0 + ay1) / 2; |
431 | 0 | fixed ax12 = (ax1 + ax2) / 2, ay12 = (ay1 + ay2) / 2; |
432 | 0 | fixed ax23 = (ax2 + ax3) / 2, ay23 = (ay2 + ay3) / 2; |
433 | 0 | fixed ax012 = (ax01 + ax12) / 2, ay012 = (ay01 + ay12) / 2; |
434 | 0 | fixed ax123 = (ax12 + ax23) / 2, ay123 = (ay12 + ay23) / 2; |
435 | 0 | fixed ax0123 = (ax012 + ax123) / 2, ay0123 = (ay012 + ay123) / 2; |
436 | 0 | fixed bx01 = (bx0 + bx1) / 2, by01 = (by0 + by1) / 2; |
437 | 0 | fixed bx12 = (bx1 + bx2) / 2, by12 = (by1 + by2) / 2; |
438 | 0 | fixed bx23 = (bx2 + bx3) / 2, by23 = (by2 + by3) / 2; |
439 | 0 | fixed bx012 = (bx01 + bx12) / 2, by012 = (by01 + by12) / 2; |
440 | 0 | fixed bx123 = (bx12 + bx23) / 2, by123 = (by12 + by23) / 2; |
441 | 0 | fixed bx0123 = (bx012 + bx123) / 2, by0123 = (by012 + by123) / 2; |
442 | |
|
443 | 0 | if (intersect_curve_curve_rec(ka - 1, kb - 1, ax0, ay0, ax01, ay01, ax012, ay012, ax0123, ay0123, |
444 | 0 | bx0, by0, bx01, by01, bx012, by012, bx0123, by0123)) |
445 | 0 | return true; |
446 | 0 | if (intersect_curve_curve_rec(ka - 1, kb - 1, ax0, ay0, ax01, ay01, ax012, ay012, ax0123, ay0123, |
447 | 0 | bx0123, by0123, bx123, by123, bx23, by23, bx3, by3)) |
448 | 0 | return true; |
449 | 0 | if (intersect_curve_curve_rec(ka - 1, kb - 1, ax0123, ay0123, ax123, ay123, ax23, ay23, ax3, ay3, |
450 | 0 | bx0, by0, bx01, by01, bx012, by012, bx0123, by0123)) |
451 | 0 | return true; |
452 | 0 | if (intersect_curve_curve_rec(ka - 1, kb - 1, ax0123, ay0123, ax123, ay123, ax23, ay23, ax3, ay3, |
453 | 0 | bx0123, by0123, bx123, by123, bx23, by23, bx3, by3)) |
454 | 0 | return true; |
455 | |
|
456 | 0 | } |
457 | 0 | return false; |
458 | 0 | } |
459 | | |
460 | | static bool t1_hinter__intersect_curve_curve(t1_hinter * self, int i, int j) |
461 | 0 | { |
462 | 0 | fixed ax0 = self->pole[i].gx; |
463 | 0 | fixed ay0 = self->pole[i].gy; |
464 | 0 | fixed ax1 = self->pole[i + 1].gx; |
465 | 0 | fixed ay1 = self->pole[i + 1].gy; |
466 | 0 | fixed ax2 = self->pole[i + 2].gx; |
467 | 0 | fixed ay2 = self->pole[i + 2].gy; |
468 | 0 | fixed ax3 = self->pole[i + 3].gx; |
469 | 0 | fixed ay3 = self->pole[i + 3].gy; |
470 | 0 | fixed bx0 = self->pole[j].gx; |
471 | 0 | fixed by0 = self->pole[j].gy; |
472 | 0 | fixed bx1 = self->pole[j + 1].gx; |
473 | 0 | fixed by1 = self->pole[j + 1].gy; |
474 | 0 | fixed bx2 = self->pole[j + 2].gx; |
475 | 0 | fixed by2 = self->pole[j + 2].gy; |
476 | 0 | fixed bx3 = self->pole[j + 3].gx; |
477 | 0 | fixed by3 = self->pole[j + 3].gy; |
478 | 0 | int ka = curve_log2_samples(ax0, ay0, ax1, ay1, ax2, ay2, ax3, ay3); |
479 | 0 | int kb = curve_log2_samples(bx0, by0, bx1, by1, bx2, by2, bx3, by3); |
480 | |
|
481 | 0 | return intersect_curve_curve_rec(ka, kb, |
482 | 0 | ax0, ay0, ax1, ay1, ax2, ay2, ax3, ay3, |
483 | 0 | bx0, by0, bx1, by1, bx2, by2, bx3, by3); |
484 | 0 | } |
485 | | |
486 | | static bool t1_hinter__contour_intersection(t1_hinter * self, int c0, int c1) |
487 | 0 | { |
488 | 0 | int b0 = self->contour[c0]; |
489 | 0 | int e0 = self->contour[c0 + 1] - 1; |
490 | 0 | int b1 = self->contour[c1]; |
491 | 0 | int e1 = self->contour[c1 + 1] - 1; |
492 | 0 | int i, j; |
493 | |
|
494 | 0 | for (i = b0; i < e0;) { |
495 | 0 | if (self->pole[i + 1].type != offcurve) { /* line or close. */ |
496 | 0 | for (j = b1; j < e1;) { |
497 | 0 | if (self->pole[j + 1].type != offcurve) { /* line or close. */ |
498 | 0 | if (t1_hinter__intersect_bar_bar(self, i, j)) |
499 | 0 | return true; |
500 | 0 | j++; |
501 | 0 | } else { |
502 | 0 | if (t1_hinter__intersect_curve_bar(self, j, i)) |
503 | 0 | return true; |
504 | 0 | j += 3; |
505 | 0 | } |
506 | 0 | } |
507 | 0 | i++; |
508 | 0 | } else { |
509 | 0 | for (j = b1; j < e1;) { |
510 | 0 | if (self->pole[j + 1].type != offcurve) { /* line or close. */ |
511 | 0 | if (t1_hinter__intersect_curve_bar(self, i, j)) |
512 | 0 | return true; |
513 | 0 | j++; |
514 | 0 | } else { |
515 | 0 | if (t1_hinter__intersect_curve_curve(self, j, i)) |
516 | 0 | return true; |
517 | 0 | j += 3; |
518 | 0 | } |
519 | 0 | } |
520 | 0 | i += 3; |
521 | 0 | } |
522 | 0 | } |
523 | 0 | return false; |
524 | 0 | } |
525 | | |
526 | 0 | #define MAX_NORMALIZING_CONTOURS 5 |
527 | | |
528 | | static void t1_hinter__fix_subglyph_contour_signs(t1_hinter * self, int first_contour, int last_contour) |
529 | 0 | { |
530 | 0 | double area[MAX_NORMALIZING_CONTOURS]; |
531 | 0 | int i, j, k, l, m; |
532 | 0 | double a = 0; |
533 | 0 | byte inside[MAX_NORMALIZING_CONTOURS][MAX_NORMALIZING_CONTOURS]; |
534 | 0 | int nesting[MAX_NORMALIZING_CONTOURS]; |
535 | 0 | gs_rect bbox[MAX_NORMALIZING_CONTOURS]; |
536 | 0 | byte isolated[MAX_NORMALIZING_CONTOURS]; |
537 | 0 | int nesting_sum; |
538 | |
|
539 | 0 | if (first_contour == last_contour) { |
540 | | /* Don't fix a single contour. */ |
541 | 0 | return; |
542 | 0 | } |
543 | | /* Compute contour bboxes : */ |
544 | 0 | k = 0; |
545 | 0 | for(i = first_contour; i <= last_contour; i++) { |
546 | 0 | int b = self->contour[i]; |
547 | 0 | int e = self->contour[i + 1] - 1; |
548 | |
|
549 | 0 | bbox[k].p.x = bbox[k].q.x = self->pole[b].gx; |
550 | 0 | bbox[k].p.y = bbox[k].q.y = self->pole[b].gy; |
551 | | /* 'close' has same coords as the starting point. */ |
552 | 0 | for (j = b; j < e; j++) { |
553 | 0 | t1_glyph_space_coord x = self->pole[j].gx; |
554 | 0 | t1_glyph_space_coord y = self->pole[j].gy; |
555 | |
|
556 | 0 | if (bbox[k].p.x > x) |
557 | 0 | bbox[k].p.x = x; |
558 | 0 | if (bbox[k].q.x < x) |
559 | 0 | bbox[k].q.x = x; |
560 | 0 | if (bbox[k].p.y > y) |
561 | 0 | bbox[k].p.y = y; |
562 | 0 | if (bbox[k].q.y < y) |
563 | 0 | bbox[k].q.y = y; |
564 | 0 | } |
565 | 0 | k++; |
566 | 0 | } |
567 | | /* mark contacting bboxes : */ |
568 | 0 | memset(isolated, 0, sizeof(isolated)); |
569 | 0 | for (i = 0; i < k; i++) { |
570 | 0 | for (j = i + 1; j < k; j++) { |
571 | 0 | if (bbox[i].p.x > bbox[j].q.x) |
572 | 0 | continue; |
573 | 0 | if (bbox[i].q.x < bbox[j].p.x) |
574 | 0 | continue; |
575 | 0 | if (bbox[i].p.y > bbox[j].q.y) |
576 | 0 | continue; |
577 | 0 | if (bbox[i].q.y < bbox[j].p.y) |
578 | 0 | continue; |
579 | 0 | isolated[i] = isolated[j] = 1; /* mark not isolated. */ |
580 | 0 | } |
581 | 0 | } |
582 | | /* Make a list of non-isolated contours : */ |
583 | 0 | j = 0; |
584 | 0 | for (i = 0; i < k; i++) { |
585 | 0 | if (isolated[i]) { |
586 | 0 | isolated[j] = first_contour + i; |
587 | 0 | j++; |
588 | 0 | } |
589 | 0 | } |
590 | 0 | k = j; |
591 | | /* So far we skip isolated contours. */ |
592 | 0 | if (k <= 1) |
593 | 0 | return; /* Nothing to fix. */ |
594 | | /* Compute contour signes : */ |
595 | 0 | for(i = 0; i < k; i++) { |
596 | 0 | int c = isolated[i]; |
597 | 0 | int b = self->contour[c]; |
598 | 0 | int e = self->contour[c + 1] - 1; |
599 | |
|
600 | 0 | a = 0; |
601 | | /* 'close' has same coords as the starting point. */ |
602 | 0 | for (j = b; j < e; ) { |
603 | 0 | if (self->pole[j + 1].type != offcurve) { /* line or close. */ |
604 | 0 | a += line_area_2(self->pole[j + 0].gx, self->pole[j + 0].gy, |
605 | 0 | self->pole[j + 1].gx, self->pole[j + 1].gy); |
606 | 0 | j++; |
607 | 0 | } else { |
608 | 0 | a += bezier_area_2(self->pole[j + 0].gx, self->pole[j + 0].gy, |
609 | 0 | self->pole[j + 1].gx, self->pole[j + 1].gy, |
610 | 0 | self->pole[j + 2].gx, self->pole[j + 2].gy, |
611 | 0 | self->pole[j + 3].gx, self->pole[j + 3].gy); |
612 | 0 | j += 3; |
613 | 0 | } |
614 | 0 | } |
615 | 0 | area[i] = a; |
616 | 0 | } |
617 | | /* If contours have different signs, don't adjust. */ |
618 | 0 | for (i = 1; i < k; i++) { |
619 | 0 | if (area[0] * area[i] < 0) |
620 | 0 | return; |
621 | 0 | } |
622 | | /* Compute the insideness matrix : |
623 | | For any contoor pair A, B, |
624 | | check if some point of A is inside B. */ |
625 | 0 | for (i = 0; i < k; i++) { |
626 | 0 | inside[i][i] = 0; |
627 | 0 | for (j = 0; j < k; j++) { |
628 | 0 | if (i != j) { |
629 | 0 | int b = self->contour[isolated[i]]; |
630 | 0 | int code = t1_hinter__is_inside(self, self->pole[b].gx, self->pole[b].gy, isolated[j]); |
631 | |
|
632 | 0 | if (code < 0) { |
633 | | /* Contours have a common point - don't fix. */ |
634 | 0 | return; |
635 | 0 | } |
636 | 0 | inside[i][j] = (byte)code; |
637 | 0 | if (i > j && inside[j][i]) { |
638 | | /* Contours intersect, don't fix. */ |
639 | 0 | return; |
640 | 0 | } |
641 | 0 | } |
642 | 0 | } |
643 | 0 | } |
644 | | /* Transitive closure : */ |
645 | 0 | do { |
646 | 0 | m = 0; |
647 | 0 | for (i = 0; i < k; i++) { |
648 | 0 | for (j = 0; j < k; j++) { |
649 | 0 | if (i != j) { |
650 | 0 | for (l = 0; l < k; l++) { |
651 | 0 | if (j != l && inside[i][j] && inside[j][l]) { |
652 | 0 | if (inside[l][i]) { |
653 | | /* Cycled - don't fix. */ |
654 | 0 | return; |
655 | 0 | } |
656 | 0 | if (!inside[i][l]) |
657 | 0 | m = 1; |
658 | 0 | inside[i][l] = 1; |
659 | 0 | } |
660 | 0 | } |
661 | 0 | } |
662 | 0 | } |
663 | 0 | } |
664 | 0 | } while(m); |
665 | | /* Compute nesting numbers : */ |
666 | 0 | nesting_sum = 0; |
667 | 0 | memset(nesting, 0, sizeof(nesting)); |
668 | 0 | for (i = 0; i < k; i++) { |
669 | 0 | for (j = 0; j < k; j++) { |
670 | 0 | if (inside[i][j]) { |
671 | 0 | nesting[i]++; |
672 | 0 | nesting_sum++; |
673 | 0 | } |
674 | 0 | } |
675 | 0 | } |
676 | 0 | if (nesting_sum == 0) { |
677 | | /* No nesting contours - don't fix. |
678 | | We want to save time from computing contour intersections. */ |
679 | 0 | return; |
680 | 0 | } |
681 | | /* Check contour intersections : */ |
682 | 0 | for (i = 0; i < k; i++) { |
683 | 0 | for (j = 0; j < k; j++) { |
684 | 0 | if (inside[i][j]) { |
685 | 0 | if (t1_hinter__contour_intersection(self, isolated[i], isolated[j])) { |
686 | | /* Contours intersect - don't fix. */ |
687 | 0 | return; |
688 | 0 | } |
689 | 0 | } |
690 | 0 | } |
691 | 0 | } |
692 | | /* Fix signs : */ |
693 | 0 | for (i = 0; i < k; i++) { |
694 | 0 | if ((nesting[i] & 1) != (area[i] < 0)) |
695 | 0 | t1_hinter__reverse_contour(self, isolated[i]); |
696 | 0 | } |
697 | | /* Note we didn't fix negative isolated contours. |
698 | | We never meet such cases actually. */ |
699 | 0 | } |
700 | | |
701 | | void t1_hinter__fix_contour_signs(t1_hinter * self) |
702 | 0 | { |
703 | 0 | int i; |
704 | |
|
705 | 0 | if (self->subglyph_count >= 3) { |
706 | | /* 3 or more subglyphs. |
707 | | We didn't meet so complex characters with wrong contours signs. |
708 | | Skip it for saving the CPU time. */ |
709 | 0 | return; |
710 | 0 | } |
711 | 0 | for (i = 1; i <= self->subglyph_count; i++) { |
712 | 0 | int first_contour = self->subglyph[i - 1]; |
713 | 0 | int last_contour = self->subglyph[i] - 1; |
714 | |
|
715 | 0 | if (last_contour - first_contour >= MAX_NORMALIZING_CONTOURS) { |
716 | | /* 4 or more contours. |
717 | | We didn't meet so complex characters with wrong contours signs. |
718 | | Skip it for saving the CPU time. */ |
719 | 0 | continue; |
720 | 0 | } |
721 | 0 | t1_hinter__fix_subglyph_contour_signs(self, first_contour, last_contour); |
722 | 0 | } |
723 | 0 | } |