2 |
- |
1 |
/* Copyright (C) 1989-2003 artofcode LLC. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: gxfdrop.c,v 1.16 2004/12/08 21:35:13 stefan Exp $ */
|
|
|
18 |
/* Dropout prevention for a character rasterization. */
|
|
|
19 |
|
|
|
20 |
#include <assert.h>
|
|
|
21 |
#include "gx.h"
|
|
|
22 |
#include "gserrors.h"
|
|
|
23 |
#include "gsstruct.h"
|
|
|
24 |
#include "gzpath.h"
|
|
|
25 |
#include "gxfixed.h"
|
|
|
26 |
#include "gxdevice.h"
|
|
|
27 |
#include "gxdcolor.h"
|
|
|
28 |
#include "gxfdrop.h"
|
|
|
29 |
#include "gxfill.h"
|
|
|
30 |
#include "vdtrace.h"
|
|
|
31 |
|
|
|
32 |
#define INTERTRAP_STEM_BUG 0 /* We're not sure that 1 gives a
|
|
|
33 |
better painting with neighbour serifs.
|
|
|
34 |
Need more testing.
|
|
|
35 |
|
|
|
36 |
|
|
|
37 |
/*
|
|
|
38 |
* Rather some margins are placed in virtual memory,
|
|
|
39 |
* we never run garbager while some of them are allocated.
|
|
|
40 |
* Therefore we use "st_simple" for margins and sections.
|
|
|
41 |
*/
|
|
|
42 |
gs_private_st_simple(st_margin, margin, "margin");
|
|
|
43 |
gs_public_st_simple(st_section, section, "section");
|
|
|
44 |
|
|
|
45 |
void init_section(section *sect, int i0, int i1)
|
|
|
46 |
{ int i;
|
|
|
47 |
|
|
|
48 |
for (i = i0; i < i1; i++) {
|
|
|
49 |
# if ADJUST_SERIF && CHECK_SPOT_CONTIGUITY
|
|
|
50 |
sect[i].x0 = fixed_1;
|
|
|
51 |
sect[i].x1 = 0;
|
|
|
52 |
# endif
|
|
|
53 |
sect[i].y0 = sect[i].y1 = -1;
|
|
|
54 |
}
|
|
|
55 |
}
|
|
|
56 |
|
|
|
57 |
private margin * alloc_margin(line_list * ll)
|
|
|
58 |
{ margin *m;
|
|
|
59 |
|
|
|
60 |
assert(ll->fo->pseudo_rasterization);
|
|
|
61 |
if (ll->free_margin_list != 0) {
|
|
|
62 |
m = ll->free_margin_list;
|
|
|
63 |
ll->free_margin_list = ll->free_margin_list->next;
|
|
|
64 |
} else if (ll->local_margin_alloc_count < MAX_LOCAL_ACTIVE) {
|
|
|
65 |
m = ll->local_margins + ll->local_margin_alloc_count;
|
|
|
66 |
++ ll->local_margin_alloc_count;
|
|
|
67 |
} else {
|
|
|
68 |
m = gs_alloc_struct(ll->memory, margin, &st_margin, "filling contiguity margin");
|
|
|
69 |
/* The allocation happens only if ll->local_margins[MAX_LOCAL_ACTIVE]
|
|
|
70 |
is exceeded. We believe it does very seldom. */
|
|
|
71 |
}
|
|
|
72 |
return m;
|
|
|
73 |
}
|
|
|
74 |
|
|
|
75 |
private void release_margin_list(line_list * ll, margin_set *ms)
|
|
|
76 |
{ margin * m1 = ms->margin_list;
|
|
|
77 |
|
|
|
78 |
if (m1 == 0)
|
|
|
79 |
return;
|
|
|
80 |
while (m1->next != 0)
|
|
|
81 |
m1 = m1->next;
|
|
|
82 |
m1->next = ll->free_margin_list;
|
|
|
83 |
ll->free_margin_list = ms->margin_list;
|
|
|
84 |
ms->margin_list = ms->margin_touched = 0;
|
|
|
85 |
}
|
|
|
86 |
|
|
|
87 |
void free_all_margins(line_list * ll)
|
|
|
88 |
{ margin * m = ll->free_margin_list;
|
|
|
89 |
|
|
|
90 |
ll->free_margin_list = 0;
|
|
|
91 |
while (m != 0) {
|
|
|
92 |
margin * m1 = m->next;
|
|
|
93 |
|
|
|
94 |
if (m < ll->local_margins || m >= ll->local_margins + MAX_LOCAL_ACTIVE)
|
|
|
95 |
gs_free_object(ll->memory, m, "filling contiguity margin");
|
|
|
96 |
m = m1;
|
|
|
97 |
}
|
|
|
98 |
}
|
|
|
99 |
|
|
|
100 |
private int store_margin(line_list * ll, margin_set * set, int ii0, int ii1)
|
|
|
101 |
{
|
|
|
102 |
/*
|
|
|
103 |
* We need to add margin to the ordered margin list.
|
|
|
104 |
* Contacting margins to be united.
|
|
|
105 |
*/
|
|
|
106 |
int i0 = ii0, i1 = ii1;
|
|
|
107 |
margin *m0 = set->margin_touched, *m1;
|
|
|
108 |
|
|
|
109 |
assert(ii0 >= 0 && ii1 <= ll->bbox_width);
|
|
|
110 |
set->margin_touched = 0; /* safety */
|
|
|
111 |
/* Find contacting elements. */
|
|
|
112 |
if (m0 != 0) {
|
|
|
113 |
margin *m_last = m0, *mb, *me;
|
|
|
114 |
|
|
|
115 |
assert(set->margin_list != 0);
|
|
|
116 |
if (i1 < m0->ibeg) {
|
|
|
117 |
do {
|
|
|
118 |
m0 = m0->prev;
|
|
|
119 |
} while (m0 != 0 && i0 <= m0->iend);
|
|
|
120 |
/* m0 points to a non-contacting at left. */
|
|
|
121 |
m1 = (m0 == 0 ? set->margin_list : m0)->next;
|
|
|
122 |
while (m1 != 0 && m1->ibeg <= i1) {
|
|
|
123 |
m_last = m1;
|
|
|
124 |
m1 = m1->next;
|
|
|
125 |
}
|
|
|
126 |
/* m1 points to a non-contacting at right. */
|
|
|
127 |
} else if (i0 > m0->iend) {
|
|
|
128 |
m1 = m0;
|
|
|
129 |
do {
|
|
|
130 |
m_last = m1;
|
|
|
131 |
m1 = m1->next;
|
|
|
132 |
} while (m1 != 0 && i1 >= m1->ibeg);
|
|
|
133 |
/* m0 points to a non-contacting at right. */
|
|
|
134 |
m0 = (m1 == 0 ? m_last : m1->prev);
|
|
|
135 |
while (m0 != 0 && m0->iend >= i0)
|
|
|
136 |
m0 = m0->prev;
|
|
|
137 |
/* m1 points to a non-contacting at left. */
|
|
|
138 |
} else {
|
|
|
139 |
m1 = m0;
|
|
|
140 |
while (m1 != 0 && m1->ibeg <= i1) {
|
|
|
141 |
m_last = m1;
|
|
|
142 |
m1 = m1->next;
|
|
|
143 |
}
|
|
|
144 |
/* m1 points to a non-contacting at right. */
|
|
|
145 |
while (m0 != 0 && m0->iend >= i0)
|
|
|
146 |
m0 = m0->prev;
|
|
|
147 |
/* m1 points to a non-contacting at left. */
|
|
|
148 |
}
|
|
|
149 |
/* Remove elements from m0->next to m1->prev, excluding the latter.
|
|
|
150 |
m0 may be NULL if we riched list start.
|
|
|
151 |
m1 may be NULL if we riched list end. */
|
|
|
152 |
mb = (m0 == 0 ? set->margin_list : m0->next);
|
|
|
153 |
if (mb != 0 && mb != m1) {
|
|
|
154 |
me = (m1 == 0 ? m_last : m1->prev);
|
|
|
155 |
/* Remove elements from mb to me, excluding the latter.
|
|
|
156 |
me may be NULL if we riched list start. */
|
|
|
157 |
if (me != 0) {
|
|
|
158 |
if (mb != me && me->prev != 0) {
|
|
|
159 |
margin *mf = me->prev;
|
|
|
160 |
|
|
|
161 |
/* Remove elements from mb to mf. */
|
|
|
162 |
if (mb->prev != 0)
|
|
|
163 |
mb->prev->next = mf->next;
|
|
|
164 |
if (mf->next != 0)
|
|
|
165 |
mf->next->prev = mb->prev;
|
|
|
166 |
if (set->margin_list == mb)
|
|
|
167 |
set->margin_list = mf->next;
|
|
|
168 |
mf->next = ll->free_margin_list;
|
|
|
169 |
ll->free_margin_list = mb;
|
|
|
170 |
i0 = min(i0, mb->ibeg);
|
|
|
171 |
i1 = max(i1, mf->iend);
|
|
|
172 |
/* 'prev' links are not used in ll->free_margin_list. */
|
|
|
173 |
}
|
|
|
174 |
}
|
|
|
175 |
}
|
|
|
176 |
me = (m0 == 0 ? set->margin_list : m0->next);
|
|
|
177 |
if (me == 0)
|
|
|
178 |
m0 = m0; /* Already set. */
|
|
|
179 |
else if (me->iend < i0)
|
|
|
180 |
m0 = me; /* Insert after me. */
|
|
|
181 |
else if (me->ibeg > i1)
|
|
|
182 |
m0 = me->prev; /* Insert before me. */
|
|
|
183 |
else if (me->iend >= i0 && me->ibeg <= i1) {
|
|
|
184 |
/* Intersects with me. Replace me boundaries. */
|
|
|
185 |
me->ibeg = min(i0, me->ibeg);
|
|
|
186 |
me->iend = max(i1, me->iend);
|
|
|
187 |
set->margin_touched = me;
|
|
|
188 |
return 0;
|
|
|
189 |
}
|
|
|
190 |
}
|
|
|
191 |
/* Insert after m0 */
|
|
|
192 |
m1 = alloc_margin(ll);
|
|
|
193 |
if (m1 == 0)
|
|
|
194 |
return_error(gs_error_VMerror);
|
|
|
195 |
if (m0 != 0) {
|
|
|
196 |
m1->next = m0->next;
|
|
|
197 |
m1->prev = m0;
|
|
|
198 |
m0->next = m1;
|
|
|
199 |
if (m1->next!= 0)
|
|
|
200 |
m1->next->prev = m1;
|
|
|
201 |
} else {
|
|
|
202 |
m1->next = set->margin_list;
|
|
|
203 |
m1->prev = 0;
|
|
|
204 |
if (set->margin_list != 0)
|
|
|
205 |
set->margin_list->prev = m1;
|
|
|
206 |
set->margin_list = m1;
|
|
|
207 |
}
|
|
|
208 |
m1->ibeg = i0;
|
|
|
209 |
m1->iend = i1;
|
|
|
210 |
set->margin_touched = m1;
|
|
|
211 |
return 0;
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
private inline int to_interval(int x, int l, int u)
|
|
|
215 |
{ return x < l ? l : x > u ? u : x;
|
|
|
216 |
}
|
|
|
217 |
|
|
|
218 |
private inline fixed Y_AT_X(active_line *alp, fixed xp)
|
|
|
219 |
{ return alp->start.y + fixed_mult_quo(xp - alp->start.x, alp->diff.y, alp->diff.x);
|
|
|
220 |
}
|
|
|
221 |
|
|
|
222 |
private int margin_boundary(line_list * ll, margin_set * set, active_line * alp,
|
|
|
223 |
fixed xx0, fixed xx1, fixed yy0, fixed yy1, int dir, fixed y0, fixed y1)
|
|
|
224 |
{ section *sect = set->sect;
|
|
|
225 |
fixed x0, x1, xmin, xmax;
|
|
|
226 |
int xp0, xp;
|
|
|
227 |
int i0, i;
|
|
|
228 |
# if !CHECK_SPOT_CONTIGUITY
|
|
|
229 |
int i1;
|
|
|
230 |
# endif
|
|
|
231 |
|
|
|
232 |
if (yy0 > yy1)
|
|
|
233 |
return 0;
|
|
|
234 |
/* enumerate integral x's in [yy0,yy1] : */
|
|
|
235 |
|
|
|
236 |
if (alp == 0)
|
|
|
237 |
x0 = xx0, x1 = xx1;
|
|
|
238 |
else {
|
|
|
239 |
x0 = (yy0 == y0 ? alp->x_current : AL_X_AT_Y(alp, yy0));
|
|
|
240 |
x1 = (yy1 == y1 ? alp->x_next : AL_X_AT_Y(alp, yy1));
|
|
|
241 |
}
|
|
|
242 |
xmin = min(x0, x1);
|
|
|
243 |
xmax = max(x0, x1);
|
|
|
244 |
# if !CHECK_SPOT_CONTIGUITY
|
|
|
245 |
xp0 = fixed_floor(xmin) + fixed_half;
|
|
|
246 |
i0 = fixed2int(xp0) - ll->bbox_left;
|
|
|
247 |
if (xp0 < xmin) {
|
|
|
248 |
xp0 += fixed_1;
|
|
|
249 |
i0++;
|
|
|
250 |
}
|
|
|
251 |
assert(i0 >= 0);
|
|
|
252 |
for (i = i0, xp = xp0; xp < xmax && i < ll->bbox_width; xp += fixed_1, i++) {
|
|
|
253 |
fixed y = (alp == 0 ? yy0 : Y_AT_X(alp, xp));
|
|
|
254 |
fixed dy = y - set->y;
|
|
|
255 |
bool ud;
|
|
|
256 |
short *b, h;
|
|
|
257 |
section *s = §[i];
|
|
|
258 |
|
|
|
259 |
if (dy < 0)
|
|
|
260 |
dy = 0; /* fix rounding errors in Y_AT_X */
|
|
|
261 |
if (dy >= fixed_1)
|
|
|
262 |
dy = fixed_1; /* safety */
|
|
|
263 |
vd_circle(xp, y, 2, 0);
|
|
|
264 |
ud = (alp == 0 ? (dir > 0) : ((alp->start.x - alp->end.x) * dir > 0));
|
|
|
265 |
b = (ud ? &s->y0 : &s->y1);
|
|
|
266 |
h = (short)dy;
|
|
|
267 |
if (*b == -1 || (*b != -2 && ( ud ? *b > h : *b < h)))
|
|
|
268 |
*b = h;
|
|
|
269 |
}
|
|
|
270 |
# else
|
|
|
271 |
xp0 = fixed_floor(xmin) + fixed_half;
|
|
|
272 |
i0 = fixed2int(xp0) - ll->bbox_left;
|
|
|
273 |
if (xp0 < xmin) {
|
|
|
274 |
i0++;
|
|
|
275 |
xp0 += fixed_1;
|
|
|
276 |
}
|
|
|
277 |
for (i = i0, xp = xp0; xp < xmax; xp += fixed_1, i++) {
|
|
|
278 |
section *s = §[i];
|
|
|
279 |
fixed y = (alp==0 ? yy0 : Y_AT_X(alp, xp));
|
|
|
280 |
fixed dy = y - set->y;
|
|
|
281 |
bool ud;
|
|
|
282 |
short *b, h;
|
|
|
283 |
|
|
|
284 |
if (dy < 0)
|
|
|
285 |
dy = 0; /* fix rounding errors in Y_AT_X */
|
|
|
286 |
if (dy >= fixed_1)
|
|
|
287 |
dy = fixed_1; /* safety */
|
|
|
288 |
vd_circle(xp, y, 2, 0);
|
|
|
289 |
ud = (alp == 0 ? (dir > 0) : ((alp->start.x - alp->end.x) * dir > 0));
|
|
|
290 |
b = (ud ? &s->y0 : &s->y1);
|
|
|
291 |
h = (short)dy;
|
|
|
292 |
if (*b == -1 || (*b != -2 && ( ud ? *b > h : *b < h)))
|
|
|
293 |
*b = h;
|
|
|
294 |
}
|
|
|
295 |
assert(i0 >= 0 && i <= ll->bbox_width);
|
|
|
296 |
# endif
|
|
|
297 |
if (i > i0)
|
|
|
298 |
return store_margin(ll, set, i0, i);
|
|
|
299 |
return 0;
|
|
|
300 |
}
|
|
|
301 |
|
|
|
302 |
int continue_margin_common(line_list * ll, margin_set * set, active_line * flp, active_line * alp, fixed y0, fixed y1)
|
|
|
303 |
{ int code;
|
|
|
304 |
# if ADJUST_SERIF
|
|
|
305 |
section *sect = set->sect;
|
|
|
306 |
fixed yy0 = max(max(y0, alp->start.y), set->y);
|
|
|
307 |
fixed yy1 = min(min(y1, alp->end.y), set->y + fixed_1);
|
|
|
308 |
|
|
|
309 |
if (yy0 <= yy1) {
|
|
|
310 |
fixed x00 = (yy0 == y0 ? flp->x_current : AL_X_AT_Y(flp, yy0));
|
|
|
311 |
fixed x10 = (yy0 == y0 ? alp->x_current : AL_X_AT_Y(alp, yy0));
|
|
|
312 |
fixed x01 = (yy1 == y1 ? flp->x_next : AL_X_AT_Y(flp, yy1));
|
|
|
313 |
fixed x11 = (yy1 == y1 ? alp->x_next : AL_X_AT_Y(alp, yy1));
|
|
|
314 |
fixed xmin = min(x00, x01), xmax = max(x10, x11);
|
|
|
315 |
|
|
|
316 |
int i0 = fixed2int(xmin) - ll->bbox_left, i;
|
|
|
317 |
int i1 = fixed2int_ceiling(xmax) - ll->bbox_left;
|
|
|
318 |
|
|
|
319 |
for (i = i0; i < i1; i++) {
|
|
|
320 |
section *s = §[i];
|
|
|
321 |
int x_pixel = int2fixed(i + ll->bbox_left);
|
|
|
322 |
int xl = max(xmin - x_pixel, 0);
|
|
|
323 |
int xu = min(xmax - x_pixel, fixed_1);
|
|
|
324 |
|
|
|
325 |
s->x0 = min(s->x0, xl);
|
|
|
326 |
s->x1 = max(s->x1, xu);
|
|
|
327 |
x_pixel+=0; /* Just a place for breakpoint */
|
|
|
328 |
}
|
|
|
329 |
code = store_margin(ll, set, i0, i1);
|
|
|
330 |
if (code < 0)
|
|
|
331 |
return code;
|
|
|
332 |
/* fixme : after ADJUST_SERIF becames permanent,
|
|
|
333 |
* don't call margin_boundary if yy0 > yy1.
|
|
|
334 |
*/
|
|
|
335 |
}
|
|
|
336 |
# endif
|
|
|
337 |
|
|
|
338 |
code = margin_boundary(ll, set, flp, 0, 0, yy0, yy1, 1, y0, y1);
|
|
|
339 |
if (code < 0)
|
|
|
340 |
return code;
|
|
|
341 |
return margin_boundary(ll, set, alp, 0, 0, yy0, yy1, -1, y0, y1);
|
|
|
342 |
}
|
|
|
343 |
|
|
|
344 |
private inline int mark_margin_interior(line_list * ll, margin_set * set, active_line * flp, active_line * alp, fixed y, fixed y0, fixed y1)
|
|
|
345 |
{
|
|
|
346 |
section *sect = set->sect;
|
|
|
347 |
fixed x0 = (y == y0 ? flp->x_current : y == y1 ? flp->x_next : AL_X_AT_Y(flp, y));
|
|
|
348 |
fixed x1 = (y == y0 ? alp->x_current : y == y1 ? alp->x_next : AL_X_AT_Y(alp, y));
|
|
|
349 |
int i0 = fixed2int(x0), ii0, ii1, i, code;
|
|
|
350 |
|
|
|
351 |
if (int2fixed(i0) + fixed_half < x0)
|
|
|
352 |
i0++;
|
|
|
353 |
ii0 = i0 - ll->bbox_left;
|
|
|
354 |
ii1 = fixed2int_var_pixround(x1) - ll->bbox_left;
|
|
|
355 |
if (ii0 < ii1) {
|
|
|
356 |
assert(ii0 >= 0 && ii1 <= ll->bbox_width);
|
|
|
357 |
for (i = ii0; i < ii1; i++) {
|
|
|
358 |
sect[i].y0 = sect[i].y1 = -2;
|
|
|
359 |
vd_circle(int2fixed(i + ll->bbox_left) + fixed_half, y, 3, RGB(255, 0, 0));
|
|
|
360 |
}
|
|
|
361 |
code = store_margin(ll, set, ii0, ii1);
|
|
|
362 |
if (code < 0)
|
|
|
363 |
return code;
|
|
|
364 |
}
|
|
|
365 |
return 0;
|
|
|
366 |
}
|
|
|
367 |
|
|
|
368 |
int margin_interior(line_list * ll, active_line * flp, active_line * alp, fixed y0, fixed y1)
|
|
|
369 |
{ int code;
|
|
|
370 |
fixed yy0, yy1;
|
|
|
371 |
|
|
|
372 |
yy0 = ll->margin_set0.y;
|
|
|
373 |
if (y0 <= yy0 && yy0 <= y1) {
|
|
|
374 |
code = mark_margin_interior(ll, &ll->margin_set0, flp, alp, yy0, y0, y1);
|
|
|
375 |
if (code < 0)
|
|
|
376 |
return code;
|
|
|
377 |
}
|
|
|
378 |
yy1 = ll->margin_set1.y + fixed_1;
|
|
|
379 |
if (y0 <= yy1 && yy1 <= y1) {
|
|
|
380 |
code = mark_margin_interior(ll, &ll->margin_set1, flp, alp, yy1, y0, y1);
|
|
|
381 |
if (code < 0)
|
|
|
382 |
return code;
|
|
|
383 |
}
|
|
|
384 |
return 0;
|
|
|
385 |
}
|
|
|
386 |
|
|
|
387 |
private inline int process_h_sect(line_list * ll, margin_set * set, active_line * hlp0,
|
|
|
388 |
active_line * plp, active_line * flp, int side, fixed y0, fixed y1)
|
|
|
389 |
{
|
|
|
390 |
active_line *hlp = hlp0;
|
|
|
391 |
fixed y = hlp->start.y;
|
|
|
392 |
fixed x0 = (plp != 0 ? (y == y0 ? plp->x_current : y == y1 ? plp->x_next : AL_X_AT_Y(plp, y))
|
|
|
393 |
: int2fixed(ll->bbox_left));
|
|
|
394 |
fixed x1 = (flp != 0 ? (y == y0 ? flp->x_current : y == y1 ? flp->x_next : AL_X_AT_Y(flp, y))
|
|
|
395 |
: int2fixed(ll->bbox_left + ll->bbox_width));
|
|
|
396 |
int code;
|
|
|
397 |
|
|
|
398 |
for (; hlp != 0; hlp = hlp->next) {
|
|
|
399 |
fixed xx0 = max(x0, min(hlp->start.x, hlp->end.x));
|
|
|
400 |
fixed xx1 = min(x1, max(hlp->start.x, hlp->end.x));
|
|
|
401 |
|
|
|
402 |
if (xx0 < xx1) {
|
|
|
403 |
vd_bar(xx0, y, xx1, y, 1, RGB(255, 0, 255));
|
|
|
404 |
code = margin_boundary(ll, set, 0, xx0, xx1, y, y, side, 0, 0);
|
|
|
405 |
if (code < 0)
|
|
|
406 |
return code;
|
|
|
407 |
}
|
|
|
408 |
}
|
|
|
409 |
return 0;
|
|
|
410 |
}
|
|
|
411 |
|
|
|
412 |
private inline int process_h_side(line_list * ll, margin_set * set, active_line * hlp,
|
|
|
413 |
active_line * plp, active_line * flp, active_line * alp, int side, fixed y0, fixed y1)
|
|
|
414 |
{ if (plp != 0 || flp != 0 || (plp == 0 && flp == 0 && alp == 0)) {
|
|
|
415 |
/* We don't know here, whether the opposite (-) side is painted with
|
|
|
416 |
* a trapezoid. mark_margin_interior may rewrite it later.
|
|
|
417 |
*/
|
|
|
418 |
int code = process_h_sect(ll, set, hlp, plp, flp, -side, y0, y1);
|
|
|
419 |
|
|
|
420 |
if (code < 0)
|
|
|
421 |
return code;
|
|
|
422 |
}
|
|
|
423 |
if (flp != 0 && alp != 0) {
|
|
|
424 |
int code = process_h_sect(ll, set, hlp, flp, alp, side, y0, y1);
|
|
|
425 |
|
|
|
426 |
if (code < 0)
|
|
|
427 |
return code;
|
|
|
428 |
}
|
|
|
429 |
return 0;
|
|
|
430 |
}
|
|
|
431 |
|
|
|
432 |
private inline int process_h_list(line_list * ll, active_line * hlp, active_line * plp,
|
|
|
433 |
active_line * flp, active_line * alp, int side, fixed y0, fixed y1)
|
|
|
434 |
{ fixed y = hlp->start.y;
|
|
|
435 |
|
|
|
436 |
if (ll->margin_set0.y <= y && y <= ll->margin_set0.y + fixed_1) {
|
|
|
437 |
int code = process_h_side(ll, &ll->margin_set0, hlp, plp, flp, alp, side, y0, y1);
|
|
|
438 |
|
|
|
439 |
if (code < 0)
|
|
|
440 |
return code;
|
|
|
441 |
}
|
|
|
442 |
if (ll->margin_set1.y <= y && y <= ll->margin_set1.y + fixed_1) {
|
|
|
443 |
int code = process_h_side(ll, &ll->margin_set1, hlp, plp, flp, alp, side, y0, y1);
|
|
|
444 |
|
|
|
445 |
if (code < 0)
|
|
|
446 |
return code;
|
|
|
447 |
}
|
|
|
448 |
return 0;
|
|
|
449 |
}
|
|
|
450 |
|
|
|
451 |
int process_h_lists(line_list * ll, active_line * plp, active_line * flp, active_line * alp,
|
|
|
452 |
fixed y0, fixed y1)
|
|
|
453 |
{
|
|
|
454 |
if (y0 == y1) {
|
|
|
455 |
/* fixme : Must not happen. Remove. */
|
|
|
456 |
return 0;
|
|
|
457 |
}
|
|
|
458 |
if (ll->h_list0 != 0) {
|
|
|
459 |
int code = process_h_list(ll, ll->h_list0, plp, flp, alp, 1, y0, y1);
|
|
|
460 |
|
|
|
461 |
if (code < 0)
|
|
|
462 |
return code;
|
|
|
463 |
}
|
|
|
464 |
if (ll->h_list1 != 0) {
|
|
|
465 |
int code = process_h_list(ll, ll->h_list1, plp, flp, alp, -1, y0, y1);
|
|
|
466 |
|
|
|
467 |
if (code < 0)
|
|
|
468 |
return code;
|
|
|
469 |
}
|
|
|
470 |
return 0;
|
|
|
471 |
}
|
|
|
472 |
|
|
|
473 |
private inline int compute_padding(section *s)
|
|
|
474 |
{
|
|
|
475 |
return (s->y0 < 0 || s->y1 < 0 ? -2 : /* contacts a trapezoid - don't paint */
|
|
|
476 |
s->y1 < fixed_half ? 0 :
|
|
|
477 |
s->y0 > fixed_half ? 1 :
|
|
|
478 |
fixed_half - s->y0 < s->y1 - fixed_half ? 1 : 0);
|
|
|
479 |
}
|
|
|
480 |
|
|
|
481 |
private int fill_margin(gx_device * dev, const line_list * ll, margin_set *ms, int i0, int i1)
|
|
|
482 |
{ /* Returns the new index (positive) or return code (negative). */
|
|
|
483 |
section *sect = ms->sect;
|
|
|
484 |
int iy = fixed2int_var_pixround(ms->y);
|
|
|
485 |
int i, ir, h = -2, code;
|
|
|
486 |
const fill_options * const fo = ll->fo;
|
|
|
487 |
const bool FILL_DIRECT = fo->fill_direct;
|
|
|
488 |
|
|
|
489 |
assert(i0 >= 0 && i1 <= ll->bbox_width);
|
|
|
490 |
ir = i0;
|
|
|
491 |
for (i = i0; i < i1; i++) {
|
|
|
492 |
int y0 = sect[i].y0, y1 = sect[i].y1, hh;
|
|
|
493 |
|
|
|
494 |
if (y0 == -1)
|
|
|
495 |
y0 = 0;
|
|
|
496 |
if (y1 == -1)
|
|
|
497 |
y1 = fixed_scale - 1;
|
|
|
498 |
hh = compute_padding(§[i]);
|
|
|
499 |
# if ADJUST_SERIF
|
|
|
500 |
if (hh >= 0) {
|
|
|
501 |
# if !CHECK_SPOT_CONTIGUITY
|
|
|
502 |
if (i == i0 && i + 1 < i1) {
|
|
|
503 |
int hhh = compute_padding(§[i + 1]);
|
|
|
504 |
|
|
|
505 |
hh = hhh;
|
|
|
506 |
} else if (i == i1 - 1 && i > i0)
|
|
|
507 |
hh = h;
|
|
|
508 |
/* We could optimize it with moving outside the cycle.
|
|
|
509 |
* Delaying the optimization until the code is well tested.
|
|
|
510 |
*/
|
|
|
511 |
# else
|
|
|
512 |
if (sect[i].x0 > 0 && sect[i].x1 == fixed_1 && i + 1 < i1) {
|
|
|
513 |
# if INTERTRAP_STEM_BUG
|
|
|
514 |
int hhh = hh;
|
|
|
515 |
# endif
|
|
|
516 |
hh = (i + 1 < i1 ? compute_padding(§[i + 1]) : -2);
|
|
|
517 |
/* We could cache hh.
|
|
|
518 |
* Delaying the optimization until the code is well tested.
|
|
|
519 |
*/
|
|
|
520 |
# if INTERTRAP_STEM_BUG
|
|
|
521 |
/* A bug in the old code. */
|
|
|
522 |
if (i > i0 && i + 1 < i1 && hh == -2 &&
|
|
|
523 |
compute_padding(§[i - 1]) == -2) {
|
|
|
524 |
/* It can be either a thin stem going from left to up or down
|
|
|
525 |
(See 'r' in 01-001.ps in 'General', ppmraw, 72dpi),
|
|
|
526 |
or a serif from the left.
|
|
|
527 |
Since it is between 2 trapezoids, it is better to paint it
|
|
|
528 |
against a dropout. */
|
|
|
529 |
hh = hhh;
|
|
|
530 |
}
|
|
|
531 |
# endif
|
|
|
532 |
} else if (sect[i].x0 == 0 && sect[i].x1 < fixed_1) {
|
|
|
533 |
# if INTERTRAP_STEM_BUG
|
|
|
534 |
int hhh = hh;
|
|
|
535 |
# endif
|
|
|
536 |
hh = h;
|
|
|
537 |
# if INTERTRAP_STEM_BUG
|
|
|
538 |
/* A bug in the old code. */
|
|
|
539 |
if (i > i0 && i + 1 < i1 && hh == -2 &&
|
|
|
540 |
compute_padding(§[i - 1]) == -2) {
|
|
|
541 |
/* It can be either a thin stem going from right to up or down
|
|
|
542 |
(See 'r' in 01-001.ps in 'General', ppmraw, 72dpi),
|
|
|
543 |
or a serif from the right.
|
|
|
544 |
Since it is between 2 trapezoids, it is better to paint it.
|
|
|
545 |
against a dropout. */
|
|
|
546 |
DO_NOTHING;
|
|
|
547 |
}
|
|
|
548 |
# endif
|
|
|
549 |
}
|
|
|
550 |
# endif
|
|
|
551 |
}
|
|
|
552 |
# endif
|
|
|
553 |
if (h != hh) {
|
|
|
554 |
if (h >= 0) {
|
|
|
555 |
VD_RECT(ir + ll->bbox_left, iy + h, i - ir, 1, VD_MARG_COLOR);
|
|
|
556 |
code = LOOP_FILL_RECTANGLE_DIRECT(fo, ir + ll->bbox_left, iy + h, i - ir, 1);
|
|
|
557 |
if (code < 0)
|
|
|
558 |
return code;
|
|
|
559 |
}
|
|
|
560 |
ir = i;
|
|
|
561 |
h = hh;
|
|
|
562 |
}
|
|
|
563 |
}
|
|
|
564 |
if (h >= 0) {
|
|
|
565 |
VD_RECT(ir + ll->bbox_left, iy + h, i - ir, 1, VD_MARG_COLOR);
|
|
|
566 |
code = LOOP_FILL_RECTANGLE_DIRECT(fo, ir + ll->bbox_left, iy + h, i - ir, 1);
|
|
|
567 |
if (code < 0)
|
|
|
568 |
return code;
|
|
|
569 |
}
|
|
|
570 |
init_section(sect, i0, i1);
|
|
|
571 |
return 0;
|
|
|
572 |
/*
|
|
|
573 |
* We added the ADJUST_SERIF feature for small fonts, which are poorly hinted.
|
|
|
574 |
* An example is 033-52-5873.pdf at 72 dpi.
|
|
|
575 |
* We either suppress a serif or move it up or down for 1 pixel.
|
|
|
576 |
* If we would paint it as an entire pixel where it occures, it looks too big
|
|
|
577 |
* relatively to the character size. Besides, a stem end may
|
|
|
578 |
* be placed a little bit below the baseline, and our dropout prevention
|
|
|
579 |
* method desides to paint a pixel below baseline, so that it looks
|
|
|
580 |
* fallen down (or fallen up in the case of character top).
|
|
|
581 |
*
|
|
|
582 |
* We assume that contacting margins are merged in margin_list.
|
|
|
583 |
* This implies that areas outside a margin are not painted
|
|
|
584 |
* (Only useful without CHECK_SPOT_CONTIGUITY).
|
|
|
585 |
*
|
|
|
586 |
* With no CHECK_SPOT_CONTIGUITY we can't perfectly handle the case when 2 serifs
|
|
|
587 |
* contact each another inside a margin interior (such as Serif 'n').
|
|
|
588 |
* Since we don't know the contiguty, we misrecognize them as a stem and
|
|
|
589 |
* leave them as they are (possibly still fallen down or up).
|
|
|
590 |
*
|
|
|
591 |
* CHECK_SPOT_CONTIGUITY computes the contiguity of the intersection of the spot
|
|
|
592 |
* and the section window. It allows to recognize contacting serifs properly.
|
|
|
593 |
*
|
|
|
594 |
* If a serif isn't painted with regular trapezoids,
|
|
|
595 |
* it appears a small one, so we don't need to measure its size.
|
|
|
596 |
* This heuristic isn't perfect, but it is very fast.
|
|
|
597 |
* Meanwhile with CHECK_SPOT_CONTIGUITY we actually have something
|
|
|
598 |
* like a bbox for a small serif, and a rough estimation is possible.
|
|
|
599 |
*
|
|
|
600 |
* We believe that in normal cases this stuff should work idle,
|
|
|
601 |
* because a perfect rendering should either use anti-aliasing
|
|
|
602 |
* (so that the character isn't small in the subpixel grid),
|
|
|
603 |
* and/or the path must be well fitted into the grid. So please consider
|
|
|
604 |
* this code as an attempt to do our best for the case of a
|
|
|
605 |
* non-well-setup rendering.
|
|
|
606 |
*/
|
|
|
607 |
}
|
|
|
608 |
|
|
|
609 |
int close_margins(gx_device * dev, line_list * ll, margin_set *ms)
|
|
|
610 |
{ margin *m = ms->margin_list;
|
|
|
611 |
int code;
|
|
|
612 |
|
|
|
613 |
for (; m != 0; m = m->next) {
|
|
|
614 |
code = fill_margin(dev, ll, ms, m->ibeg, m->iend);
|
|
|
615 |
if (code < 0)
|
|
|
616 |
return code;
|
|
|
617 |
}
|
|
|
618 |
release_margin_list(ll, ms);
|
|
|
619 |
return 0;
|
|
|
620 |
}
|
|
|
621 |
|
|
|
622 |
int start_margin_set(gx_device * dev, line_list * ll, fixed y0)
|
|
|
623 |
{ int code;
|
|
|
624 |
fixed ym = fixed_pixround(y0) - fixed_half;
|
|
|
625 |
margin_set s;
|
|
|
626 |
|
|
|
627 |
if (ll->margin_set0.y == ym)
|
|
|
628 |
return 0;
|
|
|
629 |
s = ll->margin_set1;
|
|
|
630 |
ll->margin_set1 = ll->margin_set0;
|
|
|
631 |
ll->margin_set0 = s;
|
|
|
632 |
code = close_margins(dev, ll, &ll->margin_set0);
|
|
|
633 |
ll->margin_set0.y = ym;
|
|
|
634 |
return code;
|
|
|
635 |
}
|
|
|
636 |
|
|
|
637 |
|
|
|
638 |
|