1 /*
2  * see COPYRIGHT
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <time.h>
12 #include <ctype.h>
13 #include <math.h>
14 
15 #ifndef WINDOWS
16 #	include <netinet/in.h>
17 #	include <unistd.h>
18 #else
19 #	include "windows.h"
20 #endif
21 
22 #include "ttf.h"
23 #include "pt1.h"
24 #include "global.h"
25 
26 /* big and small values for comparisons */
27 #define FBIGVAL	(1e20)
28 #define FEPS	(100000./FBIGVAL)
29 
30 /* names of the axes */
31 #define X	0
32 #define	Y	1
33 
34 /* the GENTRY extension structure used in fforceconcise() */
35 
36 struct gex_con {
37 	double d[2 /*X, Y*/]; /* sizes of curve */
38 	double sin2; /* squared sinus of the angle to the next gentry */
39 	double len2; /* squared distance between the endpoints */
40 
41 /* number of reference dots taken from each curve */
42 #define NREFDOTS	3
43 
44 	double dots[NREFDOTS][2]; /* reference dots */
45 
46 	int flags; /* flags for gentry and tits joint to the next gentry */
47 /* a vertical or horizontal line may be in 2 quadrants at once */
48 #define GEXF_QUL	0x00000001 /* in up-left quadrant */
49 #define GEXF_QUR	0x00000002 /* in up-right quadrant */
50 #define GEXF_QDR	0x00000004 /* in down-right quadrant */
51 #define GEXF_QDL	0x00000008 /* in down-left quadrant */
52 #define GEXF_QMASK	0x0000000F /* quadrant mask */
53 
54 /* if a line is nearly vertical or horizontal, we remember that idealized quartant too */
55 #define GEXF_QTO_IDEAL(f)	(((f)&0xF)<<4)
56 #define GEXF_QFROM_IDEAL(f)	(((f)&0xF0)>>4)
57 #define GEXF_IDQ_L	0x00000090 /* left */
58 #define GEXF_IDQ_R	0x00000060 /* right */
59 #define GEXF_IDQ_U	0x00000030 /* up */
60 #define GEXF_IDQ_D	0x000000C0 /* down */
61 
62 /* possibly can be joined with conditions:
63  * (in order of increasing preference, the numeric order is important)
64  */
65 #define GEXF_JLINE	0x00000100 /* into one line */
66 #define GEXF_JIGN	0x00000200 /* if one entry's tangent angle is ignored */
67 #define GEXF_JID	0x00000400 /* if one entry is idealized to hor/vert */
68 #define GEXF_JFLAT	0x00000800 /* if one entry is flattened */
69 #define GEXF_JGOOD	0x00001000 /* perfectly, no additional maodifications */
70 
71 #define GEXF_JMASK	0x00001F00 /* the mask of all above */
72 #define GEXF_JCVMASK	0x00001E00 /* the mask of all above except JLINE */
73 
74 /* which entry needs to be modified for conditional joining */
75 #define GEXF_JIGN1	0x00002000
76 #define GEXF_JIGN2	0x00004000
77 #define GEXF_JIGNDIR(dir)	(GEXF_JIGN1<<(dir))
78 #define GEXF_JID1	0x00008000
79 #define GEXF_JID2	0x00010000
80 #define GEXF_JIDDIR(dir)	(GEXF_JID1<<(dir))
81 #define GEXF_JFLAT1	0x00020000
82 #define GEXF_JFLAT2	0x00040000
83 #define GEXF_JFLATDIR(dir)	(GEXF_JFLAT1<<(dir))
84 
85 #define GEXF_VERT	0x00100000 /* is nearly vertical */
86 #define GEXF_HOR	0x00200000 /* is nearly horizontal */
87 #define GEXF_FLAT	0x00400000 /* is nearly flat */
88 
89 #define GEXF_VDOTS	0x01000000 /* the dots are valid */
90 
91 	signed char isd[2 /*X,Y*/]; /* signs of the sizes */
92 };
93 typedef struct gex_con GEX_CON;
94 
95 /* convenience macros */
96 #define	X_CON(ge)	((GEX_CON *)((ge)->ext))
97 #define X_CON_D(ge)	(X_CON(ge)->d)
98 #define X_CON_DX(ge)	(X_CON(ge)->d[0])
99 #define X_CON_DY(ge)	(X_CON(ge)->d[1])
100 #define X_CON_ISD(ge)	(X_CON(ge)->isd)
101 #define X_CON_ISDX(ge)	(X_CON(ge)->isd[0])
102 #define X_CON_ISDY(ge)	(X_CON(ge)->isd[1])
103 #define X_CON_SIN2(ge)	(X_CON(ge)->sin2)
104 #define X_CON_LEN2(ge)	(X_CON(ge)->len2)
105 #define X_CON_F(ge)	(X_CON(ge)->flags)
106 
107 /* performance statistics about guessing the concise curves */
108 static int ggoodcv=0, ggoodcvdots=0, gbadcv=0, gbadcvdots=0;
109 
110 int      stdhw, stdvw;	/* dominant stems widths */
111 int      stemsnaph[12], stemsnapv[12];	/* most typical stem width */
112 
113 int      bluevalues[14];
114 int      nblues;
115 int      otherblues[10];
116 int      notherb;
117 int      bbox[4];	/* the FontBBox array */
118 double   italic_angle;
119 
120 GLYPH   *glyph_list;
121 int    encoding[ENCTABSZ];	/* inverse of glyph[].char_no */
122 int    kerning_pairs = 0;
123 
124 /* prototypes */
125 static void fixcvdir( GENTRY * ge, int dir);
126 static void fixcvends( GENTRY * ge);
127 static int fgetcvdir( GENTRY * ge);
128 static int igetcvdir( GENTRY * ge);
129 static int fiszigzag( GENTRY *ge);
130 static int iiszigzag( GENTRY *ge);
131 static GENTRY * freethisge( GENTRY *ge);
132 static void addgeafter( GENTRY *oge, GENTRY *nge );
133 static GENTRY * newgentry( int flags);
134 static void debugstems( char *name, STEM * hstems, int nhs, STEM * vstems, int nvs);
135 static int addbluestems( STEM *s, int n);
136 static void sortstems( STEM * s, int n);
137 static int stemoverlap( STEM * s1, STEM * s2);
138 static int steminblue( STEM *s);
139 static void markbluestems( STEM *s, int nold);
140 static int joinmainstems( STEM * s, int nold, int useblues);
141 static void joinsubstems( STEM * s, short *pairs, int nold, int useblues);
142 static void fixendpath( GENTRY *ge);
143 static void fdelsmall( GLYPH *g, double minlen);
144 static void alloc_gex_con( GENTRY *ge);
145 static double fjointsin2( GENTRY *ge1, GENTRY *ge2);
146 static double fcvarea( GENTRY *ge);
147 static double fcvval( GENTRY *ge, int axis, double t);
148 static void fsampledots( GENTRY *ge, double dots[][2], int ndots);
149 static void fnormalizege( GENTRY *ge);
150 static void fanalyzege( GENTRY *ge);
151 static void fanalyzejoint( GENTRY *ge);
152 static void fconcisecontour( GLYPH *g, GENTRY *ge);
153 static double fclosegap( GENTRY *from, GENTRY *to, int axis,
154 	double gap, double *ret);
155 
156 int
isign(int x)157 isign(
158      int x
159 )
160 {
161 	if (x > 0)
162 		return 1;
163 	else if (x < 0)
164 		return -1;
165 	else
166 		return 0;
167 }
168 
169 int
fsign(double x)170 fsign(
171      double x
172 )
173 {
174 	if (x > 0.0)
175 		return 1;
176 	else if (x < 0.0)
177 		return -1;
178 	else
179 		return 0;
180 }
181 
182 static GENTRY *
newgentry(int flags)183 newgentry(
184 	int flags
185 )
186 {
187 	GENTRY         *ge;
188 
189 	ge = calloc(1, sizeof(GENTRY));
190 
191 	if (ge == 0) {
192 		fprintf(stderr, "***** Memory allocation error *****\n");
193 		exit(255);
194 	}
195 	ge->stemid = -1;
196 	ge->flags = flags;
197 	/* the rest is set to 0 by calloc() */
198 	return ge;
199 }
200 
201 /*
202  * Routines to print out Postscript functions with optimization
203  */
204 
205 void
rmoveto(int dx,int dy)206 rmoveto(
207 	int dx,
208 	int dy
209 )
210 {
211 	if (optimize && dx == 0)
212 		fprintf(pfa_file, "%d vmoveto\n", dy);
213 	else if (optimize && dy == 0)
214 		fprintf(pfa_file, "%d hmoveto\n", dx);
215 	else
216 		fprintf(pfa_file, "%d %d rmoveto\n", dx, dy);
217 }
218 
219 void
rlineto(int dx,int dy)220 rlineto(
221 	int dx,
222 	int dy
223 )
224 {
225 	if (optimize && dx == 0 && dy == 0)	/* for special pathologic
226 						 * case */
227 		return;
228 	else if (optimize && dx == 0)
229 		fprintf(pfa_file, "%d vlineto\n", dy);
230 	else if (optimize && dy == 0)
231 		fprintf(pfa_file, "%d hlineto\n", dx);
232 	else
233 		fprintf(pfa_file, "%d %d rlineto\n", dx, dy);
234 }
235 
236 void
rrcurveto(int dx1,int dy1,int dx2,int dy2,int dx3,int dy3)237 rrcurveto(
238 	  int dx1,
239 	  int dy1,
240 	  int dx2,
241 	  int dy2,
242 	  int dx3,
243 	  int dy3
244 )
245 {
246 	/* first two ifs are for crazy cases that occur surprisingly often */
247 	if (optimize && dx1 == 0 && dx2 == 0 && dx3 == 0)
248 		rlineto(0, dy1 + dy2 + dy3);
249 	else if (optimize && dy1 == 0 && dy2 == 0 && dy3 == 0)
250 		rlineto(dx1 + dx2 + dx3, 0);
251 	else if (optimize && dy1 == 0 && dx3 == 0)
252 		fprintf(pfa_file, "%d %d %d %d hvcurveto\n",
253 			dx1, dx2, dy2, dy3);
254 	else if (optimize && dx1 == 0 && dy3 == 0)
255 		fprintf(pfa_file, "%d %d %d %d vhcurveto\n",
256 			dy1, dx2, dy2, dx3);
257 	else
258 		fprintf(pfa_file, "%d %d %d %d %d %d rrcurveto\n",
259 			dx1, dy1, dx2, dy2, dx3, dy3);
260 }
261 
262 void
closepath(void)263 closepath(void)
264 {
265 	fprintf(pfa_file, "closepath\n");
266 }
267 
268 /*
269  * Many of the path processing routines exist (or will exist) in
270  * both floating-point and integer version. Fimally most of the
271  * processing will go in floating point and the integer processing
272  * will become legacy.
273  * The names of floating routines start with f, names of integer
274  * routines start with i, and those old routines existing in one
275  * version only have no such prefix at all.
276  */
277 
278 /*
279 ** Routine that checks integrity of the path, for debugging
280 */
281 
282 void
assertpath(GENTRY * from,char * file,int line,char * name)283 assertpath(
284 	   GENTRY * from,
285 	   char *file,
286 	   int line,
287 	   char *name
288 )
289 {
290 	GENTRY         *first, *pe, *ge;
291 	int	isfloat;
292 
293 	if(from==0)
294 		return;
295 	isfloat = (from->flags & GEF_FLOAT);
296 	pe = from->prev;
297 	for (ge = from; ge != 0; pe = ge, ge = ge->next) {
298 		if( (ge->flags & GEF_FLOAT) ^ isfloat ) {
299 			fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
300 			fprintf(stderr, "float flag changes from %s to %s at 0x%p (type %c, prev type %c)\n",
301 				(isfloat ? "TRUE" : "FALSE"), (isfloat ? "FALSE" : "TRUE"), ge, ge->type, pe->type);
302 			abort();
303 		}
304 		if (pe != ge->prev) {
305 			fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
306 			fprintf(stderr, "unidirectional chain 0x%x -next-> 0x%x -prev-> 0x%x \n",
307 				pe, ge, ge->prev);
308 			abort();
309 		}
310 
311 		switch(ge->type) {
312 		case GE_MOVE:
313 			break;
314 		case GE_PATH:
315 			if (ge->prev == 0) {
316 				fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
317 				fprintf(stderr, "empty path at 0x%x \n", ge);
318 				abort();
319 			}
320 			break;
321 		case GE_LINE:
322 		case GE_CURVE:
323 			if(ge->frwd->bkwd != ge) {
324 				fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
325 				fprintf(stderr, "unidirectional chain 0x%x -frwd-> 0x%x -bkwd-> 0x%x \n",
326 					ge, ge->frwd, ge->frwd->bkwd);
327 				abort();
328 			}
329 			if(ge->prev->type == GE_MOVE) {
330 				first = ge;
331 				if(ge->bkwd->next->type != GE_PATH) {
332 					fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
333 					fprintf(stderr, "broken first backlink 0x%x -bkwd-> 0x%x -next-> 0x%x \n",
334 						ge, ge->bkwd, ge->bkwd->next);
335 					abort();
336 				}
337 			}
338 			if(ge->next->type == GE_PATH) {
339 				if(ge->frwd != first) {
340 					fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
341 					fprintf(stderr, "broken loop 0x%x -...-> 0x%x -frwd-> 0x%x \n",
342 						first, ge, ge->frwd);
343 					abort();
344 				}
345 			}
346 			break;
347 		}
348 
349 	}
350 }
351 
352 void
assertisfloat(GLYPH * g,char * msg)353 assertisfloat(
354 	GLYPH *g,
355 	char *msg
356 )
357 {
358 	if( !(g->flags & GF_FLOAT) ) {
359 		fprintf(stderr, "**! Glyph %s is not float: %s\n", g->name, msg);
360 		abort();
361 	}
362 	if(g->lastentry) {
363 		if( !(g->lastentry->flags & GEF_FLOAT) ) {
364 			fprintf(stderr, "**! Glyphs %s last entry is int: %s\n", g->name, msg);
365 			abort();
366 		}
367 	}
368 }
369 
370 void
assertisint(GLYPH * g,char * msg)371 assertisint(
372 	GLYPH *g,
373 	char *msg
374 )
375 {
376 	if( (g->flags & GF_FLOAT) ) {
377 		fprintf(stderr, "**! Glyph %s is not int: %s\n", g->name, msg);
378 		abort();
379 	}
380 	if(g->lastentry) {
381 		if( (g->lastentry->flags & GEF_FLOAT) ) {
382 			fprintf(stderr, "**! Glyphs %s last entry is float: %s\n", g->name, msg);
383 			abort();
384 		}
385 	}
386 }
387 
388 
389 /*
390  * Routines to save the generated data about glyph
391  */
392 
393 void
fg_rmoveto(GLYPH * g,double x,double y)394 fg_rmoveto(
395 	  GLYPH * g,
396 	  double x,
397 	  double y)
398 {
399 	GENTRY         *oge;
400 
401 	if (ISDBG(BUILDG))
402 		fprintf(stderr, "%s: f rmoveto(%g, %g)\n", g->name, x, y);
403 
404 	assertisfloat(g, "adding float MOVE");
405 
406 	if ((oge = g->lastentry) != 0) {
407 		if (oge->type == GE_MOVE) {	/* just eat up the first move */
408 			oge->fx3 = x;
409 			oge->fy3 = y;
410 		} else if (oge->type == GE_LINE || oge->type == GE_CURVE) {
411 			fprintf(stderr, "Glyph %s: MOVE in middle of path\n", g->name);
412 		} else {
413 			GENTRY         *nge;
414 
415 			nge = newgentry(GEF_FLOAT);
416 			nge->type = GE_MOVE;
417 			nge->fx3 = x;
418 			nge->fy3 = y;
419 
420 			oge->next = nge;
421 			nge->prev = oge;
422 			g->lastentry = nge;
423 		}
424 	} else {
425 		GENTRY         *nge;
426 
427 		nge = newgentry(GEF_FLOAT);
428 		nge->type = GE_MOVE;
429 		nge->fx3 = x;
430 		nge->fy3 = y;
431 		nge->bkwd = (GENTRY*)&g->entries;
432 		g->entries = g->lastentry = nge;
433 	}
434 
435 	if (0 && ISDBG(BUILDG))
436 		dumppaths(g, NULL, NULL);
437 }
438 
439 void
ig_rmoveto(GLYPH * g,int x,int y)440 ig_rmoveto(
441 	  GLYPH * g,
442 	  int x,
443 	  int y)
444 {
445 	GENTRY         *oge;
446 
447 	if (ISDBG(BUILDG))
448 		fprintf(stderr, "%s: i rmoveto(%d, %d)\n", g->name, x, y);
449 
450 	assertisint(g, "adding int MOVE");
451 
452 	if ((oge = g->lastentry) != 0) {
453 		if (oge->type == GE_MOVE) {	/* just eat up the first move */
454 			oge->ix3 = x;
455 			oge->iy3 = y;
456 		} else if (oge->type == GE_LINE || oge->type == GE_CURVE) {
457 			fprintf(stderr, "Glyph %s: MOVE in middle of path, ignored\n", g->name);
458 		} else {
459 			GENTRY         *nge;
460 
461 			nge = newgentry(0);
462 			nge->type = GE_MOVE;
463 			nge->ix3 = x;
464 			nge->iy3 = y;
465 
466 			oge->next = nge;
467 			nge->prev = oge;
468 			g->lastentry = nge;
469 		}
470 	} else {
471 		GENTRY         *nge;
472 
473 		nge = newgentry(0);
474 		nge->type = GE_MOVE;
475 		nge->ix3 = x;
476 		nge->iy3 = y;
477 		nge->bkwd = (GENTRY*)&g->entries;
478 		g->entries = g->lastentry = nge;
479 	}
480 
481 }
482 
483 void
fg_rlineto(GLYPH * g,double x,double y)484 fg_rlineto(
485 	  GLYPH * g,
486 	  double x,
487 	  double y)
488 {
489 	GENTRY         *oge, *nge;
490 
491 	if (ISDBG(BUILDG))
492 		fprintf(stderr, "%s: f rlineto(%g, %g)\n", g->name, x, y);
493 
494 	assertisfloat(g, "adding float LINE");
495 
496 	nge = newgentry(GEF_FLOAT);
497 	nge->type = GE_LINE;
498 	nge->fx3 = x;
499 	nge->fy3 = y;
500 
501 	if ((oge = g->lastentry) != 0) {
502 		if (x == oge->fx3 && y == oge->fy3) {	/* empty line */
503 			/* ignore it or we will get in troubles later */
504 			free(nge);
505 			return;
506 		}
507 		if (g->path == 0) {
508 			g->path = nge;
509 			nge->bkwd = nge->frwd = nge;
510 		} else {
511 			oge->frwd = nge;
512 			nge->bkwd = oge;
513 			g->path->bkwd = nge;
514 			nge->frwd = g->path;
515 		}
516 
517 		oge->next = nge;
518 		nge->prev = oge;
519 		g->lastentry = nge;
520 	} else {
521 		WARNING_1 fprintf(stderr, "Glyph %s: LINE outside of path\n", g->name);
522 		free(nge);
523 	}
524 
525 	if (0 && ISDBG(BUILDG))
526 		dumppaths(g, NULL, NULL);
527 }
528 
529 void
ig_rlineto(GLYPH * g,int x,int y)530 ig_rlineto(
531 	  GLYPH * g,
532 	  int x,
533 	  int y)
534 {
535 	GENTRY         *oge, *nge;
536 
537 	if (ISDBG(BUILDG))
538 		fprintf(stderr, "%s: i rlineto(%d, %d)\n", g->name, x, y);
539 
540 	assertisint(g, "adding int LINE");
541 
542 	nge = newgentry(0);
543 	nge->type = GE_LINE;
544 	nge->ix3 = x;
545 	nge->iy3 = y;
546 
547 	if ((oge = g->lastentry) != 0) {
548 		if (x == oge->ix3 && y == oge->iy3) {	/* empty line */
549 			/* ignore it or we will get in troubles later */
550 			free(nge);
551 			return;
552 		}
553 		if (g->path == 0) {
554 			g->path = nge;
555 			nge->bkwd = nge->frwd = nge;
556 		} else {
557 			oge->frwd = nge;
558 			nge->bkwd = oge;
559 			g->path->bkwd = nge;
560 			nge->frwd = g->path;
561 		}
562 
563 		oge->next = nge;
564 		nge->prev = oge;
565 		g->lastentry = nge;
566 	} else {
567 		WARNING_1 fprintf(stderr, "Glyph %s: LINE outside of path\n", g->name);
568 		free(nge);
569 	}
570 
571 }
572 
573 void
fg_rrcurveto(GLYPH * g,double x1,double y1,double x2,double y2,double x3,double y3)574 fg_rrcurveto(
575 	    GLYPH * g,
576 	    double x1,
577 	    double y1,
578 	    double x2,
579 	    double y2,
580 	    double x3,
581 	    double y3)
582 {
583 	GENTRY         *oge, *nge;
584 
585 	oge = g->lastentry;
586 
587 	if (ISDBG(BUILDG))
588 		fprintf(stderr, "%s: f rrcurveto(%g, %g, %g, %g, %g, %g)\n"
589 			,g->name, x1, y1, x2, y2, x3, y3);
590 
591 	assertisfloat(g, "adding float CURVE");
592 
593 	if (oge && oge->fx3 == x1 && x1 == x2 && x2 == x3)	/* check if it's
594 								 * actually a line */
595 		fg_rlineto(g, x1, y3);
596 	else if (oge && oge->fy3 == y1 && y1 == y2 && y2 == y3)
597 		fg_rlineto(g, x3, y1);
598 	else {
599 		nge = newgentry(GEF_FLOAT);
600 		nge->type = GE_CURVE;
601 		nge->fx1 = x1;
602 		nge->fy1 = y1;
603 		nge->fx2 = x2;
604 		nge->fy2 = y2;
605 		nge->fx3 = x3;
606 		nge->fy3 = y3;
607 
608 		if (oge != 0) {
609 			if (x3 == oge->fx3 && y3 == oge->fy3) {
610 				free(nge);	/* consider this curve empty */
611 				/* ignore it or we will get in troubles later */
612 				return;
613 			}
614 			if (g->path == 0) {
615 				g->path = nge;
616 				nge->bkwd = nge->frwd = nge;
617 			} else {
618 				oge->frwd = nge;
619 				nge->bkwd = oge;
620 				g->path->bkwd = nge;
621 				nge->frwd = g->path;
622 			}
623 
624 			oge->next = nge;
625 			nge->prev = oge;
626 			g->lastentry = nge;
627 		} else {
628 			WARNING_1 fprintf(stderr, "Glyph %s: CURVE outside of path\n", g->name);
629 			free(nge);
630 		}
631 	}
632 
633 	if (0 && ISDBG(BUILDG))
634 		dumppaths(g, NULL, NULL);
635 }
636 
637 void
ig_rrcurveto(GLYPH * g,int x1,int y1,int x2,int y2,int x3,int y3)638 ig_rrcurveto(
639 	    GLYPH * g,
640 	    int x1,
641 	    int y1,
642 	    int x2,
643 	    int y2,
644 	    int x3,
645 	    int y3)
646 {
647 	GENTRY         *oge, *nge;
648 
649 	oge = g->lastentry;
650 
651 	if (ISDBG(BUILDG))
652 		fprintf(stderr, "%s: i rrcurveto(%d, %d, %d, %d, %d, %d)\n"
653 			,g->name, x1, y1, x2, y2, x3, y3);
654 
655 	assertisint(g, "adding int CURVE");
656 
657 	if (oge && oge->ix3 == x1 && x1 == x2 && x2 == x3)	/* check if it's
658 								 * actually a line */
659 		ig_rlineto(g, x1, y3);
660 	else if (oge && oge->iy3 == y1 && y1 == y2 && y2 == y3)
661 		ig_rlineto(g, x3, y1);
662 	else {
663 		nge = newgentry(0);
664 		nge->type = GE_CURVE;
665 		nge->ix1 = x1;
666 		nge->iy1 = y1;
667 		nge->ix2 = x2;
668 		nge->iy2 = y2;
669 		nge->ix3 = x3;
670 		nge->iy3 = y3;
671 
672 		if (oge != 0) {
673 			if (x3 == oge->ix3 && y3 == oge->iy3) {
674 				free(nge);	/* consider this curve empty */
675 				/* ignore it or we will get in troubles later */
676 				return;
677 			}
678 			if (g->path == 0) {
679 				g->path = nge;
680 				nge->bkwd = nge->frwd = nge;
681 			} else {
682 				oge->frwd = nge;
683 				nge->bkwd = oge;
684 				g->path->bkwd = nge;
685 				nge->frwd = g->path;
686 			}
687 
688 			oge->next = nge;
689 			nge->prev = oge;
690 			g->lastentry = nge;
691 		} else {
692 			WARNING_1 fprintf(stderr, "Glyph %s: CURVE outside of path\n", g->name);
693 			free(nge);
694 		}
695 	}
696 }
697 
698 void
g_closepath(GLYPH * g)699 g_closepath(
700 	    GLYPH * g
701 )
702 {
703 	GENTRY         *oge, *nge;
704 
705 	if (ISDBG(BUILDG))
706 		fprintf(stderr, "%s: closepath\n", g->name);
707 
708 	oge = g->lastentry;
709 
710 	if (g->path == 0) {
711 		WARNING_1 fprintf(stderr, "Warning: **** closepath on empty path in glyph \"%s\" ****\n",
712 			g->name);
713 		if (oge == 0) {
714 			WARNING_1 fprintf(stderr, "No previois entry\n");
715 		} else {
716 			WARNING_1 fprintf(stderr, "Previous entry type: %c\n", oge->type);
717 			if (oge->type == GE_MOVE) {
718 				g->lastentry = oge->prev;
719 				if (oge->prev == 0)
720 					g->entries = 0;
721 				else
722 					g->lastentry->next = 0;
723 				free(oge);
724 			}
725 		}
726 		return;
727 	}
728 
729 	nge = newgentry(oge->flags & GEF_FLOAT); /* keep the same type */
730 	nge->type = GE_PATH;
731 
732 	g->path = 0;
733 
734 	oge->next = nge;
735 	nge->prev = oge;
736 	g->lastentry = nge;
737 
738 	if (0 && ISDBG(BUILDG))
739 		dumppaths(g, NULL, NULL);
740 }
741 
742 /*
743  * * SB * Routines to smooth and fix the glyphs
744  */
745 
746 /*
747 ** we don't want to see the curves with coinciding middle and
748 ** outer points
749 */
750 
751 static void
fixcvends(GENTRY * ge)752 fixcvends(
753 	  GENTRY * ge
754 )
755 {
756 	int             dx, dy;
757 	int             x0, y0, x1, y1, x2, y2, x3, y3;
758 
759 	if (ge->type != GE_CURVE)
760 		return;
761 
762 	if(ge->flags & GEF_FLOAT) {
763 		fprintf(stderr, "**! fixcvends(0x%x) on floating entry, ABORT\n", ge);
764 		abort(); /* dump core */
765 	}
766 
767 	x0 = ge->prev->ix3;
768 	y0 = ge->prev->iy3;
769 	x1 = ge->ix1;
770 	y1 = ge->iy1;
771 	x2 = ge->ix2;
772 	y2 = ge->iy2;
773 	x3 = ge->ix3;
774 	y3 = ge->iy3;
775 
776 
777 	/* look at the start of the curve */
778 	if (x1 == x0 && y1 == y0) {
779 		dx = x2 - x1;
780 		dy = y2 - y1;
781 
782 		if (dx == 0 && dy == 0
783 		    || x2 == x3 && y2 == y3) {
784 			/* Oops, we actually have a straight line */
785 			/*
786 			 * if it's small, we hope that it will get optimized
787 			 * later
788 			 */
789 			if (abs(x3 - x0) <= 2 || abs(y3 - y0) <= 2) {
790 				ge->ix1 = x3;
791 				ge->iy1 = y3;
792 				ge->ix2 = x0;
793 				ge->iy2 = y0;
794 			} else {/* just make it a line */
795 				ge->type = GE_LINE;
796 			}
797 		} else {
798 			if (abs(dx) < 4 && abs(dy) < 4) {	/* consider it very
799 								 * small */
800 				ge->ix1 = x2;
801 				ge->iy1 = y2;
802 			} else if (abs(dx) < 8 && abs(dy) < 8) {	/* consider it small */
803 				ge->ix1 += dx / 2;
804 				ge->iy1 += dy / 2;
805 			} else {
806 				ge->ix1 += dx / 4;
807 				ge->iy1 += dy / 4;
808 			}
809 			/* make sure that it's still on the same side */
810 			if (abs(x3 - x0) * abs(dy) < abs(y3 - y0) * abs(dx)) {
811 				if (abs(x3 - x0) * abs(ge->iy1 - y0) > abs(y3 - y0) * abs(ge->ix1 - x0))
812 					ge->ix1 += isign(dx);
813 			} else {
814 				if (abs(x3 - x0) * abs(ge->iy1 - y0) < abs(y3 - y0) * abs(ge->ix1 - x0))
815 					ge->iy1 += isign(dy);
816 			}
817 
818 			ge->ix2 += (x3 - x2) / 8;
819 			ge->iy2 += (y3 - y2) / 8;
820 			/* make sure that it's still on the same side */
821 			if (abs(x3 - x0) * abs(y3 - y2) < abs(y3 - y0) * abs(x3 - x2)) {
822 				if (abs(x3 - x0) * abs(y3 - ge->iy2) > abs(y3 - y0) * abs(x3 - ge->ix2))
823 					ge->iy1 -= isign(y3 - y2);
824 			} else {
825 				if (abs(x3 - x0) * abs(y3 - ge->iy2) < abs(y3 - y0) * abs(x3 - ge->ix2))
826 					ge->ix1 -= isign(x3 - x2);
827 			}
828 
829 		}
830 	} else if (x2 == x3 && y2 == y3) {
831 		dx = x1 - x2;
832 		dy = y1 - y2;
833 
834 		if (dx == 0 && dy == 0) {
835 			/* Oops, we actually have a straight line */
836 			/*
837 			 * if it's small, we hope that it will get optimized
838 			 * later
839 			 */
840 			if (abs(x3 - x0) <= 2 || abs(y3 - y0) <= 2) {
841 				ge->ix1 = x3;
842 				ge->iy1 = y3;
843 				ge->ix2 = x0;
844 				ge->iy2 = y0;
845 			} else {/* just make it a line */
846 				ge->type = GE_LINE;
847 			}
848 		} else {
849 			if (abs(dx) < 4 && abs(dy) < 4) {	/* consider it very
850 								 * small */
851 				ge->ix2 = x1;
852 				ge->iy2 = y1;
853 			} else if (abs(dx) < 8 && abs(dy) < 8) {	/* consider it small */
854 				ge->ix2 += dx / 2;
855 				ge->iy2 += dy / 2;
856 			} else {
857 				ge->ix2 += dx / 4;
858 				ge->iy2 += dy / 4;
859 			}
860 			/* make sure that it's still on the same side */
861 			if (abs(x3 - x0) * abs(dy) < abs(y3 - y0) * abs(dx)) {
862 				if (abs(x3 - x0) * abs(ge->iy2 - y3) > abs(y3 - y0) * abs(ge->ix2 - x3))
863 					ge->ix2 += isign(dx);
864 			} else {
865 				if (abs(x3 - x0) * abs(ge->iy2 - y3) < abs(y3 - y0) * abs(ge->ix2 - x3))
866 					ge->iy2 += isign(dy);
867 			}
868 
869 			ge->ix1 += (x0 - x1) / 8;
870 			ge->iy1 += (y0 - y1) / 8;
871 			/* make sure that it's still on the same side */
872 			if (abs(x3 - x0) * abs(y0 - y1) < abs(y3 - y0) * abs(x0 - x1)) {
873 				if (abs(x3 - x0) * abs(y0 - ge->iy1) > abs(y3 - y0) * abs(x0 - ge->ix1))
874 					ge->iy1 -= isign(y0 - y1);
875 			} else {
876 				if (abs(x3 - x0) * abs(y0 - ge->iy1) < abs(y3 - y0) * abs(x0 - ge->ix1))
877 					ge->ix1 -= isign(x0 - x1);
878 			}
879 
880 		}
881 	}
882 }
883 
884 /*
885 ** After transformations we want to make sure that the resulting
886 ** curve is going in the same quadrant as the original one,
887 ** because rounding errors introduced during transformations
888 ** may make the result completeley wrong.
889 **
890 ** `dir' argument describes the direction of the original curve,
891 ** it is the superposition of two values for the front and
892 ** rear ends of curve:
893 **
894 ** >EQUAL - goes over the line connecting the ends
895 ** =EQUAL - coincides with the line connecting the ends
896 ** <EQUAL - goes under the line connecting the ends
897 **
898 ** See CVDIR_* for exact definitions.
899 */
900 
901 static void
fixcvdir(GENTRY * ge,int dir)902 fixcvdir(
903 	 GENTRY * ge,
904 	 int dir
905 )
906 {
907 	int             a, b, c, d;
908 	double          kk, kk1, kk2;
909 	int             changed;
910 	int             fdir, rdir;
911 
912 	if(ge->flags & GEF_FLOAT) {
913 		fprintf(stderr, "**! fixcvdir(0x%x) on floating entry, ABORT\n", ge);
914 		abort(); /* dump core */
915 	}
916 
917 	fdir = (dir & CVDIR_FRONT) - CVDIR_FEQUAL;
918 	if ((dir & CVDIR_REAR) == CVDIR_RSAME)
919 		rdir = fdir; /* we need only isign, exact value doesn't matter */
920 	else
921 		rdir = (dir & CVDIR_REAR) - CVDIR_REQUAL;
922 
923 	fixcvends(ge);
924 
925 	c = isign(ge->ix3 - ge->prev->ix3);	/* note the direction of
926 						 * curve */
927 	d = isign(ge->iy3 - ge->prev->iy3);
928 
929 	a = ge->iy3 - ge->prev->iy3;
930 	b = ge->ix3 - ge->prev->ix3;
931 	kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
932 	a = ge->iy1 - ge->prev->iy3;
933 	b = ge->ix1 - ge->prev->ix3;
934 	kk1 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
935 	a = ge->iy3 - ge->iy2;
936 	b = ge->ix3 - ge->ix2;
937 	kk2 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
938 
939 	changed = 1;
940 	while (changed) {
941 		if (ISDBG(FIXCVDIR)) {
942 			/* for debugging */
943 			fprintf(stderr, "fixcvdir %d %d (%d %d %d %d %d %d) %f %f %f\n",
944 				fdir, rdir,
945 				ge->ix1 - ge->prev->ix3,
946 				ge->iy1 - ge->prev->iy3,
947 				ge->ix2 - ge->ix1,
948 				ge->iy2 - ge->iy1,
949 				ge->ix3 - ge->ix2,
950 				ge->iy3 - ge->iy2,
951 				kk1, kk, kk2);
952 		}
953 		changed = 0;
954 
955 		if (fdir > 0) {
956 			if (kk1 > kk) {	/* the front end has problems */
957 				if (c * (ge->ix1 - ge->prev->ix3) > 0) {
958 					ge->ix1 -= c;
959 					changed = 1;
960 				} if (d * (ge->iy2 - ge->iy1) > 0) {
961 					ge->iy1 += d;
962 					changed = 1;
963 				}
964 				/* recalculate the coefficients */
965 				a = ge->iy3 - ge->prev->iy3;
966 				b = ge->ix3 - ge->prev->ix3;
967 				kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
968 				a = ge->iy1 - ge->prev->iy3;
969 				b = ge->ix1 - ge->prev->ix3;
970 				kk1 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
971 			}
972 		} else if (fdir < 0) {
973 			if (kk1 < kk) {	/* the front end has problems */
974 				if (c * (ge->ix2 - ge->ix1) > 0) {
975 					ge->ix1 += c;
976 					changed = 1;
977 				} if (d * (ge->iy1 - ge->prev->iy3) > 0) {
978 					ge->iy1 -= d;
979 					changed = 1;
980 				}
981 				/* recalculate the coefficients */
982 				a = ge->iy1 - ge->prev->iy3;
983 				b = ge->ix1 - ge->prev->ix3;
984 				kk1 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
985 				a = ge->iy3 - ge->prev->iy3;
986 				b = ge->ix3 - ge->prev->ix3;
987 				kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
988 			}
989 		}
990 		if (rdir > 0) {
991 			if (kk2 < kk) {	/* the rear end has problems */
992 				if (c * (ge->ix2 - ge->ix1) > 0) {
993 					ge->ix2 -= c;
994 					changed = 1;
995 				} if (d * (ge->iy3 - ge->iy2) > 0) {
996 					ge->iy2 += d;
997 					changed = 1;
998 				}
999 				/* recalculate the coefficients */
1000 				a = ge->iy3 - ge->prev->iy3;
1001 				b = ge->ix3 - ge->prev->ix3;
1002 				kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1003 				a = ge->iy3 - ge->iy2;
1004 				b = ge->ix3 - ge->ix2;
1005 				kk2 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1006 			}
1007 		} else if (rdir < 0) {
1008 			if (kk2 > kk) {	/* the rear end has problems */
1009 				if (c * (ge->ix3 - ge->ix2) > 0) {
1010 					ge->ix2 += c;
1011 					changed = 1;
1012 				} if (d * (ge->iy2 - ge->iy1) > 0) {
1013 					ge->iy2 -= d;
1014 					changed = 1;
1015 				}
1016 				/* recalculate the coefficients */
1017 				a = ge->iy3 - ge->prev->iy3;
1018 				b = ge->ix3 - ge->prev->ix3;
1019 				kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1020 				a = ge->iy3 - ge->iy2;
1021 				b = ge->ix3 - ge->ix2;
1022 				kk2 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1023 			}
1024 		}
1025 	}
1026 	fixcvends(ge);
1027 }
1028 
1029 /* Get the directions of ends of curve for further usage */
1030 
1031 /* expects that the previous element is also float */
1032 
1033 static int
fgetcvdir(GENTRY * ge)1034 fgetcvdir(
1035 	 GENTRY * ge
1036 )
1037 {
1038 	double          a, b;
1039 	double          k, k1, k2;
1040 	int             dir = 0;
1041 
1042 	if( !(ge->flags & GEF_FLOAT) ) {
1043 		fprintf(stderr, "**! fgetcvdir(0x%x) on int entry, ABORT\n", ge);
1044 		abort(); /* dump core */
1045 	}
1046 
1047 	a = fabs(ge->fy3 - ge->prev->fy3);
1048 	b = fabs(ge->fx3 - ge->prev->fx3);
1049 	k = a < FEPS ? (b < FEPS ? 1. : 100000.) : ( b / a);
1050 
1051 	a = fabs(ge->fy1 - ge->prev->fy3);
1052 	b = fabs(ge->fx1 - ge->prev->fx3);
1053 	if(a < FEPS) {
1054 		if(b < FEPS) {
1055 			a = fabs(ge->fy2 - ge->prev->fy3);
1056 			b = fabs(ge->fx2 - ge->prev->fx3);
1057 			k1 = a < FEPS ? (b < FEPS ? k : 100000.) : ( b / a);
1058 		} else
1059 			k1 = FBIGVAL;
1060 	} else
1061 		k1 = b / a;
1062 
1063 	a = fabs(ge->fy3 - ge->fy2);
1064 	b = fabs(ge->fx3 - ge->fx2);
1065 	if(a < FEPS) {
1066 		if(b < FEPS) {
1067 			a = fabs(ge->fy3 - ge->fy1);
1068 			b = fabs(ge->fx3 - ge->fx1);
1069 			k2 = a < FEPS ? (b < FEPS ? k : 100000.) : ( b / a);
1070 		} else
1071 			k2 = FBIGVAL;
1072 	} else
1073 		k2 = b / a;
1074 
1075 	if(fabs(k1-k) < 0.0001)
1076 		dir |= CVDIR_FEQUAL;
1077 	else if (k1 < k)
1078 		dir |= CVDIR_FUP;
1079 	else
1080 		dir |= CVDIR_FDOWN;
1081 
1082 	if(fabs(k2-k) < 0.0001)
1083 		dir |= CVDIR_REQUAL;
1084 	else if (k2 > k)
1085 		dir |= CVDIR_RUP;
1086 	else
1087 		dir |= CVDIR_RDOWN;
1088 
1089 	return dir;
1090 }
1091 
1092 
1093 /* expects that the previous element is also int */
1094 
1095 static int
igetcvdir(GENTRY * ge)1096 igetcvdir(
1097 	 GENTRY * ge
1098 )
1099 {
1100 	int             a, b;
1101 	double          k, k1, k2;
1102 	int             dir = 0;
1103 
1104 	if(ge->flags & GEF_FLOAT) {
1105 		fprintf(stderr, "**! igetcvdir(0x%x) on floating entry, ABORT\n", ge);
1106 		abort(); /* dump core */
1107 	}
1108 
1109 	a = ge->iy3 - ge->prev->iy3;
1110 	b = ge->ix3 - ge->prev->ix3;
1111 	k = (a == 0) ? (b == 0 ? 1. : 100000.) : fabs((double) b / (double) a);
1112 
1113 	a = ge->iy1 - ge->prev->iy3;
1114 	b = ge->ix1 - ge->prev->ix3;
1115 	if(a == 0) {
1116 		if(b == 0) {
1117 			a = ge->iy2 - ge->prev->iy3;
1118 			b = ge->ix2 - ge->prev->ix3;
1119 			k1 = (a == 0) ? (b == 0 ? k : 100000.) : fabs((double) b / (double) a);
1120 		} else
1121 			k1 = FBIGVAL;
1122 	} else
1123 		k1 = fabs((double) b / (double) a);
1124 
1125 	a = ge->iy3 - ge->iy2;
1126 	b = ge->ix3 - ge->ix2;
1127 	if(a == 0) {
1128 		if(b == 0) {
1129 			a = ge->iy3 - ge->iy1;
1130 			b = ge->ix3 - ge->ix1;
1131 			k2 = (a == 0) ? (b == 0 ? k : 100000.) : fabs((double) b / (double) a);
1132 		} else
1133 			k2 = FBIGVAL;
1134 	} else
1135 		k2 = fabs((double) b / (double) a);
1136 
1137 	if(fabs(k1-k) < 0.0001)
1138 		dir |= CVDIR_FEQUAL;
1139 	else if (k1 < k)
1140 		dir |= CVDIR_FUP;
1141 	else
1142 		dir |= CVDIR_FDOWN;
1143 
1144 	if(fabs(k2-k) < 0.0001)
1145 		dir |= CVDIR_REQUAL;
1146 	else if (k2 > k)
1147 		dir |= CVDIR_RUP;
1148 	else
1149 		dir |= CVDIR_RDOWN;
1150 
1151 	return dir;
1152 }
1153 
1154 #if 0
1155 /* a function just to test the work of fixcvdir() */
1156 static void
1157 testfixcvdir(
1158 	     GLYPH * g
1159 )
1160 {
1161 	GENTRY         *ge;
1162 	int             dir;
1163 
1164 	for (ge = g->entries; ge != 0; ge = ge->next) {
1165 		if (ge->type == GE_CURVE) {
1166 			dir = igetcvdir(ge);
1167 			fixcvdir(ge, dir);
1168 		}
1169 	}
1170 }
1171 #endif
1172 
1173 static int
iround(double val)1174 iround(
1175 	double val
1176 )
1177 {
1178 	return (int) (val > 0 ? val + 0.5 : val - 0.5);
1179 }
1180 
1181 /* for debugging - dump the glyph
1182  * mark with a star the entries from start to end inclusive
1183  * (start == NULL means don't mark any, end == NULL means to the last)
1184  */
1185 
1186 void
dumppaths(GLYPH * g,GENTRY * start,GENTRY * end)1187 dumppaths(
1188 	GLYPH *g,
1189 	GENTRY *start,
1190 	GENTRY *end
1191 )
1192 {
1193 	GENTRY *ge;
1194 	int i;
1195 	char mark=' ';
1196 
1197 	fprintf(stderr, "Glyph %s:\n", g->name);
1198 
1199 	/* now do the conversion */
1200 	for(ge = g->entries; ge != 0; ge = ge->next) {
1201 		if(ge == start)
1202 			mark = '*';
1203 		fprintf(stderr, " %c %8x", mark, ge);
1204 		switch(ge->type) {
1205 		case GE_MOVE:
1206 		case GE_LINE:
1207 			if(ge->flags & GEF_FLOAT)
1208 				fprintf(stderr," %c float (%g, %g)\n", ge->type, ge->fx3, ge->fy3);
1209 			else
1210 				fprintf(stderr," %c int (%d, %d)\n", ge->type, ge->ix3, ge->iy3);
1211 			break;
1212 		case GE_CURVE:
1213 			if(ge->flags & GEF_FLOAT) {
1214 				fprintf(stderr," C float ");
1215 				for(i=0; i<3; i++)
1216 					fprintf(stderr,"(%g, %g) ", ge->fxn[i], ge->fyn[i]);
1217 				fprintf(stderr,"\n");
1218 			} else {
1219 				fprintf(stderr," C int ");
1220 				for(i=0; i<3; i++)
1221 					fprintf(stderr,"(%d, %d) ", ge->ixn[i], ge->iyn[i]);
1222 				fprintf(stderr,"\n");
1223 			}
1224 			break;
1225 		default:
1226 			fprintf(stderr, " %c\n", ge->type);
1227 			break;
1228 		}
1229 		if(ge == end)
1230 			mark = ' ';
1231 	}
1232 }
1233 
1234 /*
1235  * Routine that converts all entries in the path from float to int
1236  */
1237 
1238 void
pathtoint(GLYPH * g)1239 pathtoint(
1240 	GLYPH *g
1241 )
1242 {
1243 	GENTRY *ge;
1244 	int x[3], y[3];
1245 	int i;
1246 
1247 
1248 	if(ISDBG(TOINT))
1249 		fprintf(stderr, "TOINT: glyph %s\n", g->name);
1250 	assertisfloat(g, "converting path to int\n");
1251 
1252 	fdelsmall(g, 1.0); /* get rid of sub-pixel contours */
1253 	assertpath(g->entries, __FILE__, __LINE__, g->name);
1254 
1255 	/* 1st pass, collect the directions of the curves: have
1256 	 * to do that in advance, while everyting is float
1257 	 */
1258 	for(ge = g->entries; ge != 0; ge = ge->next) {
1259 		if( !(ge->flags & GEF_FLOAT) ) {
1260 			fprintf(stderr, "**! glyphs %s has int entry, found in conversion to int\n",
1261 				g->name);
1262 			exit(1);
1263 		}
1264 		if(ge->type == GE_CURVE) {
1265 			ge->dir = fgetcvdir(ge);
1266 		}
1267 	}
1268 
1269 	/* now do the conversion */
1270 	for(ge = g->entries; ge != 0; ge = ge->next) {
1271 		switch(ge->type) {
1272 		case GE_MOVE:
1273 		case GE_LINE:
1274 			if(ISDBG(TOINT))
1275 				fprintf(stderr," %c float x=%g y=%g\n", ge->type, ge->fx3, ge->fy3);
1276 			x[0] = iround(ge->fx3);
1277 			y[0] = iround(ge->fy3);
1278 			for(i=0; i<3; i++) { /* put some valid values everywhere, for convenience */
1279 				ge->ixn[i] = x[0];
1280 				ge->iyn[i] = y[0];
1281 			}
1282 			if(ISDBG(TOINT))
1283 				fprintf(stderr,"   int   x=%d y=%d\n", ge->ix3, ge->iy3);
1284 			break;
1285 		case GE_CURVE:
1286 			if(ISDBG(TOINT))
1287 				fprintf(stderr," %c float ", ge->type);
1288 
1289 			for(i=0; i<3; i++) {
1290 				if(ISDBG(TOINT))
1291 					fprintf(stderr,"(%g, %g) ", ge->fxn[i], ge->fyn[i]);
1292 				x[i] = iround(ge->fxn[i]);
1293 				y[i] = iround(ge->fyn[i]);
1294 			}
1295 
1296 			if(ISDBG(TOINT))
1297 				fprintf(stderr,"\n   int   ");
1298 
1299 			for(i=0; i<3; i++) {
1300 				ge->ixn[i] = x[i];
1301 				ge->iyn[i] = y[i];
1302 				if(ISDBG(TOINT))
1303 					fprintf(stderr,"(%d, %d) ", ge->ixn[i], ge->iyn[i]);
1304 			}
1305 			ge->flags &= ~GEF_FLOAT; /* for fixcvdir */
1306 			fixcvdir(ge, ge->dir);
1307 
1308 			if(ISDBG(TOINT)) {
1309 				fprintf(stderr,"\n   fixed ");
1310 				for(i=0; i<3; i++)
1311 					fprintf(stderr,"(%d, %d) ", ge->ixn[i], ge->iyn[i]);
1312 				fprintf(stderr,"\n");
1313 			}
1314 
1315 			break;
1316 		}
1317 		ge->flags &= ~GEF_FLOAT;
1318 	}
1319 	g->flags &= ~GF_FLOAT;
1320 }
1321 
1322 
1323 /* check whether we can fix up the curve to change its size by (dx,dy) */
1324 /* 0 means NO, 1 means YES */
1325 
1326 /* for float: if scaling would be under 10% */
1327 
1328 int
fcheckcv(GENTRY * ge,double dx,double dy)1329 fcheckcv(
1330 	GENTRY * ge,
1331 	double dx,
1332 	double dy
1333 )
1334 {
1335 	if( !(ge->flags & GEF_FLOAT) ) {
1336 		fprintf(stderr, "**! fcheckcv(0x%x) on int entry, ABORT\n", ge);
1337 		abort(); /* dump core */
1338 	}
1339 
1340 	if (ge->type != GE_CURVE)
1341 		return 0;
1342 
1343 	if( fabs(ge->fx3 - ge->prev->fx3) < fabs(dx) * 10 )
1344 		return 0;
1345 
1346 	if( fabs(ge->fy3 - ge->prev->fy3) < fabs(dy) * 10 )
1347 		return 0;
1348 
1349 	return 1;
1350 }
1351 
1352 /* for int: if won't create new zigzags at the ends */
1353 
1354 int
icheckcv(GENTRY * ge,int dx,int dy)1355 icheckcv(
1356 	GENTRY * ge,
1357 	int dx,
1358 	int dy
1359 )
1360 {
1361 	int             xdep, ydep;
1362 
1363 	if(ge->flags & GEF_FLOAT) {
1364 		fprintf(stderr, "**! icheckcv(0x%x) on floating entry, ABORT\n", ge);
1365 		abort(); /* dump core */
1366 	}
1367 
1368 	if (ge->type != GE_CURVE)
1369 		return 0;
1370 
1371 	xdep = ge->ix3 - ge->prev->ix3;
1372 	ydep = ge->iy3 - ge->prev->iy3;
1373 
1374 	if (ge->type == GE_CURVE
1375 	    && (xdep * (xdep + dx)) > 0
1376 	    && (ydep * (ydep + dy)) > 0) {
1377 		return 1;
1378 	} else
1379 		return 0;
1380 }
1381 
1382 /* float connect the ends of open contours */
1383 
1384 void
fclosepaths(GLYPH * g)1385 fclosepaths(
1386 	   GLYPH * g
1387 )
1388 {
1389 	GENTRY         *ge, *fge, *xge, *nge;
1390 	int             i;
1391 
1392 	assertisfloat(g, "fclosepaths float\n");
1393 
1394 	for (xge = g->entries; xge != 0; xge = xge->next) {
1395 		if( xge->type != GE_PATH )
1396 			continue;
1397 
1398 		ge = xge->prev;
1399 		if(ge == 0 || ge->type != GE_LINE && ge->type!= GE_CURVE) {
1400 			fprintf(stderr, "**! Glyph %s got empty path\n",
1401 				g->name);
1402 			exit(1);
1403 		}
1404 
1405 		fge = ge->frwd;
1406 		if (fge->prev == 0 || fge->prev->type != GE_MOVE) {
1407 			fprintf(stderr, "**! Glyph %s got strange beginning of path\n",
1408 				g->name);
1409 			exit(1);
1410 		}
1411 		fge = fge->prev;
1412 		if (fge->fx3 != ge->fx3 || fge->fy3 != ge->fy3) {
1413 			/* we have to fix this open path */
1414 
1415 			WARNING_4 fprintf(stderr, "Glyph %s got path open by dx=%g dy=%g\n",
1416 			g->name, fge->fx3 - ge->fx3, fge->fy3 - ge->fy3);
1417 
1418 
1419 			/* add a new line */
1420 			nge = newgentry(GEF_FLOAT);
1421 			(*nge) = (*ge);
1422 			nge->fx3 = fge->fx3;
1423 			nge->fy3 = fge->fy3;
1424 			nge->type = GE_LINE;
1425 
1426 			addgeafter(ge, nge);
1427 
1428 			if (fabs(ge->fx3 - fge->fx3) <= 2 && fabs(ge->fy3 - fge->fy3) <= 2) {
1429 				/*
1430 				 * small change, try to get rid of the new entry
1431 				 */
1432 
1433 				double df[2];
1434 
1435 				for(i=0; i<2; i++) {
1436 					df[i] = ge->fpoints[i][2] - fge->fpoints[i][2];
1437 					df[i] = fclosegap(nge, nge, i, df[i], NULL);
1438 				}
1439 
1440 				if(df[0] == 0. && df[1] == 0.) {
1441 					/* closed gap successfully, remove the added entry */
1442 					freethisge(nge);
1443 				}
1444 			}
1445 		}
1446 	}
1447 }
1448 
1449 void
smoothjoints(GLYPH * g)1450 smoothjoints(
1451 	     GLYPH * g
1452 )
1453 {
1454 	GENTRY         *ge, *ne;
1455 	int             dx1, dy1, dx2, dy2, k;
1456 	int             dir;
1457 
1458 	return; /* this stuff seems to create problems */
1459 
1460 	assertisint(g, "smoothjoints int");
1461 
1462 	if (g->entries == 0)	/* nothing to do */
1463 		return;
1464 
1465 	for (ge = g->entries->next; ge != 0; ge = ge->next) {
1466 		ne = ge->frwd;
1467 
1468 		/*
1469 		 * although there should be no one-line path * and any path
1470 		 * must end with CLOSEPATH, * nobody can say for sure
1471 		 */
1472 
1473 		if (ge == ne || ne == 0)
1474 			continue;
1475 
1476 		/* now handle various joints */
1477 
1478 		if (ge->type == GE_LINE && ne->type == GE_LINE) {
1479 			dx1 = ge->ix3 - ge->prev->ix3;
1480 			dy1 = ge->iy3 - ge->prev->iy3;
1481 			dx2 = ne->ix3 - ge->ix3;
1482 			dy2 = ne->iy3 - ge->iy3;
1483 
1484 			/* check whether they have the same direction */
1485 			/* and the same slope */
1486 			/* then we can join them into one line */
1487 
1488 			if (dx1 * dx2 >= 0 && dy1 * dy2 >= 0 && dx1 * dy2 == dy1 * dx2) {
1489 				/* extend the previous line */
1490 				ge->ix3 = ne->ix3;
1491 				ge->iy3 = ne->iy3;
1492 
1493 				/* and get rid of the next line */
1494 				freethisge(ne);
1495 			}
1496 		} else if (ge->type == GE_LINE && ne->type == GE_CURVE) {
1497 			fixcvends(ne);
1498 
1499 			dx1 = ge->ix3 - ge->prev->ix3;
1500 			dy1 = ge->iy3 - ge->prev->iy3;
1501 			dx2 = ne->ix1 - ge->ix3;
1502 			dy2 = ne->iy1 - ge->iy3;
1503 
1504 			/* if the line is nearly horizontal and we can fix it */
1505 			if (dx1 != 0 && 5 * abs(dy1) / abs(dx1) == 0
1506 			    && icheckcv(ne, 0, -dy1)
1507 			    && abs(dy1) <= 4) {
1508 				dir = igetcvdir(ne);
1509 				ge->iy3 -= dy1;
1510 				ne->iy1 -= dy1;
1511 				fixcvdir(ne, dir);
1512 				if (ge->next != ne)
1513 					ne->prev->iy3 -= dy1;
1514 				dy1 = 0;
1515 			} else if (dy1 != 0 && 5 * abs(dx1) / abs(dy1) == 0
1516 				   && icheckcv(ne, -dx1, 0)
1517 				   && abs(dx1) <= 4) {
1518 				/* the same but vertical */
1519 				dir = igetcvdir(ne);
1520 				ge->ix3 -= dx1;
1521 				ne->ix1 -= dx1;
1522 				fixcvdir(ne, dir);
1523 				if (ge->next != ne)
1524 					ne->prev->ix3 -= dx1;
1525 				dx1 = 0;
1526 			}
1527 			/*
1528 			 * if line is horizontal and curve begins nearly
1529 			 * horizontally
1530 			 */
1531 			if (dy1 == 0 && dx2 != 0 && 5 * abs(dy2) / abs(dx2) == 0) {
1532 				dir = igetcvdir(ne);
1533 				ne->iy1 -= dy2;
1534 				fixcvdir(ne, dir);
1535 				dy2 = 0;
1536 			} else if (dx1 == 0 && dy2 != 0 && 5 * abs(dx2) / abs(dy2) == 0) {
1537 				/* the same but vertical */
1538 				dir = igetcvdir(ne);
1539 				ne->ix1 -= dx2;
1540 				fixcvdir(ne, dir);
1541 				dx2 = 0;
1542 			}
1543 		} else if (ge->type == GE_CURVE && ne->type == GE_LINE) {
1544 			fixcvends(ge);
1545 
1546 			dx1 = ge->ix3 - ge->ix2;
1547 			dy1 = ge->iy3 - ge->iy2;
1548 			dx2 = ne->ix3 - ge->ix3;
1549 			dy2 = ne->iy3 - ge->iy3;
1550 
1551 			/* if the line is nearly horizontal and we can fix it */
1552 			if (dx2 != 0 && 5 * abs(dy2) / abs(dx2) == 0
1553 			    && icheckcv(ge, 0, dy2)
1554 			    && abs(dy2) <= 4) {
1555 				dir = igetcvdir(ge);
1556 				ge->iy3 += dy2;
1557 				ge->iy2 += dy2;
1558 				fixcvdir(ge, dir);
1559 				if (ge->next != ne)
1560 					ne->prev->iy3 += dy2;
1561 				dy2 = 0;
1562 			} else if (dy2 != 0 && 5 * abs(dx2) / abs(dy2) == 0
1563 				   && icheckcv(ge, dx2, 0)
1564 				   && abs(dx2) <= 4) {
1565 				/* the same but vertical */
1566 				dir = igetcvdir(ge);
1567 				ge->ix3 += dx2;
1568 				ge->ix2 += dx2;
1569 				fixcvdir(ge, dir);
1570 				if (ge->next != ne)
1571 					ne->prev->ix3 += dx2;
1572 				dx2 = 0;
1573 			}
1574 			/*
1575 			 * if line is horizontal and curve ends nearly
1576 			 * horizontally
1577 			 */
1578 			if (dy2 == 0 && dx1 != 0 && 5 * abs(dy1) / abs(dx1) == 0) {
1579 				dir = igetcvdir(ge);
1580 				ge->iy2 += dy1;
1581 				fixcvdir(ge, dir);
1582 				dy1 = 0;
1583 			} else if (dx2 == 0 && dy1 != 0 && 5 * abs(dx1) / abs(dy1) == 0) {
1584 				/* the same but vertical */
1585 				dir = igetcvdir(ge);
1586 				ge->ix2 += dx1;
1587 				fixcvdir(ge, dir);
1588 				dx1 = 0;
1589 			}
1590 		} else if (ge->type == GE_CURVE && ne->type == GE_CURVE) {
1591 			fixcvends(ge);
1592 			fixcvends(ne);
1593 
1594 			dx1 = ge->ix3 - ge->ix2;
1595 			dy1 = ge->iy3 - ge->iy2;
1596 			dx2 = ne->ix1 - ge->ix3;
1597 			dy2 = ne->iy1 - ge->iy3;
1598 
1599 			/*
1600 			 * check if we have a rather smooth joint at extremal
1601 			 * point
1602 			 */
1603 			/* left or right extremal point */
1604 			if (abs(dx1) <= 4 && abs(dx2) <= 4
1605 			    && dy1 != 0 && 5 * abs(dx1) / abs(dy1) == 0
1606 			    && dy2 != 0 && 5 * abs(dx2) / abs(dy2) == 0
1607 			    && (ge->iy3 < ge->prev->iy3 && ne->iy3 < ge->iy3
1608 				|| ge->iy3 > ge->prev->iy3 && ne->iy3 > ge->iy3)
1609 			  && (ge->ix3 - ge->prev->ix3) * (ne->ix3 - ge->ix3) < 0
1610 				) {
1611 				dir = igetcvdir(ge);
1612 				ge->ix2 += dx1;
1613 				dx1 = 0;
1614 				fixcvdir(ge, dir);
1615 				dir = igetcvdir(ne);
1616 				ne->ix1 -= dx2;
1617 				dx2 = 0;
1618 				fixcvdir(ne, dir);
1619 			}
1620 			/* top or down extremal point */
1621 			else if (abs(dy1) <= 4 && abs(dy2) <= 4
1622 				 && dx1 != 0 && 5 * abs(dy1) / abs(dx1) == 0
1623 				 && dx2 != 0 && 5 * abs(dy2) / abs(dx2) == 0
1624 				 && (ge->ix3 < ge->prev->ix3 && ne->ix3 < ge->ix3
1625 				|| ge->ix3 > ge->prev->ix3 && ne->ix3 > ge->ix3)
1626 				 && (ge->iy3 - ge->prev->iy3) * (ne->iy3 - ge->iy3) < 0
1627 				) {
1628 				dir = igetcvdir(ge);
1629 				ge->iy2 += dy1;
1630 				dy1 = 0;
1631 				fixcvdir(ge, dir);
1632 				dir = igetcvdir(ne);
1633 				ne->iy1 -= dy2;
1634 				dy2 = 0;
1635 				fixcvdir(ne, dir);
1636 			}
1637 			/* or may be we just have a smooth junction */
1638 			else if (dx1 * dx2 >= 0 && dy1 * dy2 >= 0
1639 				 && 10 * abs(k = abs(dx1 * dy2) - abs(dy1 * dx2)) < (abs(dx1 * dy2) + abs(dy1 * dx2))) {
1640 				int             tries[6][4];
1641 				int             results[6];
1642 				int             i, b;
1643 
1644 				/* build array of changes we are going to try */
1645 				/* uninitalized entries are 0 */
1646 				if (k > 0) {
1647 					static int      t1[6][4] = {
1648 						{0, 0, 0, 0},
1649 						{-1, 0, 1, 0},
1650 						{-1, 0, 0, 1},
1651 						{0, -1, 1, 0},
1652 						{0, -1, 0, 1},
1653 					{-1, -1, 1, 1}};
1654 					memcpy(tries, t1, sizeof tries);
1655 				} else {
1656 					static int      t1[6][4] = {
1657 						{0, 0, 0, 0},
1658 						{1, 0, -1, 0},
1659 						{1, 0, 0, -1},
1660 						{0, 1, -1, 0},
1661 						{0, 1, 0, -1},
1662 					{1, 1, -1, -1}};
1663 					memcpy(tries, t1, sizeof tries);
1664 				}
1665 
1666 				/* now try the changes */
1667 				results[0] = abs(k);
1668 				for (i = 1; i < 6; i++) {
1669 					results[i] = abs((abs(dx1) + tries[i][0]) * (abs(dy2) + tries[i][1]) -
1670 							 (abs(dy1) + tries[i][2]) * (abs(dx2) + tries[i][3]));
1671 				}
1672 
1673 				/* and find the best try */
1674 				k = abs(k);
1675 				b = 0;
1676 				for (i = 1; i < 6; i++)
1677 					if (results[i] < k) {
1678 						k = results[i];
1679 						b = i;
1680 					}
1681 				/* and finally apply it */
1682 				if (dx1 < 0)
1683 					tries[b][0] = -tries[b][0];
1684 				if (dy2 < 0)
1685 					tries[b][1] = -tries[b][1];
1686 				if (dy1 < 0)
1687 					tries[b][2] = -tries[b][2];
1688 				if (dx2 < 0)
1689 					tries[b][3] = -tries[b][3];
1690 
1691 				dir = igetcvdir(ge);
1692 				ge->ix2 -= tries[b][0];
1693 				ge->iy2 -= tries[b][2];
1694 				fixcvdir(ge, dir);
1695 				dir = igetcvdir(ne);
1696 				ne->ix1 += tries[b][3];
1697 				ne->iy1 += tries[b][1];
1698 				fixcvdir(ne, dir);
1699 			}
1700 		}
1701 	}
1702 }
1703 
1704 /* debugging: print out stems of a glyph */
1705 static void
debugstems(char * name,STEM * hstems,int nhs,STEM * vstems,int nvs)1706 debugstems(
1707 	   char *name,
1708 	   STEM * hstems,
1709 	   int nhs,
1710 	   STEM * vstems,
1711 	   int nvs
1712 )
1713 {
1714 	int             i;
1715 
1716 	fprintf(pfa_file, "%% %s\n", name);
1717 	fprintf(pfa_file, "%% %d horizontal stems:\n", nhs);
1718 	for (i = 0; i < nhs; i++)
1719 		fprintf(pfa_file, "%% %3d    %d (%d...%d) %c %c%c%c%c\n", i, hstems[i].value,
1720 			hstems[i].from, hstems[i].to,
1721 			((hstems[i].flags & ST_UP) ? 'U' : 'D'),
1722 			((hstems[i].flags & ST_END) ? 'E' : '-'),
1723 			((hstems[i].flags & ST_FLAT) ? 'F' : '-'),
1724 			((hstems[i].flags & ST_ZONE) ? 'Z' : ' '),
1725 			((hstems[i].flags & ST_TOPZONE) ? 'T' : ' '));
1726 	fprintf(pfa_file, "%% %d vertical stems:\n", nvs);
1727 	for (i = 0; i < nvs; i++)
1728 		fprintf(pfa_file, "%% %3d    %d (%d...%d) %c %c%c\n", i, vstems[i].value,
1729 			vstems[i].from, vstems[i].to,
1730 			((vstems[i].flags & ST_UP) ? 'U' : 'D'),
1731 			((vstems[i].flags & ST_END) ? 'E' : '-'),
1732 			((vstems[i].flags & ST_FLAT) ? 'F' : '-'));
1733 }
1734 
1735 /* add pseudo-stems for the limits of the Blue zones to the stem array */
1736 static int
addbluestems(STEM * s,int n)1737 addbluestems(
1738 	STEM *s,
1739 	int n
1740 )
1741 {
1742 	int i;
1743 
1744 	for(i=0; i<nblues && i<2; i+=2) { /* baseline */
1745 		s[n].value=bluevalues[i];
1746 		s[n].flags=ST_UP|ST_ZONE;
1747 		/* don't overlap with anything */
1748 		s[n].origin=s[n].from=s[n].to= -10000+i;
1749 		n++;
1750 		s[n].value=bluevalues[i+1];
1751 		s[n].flags=ST_ZONE;
1752 		/* don't overlap with anything */
1753 		s[n].origin=s[n].from=s[n].to= -10000+i+1;
1754 		n++;
1755 	}
1756 	for(i=2; i<nblues; i+=2) { /* top zones */
1757 		s[n].value=bluevalues[i];
1758 		s[n].flags=ST_UP|ST_ZONE|ST_TOPZONE;
1759 		/* don't overlap with anything */
1760 		s[n].origin=s[n].from=s[n].to= -10000+i;
1761 		n++;
1762 		s[n].value=bluevalues[i+1];
1763 		s[n].flags=ST_ZONE|ST_TOPZONE;
1764 		/* don't overlap with anything */
1765 		s[n].origin=s[n].from=s[n].to= -10000+i+1;
1766 		n++;
1767 	}
1768 	for(i=0; i<notherb; i+=2) { /* bottom zones */
1769 		s[n].value=otherblues[i];
1770 		s[n].flags=ST_UP|ST_ZONE;
1771 		/* don't overlap with anything */
1772 		s[n].origin=s[n].from=s[n].to= -10000+i+nblues;
1773 		n++;
1774 		s[n].value=otherblues[i+1];
1775 		s[n].flags=ST_ZONE;
1776 		/* don't overlap with anything */
1777 		s[n].origin=s[n].from=s[n].to= -10000+i+1+nblues;
1778 		n++;
1779 	}
1780 	return n;
1781 }
1782 
1783 /* sort stems in array */
1784 static void
sortstems(STEM * s,int n)1785 sortstems(
1786 	  STEM * s,
1787 	  int n
1788 )
1789 {
1790 	int             i, j;
1791 	STEM            x;
1792 
1793 
1794 	/* a simple sorting */
1795 	/* hm, the ordering criteria are not quite simple :-)
1796 	 * if the values are tied
1797 	 * ST_UP always goes under not ST_UP
1798 	 * ST_ZONE goes on the most outer side
1799 	 * ST_END goes towards inner side after ST_ZONE
1800 	 * ST_FLAT goes on the inner side
1801 	 */
1802 
1803 	for (i = 0; i < n; i++)
1804 		for (j = i + 1; j < n; j++) {
1805 			if(s[i].value < s[j].value)
1806 				continue;
1807 			if(s[i].value == s[j].value) {
1808 				if( (s[i].flags & ST_UP) < (s[j].flags & ST_UP) )
1809 					continue;
1810 				if( (s[i].flags & ST_UP) == (s[j].flags & ST_UP) ) {
1811 					if( s[i].flags & ST_UP ) {
1812 						if(
1813 						(s[i].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1814 							>
1815 						(s[j].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1816 						)
1817 							continue;
1818 					} else {
1819 						if(
1820 						(s[i].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1821 							<
1822 						(s[j].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1823 						)
1824 							continue;
1825 					}
1826 				}
1827 			}
1828 			x = s[j];
1829 			s[j] = s[i];
1830 			s[i] = x;
1831 		}
1832 }
1833 
1834 /* check whether two stem borders overlap */
1835 
1836 static int
stemoverlap(STEM * s1,STEM * s2)1837 stemoverlap(
1838 	    STEM * s1,
1839 	    STEM * s2
1840 )
1841 {
1842 	int             result;
1843 
1844 	if (s1->from <= s2->from && s1->to >= s2->from
1845 	    || s2->from <= s1->from && s2->to >= s1->from)
1846 		result = 1;
1847 	else
1848 		result = 0;
1849 
1850 	if (ISDBG(STEMOVERLAP))
1851 		fprintf(pfa_file, "%% overlap %d(%d..%d)x%d(%d..%d)=%d\n",
1852 			s1->value, s1->from, s1->to, s2->value, s2->from, s2->to, result);
1853 	return result;
1854 }
1855 
1856 /*
1857  * check if the stem [border] is in an appropriate blue zone
1858  * (currently not used)
1859  */
1860 
1861 static int
steminblue(STEM * s)1862 steminblue(
1863 	STEM *s
1864 )
1865 {
1866 	int i, val;
1867 
1868 	val=s->value;
1869 	if(s->flags & ST_UP) {
1870 		/* painted size up, look at lower zones */
1871 		if(nblues>=2 && val>=bluevalues[0] && val<=bluevalues[1] )
1872 			return 1;
1873 		for(i=0; i<notherb; i++) {
1874 			if( val>=otherblues[i] && val<=otherblues[i+1] )
1875 				return 1;
1876 		}
1877 	} else {
1878 		/* painted side down, look at upper zones */
1879 		for(i=2; i<nblues; i++) {
1880 			if( val>=bluevalues[i] && val<=bluevalues[i+1] )
1881 				return 1;
1882 		}
1883 	}
1884 
1885 	return 0;
1886 }
1887 
1888 /* mark the outermost stem [borders] in the blue zones */
1889 
1890 static void
markbluestems(STEM * s,int nold)1891 markbluestems(
1892 	STEM *s,
1893 	int nold
1894 )
1895 {
1896 	int i, j, a, b, c;
1897 	/*
1898 	 * traverse the list of Blue Values, mark the lowest upper
1899 	 * stem in each bottom zone and the topmost lower stem in
1900 	 * each top zone with ST_BLUE
1901 	 */
1902 
1903 	/* top zones */
1904 	for(i=2; i<nblues; i+=2) {
1905 		a=bluevalues[i]; b=bluevalues[i+1];
1906 		if(ISDBG(BLUESTEMS))
1907 			fprintf(pfa_file, "%% looking at blue zone %d...%d\n", a, b);
1908 		for(j=nold-1; j>=0; j--) {
1909 			if( s[j].flags & (ST_ZONE|ST_UP|ST_END) )
1910 				continue;
1911 			c=s[j].value;
1912 			if(c<a) /* too low */
1913 				break;
1914 			if(c<=b) { /* found the topmost stem border */
1915 				/* mark all the stems with the same value */
1916 				if(ISDBG(BLUESTEMS))
1917 					fprintf(pfa_file, "%% found D BLUE at %d\n", s[j].value);
1918 				/* include ST_END values */
1919 				while( s[j+1].value==c && (s[j+1].flags & ST_ZONE)==0 )
1920 					j++;
1921 				s[j].flags |= ST_BLUE;
1922 				for(j--; j>=0 && s[j].value==c
1923 						&& (s[j].flags & (ST_UP|ST_ZONE))==0 ; j--)
1924 					s[j].flags |= ST_BLUE;
1925 				break;
1926 			}
1927 		}
1928 	}
1929 	/* baseline */
1930 	if(nblues>=2) {
1931 		a=bluevalues[0]; b=bluevalues[1];
1932 		for(j=0; j<nold; j++) {
1933 			if( (s[j].flags & (ST_ZONE|ST_UP|ST_END))!=ST_UP )
1934 				continue;
1935 			c=s[j].value;
1936 			if(c>b) /* too high */
1937 				break;
1938 			if(c>=a) { /* found the lowest stem border */
1939 				/* mark all the stems with the same value */
1940 				if(ISDBG(BLUESTEMS))
1941 					fprintf(pfa_file, "%% found U BLUE at %d\n", s[j].value);
1942 				/* include ST_END values */
1943 				while( s[j-1].value==c && (s[j-1].flags & ST_ZONE)==0 )
1944 					j--;
1945 				s[j].flags |= ST_BLUE;
1946 				for(j++; j<nold && s[j].value==c
1947 						&& (s[j].flags & (ST_UP|ST_ZONE))==ST_UP ; j++)
1948 					s[j].flags |= ST_BLUE;
1949 				break;
1950 			}
1951 		}
1952 	}
1953 	/* bottom zones: the logic is the same as for baseline */
1954 	for(i=0; i<notherb; i+=2) {
1955 		a=otherblues[i]; b=otherblues[i+1];
1956 		for(j=0; j<nold; j++) {
1957 			if( (s[j].flags & (ST_UP|ST_ZONE|ST_END))!=ST_UP )
1958 				continue;
1959 			c=s[j].value;
1960 			if(c>b) /* too high */
1961 				break;
1962 			if(c>=a) { /* found the lowest stem border */
1963 				/* mark all the stems with the same value */
1964 				if(ISDBG(BLUESTEMS))
1965 					fprintf(pfa_file, "%% found U BLUE at %d\n", s[j].value);
1966 				/* include ST_END values */
1967 				while( s[j-1].value==c && (s[j-1].flags & ST_ZONE)==0 )
1968 					j--;
1969 				s[j].flags |= ST_BLUE;
1970 				for(j++; j<nold && s[j].value==c
1971 						&& (s[j].flags & (ST_UP|ST_ZONE))==ST_UP ; j++)
1972 					s[j].flags |= ST_BLUE;
1973 				break;
1974 			}
1975 		}
1976 	}
1977 }
1978 
1979 /* Eliminate invalid stems, join equivalent lines and remove nested stems
1980  * to build the main (non-substituted) set of stems.
1981  * XXX add consideration of the italic angle
1982  */
1983 static int
joinmainstems(STEM * s,int nold,int useblues)1984 joinmainstems(
1985 	  STEM * s,
1986 	  int nold,
1987 	  int useblues /* do we use the blue values ? */
1988 )
1989 {
1990 #define MAX_STACK	1000
1991 	STEM            stack[MAX_STACK];
1992 	int             nstack = 0;
1993 	int             sbottom = 0;
1994 	int             nnew;
1995 	int             i, j, k;
1996 	int             a, b, c, w1, w2, w3;
1997 	int             fw, fd;
1998 	/*
1999 	 * priority of the last found stem:
2000 	 * 0 - nothing found yet
2001 	 * 1 - has ST_END in it (one or more)
2002 	 * 2 - has no ST_END and no ST_FLAT, can override only one stem
2003 	 *     with priority 1
2004 	 * 3 - has no ST_END and at least one ST_FLAT, can override one
2005 	 *     stem with priority 2 or any number of stems with priority 1
2006 	 * 4 (handled separately) - has ST_BLUE, can override anything
2007 	 */
2008 	int             readystem = 0;
2009 	int             pri;
2010 	int             nlps = 0;	/* number of non-committed
2011 					 * lowest-priority stems */
2012 
2013 
2014 	for (i = 0, nnew = 0; i < nold; i++) {
2015 		if (s[i].flags & (ST_UP|ST_ZONE)) {
2016 			if(s[i].flags & ST_BLUE) {
2017 				/* we just HAVE to use this value */
2018 				if (readystem)
2019 					nnew += 2;
2020 				readystem=0;
2021 
2022 				/* remember the list of Blue zone stems with the same value */
2023 				for(a=i, i++; i<nold && s[a].value==s[i].value
2024 					&& (s[i].flags & ST_BLUE); i++)
2025 					{}
2026 				b=i; /* our range is a <= i < b */
2027 				c= -1; /* index of our best guess up to now */
2028 				pri=0;
2029 				/* try to find a match, don't cross blue zones */
2030 				for(; i<nold && (s[i].flags & ST_BLUE)==0; i++) {
2031 					if(s[i].flags & ST_UP) {
2032 						if(s[i].flags & ST_TOPZONE)
2033 							break;
2034 						else
2035 							continue;
2036 					}
2037 					for(j=a; j<b; j++) {
2038 						if(!stemoverlap(&s[j], &s[i]) )
2039 							continue;
2040 						/* consider priorities */
2041 						if( ( (s[j].flags|s[i].flags) & (ST_FLAT|ST_END) )==ST_FLAT ) {
2042 							c=i;
2043 							goto bluematch;
2044 						}
2045 						if( ((s[j].flags|s[i].flags) & ST_END)==0 )  {
2046 							if(pri < 2) {
2047 								c=i; pri=2;
2048 							}
2049 						} else {
2050 							if(pri == 0) {
2051 								c=i; pri=1;
2052 							}
2053 						}
2054 					}
2055 				}
2056 			bluematch:
2057 				/* clean up the stack */
2058 				nstack=sbottom=0;
2059 				readystem=0;
2060 				/* add this stem */
2061 				s[nnew++]=s[a];
2062 				if(c<0) { /* make one-dot-wide stem */
2063 					if(nnew>=b) { /* have no free space */
2064 						for(j=nold; j>=b; j--) /* make free space */
2065 							s[j]=s[j-1];
2066 						b++;
2067 						nold++;
2068 					}
2069 					s[nnew]=s[a];
2070 					s[nnew].flags &= ~(ST_UP|ST_BLUE);
2071 					nnew++;
2072 					i=b-1;
2073 				} else {
2074 					s[nnew++]=s[c];
2075 					i=c; /* skip up to this point */
2076 				}
2077 				if (ISDBG(MAINSTEMS))
2078 					fprintf(pfa_file, "%% +stem %d...%d U BLUE\n",
2079 						s[nnew-2].value, s[nnew-1].value);
2080 			} else {
2081 				if (nstack >= MAX_STACK) {
2082 					WARNING_1 fprintf(stderr, "Warning: **** converter's stem stack overflow ****\n");
2083 					nstack = 0;
2084 				}
2085 				stack[nstack++] = s[i];
2086 			}
2087 		} else if(s[i].flags & ST_BLUE) {
2088 			/* again, we just HAVE to use this value */
2089 			if (readystem)
2090 				nnew += 2;
2091 			readystem=0;
2092 
2093 			/* remember the list of Blue zone stems with the same value */
2094 			for(a=i, i++; i<nold && s[a].value==s[i].value
2095 				&& (s[i].flags & ST_BLUE); i++)
2096 				{}
2097 			b=i; /* our range is a <= i < b */
2098 			c= -1; /* index of our best guess up to now */
2099 			pri=0;
2100 			/* try to find a match */
2101 			for (i = nstack - 1; i >= 0; i--) {
2102 				if( (stack[i].flags & ST_UP)==0 ) {
2103 					if( (stack[i].flags & (ST_ZONE|ST_TOPZONE))==ST_ZONE )
2104 						break;
2105 					else
2106 						continue;
2107 				}
2108 				for(j=a; j<b; j++) {
2109 					if(!stemoverlap(&s[j], &stack[i]) )
2110 						continue;
2111 					/* consider priorities */
2112 					if( ( (s[j].flags|stack[i].flags) & (ST_FLAT|ST_END) )==ST_FLAT ) {
2113 						c=i;
2114 						goto bluedownmatch;
2115 					}
2116 					if( ((s[j].flags|stack[i].flags) & ST_END)==0 )  {
2117 						if(pri < 2) {
2118 							c=i; pri=2;
2119 						}
2120 					} else {
2121 						if(pri == 0) {
2122 							c=i; pri=1;
2123 						}
2124 					}
2125 				}
2126 			}
2127 		bluedownmatch:
2128 			/* if found no match make a one-dot-wide stem */
2129 			if(c<0) {
2130 				c=0;
2131 				stack[0]=s[b-1];
2132 				stack[0].flags |= ST_UP;
2133 				stack[0].flags &= ~ST_BLUE;
2134 			}
2135 			/* remove all the stems conflicting with this one */
2136 			readystem=0;
2137 			for(j=nnew-2; j>=0; j-=2) {
2138 				if (ISDBG(MAINSTEMS))
2139 					fprintf(pfa_file, "%% ?stem %d...%d -- %d\n",
2140 						s[j].value, s[j+1].value, stack[c].value);
2141 				if(s[j+1].value < stack[c].value) /* no conflict */
2142 					break;
2143 				if(s[j].flags & ST_BLUE) {
2144 					/* oops, we don't want to spoil other blue zones */
2145 					stack[c].value=s[j+1].value+1;
2146 					break;
2147 				}
2148 				if( (s[j].flags|s[j+1].flags) & ST_END ) {
2149 					if (ISDBG(MAINSTEMS))
2150 						fprintf(pfa_file, "%% -stem %d...%d p=1\n",
2151 							s[j].value, s[j+1].value);
2152 					continue; /* pri==1, silently discard it */
2153 				}
2154 				/* we want to discard no nore than 2 stems of pri>=2 */
2155 				if( ++readystem > 2 ) {
2156 					/* change our stem to not conflict */
2157 					stack[c].value=s[j+1].value+1;
2158 					break;
2159 				} else {
2160 					if (ISDBG(MAINSTEMS))
2161 						fprintf(pfa_file, "%% -stem %d...%d p>=2\n",
2162 							s[j].value, s[j+1].value);
2163 					continue;
2164 				}
2165 			}
2166 			nnew=j+2;
2167 			/* add this stem */
2168 			if(nnew>=b-1) { /* have no free space */
2169 				for(j=nold; j>=b-1; j--) /* make free space */
2170 					s[j]=s[j-1];
2171 				b++;
2172 				nold++;
2173 			}
2174 			s[nnew++]=stack[c];
2175 			s[nnew++]=s[b-1];
2176 			/* clean up the stack */
2177 			nstack=sbottom=0;
2178 			readystem=0;
2179 			/* set the next position to search */
2180 			i=b-1;
2181 			if (ISDBG(MAINSTEMS))
2182 				fprintf(pfa_file, "%% +stem %d...%d D BLUE\n",
2183 					s[nnew-2].value, s[nnew-1].value);
2184 		} else if (nstack > 0) {
2185 
2186 			/*
2187 			 * check whether our stem overlaps with anything in
2188 			 * stack
2189 			 */
2190 			for (j = nstack - 1; j >= sbottom; j--) {
2191 				if (s[i].value <= stack[j].value)
2192 					break;
2193 				if (stack[j].flags & ST_ZONE)
2194 					continue;
2195 
2196 				if ((s[i].flags & ST_END)
2197 				    || (stack[j].flags & ST_END))
2198 					pri = 1;
2199 				else if ((s[i].flags & ST_FLAT)
2200 					 || (stack[j].flags & ST_FLAT))
2201 					pri = 3;
2202 				else
2203 					pri = 2;
2204 
2205 				if (pri < readystem && s[nnew + 1].value >= stack[j].value
2206 				    || !stemoverlap(&stack[j], &s[i]))
2207 					continue;
2208 
2209 				if (readystem > 1 && s[nnew + 1].value < stack[j].value) {
2210 					nnew += 2;
2211 					readystem = 0;
2212 					nlps = 0;
2213 				}
2214 				/*
2215 				 * width of the previous stem (if it's
2216 				 * present)
2217 				 */
2218 				w1 = s[nnew + 1].value - s[nnew].value;
2219 
2220 				/* width of this stem */
2221 				w2 = s[i].value - stack[j].value;
2222 
2223 				if (readystem == 0) {
2224 					/* nothing yet, just add a new stem */
2225 					s[nnew] = stack[j];
2226 					s[nnew + 1] = s[i];
2227 					readystem = pri;
2228 					if (pri == 1)
2229 						nlps = 1;
2230 					else if (pri == 2)
2231 						sbottom = j;
2232 					else {
2233 						sbottom = j + 1;
2234 						while (sbottom < nstack
2235 						       && stack[sbottom].value <= stack[j].value)
2236 							sbottom++;
2237 					}
2238 					if (ISDBG(MAINSTEMS))
2239 						fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2240 							stack[j].value, s[i].value, pri, nlps);
2241 				} else if (pri == 1) {
2242 					if (stack[j].value > s[nnew + 1].value) {
2243 						/*
2244 						 * doesn't overlap with the
2245 						 * previous one
2246 						 */
2247 						nnew += 2;
2248 						nlps++;
2249 						s[nnew] = stack[j];
2250 						s[nnew + 1] = s[i];
2251 						if (ISDBG(MAINSTEMS))
2252 							fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2253 								stack[j].value, s[i].value, pri, nlps);
2254 					} else if (w2 < w1) {
2255 						/* is narrower */
2256 						s[nnew] = stack[j];
2257 						s[nnew + 1] = s[i];
2258 						if (ISDBG(MAINSTEMS))
2259 							fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d %d->%d\n",
2260 								stack[j].value, s[i].value, pri, nlps, w1, w2);
2261 					}
2262 				} else if (pri == 2) {
2263 					if (readystem == 2) {
2264 						/* choose the narrower stem */
2265 						if (w1 > w2) {
2266 							s[nnew] = stack[j];
2267 							s[nnew + 1] = s[i];
2268 							sbottom = j;
2269 							if (ISDBG(MAINSTEMS))
2270 								fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d\n",
2271 									stack[j].value, s[i].value, pri, nlps);
2272 						}
2273 						/* else readystem==1 */
2274 					} else if (stack[j].value > s[nnew + 1].value) {
2275 						/*
2276 						 * value doesn't overlap with
2277 						 * the previous one
2278 						 */
2279 						nnew += 2;
2280 						nlps = 0;
2281 						s[nnew] = stack[j];
2282 						s[nnew + 1] = s[i];
2283 						sbottom = j;
2284 						readystem = pri;
2285 						if (ISDBG(MAINSTEMS))
2286 							fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2287 								stack[j].value, s[i].value, pri, nlps);
2288 					} else if (nlps == 1
2289 						   || stack[j].value > s[nnew - 1].value) {
2290 						/*
2291 						 * we can replace the top
2292 						 * stem
2293 						 */
2294 						nlps = 0;
2295 						s[nnew] = stack[j];
2296 						s[nnew + 1] = s[i];
2297 						readystem = pri;
2298 						sbottom = j;
2299 						if (ISDBG(MAINSTEMS))
2300 							fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d\n",
2301 								stack[j].value, s[i].value, pri, nlps);
2302 					}
2303 				} else if (readystem == 3) {	/* that means also
2304 								 * pri==3 */
2305 					/* choose the narrower stem */
2306 					if (w1 > w2) {
2307 						s[nnew] = stack[j];
2308 						s[nnew + 1] = s[i];
2309 						sbottom = j + 1;
2310 						while (sbottom < nstack
2311 						       && stack[sbottom].value <= stack[j].value)
2312 							sbottom++;
2313 						if (ISDBG(MAINSTEMS))
2314 							fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d\n",
2315 								stack[j].value, s[i].value, pri, nlps);
2316 					}
2317 				} else if (pri == 3) {
2318 					/*
2319 					 * we can replace as many stems as
2320 					 * neccessary
2321 					 */
2322 					nnew += 2;
2323 					while (nnew > 0 && s[nnew - 1].value >= stack[j].value) {
2324 						nnew -= 2;
2325 						if (ISDBG(MAINSTEMS))
2326 							fprintf(pfa_file, "%% -stem %d..%d\n",
2327 								s[nnew].value, s[nnew + 1].value);
2328 					}
2329 					nlps = 0;
2330 					s[nnew] = stack[j];
2331 					s[nnew + 1] = s[i];
2332 					readystem = pri;
2333 					sbottom = j + 1;
2334 					while (sbottom < nstack
2335 					       && stack[sbottom].value <= stack[j].value)
2336 						sbottom++;
2337 					if (ISDBG(MAINSTEMS))
2338 						fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2339 							stack[j].value, s[i].value, pri, nlps);
2340 				}
2341 			}
2342 		}
2343 	}
2344 	if (readystem)
2345 		nnew += 2;
2346 
2347 	/* change the 1-pixel-wide stems to 20-pixel-wide stems if possible
2348 	 * the constant 20 is recommended in the Type1 manual
2349 	 */
2350 	if(useblues) {
2351 		for(i=0; i<nnew; i+=2) {
2352 			if(s[i].value != s[i+1].value)
2353 				continue;
2354 			if( ((s[i].flags ^ s[i+1].flags) & ST_BLUE)==0 )
2355 				continue;
2356 			if( s[i].flags & ST_BLUE ) {
2357 				if(nnew>i+2 && s[i+2].value<s[i].value+22)
2358 					s[i+1].value=s[i+2].value-2; /* compensate for fuzziness */
2359 				else
2360 					s[i+1].value+=20;
2361 			} else {
2362 				if(i>0 && s[i-1].value>s[i].value-22)
2363 					s[i].value=s[i-1].value+2; /* compensate for fuzziness */
2364 				else
2365 					s[i].value-=20;
2366 			}
2367 		}
2368 	}
2369 	/* make sure that no stem it stretched between
2370 	 * a top zone and a bottom zone
2371 	 */
2372 	if(useblues) {
2373 		for(i=0; i<nnew; i+=2) {
2374 			a=10000; /* lowest border of top zone crosing the stem */
2375 			b= -10000; /* highest border of bottom zone crossing the stem */
2376 
2377 			for(j=2; j<nblues; j++) {
2378 				c=bluevalues[j];
2379 				if( c>=s[i].value && c<=s[i+1].value && c<a )
2380 					a=c;
2381 			}
2382 			if(nblues>=2) {
2383 				c=bluevalues[1];
2384 				if( c>=s[i].value && c<=s[i+1].value && c>b )
2385 					b=c;
2386 			}
2387 			for(j=1; j<notherb; j++) {
2388 				c=otherblues[j];
2389 				if( c>=s[i].value && c<=s[i+1].value && c>b )
2390 					b=c;
2391 			}
2392 			if( a!=10000 && b!= -10000 ) { /* it is stretched */
2393 				/* split the stem into 2 ghost stems */
2394 				for(j=nnew+1; j>i+1; j--) /* make free space */
2395 					s[j]=s[j-2];
2396 				nnew+=2;
2397 
2398 				if(s[i].value+22 >= a)
2399 					s[i+1].value=a-2; /* leave space for fuzziness */
2400 				else
2401 					s[i+1].value=s[i].value+20;
2402 
2403 				if(s[i+3].value-22 <= b)
2404 					s[i+2].value=b+2; /* leave space for fuzziness */
2405 				else
2406 					s[i+2].value=s[i+3].value-20;
2407 
2408 				i+=2;
2409 			}
2410 		}
2411 	}
2412 	/* look for triple stems */
2413 	for (i = 0; i < nnew; i += 2) {
2414 		if (nnew - i >= 6) {
2415 			a = s[i].value + s[i + 1].value;
2416 			b = s[i + 2].value + s[i + 3].value;
2417 			c = s[i + 4].value + s[i + 5].value;
2418 
2419 			w1 = s[i + 1].value - s[i].value;
2420 			w2 = s[i + 3].value - s[i + 2].value;
2421 			w3 = s[i + 5].value - s[i + 4].value;
2422 
2423 			fw = w3 - w1;	/* fuzz in width */
2424 			fd = ((c - b) - (b - a));	/* fuzz in distance
2425 							 * (doubled) */
2426 
2427 			/* we are able to handle some fuzz */
2428 			/*
2429 			 * it doesn't hurt if the declared stem is a bit
2430 			 * narrower than actual unless it's an edge in
2431 			 * a blue zone
2432 			 */
2433 			if (abs(abs(fd) - abs(fw)) * 5 < w2
2434 			    && abs(fw) * 20 < (w1 + w3)) {	/* width dirrerence <10% */
2435 
2436 				if(useblues) { /* check that we don't disturb any blue stems */
2437 					j=c; k=a;
2438 					if (fw > 0) {
2439 						if (fd > 0) {
2440 							if( s[i+5].flags & ST_BLUE )
2441 								continue;
2442 							j -= fw;
2443 						} else {
2444 							if( s[i+4].flags & ST_BLUE )
2445 								continue;
2446 							j += fw;
2447 						}
2448 					} else if(fw < 0) {
2449 						if (fd > 0) {
2450 							if( s[i+1].flags & ST_BLUE )
2451 								continue;
2452 							k -= fw;
2453 						} else {
2454 							if( s[i].flags & ST_BLUE )
2455 								continue;
2456 							k += fw;
2457 						}
2458 					}
2459 					pri = ((j - b) - (b - k));
2460 
2461 					if (pri > 0) {
2462 						if( s[i+2].flags & ST_BLUE )
2463 							continue;
2464 					} else if(pri < 0) {
2465 						if( s[i+3].flags & ST_BLUE )
2466 							continue;
2467 					}
2468 				}
2469 
2470 				/*
2471 				 * first fix up the width of 1st and 3rd
2472 				 * stems
2473 				 */
2474 				if (fw > 0) {
2475 					if (fd > 0) {
2476 						s[i + 5].value -= fw;
2477 						c -= fw;
2478 					} else {
2479 						s[i + 4].value += fw;
2480 						c += fw;
2481 					}
2482 				} else {
2483 					if (fd > 0) {
2484 						s[i + 1].value -= fw;
2485 						a -= fw;
2486 					} else {
2487 						s[i].value += fw;
2488 						a += fw;
2489 					}
2490 				}
2491 				fd = ((c - b) - (b - a));
2492 
2493 				if (fd > 0) {
2494 					s[i + 2].value += abs(fd) / 2;
2495 				} else {
2496 					s[i + 3].value -= abs(fd) / 2;
2497 				}
2498 
2499 				s[i].flags |= ST_3;
2500 				i += 4;
2501 			}
2502 		}
2503 	}
2504 
2505 	return (nnew & ~1);	/* number of lines must be always even */
2506 }
2507 
2508 /*
2509  * these macros and function allow to set the base stem,
2510  * check that it's not empty and subtract another stem
2511  * from the base stem (possibly dividing it into multiple parts)
2512  */
2513 
2514 /* pairs for pieces of the base stem */
2515 static short xbstem[MAX_STEMS*2];
2516 /* index of the last point */
2517 static int xblast= -1;
2518 
2519 #define setbasestem(from, to) \
2520 	(xbstem[0]=from, xbstem[1]=to, xblast=1)
2521 #define isbaseempty()	(xblast<=0)
2522 
2523 /* returns 1 if was overlapping, 0 otherwise */
2524 static int
subfrombase(int from,int to)2525 subfrombase(
2526 	int from,
2527 	int to
2528 )
2529 {
2530 	int a, b;
2531 	int i, j;
2532 
2533 	if(isbaseempty())
2534 		return 0;
2535 
2536 	/* handle the simple case simply */
2537 	if(from > xbstem[xblast] || to < xbstem[0])
2538 		return 0;
2539 
2540 	/* the binary search may be more efficient */
2541 	/* but for now the linear search is OK */
2542 	for(b=1; from > xbstem[b]; b+=2) {} /* result: from <= xbstem[b] */
2543 	for(a=xblast-1; to < xbstem[a]; a-=2) {} /* result: to >= xbstem[a] */
2544 
2545 	/* now the interesting examples are:
2546 	 * (it was hard for me to understand, so I looked at the examples)
2547 	 * 1
2548 	 *     a|-----|          |-----|b   |-----|     |-----|
2549 	 *              f|-----|t
2550 	 * 2
2551 	 *     a|-----|b         |-----|    |-----|     |-----|
2552 	 *      f|--|t
2553 	 * 3
2554 	 *     a|-----|b         |-----|    |-----|     |-----|
2555 	 *           f|-----|t
2556 	 * 4
2557 	 *      |-----|b        a|-----|    |-----|     |-----|
2558 	 *          f|------------|t
2559 	 * 5
2560 	 *      |-----|          |-----|b   |-----|    a|-----|
2561 	 *                   f|-----------------------------|t
2562 	 * 6
2563 	 *      |-----|b         |-----|    |-----|    a|-----|
2564 	 *   f|--------------------------------------------------|t
2565 	 * 7
2566 	 *      |-----|b         |-----|   a|-----|     |-----|
2567 	 *          f|--------------------------|t
2568 	 */
2569 
2570 	if(a < b-1) /* hits a gap  - example 1 */
2571 		return 0;
2572 
2573 	/* now the subtraction itself */
2574 
2575 	if(a==b-1 && from > xbstem[a] && to < xbstem[b]) {
2576 		/* overlaps with only one subrange and splits it - example 2 */
2577 		j=xblast; i=(xblast+=2);
2578 		while(j>=b)
2579 			xbstem[i--]=xbstem[j--];
2580 		xbstem[b]=from-1;
2581 		xbstem[b+1]=to+1;
2582 		return 1;
2583 	/* becomes
2584 	 * 2a
2585 	 *     a|b   ||          |-----|    |-----|     |-----|
2586 	 *      f|--|t
2587 	 */
2588 	}
2589 
2590 	if(xbstem[b-1] < from) {
2591 		/* cuts the back of this subrange - examples 3, 4, 7 */
2592 		xbstem[b] = from-1;
2593 		b+=2;
2594 	/* becomes
2595 	 * 3a
2596 	 *     a|----|           |-----|b   |-----|     |-----|
2597 	 *           f|-----|t
2598 	 * 4a
2599 	 *      |---|           a|-----|b   |-----|     |-----|
2600 	 *          f|------------|t
2601 	 * 7a
2602 	 *      |---|            |-----|b  a|-----|     |-----|
2603 	 *          f|--------------------------|t
2604 	 */
2605 	}
2606 
2607 	if(xbstem[a+1] > to) {
2608 		/* cuts the front of this subrange - examples 4a, 5, 7a */
2609 		xbstem[a] = to+1;
2610 		a-=2;
2611 	/* becomes
2612 	 * 4b
2613 	 *     a|---|              |---|b   |-----|     |-----|
2614 	 *          f|------------|t
2615 	 * 5b
2616 	 *      |-----|          |-----|b  a|-----|          ||
2617 	 *                   f|-----------------------------|t
2618 	 * 7b
2619 	 *      |---|           a|-----|b        ||     |-----|
2620 	 *          f|--------------------------|t
2621 	 */
2622 	}
2623 
2624 	if(a < b-1) /* now after modification it hits a gap - examples 3a, 4b */
2625 		return 1; /* because we have removed something */
2626 
2627 	/* now remove the subranges completely covered by the new stem */
2628 	/* examples 5b, 6, 7b */
2629 	i=b-1; j=a+2;
2630 	/* positioned as:
2631 	 * 5b                    i                           j
2632 	 *      |-----|          |-----|b  a|-----|          ||
2633 	 *                   f|-----------------------------|t
2634 	 * 6    i                                             xblast  j
2635 	 *      |-----|b         |-----|    |-----|    a|-----|
2636 	 *   f|--------------------------------------------------|t
2637 	 * 7b                    i               j
2638 	 *      |---|           a|-----|b        ||     |-----|
2639 	 *          f|--------------------------|t
2640 	 */
2641 	while(j <= xblast)
2642 		xbstem[i++]=xbstem[j++];
2643 	xblast=i-1;
2644 	return 1;
2645 }
2646 
2647 /* for debugging */
2648 static void
printbasestem(void)2649 printbasestem(void)
2650 {
2651 	int i;
2652 
2653 	printf("( ");
2654 	for(i=0; i<xblast; i+=2)
2655 		printf("%d-%d ", xbstem[i], xbstem[i+1]);
2656 	printf(") %d\n", xblast);
2657 }
2658 
2659 /*
2660  * Join the stem borders to build the sets of substituted stems
2661  * XXX add consideration of the italic angle
2662  */
2663 static void
joinsubstems(STEM * s,short * pairs,int nold,int useblues)2664 joinsubstems(
2665 	  STEM * s,
2666 	  short *pairs,
2667 	  int nold,
2668 	  int useblues /* do we use the blue values ? */
2669 )
2670 {
2671 	int i, j, x;
2672 	static unsigned char mx[MAX_STEMS][MAX_STEMS];
2673 
2674 	/* we do the substituted groups of stems first
2675 	 * and it looks like it's going to be REALLY SLOW
2676 	 * AND PAINFUL but let's bother about it later
2677 	 */
2678 
2679 	/* for the substituted stems we don't bother about [hv]stem3 -
2680 	 * anyway the X11R6 rasterizer does not bother about hstem3
2681 	 * at all and is able to handle only one global vstem3
2682 	 * per glyph
2683 	 */
2684 
2685 	/* clean the used part of matrix */
2686 	for(i=0; i<nold; i++)
2687 		for(j=0; j<nold; j++)
2688 			mx[i][j]=0;
2689 
2690 	/* build the matrix of stem pairs */
2691 	for(i=0; i<nold; i++) {
2692 		if( s[i].flags & ST_ZONE )
2693 			continue;
2694 		if(s[i].flags & ST_BLUE)
2695 			mx[i][i]=1; /* allow to pair with itself if no better pair */
2696 		if(s[i].flags & ST_UP) { /* the down-stems are already matched */
2697 			setbasestem(s[i].from, s[i].to);
2698 			for(j=i+1; j<nold; j++) {
2699 				if(s[i].value==s[j].value
2700 				|| s[j].flags & ST_ZONE ) {
2701 					continue;
2702 				}
2703 				x=subfrombase(s[j].from, s[j].to);
2704 
2705 				if(s[j].flags & ST_UP) /* match only up+down pairs */
2706 					continue;
2707 
2708 				mx[i][j]=mx[j][i]=x;
2709 
2710 				if(isbaseempty()) /* nothing else to do */
2711 					break;
2712 			}
2713 		}
2714 	}
2715 
2716 	if(ISDBG(SUBSTEMS)) {
2717 		fprintf(pfa_file, "%%     ");
2718 		for(j=0; j<nold; j++)
2719 			putc( j%10==0 ? '0'+(j/10)%10 : ' ', pfa_file);
2720 		fprintf(pfa_file, "\n%%     ");
2721 		for(j=0; j<nold; j++)
2722 			putc('0'+j%10, pfa_file);
2723 		putc('\n', pfa_file);
2724 		for(i=0; i<nold; i++) {
2725 			fprintf(pfa_file, "%% %3d ",i);
2726 			for(j=0; j<nold; j++)
2727 				putc( mx[i][j] ? 'X' : '.', pfa_file);
2728 			putc('\n', pfa_file);
2729 		}
2730 	}
2731 
2732 	/* now use the matrix to find the best pair for each stem */
2733 	for(i=0; i<nold; i++) {
2734 		int pri, lastpri, v, f;
2735 
2736 		x= -1; /* best pair: none */
2737 		lastpri=0;
2738 
2739 		v=s[i].value;
2740 		f=s[i].flags;
2741 
2742 		if(f & ST_ZONE) {
2743 			pairs[i]= -1;
2744 			continue;
2745 		}
2746 
2747 		if(f & ST_UP) {
2748 			for(j=i+1; j<nold; j++) {
2749 				if(mx[i][j]==0)
2750 					continue;
2751 
2752 				if( (f | s[j].flags) & ST_END )
2753 					pri=1;
2754 				else if( (f | s[j].flags) & ST_FLAT )
2755 					pri=3;
2756 				else
2757 					pri=2;
2758 
2759 				if(lastpri==0
2760 				|| pri > lastpri
2761 				&& ( lastpri==1 || s[j].value-v<20 || (s[x].value-v)*2 >= s[j].value-v ) ) {
2762 					lastpri=pri;
2763 					x=j;
2764 				}
2765 			}
2766 		} else {
2767 			for(j=i-1; j>=0; j--) {
2768 				if(mx[i][j]==0)
2769 					continue;
2770 
2771 				if( (f | s[j].flags) & ST_END )
2772 					pri=1;
2773 				else if( (f | s[j].flags) & ST_FLAT )
2774 					pri=3;
2775 				else
2776 					pri=2;
2777 
2778 				if(lastpri==0
2779 				|| pri > lastpri
2780 				&& ( lastpri==1 || v-s[j].value<20 || (v-s[x].value)*2 >= v-s[j].value ) ) {
2781 					lastpri=pri;
2782 					x=j;
2783 				}
2784 			}
2785 		}
2786 		if(x== -1 && mx[i][i])
2787 			pairs[i]=i; /* a special case */
2788 		else
2789 			pairs[i]=x;
2790 	}
2791 
2792 	if(ISDBG(SUBSTEMS)) {
2793 		for(i=0; i<nold; i++) {
2794 			j=pairs[i];
2795 			if(j>0)
2796 				fprintf(pfa_file, "%% %d...%d  (%d x %d)\n", s[i].value, s[j].value, i, j);
2797 		}
2798 	}
2799 }
2800 
2801 /*
2802  * Make all the stems originating at the same value get the
2803  * same width. Without this the rasterizer may move the dots
2804  * randomly up or down by one pixel, and that looks bad.
2805  * The prioritisation is the same as in findstemat().
2806  */
2807 static void
uniformstems(STEM * s,short * pairs,int ns)2808 uniformstems(
2809 	  STEM * s,
2810 	  short *pairs,
2811 	  int ns
2812 )
2813 {
2814 	int i, j, from, to, val, dir;
2815 	int pri, prevpri[2], wd, prevwd[2], prevbest[2];
2816 
2817 	for(from=0; from<ns; from=to) {
2818 		prevpri[0] = prevpri[1] = 0;
2819 		prevwd[0] = prevwd[1] = 0;
2820 		prevbest[0] = prevbest[1] = -1;
2821 		val = s[from].value;
2822 
2823 		for(to = from; to<ns && s[to].value == val; to++) {
2824 			dir = ((s[to].flags & ST_UP)!=0);
2825 
2826 			i=pairs[to]; /* the other side of this stem */
2827 			if(i<0 || i==to)
2828 				continue; /* oops, no other side */
2829 			wd=abs(s[i].value-val);
2830 			if(wd == 0)
2831 				continue;
2832 			pri=1;
2833 			if( (s[to].flags | s[i].flags) & ST_END )
2834 				pri=0;
2835 			if( prevbest[dir] == -1 || pri > prevpri[dir] || wd<prevwd[dir] ) {
2836 				prevbest[dir]=i;
2837 				prevpri[dir]=pri;
2838 				prevwd[dir]=wd;
2839 			}
2840 		}
2841 
2842 		for(i=from; i<to; i++) {
2843 			dir = ((s[i].flags & ST_UP)!=0);
2844 			if(prevbest[dir] >= 0) {
2845 				if(ISDBG(SUBSTEMS)) {
2846 					fprintf(stderr, "at %d (%s %d) pair %d->%d(%d)\n", i,
2847 						(dir ? "UP":"DOWN"), s[i].value, pairs[i], prevbest[dir],
2848 						s[prevbest[dir]].value);
2849 				}
2850 				pairs[i] = prevbest[dir];
2851 			}
2852 		}
2853 	}
2854 }
2855 
2856 /*
2857  * Find the best stem in the array at the specified (value, origin),
2858  * related to the entry ge.
2859  * Returns its index in the array sp, -1 means "none".
2860  * prevbest is the result for the other end of the line, we must
2861  * find something better than it or leave it as it is.
2862  */
2863 static int
findstemat(int value,int origin,GENTRY * ge,STEM * sp,short * pairs,int ns,int prevbest)2864 findstemat(
2865 	int value,
2866 	int origin,
2867 	GENTRY *ge,
2868 	STEM *sp,
2869 	short *pairs,
2870 	int ns,
2871 	int prevbest /* -1 means "none" */
2872 )
2873 {
2874 	int i, min, max;
2875 	int v, si;
2876 	int pri, prevpri; /* priority, 0 = has ST_END, 1 = no ST_END */
2877 	int wd, prevwd; /* stem width */
2878 
2879 	si= -1; /* nothing yet */
2880 
2881 	/* stems are ordered by value, binary search */
2882 	min=0; max=ns; /* min <= i < max */
2883 	while( min < max ) {
2884 		i=(min+max)/2;
2885 		v=sp[i].value;
2886 		if(v<value)
2887 			min=i+1;
2888 		else if(v>value)
2889 			max=i;
2890 		else {
2891 			si=i; /* temporary value */
2892 			break;
2893 		}
2894 	}
2895 
2896 	if( si < 0 ) /* found nothing this time */
2897 		return prevbest;
2898 
2899 	/* find the priority of the prevbest */
2900 	/* we expect that prevbest has a pair */
2901 	if(prevbest>=0) {
2902 		i=pairs[prevbest];
2903 		prevpri=1;
2904 		if( (sp[prevbest].flags | sp[i].flags) & ST_END )
2905 			prevpri=0;
2906 		prevwd=abs(sp[i].value-value);
2907 	}
2908 
2909 	/* stems are not ordered by origin, so now do the linear search */
2910 
2911 	while( si>0 && sp[si-1].value==value ) /* find the first one */
2912 		si--;
2913 
2914 	for(; si<ns && sp[si].value==value; si++) {
2915 		if(sp[si].origin != origin)
2916 			continue;
2917 		if(sp[si].ge != ge) {
2918 			if(ISDBG(SUBSTEMS)) {
2919 				fprintf(stderr,
2920 					"dbg: possible self-intersection at v=%d o=%d exp_ge=0x%x ge=0x%x\n",
2921 					value, origin, ge, sp[si].ge);
2922 			}
2923 			continue;
2924 		}
2925 		i=pairs[si]; /* the other side of this stem */
2926 		if(i<0)
2927 			continue; /* oops, no other side */
2928 		pri=1;
2929 		if( (sp[si].flags | sp[i].flags) & ST_END )
2930 			pri=0;
2931 		wd=abs(sp[i].value-value);
2932 		if( prevbest == -1 || pri >prevpri
2933 		|| pri==prevpri && prevwd==0 || wd!=0 && wd<prevwd ) {
2934 			prevbest=si;
2935 			prevpri=pri;
2936 			prevwd=wd;
2937 			continue;
2938 		}
2939 	}
2940 
2941 	return prevbest;
2942 }
2943 
2944 /* add the substems for one glyph entry
2945  * (called from groupsubstems())
2946  * returns 0 if all OK, 1 if too many groups
2947  */
2948 
2949 static int gssentry_lastgrp=0; /* reset to 0 for each new glyph */
2950 
2951 static int
gssentry(GENTRY * ge,STEM * hs,short * hpairs,int nhs,STEM * vs,short * vpairs,int nvs,STEMBOUNDS * s,short * egp,int * nextvsi,int * nexthsi)2952 gssentry( /* crazy number of parameters */
2953 	GENTRY *ge,
2954 	STEM *hs, /* horizontal stems, sorted by value */
2955 	short *hpairs,
2956 	int nhs,
2957 	STEM *vs, /* vertical stems, sorted by value */
2958 	short *vpairs,
2959 	int nvs,
2960 	STEMBOUNDS *s,
2961 	short *egp,
2962 	int *nextvsi,
2963 	int *nexthsi /* -2 means "check by yourself" */
2964 ) {
2965 	enum {
2966 		SI_VP,	/* vertical primary */
2967 		SI_HP,	/* horizontal primary */
2968 		SI_SIZE /* size of the array */
2969 	};
2970 	int si[SI_SIZE]; /* indexes of relevant stems */
2971 
2972 	/* the bounds of the existing relevant stems */
2973 	STEMBOUNDS r[ sizeof(si) / sizeof(si[0]) * 2 ];
2974 	char rexpand; /* by how much we need to expand the group */
2975 	int nr; /* and the number of them */
2976 
2977 	/* yet more temporary storage */
2978 	short lb, hb, isvert;
2979 	int conflict, grp;
2980 	int i, j, x, y;
2981 
2982 
2983 	/* for each line or curve we try to find a horizontal and
2984 	 * a vertical stem corresponding to its first point
2985 	 * (corresponding to the last point of the previous
2986 	 * glyph entry), because the directions of the lines
2987 	 * will be eventually reversed and it will then become the last
2988 	 * point. And the T1 rasterizer applies the hints to
2989 	 * the last point.
2990 	 *
2991 	 */
2992 
2993 	/* start with the common part, the first point */
2994 	x=ge->prev->ix3;
2995 	y=ge->prev->iy3;
2996 
2997 	if(*nextvsi == -2)
2998 		si[SI_VP]=findstemat(x, y, ge, vs, vpairs, nvs, -1);
2999 	else {
3000 		si[SI_VP]= *nextvsi; *nextvsi= -2;
3001 	}
3002 	if(*nexthsi == -2)
3003 		si[SI_HP]=findstemat(y, x, ge, hs, hpairs, nhs, -1);
3004 	else {
3005 		si[SI_HP]= *nexthsi; *nexthsi= -2;
3006 	}
3007 
3008 	/*
3009 	 * For the horizontal lines we make sure that both
3010 	 * ends of the line have the same horizontal stem,
3011 	 * and the same thing for vertical lines and stems.
3012 	 * In both cases we enforce the stem for the next entry.
3013 	 * Otherwise unpleasant effects may arise.
3014 	 */
3015 
3016 	if(ge->type==GE_LINE) {
3017 		if(ge->ix3==x) { /* vertical line */
3018 			*nextvsi=si[SI_VP]=findstemat(x, ge->iy3, ge->frwd, vs, vpairs, nvs, si[SI_VP]);
3019 		} else if(ge->iy3==y) { /* horizontal line */
3020 			*nexthsi=si[SI_HP]=findstemat(y, ge->ix3, ge->frwd, hs, hpairs, nhs, si[SI_HP]);
3021 		}
3022 	}
3023 
3024 	if(si[SI_VP]+si[SI_HP] == -2) /* no stems, leave it alone */
3025 		return 0;
3026 
3027 	/* build the array of relevant bounds */
3028 	nr=0;
3029 	for(i=0; i< sizeof(si) / sizeof(si[0]); i++) {
3030 		STEM *sp;
3031 		short *pairs;
3032 		int step;
3033 		int f;
3034 		int nzones, firstzone, binzone, einzone;
3035 		int btype, etype;
3036 
3037 		if(si[i] < 0)
3038 			continue;
3039 
3040 		if(i<SI_HP) {
3041 			r[nr].isvert=1; sp=vs; pairs=vpairs;
3042 		} else {
3043 			r[nr].isvert=0; sp=hs; pairs=hpairs;
3044 		}
3045 
3046 		r[nr].low=sp[ si[i] ].value;
3047 		r[nr].high=sp[ pairs[ si[i] ] ].value;
3048 
3049 		if(r[nr].low > r[nr].high) {
3050 			j=r[nr].low; r[nr].low=r[nr].high; r[nr].high=j;
3051 			step= -1;
3052 		} else {
3053 			step=1;
3054 		}
3055 
3056 		/* handle the interaction with Blue Zones */
3057 
3058 		if(i>=SI_HP) { /* only for horizontal stems */
3059 			if(si[i]==pairs[si[i]]) {
3060 				/* special case, the outermost stem in the
3061 				 * Blue Zone without a pair, simulate it to 20-pixel
3062 				 */
3063 				if(sp[ si[i] ].flags & ST_UP) {
3064 					r[nr].high+=20;
3065 					for(j=si[i]+1; j<nhs; j++)
3066 						if( (sp[j].flags & (ST_ZONE|ST_TOPZONE))
3067 						== (ST_ZONE|ST_TOPZONE) ) {
3068 							if(r[nr].high > sp[j].value-2)
3069 								r[nr].high=sp[j].value-2;
3070 							break;
3071 						}
3072 				} else {
3073 					r[nr].low-=20;
3074 					for(j=si[i]-1; j>=0; j--)
3075 						if( (sp[j].flags & (ST_ZONE|ST_TOPZONE))
3076 						== (ST_ZONE) ) {
3077 							if(r[nr].low < sp[j].value+2)
3078 								r[nr].low=sp[j].value+2;
3079 							break;
3080 						}
3081 				}
3082 			}
3083 
3084 			/* check that the stem borders don't end up in
3085 			 * different Blue Zones */
3086 			f=sp[ si[i] ].flags;
3087 			nzones=0; einzone=binzone=0;
3088 			for(j=si[i]; j!=pairs[ si[i] ]; j+=step) {
3089 				if( (sp[j].flags & ST_ZONE)==0 )
3090 					continue;
3091 				/* if see a zone border going in the same direction */
3092 				if( ((f ^ sp[j].flags) & ST_UP)==0 ) {
3093 					if( ++nzones == 1 ) {
3094 						firstzone=sp[j].value; /* remember the first one */
3095 						etype=sp[j].flags & ST_TOPZONE;
3096 					}
3097 					einzone=1;
3098 
3099 				} else { /* the opposite direction */
3100 					if(nzones==0) { /* beginning is in a blue zone */
3101 						binzone=1;
3102 						btype=sp[j].flags & ST_TOPZONE;
3103 					}
3104 					einzone=0;
3105 				}
3106 			}
3107 
3108 			/* beginning and end are in Blue Zones of different types */
3109 			if( binzone && einzone && (btype ^ etype)!=0 ) {
3110 				if( sp[si[i]].flags & ST_UP ) {
3111 					if(firstzone > r[nr].low+22)
3112 						r[nr].high=r[nr].low+20;
3113 					else
3114 						r[nr].high=firstzone-2;
3115 				} else {
3116 					if(firstzone < r[nr].high-22)
3117 						r[nr].low=r[nr].high-20;
3118 					else
3119 						r[nr].low=firstzone+2;
3120 				}
3121 			}
3122 		}
3123 
3124 		if(ISDBG(SUBSTEMS))
3125 			fprintf(pfa_file, "%%  at(%d,%d)[%d,%d] %d..%d %c (%d x %d)\n", x, y, i, nr,
3126 				r[nr].low, r[nr].high, r[nr].isvert ? 'v' : 'h',
3127 				si[i], pairs[si[i]]);
3128 
3129 		nr++;
3130 	}
3131 
3132 	/* now try to find a group */
3133 	conflict=0; /* no conflicts found yet */
3134 	for(j=0; j<nr; j++)
3135 		r[j].already=0;
3136 
3137 	/* check if it fits into the last group */
3138 	grp = gssentry_lastgrp;
3139 	i = (grp==0)? 0 : egp[grp-1];
3140 	for(; i<egp[grp]; i++) {
3141 		lb=s[i].low; hb=s[i].high; isvert=s[i].isvert;
3142 		for(j=0; j<nr; j++)
3143 			if( r[j].isvert==isvert  /* intersects */
3144 			&& r[j].low <= hb && r[j].high >= lb ) {
3145 				if( r[j].low == lb && r[j].high == hb ) /* coincides */
3146 					r[j].already=1;
3147 				else
3148 					conflict=1;
3149 			}
3150 
3151 		if(conflict)
3152 			break;
3153 	}
3154 
3155 	if(conflict) { /* nope, check all the groups */
3156 		for(j=0; j<nr; j++)
3157 			r[j].already=0;
3158 
3159 		for(i=0, grp=0; i<egp[NSTEMGRP-1]; i++) {
3160 			if(i == egp[grp]) { /* checked all stems in a group */
3161 				if(conflict) {
3162 					grp++; conflict=0; /* check the next group */
3163 					for(j=0; j<nr; j++)
3164 						r[j].already=0;
3165 				} else
3166 					break; /* insert into this group */
3167 			}
3168 
3169 			lb=s[i].low; hb=s[i].high; isvert=s[i].isvert;
3170 			for(j=0; j<nr; j++)
3171 				if( r[j].isvert==isvert  /* intersects */
3172 				&& r[j].low <= hb && r[j].high >= lb ) {
3173 					if( r[j].low == lb && r[j].high == hb ) /* coincides */
3174 						r[j].already=1;
3175 					else
3176 						conflict=1;
3177 				}
3178 
3179 			if(conflict)
3180 				i=egp[grp]-1; /* fast forward to the next group */
3181 		}
3182 	}
3183 
3184 	/* do we have any empty group ? */
3185 	if(conflict && grp < NSTEMGRP-1) {
3186 		grp++; conflict=0;
3187 		for(j=0; j<nr; j++)
3188 			r[j].already=0;
3189 	}
3190 
3191 	if(conflict) { /* oops, can't find any group to fit */
3192 		return 1;
3193 	}
3194 
3195 	/* OK, add stems to this group */
3196 
3197 	rexpand = nr;
3198 	for(j=0; j<nr; j++)
3199 		rexpand -= r[j].already;
3200 
3201 	if(rexpand > 0) {
3202 		for(i=egp[NSTEMGRP-1]-1; i>=egp[grp]; i--)
3203 			s[i+rexpand]=s[i];
3204 		for(i=0; i<nr; i++)
3205 			if(!r[i].already)
3206 				s[egp[grp]++]=r[i];
3207 		for(i=grp+1; i<NSTEMGRP; i++)
3208 			egp[i]+=rexpand;
3209 	}
3210 
3211 	ge->stemid = gssentry_lastgrp = grp;
3212 	return 0;
3213 }
3214 
3215 /*
3216  * Create the groups of substituted stems from the list.
3217  * Each group will be represented by a subroutine in the Subs
3218  * array.
3219  */
3220 
3221 static void
groupsubstems(GLYPH * g,STEM * hs,short * hpairs,int nhs,STEM * vs,short * vpairs,int nvs)3222 groupsubstems(
3223 	GLYPH *g,
3224 	STEM *hs, /* horizontal stems, sorted by value */
3225 	short *hpairs,
3226 	int nhs,
3227 	STEM *vs, /* vertical stems, sorted by value */
3228 	short *vpairs,
3229 	int nvs
3230 )
3231 {
3232 	GENTRY *ge;
3233 	int i, j;
3234 
3235 	/* temporary storage */
3236 	STEMBOUNDS s[MAX_STEMS*2];
3237 	/* indexes in there, pointing past the end each stem group */
3238 	short egp[NSTEMGRP];
3239 
3240 	int nextvsi, nexthsi; /* -2 means "check by yourself" */
3241 
3242 	for(i=0; i<NSTEMGRP; i++)
3243 		egp[i]=0;
3244 
3245 	nextvsi=nexthsi= -2; /* processed no horiz/vert line */
3246 
3247 	gssentry_lastgrp = 0; /* reset the last group for new glyph */
3248 
3249 	for (ge = g->entries; ge != 0; ge = ge->next) {
3250 		if(ge->type!=GE_LINE && ge->type!=GE_CURVE) {
3251 			nextvsi=nexthsi= -2; /* next path is independent */
3252 			continue;
3253 		}
3254 
3255 		if( gssentry(ge, hs, hpairs, nhs, vs, vpairs, nvs, s, egp, &nextvsi, &nexthsi) ) {
3256 			WARNING_2 fprintf(stderr, "*** glyph %s requires over %d hint subroutines, ignored them\n",
3257 				g->name, NSTEMGRP);
3258 			/* it's better to have no substituted hints at all than have only part */
3259 			for (ge = g->entries; ge != 0; ge = ge->next)
3260 				ge->stemid= -1;
3261 			g->nsg=0; /* just to be safe, already is 0 by initialization */
3262 			return;
3263 		}
3264 
3265 		/*
3266 		 * handle the last vert/horiz line of the path specially,
3267 		 * correct the hint for the first entry of the path
3268 		 */
3269 		if(ge->frwd != ge->next && (nextvsi != -2 || nexthsi != -2) ) {
3270 			if( gssentry(ge->frwd, hs, hpairs, nhs, vs, vpairs, nvs, s, egp, &nextvsi, &nexthsi) ) {
3271 				WARNING_2 fprintf(stderr, "*** glyph %s requires over %d hint subroutines, ignored them\n",
3272 					g->name, NSTEMGRP);
3273 				/* it's better to have no substituted hints at all than have only part */
3274 				for (ge = g->entries; ge != 0; ge = ge->next)
3275 					ge->stemid= -1;
3276 				g->nsg=0; /* just to be safe, already is 0 by initialization */
3277 				return;
3278 			}
3279 		}
3280 
3281 	}
3282 
3283 	/* find the index of the first empty group - same as the number of groups */
3284 	if(egp[0]>0) {
3285 		for(i=1; i<NSTEMGRP && egp[i]!=egp[i-1]; i++)
3286 			{}
3287 		g->nsg=i;
3288 	} else
3289 		g->nsg=0;
3290 
3291 	if(ISDBG(SUBSTEMS)) {
3292 		fprintf(pfa_file, "%% %d substem groups (%d %d %d)\n", g->nsg,
3293 			g->nsg>1 ? egp[g->nsg-2] : -1,
3294 			g->nsg>0 ? egp[g->nsg-1] : -1,
3295 			g->nsg<NSTEMGRP ? egp[g->nsg] : -1 );
3296 		j=0;
3297 		for(i=0; i<g->nsg; i++) {
3298 			fprintf(pfa_file, "%% grp %3d:      ", i);
3299 			for(; j<egp[i]; j++) {
3300 				fprintf(pfa_file, " %4d...%-4d %c  ", s[j].low, s[j].high,
3301 					s[j].isvert ? 'v' : 'h');
3302 			}
3303 			fprintf(pfa_file, "\n");
3304 		}
3305 	}
3306 
3307 	if(g->nsg==1) { /* it would be the same as the main stems */
3308 		/* so erase it */
3309 		for (ge = g->entries; ge != 0; ge = ge->next)
3310 			ge->stemid= -1;
3311 		g->nsg=0;
3312 	}
3313 
3314 	if(g->nsg>0) {
3315 		if( (g->nsbs=malloc(g->nsg * sizeof (egp[0]))) == 0 ) {
3316 			fprintf(stderr, "**** not enough memory for substituted hints ****\n");
3317 			exit(255);
3318 		}
3319 		memmove(g->nsbs, egp, g->nsg * sizeof(short));
3320 		if( (g->sbstems=malloc(egp[g->nsg-1] * sizeof (s[0]))) == 0 ) {
3321 			fprintf(stderr, "**** not enough memory for substituted hints ****\n");
3322 			exit(255);
3323 		}
3324 		memmove(g->sbstems, s, egp[g->nsg-1] * sizeof(s[0]));
3325 	}
3326 }
3327 
3328 void
buildstems(GLYPH * g)3329 buildstems(
3330 	   GLYPH * g
3331 )
3332 {
3333 	STEM            hs[MAX_STEMS], vs[MAX_STEMS];	/* temporary working
3334 							 * storage */
3335 	short	hs_pairs[MAX_STEMS], vs_pairs[MAX_STEMS]; /* best pairs for these stems */
3336 	STEM           *sp;
3337 	GENTRY         *ge, *nge, *pge;
3338 	int             nx, ny;
3339 	int ovalue;
3340 	int totals, grp, lastgrp;
3341 
3342 	assertisint(g, "buildstems int");
3343 
3344 	g->nhs = g->nvs = 0;
3345 	memset(hs, 0, sizeof hs);
3346 	memset(vs, 0, sizeof vs);
3347 
3348 	/* first search the whole character for possible stem points */
3349 
3350 	for (ge = g->entries; ge != 0; ge = ge->next) {
3351 		if (ge->type == GE_CURVE) {
3352 
3353 			/*
3354 			 * SURPRISE!
3355 			 * We consider the stems bound by the
3356 			 * H/V ends of the curves as flat ones.
3357 			 *
3358 			 * But we don't include the point on the
3359 			 * other end into the range.
3360 			 */
3361 
3362 			/* first check the beginning of curve */
3363 			/* if it is horizontal, add a hstem */
3364 			if (ge->iy1 == ge->prev->iy3) {
3365 				hs[g->nhs].value = ge->iy1;
3366 
3367 				if (ge->ix1 < ge->prev->ix3)
3368 					hs[g->nhs].flags = ST_FLAT | ST_UP;
3369 				else
3370 					hs[g->nhs].flags = ST_FLAT;
3371 
3372 				hs[g->nhs].origin = ge->prev->ix3;
3373 				hs[g->nhs].ge = ge;
3374 
3375 				if (ge->ix1 < ge->prev->ix3) {
3376 					hs[g->nhs].from = ge->ix1+1;
3377 					hs[g->nhs].to = ge->prev->ix3;
3378 					if(hs[g->nhs].from > hs[g->nhs].to)
3379 						hs[g->nhs].from--;
3380 				} else {
3381 					hs[g->nhs].from = ge->prev->ix3;
3382 					hs[g->nhs].to = ge->ix1-1;
3383 					if(hs[g->nhs].from > hs[g->nhs].to)
3384 						hs[g->nhs].to++;
3385 				}
3386 				if (ge->ix1 != ge->prev->ix3)
3387 					g->nhs++;
3388 			}
3389 			/* if it is vertical, add a vstem */
3390 			else if (ge->ix1 == ge->prev->ix3) {
3391 				vs[g->nvs].value = ge->ix1;
3392 
3393 				if (ge->iy1 > ge->prev->iy3)
3394 					vs[g->nvs].flags = ST_FLAT | ST_UP;
3395 				else
3396 					vs[g->nvs].flags = ST_FLAT;
3397 
3398 				vs[g->nvs].origin = ge->prev->iy3;
3399 				vs[g->nvs].ge = ge;
3400 
3401 				if (ge->iy1 < ge->prev->iy3) {
3402 					vs[g->nvs].from = ge->iy1+1;
3403 					vs[g->nvs].to = ge->prev->iy3;
3404 					if(vs[g->nvs].from > vs[g->nvs].to)
3405 						vs[g->nvs].from--;
3406 				} else {
3407 					vs[g->nvs].from = ge->prev->iy3;
3408 					vs[g->nvs].to = ge->iy1-1;
3409 					if(vs[g->nvs].from > vs[g->nvs].to)
3410 						vs[g->nvs].to++;
3411 				}
3412 
3413 				if (ge->iy1 != ge->prev->iy3)
3414 					g->nvs++;
3415 			}
3416 			/* then check the end of curve */
3417 			/* if it is horizontal, add a hstem */
3418 			if (ge->iy3 == ge->iy2) {
3419 				hs[g->nhs].value = ge->iy3;
3420 
3421 				if (ge->ix3 < ge->ix2)
3422 					hs[g->nhs].flags = ST_FLAT | ST_UP;
3423 				else
3424 					hs[g->nhs].flags = ST_FLAT;
3425 
3426 				hs[g->nhs].origin = ge->ix3;
3427 				hs[g->nhs].ge = ge->frwd;
3428 
3429 				if (ge->ix3 < ge->ix2) {
3430 					hs[g->nhs].from = ge->ix3;
3431 					hs[g->nhs].to = ge->ix2-1;
3432 					if( hs[g->nhs].from > hs[g->nhs].to )
3433 						hs[g->nhs].to++;
3434 				} else {
3435 					hs[g->nhs].from = ge->ix2+1;
3436 					hs[g->nhs].to = ge->ix3;
3437 					if( hs[g->nhs].from > hs[g->nhs].to )
3438 						hs[g->nhs].from--;
3439 				}
3440 
3441 				if (ge->ix3 != ge->ix2)
3442 					g->nhs++;
3443 			}
3444 			/* if it is vertical, add a vstem */
3445 			else if (ge->ix3 == ge->ix2) {
3446 				vs[g->nvs].value = ge->ix3;
3447 
3448 				if (ge->iy3 > ge->iy2)
3449 					vs[g->nvs].flags = ST_FLAT | ST_UP;
3450 				else
3451 					vs[g->nvs].flags = ST_FLAT;
3452 
3453 				vs[g->nvs].origin = ge->iy3;
3454 				vs[g->nvs].ge = ge->frwd;
3455 
3456 				if (ge->iy3 < ge->iy2) {
3457 					vs[g->nvs].from = ge->iy3;
3458 					vs[g->nvs].to = ge->iy2-1;
3459 					if( vs[g->nvs].from > vs[g->nvs].to )
3460 						vs[g->nvs].to++;
3461 				} else {
3462 					vs[g->nvs].from = ge->iy2+1;
3463 					vs[g->nvs].to = ge->iy3;
3464 					if( vs[g->nvs].from > vs[g->nvs].to )
3465 						vs[g->nvs].from--;
3466 				}
3467 
3468 				if (ge->iy3 != ge->iy2)
3469 					g->nvs++;
3470 			} else {
3471 
3472 				/*
3473 				 * check the end of curve for a not smooth
3474 				 * local extremum
3475 				 */
3476 				nge = ge->frwd;
3477 
3478 				if (nge == 0)
3479 					continue;
3480 				else if (nge->type == GE_LINE) {
3481 					nx = nge->ix3;
3482 					ny = nge->iy3;
3483 				} else if (nge->type == GE_CURVE) {
3484 					nx = nge->ix1;
3485 					ny = nge->iy1;
3486 				} else
3487 					continue;
3488 
3489 				/* check for vertical extremums */
3490 				if (ge->iy3 > ge->iy2 && ge->iy3 > ny
3491 				|| ge->iy3 < ge->iy2 && ge->iy3 < ny) {
3492 					hs[g->nhs].value = ge->iy3;
3493 					hs[g->nhs].from
3494 						= hs[g->nhs].to
3495 						= hs[g->nhs].origin = ge->ix3;
3496 					hs[g->nhs].ge = ge->frwd;
3497 
3498 					if (ge->ix3 < ge->ix2
3499 					    || nx < ge->ix3)
3500 						hs[g->nhs].flags = ST_UP;
3501 					else
3502 						hs[g->nhs].flags = 0;
3503 
3504 					if (ge->ix3 != ge->ix2 || nx != ge->ix3)
3505 						g->nhs++;
3506 				}
3507 				/*
3508 				 * the same point may be both horizontal and
3509 				 * vertical extremum
3510 				 */
3511 				/* check for horizontal extremums */
3512 				if (ge->ix3 > ge->ix2 && ge->ix3 > nx
3513 				|| ge->ix3 < ge->ix2 && ge->ix3 < nx) {
3514 					vs[g->nvs].value = ge->ix3;
3515 					vs[g->nvs].from
3516 						= vs[g->nvs].to
3517 						= vs[g->nvs].origin = ge->iy3;
3518 					vs[g->nvs].ge = ge->frwd;
3519 
3520 					if (ge->iy3 > ge->iy2
3521 					    || ny > ge->iy3)
3522 						vs[g->nvs].flags = ST_UP;
3523 					else
3524 						vs[g->nvs].flags = 0;
3525 
3526 					if (ge->iy3 != ge->iy2 || ny != ge->iy3)
3527 						g->nvs++;
3528 				}
3529 			}
3530 
3531 		} else if (ge->type == GE_LINE) {
3532 			nge = ge->frwd;
3533 
3534 			/* if it is horizontal, add a hstem */
3535 			/* and the ends as vstems if they brace the line */
3536 			if (ge->iy3 == ge->prev->iy3
3537 			&& ge->ix3 != ge->prev->ix3) {
3538 				hs[g->nhs].value = ge->iy3;
3539 				if (ge->ix3 < ge->prev->ix3) {
3540 					hs[g->nhs].flags = ST_FLAT | ST_UP;
3541 					hs[g->nhs].from = ge->ix3;
3542 					hs[g->nhs].to = ge->prev->ix3;
3543 				} else {
3544 					hs[g->nhs].flags = ST_FLAT;
3545 					hs[g->nhs].from = ge->prev->ix3;
3546 					hs[g->nhs].to = ge->ix3;
3547 				}
3548 				hs[g->nhs].origin = ge->ix3;
3549 				hs[g->nhs].ge = ge->frwd;
3550 
3551 				pge = ge->bkwd;
3552 
3553 				/* add beginning as vstem */
3554 				vs[g->nvs].value = pge->ix3;
3555 				vs[g->nvs].origin
3556 					= vs[g->nvs].from
3557 					= vs[g->nvs].to = pge->iy3;
3558 				vs[g->nvs].ge = ge;
3559 
3560 				if(pge->type==GE_CURVE)
3561 					ovalue=pge->iy2;
3562 				else
3563 					ovalue=pge->prev->iy3;
3564 
3565 				if (pge->iy3 > ovalue)
3566 					vs[g->nvs].flags = ST_UP | ST_END;
3567 				else if (pge->iy3 < ovalue)
3568 					vs[g->nvs].flags = ST_END;
3569 				else
3570 					vs[g->nvs].flags = 0;
3571 
3572 				if( vs[g->nvs].flags != 0 )
3573 					g->nvs++;
3574 
3575 				/* add end as vstem */
3576 				vs[g->nvs].value = ge->ix3;
3577 				vs[g->nvs].origin
3578 					= vs[g->nvs].from
3579 					= vs[g->nvs].to = ge->iy3;
3580 				vs[g->nvs].ge = ge->frwd;
3581 
3582 				if(nge->type==GE_CURVE)
3583 					ovalue=nge->iy1;
3584 				else
3585 					ovalue=nge->iy3;
3586 
3587 				if (ovalue > ge->iy3)
3588 					vs[g->nvs].flags = ST_UP | ST_END;
3589 				else if (ovalue < ge->iy3)
3590 					vs[g->nvs].flags = ST_END;
3591 				else
3592 					vs[g->nvs].flags = 0;
3593 
3594 				if( vs[g->nvs].flags != 0 )
3595 					g->nvs++;
3596 
3597 				g->nhs++;
3598 			}
3599 			/* if it is vertical, add a vstem */
3600 			/* and the ends as hstems if they brace the line  */
3601 			else if (ge->ix3 == ge->prev->ix3
3602 			&& ge->iy3 != ge->prev->iy3) {
3603 				vs[g->nvs].value = ge->ix3;
3604 				if (ge->iy3 > ge->prev->iy3) {
3605 					vs[g->nvs].flags = ST_FLAT | ST_UP;
3606 					vs[g->nvs].from = ge->prev->iy3;
3607 					vs[g->nvs].to = ge->iy3;
3608 				} else {
3609 					vs[g->nvs].flags = ST_FLAT;
3610 					vs[g->nvs].from = ge->iy3;
3611 					vs[g->nvs].to = ge->prev->iy3;
3612 				}
3613 				vs[g->nvs].origin = ge->iy3;
3614 				vs[g->nvs].ge = ge->frwd;
3615 
3616 				pge = ge->bkwd;
3617 
3618 				/* add beginning as hstem */
3619 				hs[g->nhs].value = pge->iy3;
3620 				hs[g->nhs].origin
3621 					= hs[g->nhs].from
3622 					= hs[g->nhs].to = pge->ix3;
3623 				hs[g->nhs].ge = ge;
3624 
3625 				if(pge->type==GE_CURVE)
3626 					ovalue=pge->ix2;
3627 				else
3628 					ovalue=pge->prev->ix3;
3629 
3630 				if (pge->ix3 < ovalue)
3631 					hs[g->nhs].flags = ST_UP | ST_END;
3632 				else if (pge->ix3 > ovalue)
3633 					hs[g->nhs].flags = ST_END;
3634 				else
3635 					hs[g->nhs].flags = 0;
3636 
3637 				if( hs[g->nhs].flags != 0 )
3638 					g->nhs++;
3639 
3640 				/* add end as hstem */
3641 				hs[g->nhs].value = ge->iy3;
3642 				hs[g->nhs].origin
3643 					= hs[g->nhs].from
3644 					= hs[g->nhs].to = ge->ix3;
3645 				hs[g->nhs].ge = ge->frwd;
3646 
3647 				if(nge->type==GE_CURVE)
3648 					ovalue=nge->ix1;
3649 				else
3650 					ovalue=nge->ix3;
3651 
3652 				if (ovalue < ge->ix3)
3653 					hs[g->nhs].flags = ST_UP | ST_END;
3654 				else if (ovalue > ge->ix3)
3655 					hs[g->nhs].flags = ST_END;
3656 				else
3657 					hs[g->nhs].flags = 0;
3658 
3659 				if( hs[g->nhs].flags != 0 )
3660 					g->nhs++;
3661 
3662 				g->nvs++;
3663 			}
3664 			/*
3665 			 * check the end of line for a not smooth local
3666 			 * extremum
3667 			 */
3668 			nge = ge->frwd;
3669 
3670 			if (nge == 0)
3671 				continue;
3672 			else if (nge->type == GE_LINE) {
3673 				nx = nge->ix3;
3674 				ny = nge->iy3;
3675 			} else if (nge->type == GE_CURVE) {
3676 				nx = nge->ix1;
3677 				ny = nge->iy1;
3678 			} else
3679 				continue;
3680 
3681 			/* check for vertical extremums */
3682 			if (ge->iy3 > ge->prev->iy3 && ge->iy3 > ny
3683 			|| ge->iy3 < ge->prev->iy3 && ge->iy3 < ny) {
3684 				hs[g->nhs].value = ge->iy3;
3685 				hs[g->nhs].from
3686 					= hs[g->nhs].to
3687 					= hs[g->nhs].origin = ge->ix3;
3688 				hs[g->nhs].ge = ge->frwd;
3689 
3690 				if (ge->ix3 < ge->prev->ix3
3691 				    || nx < ge->ix3)
3692 					hs[g->nhs].flags = ST_UP;
3693 				else
3694 					hs[g->nhs].flags = 0;
3695 
3696 				if (ge->ix3 != ge->prev->ix3 || nx != ge->ix3)
3697 					g->nhs++;
3698 			}
3699 			/*
3700 			 * the same point may be both horizontal and vertical
3701 			 * extremum
3702 			 */
3703 			/* check for horizontal extremums */
3704 			if (ge->ix3 > ge->prev->ix3 && ge->ix3 > nx
3705 			|| ge->ix3 < ge->prev->ix3 && ge->ix3 < nx) {
3706 				vs[g->nvs].value = ge->ix3;
3707 				vs[g->nvs].from
3708 					= vs[g->nvs].to
3709 					= vs[g->nvs].origin = ge->iy3;
3710 				vs[g->nvs].ge = ge->frwd;
3711 
3712 				if (ge->iy3 > ge->prev->iy3
3713 				    || ny > ge->iy3)
3714 					vs[g->nvs].flags = ST_UP;
3715 				else
3716 					vs[g->nvs].flags = 0;
3717 
3718 				if (ge->iy3 != ge->prev->iy3 || ny != ge->iy3)
3719 					g->nvs++;
3720 			}
3721 		}
3722 	}
3723 
3724 	g->nhs=addbluestems(hs, g->nhs);
3725 	sortstems(hs, g->nhs);
3726 	sortstems(vs, g->nvs);
3727 
3728 	if (ISDBG(STEMS))
3729 		debugstems(g->name, hs, g->nhs, vs, g->nvs);
3730 
3731 	/* find the stems interacting with the Blue Zones */
3732 	markbluestems(hs, g->nhs);
3733 
3734 	if(subhints) {
3735 		if (ISDBG(SUBSTEMS))
3736 			fprintf(pfa_file, "%% %s: joining subst horizontal stems\n", g->name);
3737 		joinsubstems(hs, hs_pairs, g->nhs, 1);
3738 		uniformstems(hs, hs_pairs, g->nhs);
3739 
3740 		if (ISDBG(SUBSTEMS))
3741 			fprintf(pfa_file, "%% %s: joining subst vertical stems\n", g->name);
3742 		joinsubstems(vs, vs_pairs, g->nvs, 0);
3743 
3744 		groupsubstems(g, hs, hs_pairs, g->nhs, vs, vs_pairs, g->nvs);
3745 	}
3746 
3747 	if (ISDBG(MAINSTEMS))
3748 		fprintf(pfa_file, "%% %s: joining main horizontal stems\n", g->name);
3749 	g->nhs = joinmainstems(hs, g->nhs, 1);
3750 	if (ISDBG(MAINSTEMS))
3751 		fprintf(pfa_file, "%% %s: joining main vertical stems\n", g->name);
3752 	g->nvs = joinmainstems(vs, g->nvs, 0);
3753 
3754 	if (ISDBG(MAINSTEMS))
3755 		debugstems(g->name, hs, g->nhs, vs, g->nvs);
3756 
3757 	if(g->nhs > 0) {
3758 		if ((sp = malloc(sizeof(STEM) * g->nhs)) == 0) {
3759 			fprintf(stderr, "**** not enough memory for hints ****\n");
3760 			exit(255);
3761 		}
3762 		g->hstems = sp;
3763 		memcpy(sp, hs, sizeof(STEM) * g->nhs);
3764 	} else
3765 		g->hstems = 0;
3766 
3767 	if(g->nvs > 0) {
3768 		if ((sp = malloc(sizeof(STEM) * g->nvs)) == 0) {
3769 			fprintf(stderr, "**** not enough memory for hints ****\n");
3770 			exit(255);
3771 		}
3772 		g->vstems = sp;
3773 		memcpy(sp, vs, sizeof(STEM) * g->nvs);
3774 	} else
3775 		g->vstems = 0;
3776 
3777 	/* now check that the stems won't overflow the interpreter's stem stack:
3778 	 * some interpreters (like X11) push the stems on each change into
3779 	 * stack and pop them only after the whole glyphs is completed.
3780 	 */
3781 
3782 	totals = (g->nhs+g->nvs) / 2; /* we count whole stems, not halves */
3783 	lastgrp = -1;
3784 
3785 	for (ge = g->entries; ge != 0; ge = ge->next) {
3786 		grp=ge->stemid;
3787 		if(grp >= 0 && grp != lastgrp)  {
3788 			if(grp==0)
3789 				totals += g->nsbs[0];
3790 			else
3791 				totals += g->nsbs[grp] - g->nsbs[grp-1];
3792 
3793 			lastgrp = grp;
3794 		}
3795 	}
3796 
3797 	/* be on the safe side, check for >= , not > */
3798 	if(totals >= max_stemdepth) {  /* oops, too deep */
3799 		WARNING_2 {
3800 			fprintf(stderr, "Warning: glyph %s needs hint stack depth %d\n", g->name, totals);
3801 			fprintf(stderr, "  (limit %d): removed the substituted hints from it\n", max_stemdepth);
3802 		}
3803 		if(g->nsg > 0) {
3804 			for (ge = g->entries; ge != 0; ge = ge->next)
3805 				ge->stemid = -1;
3806 			free(g->sbstems); g->sbstems = 0;
3807 			free(g->nsbs); g->nsbs = 0;
3808 			g->nsg = 0;
3809 		}
3810 	}
3811 
3812 	/* now check if there are too many main stems */
3813 	totals = (g->nhs+g->nvs) / 2; /* we count whole stems, not halves */
3814 	if(totals >= max_stemdepth) {
3815 		/* even worse, too much of non-substituted stems */
3816 		WARNING_2 {
3817 			fprintf(stderr, "Warning: glyph %s has %d main hints\n", g->name, totals);
3818 			fprintf(stderr, "  (limit %d): removed the hints from it\n", max_stemdepth);
3819 		}
3820 		if(g->vstems) {
3821 			free(g->vstems); g->vstems = 0; g->nvs = 0;
3822 		}
3823 		if(g->hstems) {
3824 			free(g->hstems); g->hstems = 0; g->nhs = 0;
3825 		}
3826 	}
3827 }
3828 
3829 /* convert weird curves that are close to lines into lines.
3830 */
3831 
3832 void
fstraighten(GLYPH * g)3833 fstraighten(
3834 	   GLYPH * g
3835 )
3836 {
3837 	GENTRY         *ge, *pge, *nge, *ige;
3838 	double          df;
3839 	int             dir;
3840 	double          iln, oln;
3841 	int             svdir, i, o;
3842 
3843 	for (ige = g->entries; ige != 0; ige = ige->next) {
3844 		if (ige->type != GE_CURVE)
3845 			continue;
3846 
3847 		ge = ige;
3848 		pge = ge->bkwd;
3849 		nge = ge->frwd;
3850 
3851 		df = 0.;
3852 
3853 		/* look for vertical then horizontal */
3854 		for(i=0; i<2; i++) {
3855 			o = !i; /* other axis */
3856 
3857 			iln = fabs(ge->fpoints[i][2] - pge->fpoints[i][2]);
3858 			oln = fabs(ge->fpoints[o][2] - pge->fpoints[o][2]);
3859 			/*
3860 			 * if current curve is almost a vertical line, and it
3861 			 * doesn't begin or end horizontally (and the prev/next
3862 			 * line doesn't join smoothly ?)
3863 			 */
3864 			if( oln < 1.
3865 			|| ge->fpoints[o][2] == ge->fpoints[o][1]
3866 			|| ge->fpoints[o][0] == pge->fpoints[o][2]
3867 			|| iln > 2.
3868 			|| iln > 1.  && iln/oln > 0.1 )
3869 				continue;
3870 
3871 
3872 			if(ISDBG(STRAIGHTEN))
3873 				fprintf(stderr,"** straighten almost %s\n", (i? "horizontal":"vertical"));
3874 
3875 			df = ge->fpoints[i][2] - pge->fpoints[i][2];
3876 			dir = fsign(ge->fpoints[o][2] - pge->fpoints[o][2]);
3877 			ge->type = GE_LINE;
3878 
3879 			/*
3880 			 * suck in all the sequence of such almost lines
3881 			 * going in the same direction but not deviating
3882 			 * too far from vertical
3883 			 */
3884 			iln = fabs(nge->fpoints[i][2] - ge->fpoints[i][2]);
3885 			oln = nge->fpoints[o][2] - ge->fpoints[o][2];
3886 
3887 			while (fabs(df) <= 5 && nge->type == GE_CURVE
3888 			&& dir == fsign(oln) /* that also gives oln != 0 */
3889 			&& iln <= 2.
3890 			&& ( iln <= 1.  || iln/fabs(oln) <= 0.1 ) ) {
3891 				ge->fx3 = nge->fx3;
3892 				ge->fy3 = nge->fy3;
3893 
3894 				if(ISDBG(STRAIGHTEN))
3895 					fprintf(stderr,"** straighten collapsing %s\n", (i? "horizontal":"vertical"));
3896 				freethisge(nge);
3897 				fixendpath(ge);
3898 				pge = ge->bkwd;
3899 				nge = ge->frwd;
3900 
3901 				df = ge->fpoints[i][2] - pge->fpoints[i][2];
3902 
3903 				iln = fabs(nge->fpoints[i][2] - ge->fpoints[i][2]);
3904 				oln = nge->fpoints[o][2] - ge->fpoints[o][2];
3905 			}
3906 
3907 			/* now check what do we have as previous/next line */
3908 
3909 			if(ge != pge) {
3910 				if( pge->type == GE_LINE && pge->fpoints[i][2] == pge->prev->fpoints[i][2]
3911 				&& fabs(pge->fpoints[o][2] != pge->prev->fpoints[o][2]) ) {
3912 					if(ISDBG(STRAIGHTEN)) fprintf(stderr,"** straighten join with previous 0x%x 0x%x\n", pge, ge);
3913 					/* join the previous line with current */
3914 					pge->fx3 = ge->fx3;
3915 					pge->fy3 = ge->fy3;
3916 
3917 					ige = freethisge(ge)->prev; /* keep the iterator valid */
3918 					ge = pge;
3919 					fixendpath(ge);
3920 					pge = ge->bkwd;
3921 				}
3922 			}
3923 
3924 			if(ge != nge) {
3925 				if (nge->type == GE_LINE && nge->fpoints[i][2] == ge->fpoints[i][2]
3926 				&& fabs(nge->fpoints[o][2] != ge->fpoints[o][2]) ) {
3927 					if(ISDBG(STRAIGHTEN)) fprintf(stderr,"** straighten join with next 0x%x 0x%x\n", ge, nge);
3928 					/* join the next line with current */
3929 					ge->fx3 = nge->fx3;
3930 					ge->fy3 = nge->fy3;
3931 
3932 					freethisge(nge);
3933 					fixendpath(ge);
3934 					pge = ge->bkwd;
3935 					nge = ge->frwd;
3936 
3937 				}
3938 			}
3939 
3940 			if(ge != pge) {
3941 				/* try to align the lines if neccessary */
3942 				if(df != 0.)
3943 					fclosegap(ge, ge, i, df, NULL);
3944 			} else {
3945 				/* contour consists of only one line, get rid of it */
3946 				ige = freethisge(ge); /* keep the iterator valid */
3947 				if(ige == 0) /* this was the last contour */
3948 					return;
3949 				ige = ige->prev;
3950 			}
3951 
3952 			break; /* don't bother looking at the other axis */
3953 		}
3954 	}
3955 }
3956 
3957 /* solve a square equation,
3958  * returns the number of solutions found, the solutions
3959  * are stored in res which should point to array of two doubles.
3960  * min and max limit the area for solutions
3961  */
3962 
3963 static int
fsqequation(double a,double b,double c,double * res,double min,double max)3964 fsqequation(
3965 	double a,
3966 	double b,
3967 	double c,
3968 	double *res,
3969 	double min,
3970 	double max
3971 )
3972 {
3973 	double D;
3974 	int n;
3975 
3976 	if(ISDBG(SQEQ)) fprintf(stderr, "sqeq(%g,%g,%g) [%g;%g]\n", a, b, c, min, max);
3977 
3978 	if(fabs(a) < 0.000001) { /* if a linear equation */
3979 		n=0;
3980 		if(fabs(b) < 0.000001) /* not an equation at all */
3981 			return 0;
3982 		res[0] = -c/b;
3983 		if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: linear t=%g\n", res[0]);
3984 		if(res[0] >= min && res[0] <= max)
3985 			n++;
3986 		return n;
3987 	}
3988 
3989 	D = b*b - 4.0*a*c;
3990 	if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: D=%g\n", D);
3991 	if(D<0)
3992 		return 0;
3993 
3994 	D = sqrt(D);
3995 
3996 	n=0;
3997 	res[0] = (-b+D) / (2*a);
3998 	if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: t1=%g\n", res[0]);
3999 	if(res[0] >= min && res[0] <= max)
4000 		n++;
4001 
4002 	res[n] = (-b-D) / (2*a);
4003 	if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: t2=%g\n", res[n]);
4004 	if(res[n] >= min && res[n] <= max)
4005 		n++;
4006 
4007 	/* return 2nd solution only if it's different enough */
4008 	if(n==2 && fabs(res[0]-res[1])<0.000001)
4009 		n=1;
4010 
4011 	return n;
4012 }
4013 
4014 /* check that the curves don't cross quadrant boundary */
4015 /* (float) */
4016 
4017 /*
4018   Here we make sure that the curve does not continue past
4019   horizontal or vertical extremums. The horizontal points are
4020   explained, vertical points are by analogy.
4021 
4022   The horizontal points are where the derivative
4023   dy/dx is equal to 0. But the Bezier curves are defined by
4024   parametric formulas
4025    x=fx(t)
4026    y=fy(t)
4027   so finding this derivative is complicated.
4028   Also even if we find some point (x,y) splitting at this point
4029   is far not obvious. Fortunately we can use dy/dt = 0 instead,
4030   this gets to a rather simple square equation and splitting
4031   at a known value of t is simple.
4032 
4033   The formulas are:
4034 
4035   y = A*(1-t)^3 + 3*B*(1-t)^2*t + 3*C*(1-t)*t^2 + D*t^3
4036   y = (-A+3*B-3*C+D)*t^3 + (3*A-6*B+3*C)*t^2 + (-3*A+3*B)*t + A
4037   dy/dt = 3*(-A+3*B-3*C+D)*t^2 + 2*(3*A-6*B+3*C)*t + (-3*A+3*B)
4038  */
4039 
4040 void
ffixquadrants(GLYPH * g)4041 ffixquadrants(
4042 	GLYPH *g
4043 )
4044 {
4045 	GENTRY         *ge, *nge;
4046 	int	i, j, np, oldnp;
4047 	double	sp[5]; /* split points, last one empty */
4048 	char dir[5]; /* for debugging, direction by which split happened */
4049 	double a, b, *pts; /* points of a curve */
4050 
4051 	for (ge = g->entries; ge != 0; ge = ge->next) {
4052 		if (ge->type != GE_CURVE)
4053 			continue;
4054 
4055 	doagain:
4056 		np = 0; /* no split points yet */
4057 		if(ISDBG(QUAD)) {
4058 			fprintf(stderr, "%s: trying 0x%x (%g %g) (%g %g) (%g %g) (%g %g)\n  ", g->name,
4059 				ge,  ge->prev->fx3, ge->prev->fy3, ge->fx1, ge->fy1, ge->fx2, ge->fy2,
4060 				ge->fx3, ge->fy3);
4061 		}
4062 		for(i=0; i<2; i++) { /* first for x then for y */
4063 			/* find the cooridnates of control points */
4064 			a = ge->prev->fpoints[i][2];
4065 			pts = &ge->fpoints[i][0];
4066 
4067 			oldnp = np;
4068 			np += fsqequation(
4069 				3.0*(-a + 3.0*pts[0] - 3.0*pts[1] + pts[2]),
4070 				6.0*(a - 2.0*pts[0] + pts[1]),
4071 				3.0*(-a + pts[0]),
4072 				&sp[np],
4073 				0.0, 1.0); /* XXX range is [0;1] */
4074 
4075 			if(np == oldnp)
4076 				continue;
4077 
4078 			if(ISDBG(QUAD))
4079 				fprintf(stderr, "%s: 0x%x: %d pts(%c): ",
4080 					g->name, ge, np-oldnp, i? 'y':'x');
4081 
4082 			/* remove points that are too close to the ends
4083 			 * because hor/vert ends are permitted, also
4084 			 * if the split point is VERY close to the ends
4085 			 * but not exactly then just flatten it and check again.
4086 			 */
4087 			for(j = oldnp; j<np; j++) {
4088 				dir[j] = i;
4089 				if(ISDBG(QUAD))
4090 					fprintf(stderr, "%g ", sp[j]);
4091 				if(sp[j] < 0.03) { /* front end of curve */
4092 					if(ge->fpoints[i][0] != ge->prev->fpoints[i][2]) {
4093 						ge->fpoints[i][0] = ge->prev->fpoints[i][2];
4094 						if(ISDBG(QUAD)) fprintf(stderr, "flattened at front\n");
4095 						goto doagain;
4096 					}
4097 					if( ge->fpoints[i][1] != ge->fpoints[i][0]
4098 					&& fsign(ge->fpoints[i][2] - ge->fpoints[i][1])
4099 							!= fsign(ge->fpoints[i][1] - ge->fpoints[i][0]) ) {
4100 						ge->fpoints[i][1] = ge->fpoints[i][0];
4101 						if(ISDBG(QUAD)) fprintf(stderr, "flattened zigzag at front\n");
4102 						goto doagain;
4103 					}
4104 					sp[j] = sp[j+1]; np--; j--;
4105 					if(ISDBG(QUAD)) fprintf(stderr, "(front flat)  ");
4106 				} else if(sp[j] > 0.97) { /* rear end of curve */
4107 					if(ge->fpoints[i][1] != ge->fpoints[i][2]) {
4108 						ge->fpoints[i][1] = ge->fpoints[i][2];
4109 						if(ISDBG(QUAD)) fprintf(stderr, "flattened at rear\n");
4110 						goto doagain;
4111 					}
4112 					if( ge->fpoints[i][0] != ge->fpoints[i][1]
4113 					&& fsign(ge->prev->fpoints[i][2] - ge->fpoints[i][0])
4114 							!= fsign(ge->fpoints[i][0] - ge->fpoints[i][1]) ) {
4115 						ge->fpoints[i][0] = ge->fpoints[i][1];
4116 						if(ISDBG(QUAD)) fprintf(stderr, "flattened zigzag at rear\n");
4117 						goto doagain;
4118 					}
4119 					sp[j] = sp[j+1]; np--; j--;
4120 					if(ISDBG(QUAD)) fprintf(stderr, "(rear flat)  ");
4121 				}
4122 			}
4123 			if(ISDBG(QUAD)) fprintf(stderr, "\n");
4124 		}
4125 
4126 		if(np==0) /* no split points, leave it alone */
4127 			continue;
4128 
4129 		if(ISDBG(QUAD)) {
4130 			fprintf(stderr, "%s: splitting 0x%x (%g %g) (%g %g) (%g %g) (%g %g) at %d points\n  ", g->name,
4131 				ge,  ge->prev->fx3, ge->prev->fy3, ge->fx1, ge->fy1, ge->fx2, ge->fy2,
4132 				ge->fx3, ge->fy3, np);
4133 			for(i=0; i<np; i++)
4134 				fprintf(stderr, "%g(%c) ", sp[i], dir[i] ? 'y':'x');
4135 			fprintf(stderr, "\n");
4136 		}
4137 
4138 		/* sort the points ascending */
4139 		for(i=0; i<np; i++)
4140 			for(j=i+1; j<np; j++)
4141 				if(sp[i] > sp[j]) {
4142 					a = sp[i]; sp[i] = sp[j]; sp[j] = a;
4143 				}
4144 
4145 		/* now finally do the split on each point */
4146 		for(j=0; j<np; j++) {
4147 			double k1, k2, c;
4148 
4149 			k1 = sp[j];
4150 			k2 = 1 - k1;
4151 
4152 			if(ISDBG(QUAD)) fprintf(stderr, "   0x%x %g/%g\n", ge, k1, k2);
4153 
4154 			nge = newgentry(GEF_FLOAT);
4155 			(*nge) = (*ge);
4156 
4157 #define SPLIT(pt1, pt2)	( (pt1) + k1*((pt2)-(pt1)) ) /* order is important! */
4158 			for(i=0; i<2; i++) { /* for x and y */
4159 				a = ge->fpoints[i][0]; /* get the middle points */
4160 				b = ge->fpoints[i][1];
4161 
4162 				/* calculate new internal points */
4163 				c = SPLIT(a, b);
4164 
4165 				ge->fpoints[i][0] = SPLIT(ge->prev->fpoints[i][2], a);
4166 				ge->fpoints[i][1] = SPLIT(ge->fpoints[i][0], c);
4167 
4168 				nge->fpoints[i][1] = SPLIT(b, nge->fpoints[i][2]);
4169 				nge->fpoints[i][0] = SPLIT(c, nge->fpoints[i][1]);
4170 
4171 				ge->fpoints[i][2] = SPLIT(ge->fpoints[i][1],
4172 					+ nge->fpoints[i][0]);
4173 			}
4174 #undef SPLIT
4175 
4176 			addgeafter(ge, nge);
4177 
4178 			/* go to the next part, adjust remaining points */
4179 			ge = nge;
4180 			for(i=j+1; i<np; i++)
4181 				sp[i] = (sp[i]-k1) / k2;
4182 		}
4183 	}
4184 
4185 }
4186 
4187 /* check if a curve is a zigzag */
4188 
4189 static int
iiszigzag(GENTRY * ge)4190 iiszigzag(
4191 	GENTRY *ge
4192 )
4193 {
4194 	double          k, k1, k2;
4195 	int             a, b;
4196 
4197 	if (ge->type != GE_CURVE)
4198 		return 0;
4199 
4200 	a = ge->iy2 - ge->iy1;
4201 	b = ge->ix2 - ge->ix1;
4202 	if(a == 0) {
4203 		if(b == 0) {
4204 			return 0;
4205 		} else
4206 			k = FBIGVAL;
4207 	} else
4208 		k = fabs((double) b / (double) a);
4209 
4210 	a = ge->iy1 - ge->prev->iy3;
4211 	b = ge->ix1 - ge->prev->ix3;
4212 	if(a == 0) {
4213 		if(b == 0) {
4214 			return 0;
4215 		} else
4216 			k1 = FBIGVAL;
4217 	} else
4218 		k1 = fabs((double) b / (double) a);
4219 
4220 	a = ge->iy3 - ge->iy2;
4221 	b = ge->ix3 - ge->ix2;
4222 	if(a == 0) {
4223 		if(b == 0) {
4224 			return 0;
4225 		} else
4226 			k2 = FBIGVAL;
4227 	} else
4228 		k2 = fabs((double) b / (double) a);
4229 
4230 	/* if the curve is not a zigzag */
4231 	if (k1+0.0001 >= k && k2 <= k+0.0001 || k1 <= k+0.0001 && k2+0.0001 >= k)
4232 		return 0;
4233 	else
4234 		return 1;
4235 }
4236 
4237 /* check if a curve is a zigzag - floating */
4238 
4239 static int
fiszigzag(GENTRY * ge)4240 fiszigzag(
4241 	GENTRY *ge
4242 )
4243 {
4244 	double          k, k1, k2;
4245 	double          a, b;
4246 
4247 	if (ge->type != GE_CURVE)
4248 		return 0;
4249 
4250 	a = fabs(ge->fy2 - ge->fy1);
4251 	b = fabs(ge->fx2 - ge->fx1);
4252 	if(a < FEPS) {
4253 		if(b < FEPS) {
4254 			return 0;
4255 		} else
4256 			k = FBIGVAL;
4257 	} else
4258 		k = b / a;
4259 
4260 	a = fabs(ge->fy1 - ge->prev->fy3);
4261 	b = fabs(ge->fx1 - ge->prev->fx3);
4262 	if(a < FEPS) {
4263 		if(b < FEPS) {
4264 			return 0;
4265 		} else
4266 			k1 = FBIGVAL;
4267 	} else
4268 		k1 = b / a;
4269 
4270 	a = fabs(ge->fy3 - ge->fy2);
4271 	b = fabs(ge->fx3 - ge->fx2);
4272 	if(a < FEPS) {
4273 		if(b < FEPS) {
4274 			return 0;
4275 		} else
4276 			k2 = FBIGVAL;
4277 	} else
4278 		k2 = b / a;
4279 
4280 	/* if the curve is not a zigzag */
4281 	if (k1+0.0001 >= k && k2 <= k+0.0001 || k1 <= k+0.0001 && k2+0.0001 >= k)
4282 		return 0;
4283 	else
4284 		return 1;
4285 }
4286 
4287 /* split the zigzag-like curves into two parts */
4288 
4289 void
fsplitzigzags(GLYPH * g)4290 fsplitzigzags(
4291 	     GLYPH * g
4292 )
4293 {
4294 	GENTRY         *ge, *nge;
4295 	double          a, b, c, d;
4296 
4297 	assertisfloat(g, "splitting zigzags");
4298 	for (ge = g->entries; ge != 0; ge = ge->next) {
4299 		if (ge->type != GE_CURVE)
4300 			continue;
4301 
4302 		/* if the curve is not a zigzag */
4303 		if ( !fiszigzag(ge) ) {
4304 			continue;
4305 		}
4306 
4307 		if(ISDBG(FCONCISE)) {
4308 			double maxsc1, maxsc2;
4309 			fprintf(stderr, "split a zigzag ");
4310 			fnormalizege(ge);
4311 			if( fcrossraysge(ge, ge, &maxsc1, &maxsc2, NULL) ) {
4312 				fprintf(stderr, "sc1=%g sc2=%g\n", maxsc1, maxsc2);
4313 			} else {
4314 				fprintf(stderr, "(rays don't cross)\n");
4315 			}
4316 		}
4317 		/* split the curve by t=0.5 */
4318 		nge = newgentry(GEF_FLOAT);
4319 		(*nge) = (*ge);
4320 		nge->type = GE_CURVE;
4321 
4322 		a = ge->prev->fx3;
4323 		b = ge->fx1;
4324 		c = ge->fx2;
4325 		d = ge->fx3;
4326 		nge->fx3 = d;
4327 		nge->fx2 = (c + d) / 2.;
4328 		nge->fx1 = (b + 2. * c + d) / 4.;
4329 		ge->fx3 = (a + b * 3. + c * 3. + d) / 8.;
4330 		ge->fx2 = (a + 2. * b + c) / 4.;
4331 		ge->fx1 = (a + b) / 2.;
4332 
4333 		a = ge->prev->fy3;
4334 		b = ge->fy1;
4335 		c = ge->fy2;
4336 		d = ge->fy3;
4337 		nge->fy3 = d;
4338 		nge->fy2 = (c + d) / 2.;
4339 		nge->fy1 = (b + 2. * c + d) / 4.;
4340 		ge->fy3 = (a + b * 3. + c * 3. + d) / 8.;
4341 		ge->fy2 = (a + 2. * b + c) / 4.;
4342 		ge->fy1 = (a + b) / 2.;
4343 
4344 		addgeafter(ge, nge);
4345 
4346 		if(ISDBG(FCONCISE)) {
4347 			dumppaths(g, ge, nge);
4348 		}
4349 	}
4350 }
4351 
4352 /* free this GENTRY, returns what was ge->next
4353  * (ge must be of type GE_LINE or GE_CURVE)
4354  * works on both float and int entries
4355  */
4356 
4357 static GENTRY *
freethisge(GENTRY * ge)4358 freethisge(
4359 	GENTRY *ge
4360 )
4361 {
4362 	GENTRY *xge;
4363 
4364 	if (ge->bkwd != ge->prev) {
4365 		/* at beginning of the contour */
4366 
4367 		xge = ge->bkwd;
4368 		if(xge == ge) { /* was the only line in contour */
4369 			/* remove the contour completely */
4370 			/* prev is GE_MOVE, next is GE_PATH, remove them all */
4371 
4372 			/* may be the first contour, then ->bkwd points to ge->entries */
4373 			if(ge->prev->prev == 0)
4374 				*(GENTRY **)(ge->prev->bkwd) = ge->next->next;
4375 			else
4376 				ge->prev->prev->next = ge->next->next;
4377 
4378 			if(ge->next->next) {
4379 				ge->next->next->prev = ge->prev->prev;
4380 				ge->next->next->bkwd = ge->prev->bkwd;
4381 			}
4382 
4383 			xge = ge->next->next;
4384 			free(ge->prev); free(ge->next); free(ge);
4385 			return xge;
4386 		}
4387 
4388 		/* move the start point of the contour */
4389 		if(ge->flags & GEF_FLOAT) {
4390 			ge->prev->fx3 = xge->fx3;
4391 			ge->prev->fy3 = xge->fy3;
4392 		} else {
4393 			ge->prev->ix3 = xge->ix3;
4394 			ge->prev->iy3 = xge->iy3;
4395 		}
4396 	} else if(ge->frwd != ge->next) {
4397 		/* at end of the contour */
4398 
4399 		xge = ge->frwd->prev;
4400 		/* move the start point of the contour */
4401 		if(ge->flags & GEF_FLOAT) {
4402 			xge->fx3 = ge->bkwd->fx3;
4403 			xge->fy3 = ge->bkwd->fy3;
4404 		} else {
4405 			xge->ix3 = ge->bkwd->ix3;
4406 			xge->iy3 = ge->bkwd->iy3;
4407 		}
4408 	}
4409 
4410 	ge->prev->next = ge->next;
4411 	ge->next->prev = ge->prev;
4412 	ge->bkwd->frwd = ge->frwd;
4413 	ge->frwd->bkwd = ge->bkwd;
4414 
4415 	xge = ge->next;
4416 	free(ge);
4417 	return xge;
4418 }
4419 
4420 /* inserts a new gentry (LINE or CURVE) after another (MOVE
4421  * or LINE or CURVE)
4422  * corrects the first GE_MOVE if neccessary
4423  */
4424 
4425 static void
addgeafter(GENTRY * oge,GENTRY * nge)4426 addgeafter(
4427 	GENTRY *oge, /* after this */
4428 	GENTRY *nge /* insert this */
4429 )
4430 {
4431 	if(oge->type == GE_MOVE) {
4432 		/* insert before next */
4433 		if(oge->next->type == GE_PATH) {
4434 			/* first and only GENTRY in path */
4435 			nge->frwd = nge->bkwd = nge;
4436 		} else {
4437 			nge->frwd = oge->next;
4438 			nge->bkwd = oge->next->bkwd;
4439 			oge->next->bkwd->frwd = nge;
4440 			oge->next->bkwd = nge;
4441 		}
4442 	} else {
4443 		nge->frwd = oge->frwd;
4444 		nge->bkwd = oge;
4445 		oge->frwd->bkwd = nge;
4446 		oge->frwd = nge;
4447 	}
4448 
4449 	nge->next = oge->next;
4450 	nge->prev = oge;
4451 	oge->next->prev = nge;
4452 	oge->next = nge;
4453 
4454 	if(nge->frwd->prev->type == GE_MOVE) {
4455 		/* fix up the GE_MOVE entry */
4456 		if(nge->flags & GEF_FLOAT) {
4457 			nge->frwd->prev->fx3 = nge->fx3;
4458 			nge->frwd->prev->fy3 = nge->fy3;
4459 		} else {
4460 			nge->frwd->prev->ix3 = nge->ix3;
4461 			nge->frwd->prev->iy3 = nge->iy3;
4462 		}
4463 	}
4464 }
4465 
4466 /*
4467  * Check if this GENTRY happens to be at the end of path
4468  * and fix the first MOVETO accordingly
4469  * handles both int and float
4470  */
4471 
4472 static void
fixendpath(GENTRY * ge)4473 fixendpath(
4474 	GENTRY *ge
4475 )
4476 {
4477 	GENTRY *mge;
4478 
4479 	mge = ge->frwd->prev;
4480 	if(mge->type == GE_MOVE) {
4481 		if(ge->flags & GEF_FLOAT) {
4482 			mge->fx3 = ge->fx3;
4483 			mge->fy3 = ge->fy3;
4484 		} else {
4485 			mge->ix3 = ge->ix3;
4486 			mge->iy3 = ge->iy3;
4487 		}
4488 	}
4489 }
4490 
4491 /*
4492  * This function adjusts the rest of path (the part from...to is NOT changed)
4493  * to cover the specified gap by the specified axis (0 - X, 1 - Y).
4494  * Gap is counted in direction (end_of_to - beginning_of_from).
4495  * Returns by how much the gap was not closed (0.0 if it was fully closed).
4496  * Ret contains by how much the first and last points of [from...to]
4497  * were moved to bring them in consistence to the rest of the path.
4498  * If ret==NULL then this info is not returned.
4499  */
4500 
4501 static double
fclosegap(GENTRY * from,GENTRY * to,int axis,double gap,double * ret)4502 fclosegap(
4503 	GENTRY *from,
4504 	GENTRY *to,
4505 	int axis,
4506 	double gap,
4507 	double *ret
4508 )
4509 {
4510 #define TIMESLARGER 10.	/* how many times larger must be a curve to not change too much */
4511 	double rm[2];
4512 	double oldpos[2];
4513 	double times, limit, df, dx;
4514 	int j, k;
4515 	GENTRY *xge, *pge, *nge, *bge[2];
4516 
4517 	/* remember the old points to calculate ret */
4518 	oldpos[0] = from->prev->fpoints[axis][2];
4519 	oldpos[1] = to->fpoints[axis][2];
4520 
4521 	rm[0] = rm[1] = gap / 2. ;
4522 
4523 	bge[0] = from; /* this is convenient for iterations */
4524 	bge[1] = to;
4525 
4526 	/* first try to modify large curves but if have none then settle for small */
4527 	for(times = (TIMESLARGER-1); times > 0.1; times /= 2. ) {
4528 
4529 		if(rm[0]+rm[1] == 0.)
4530 			break;
4531 
4532 		/* iterate in both directions, backwards then forwards */
4533 		for(j = 0; j<2; j++) {
4534 
4535 			if(rm[j] == 0.) /* if this direction is exhausted */
4536 				continue;
4537 
4538 			limit = fabs(rm[j]) * (1.+times);
4539 
4540 			for(xge = bge[j]->cntr[j]; xge != bge[!j]; xge = xge->cntr[j]) {
4541 				dx = xge->fpoints[axis][2] - xge->prev->fpoints[axis][2];
4542 				df = fabs(dx) - limit;
4543 				if( df <= FEPS ) /* curve is too small to change */
4544 					continue;
4545 
4546 				if( df >= fabs(rm[j]) )
4547 					df = rm[j];
4548 				else
4549 					df *= fsign(rm[j]); /* we may cover this part of rm */
4550 
4551 				rm[j] -= df;
4552 				limit = fabs(rm[j]) * (1.+times);
4553 
4554 				if(xge->type == GE_CURVE) { /* correct internal points */
4555 					double scale = ((dx+df) / dx) - 1.;
4556 					double base;
4557 
4558 					if(j)
4559 						base = xge->fpoints[axis][2];
4560 					else
4561 						base = xge->prev->fpoints[axis][2];
4562 
4563 					for(k = 0; k<2; k++)
4564 						xge->fpoints[axis][k] += scale *
4565 							(xge->fpoints[axis][k] - base);
4566 				}
4567 
4568 				/* move all the intermediate lines */
4569 				if(j) {
4570 					df = -df; /* absolute direction */
4571 					pge = bge[1]->bkwd;
4572 					nge = xge->bkwd;
4573 				} else {
4574 					xge->fpoints[axis][2] += df;
4575 					pge = bge[0];
4576 					nge = xge->frwd;
4577 				}
4578 				while(nge != pge) {
4579 					if(nge->type == GE_CURVE) {
4580 						nge->fpoints[axis][0] +=df;
4581 						nge->fpoints[axis][1] +=df;
4582 					}
4583 					nge->fpoints[axis][2] += df;
4584 					if(nge->next != nge->frwd) { /* last entry of contour */
4585 						nge->frwd->prev->fpoints[axis][2] += df;
4586 					}
4587 					nge = nge->cntr[!j];
4588 				}
4589 
4590 				if(rm[j] == 0.)
4591 					break;
4592 			}
4593 		}
4594 	}
4595 
4596 	/* find the difference */
4597 	oldpos[0] -= from->prev->fpoints[axis][2];
4598 	oldpos[1] -= to->fpoints[axis][2];
4599 
4600 	if(ret) {
4601 		ret[0] = oldpos[0] - from->prev->fpoints[axis][2];
4602 		ret[1] = oldpos[1] - to->fpoints[axis][2];
4603 	}
4604 
4605 #if 0
4606 	if( rm[0]+rm[1] != gap - oldpos[1] + oldpos[0]) {
4607 		fprintf(stderr, "** gap=%g rm[0]=%g rm[1]=%g o[0]=%g o[1]=%g rg=%g og=%g\n",
4608 			gap, rm[0], rm[1], oldpos[0], oldpos[1], rm[0]+rm[1],
4609 			gap - oldpos[1] + oldpos[0]);
4610 	}
4611 #endif
4612 
4613 	return rm[0]+rm[1];
4614 #undef TIMESLARGER
4615 }
4616 
4617 /* remove the lines or curves smaller or equal to the size limit */
4618 
4619 static void
fdelsmall(GLYPH * g,double minlen)4620 fdelsmall(
4621 	GLYPH *g,
4622 	double minlen
4623 )
4624 {
4625 	GENTRY  *ge, *nge, *pge, *xge, *next;
4626 	int i, k;
4627 	double dx, dy, d2, d2m;
4628 	double minlen2;
4629 #define TIMESLARGER 10.	/* how much larger must be a curve to not change too much */
4630 
4631 	minlen2 = minlen*minlen;
4632 
4633 	for (ge = g->entries; ge != 0; ge = next) {
4634 		next = ge->next;
4635 
4636 		if (ge->type != GE_CURVE && ge->type != GE_LINE)
4637 			continue;
4638 
4639 		d2m = 0;
4640 		for(i= (ge->type==GE_CURVE? 0: 2); i<3; i++) {
4641 			dx = ge->fxn[i] - ge->prev->fx3;
4642 			dy = ge->fyn[i] - ge->prev->fy3;
4643 			d2 = dx*dx + dy*dy;
4644 			if(d2m < d2)
4645 				d2m = d2;
4646 		}
4647 
4648 		if( d2m > minlen2 ) { /* line is not too small */
4649 			/* XXX add more normalization here */
4650 			continue;
4651 		}
4652 
4653 		/* if the line is too small */
4654 
4655 		/* check forwards if we have a whole sequence of them */
4656 		nge = ge;
4657 		for(xge = ge->frwd; xge != ge; xge = xge->frwd) {
4658 			d2m = 0;
4659 			for(i= (xge->type==GE_CURVE? 0: 2); i<3; i++) {
4660 				dx = xge->fxn[i] - xge->prev->fx3;
4661 				dy = xge->fyn[i] - xge->prev->fy3;
4662 				d2 = dx*dx + dy*dy;
4663 				if(d2m < d2)
4664 					d2m = d2;
4665 			}
4666 			if( d2m > minlen2 ) /* line is not too small */
4667 				break;
4668 			nge = xge;
4669 			if(next == nge) /* move the next step past this sequence */
4670 				next = next->next;
4671 		}
4672 
4673 		/* check backwards if we have a whole sequence of them */
4674 		pge = ge;
4675 		for(xge = ge->bkwd; xge != ge; xge = xge->bkwd) {
4676 			d2m = 0;
4677 			for(i= (xge->type==GE_CURVE? 0: 2); i<3; i++) {
4678 				dx = xge->fxn[i] - xge->prev->fx3;
4679 				dy = xge->fyn[i] - xge->prev->fy3;
4680 				d2 = dx*dx + dy*dy;
4681 				if(d2m < d2)
4682 					d2m = d2;
4683 			}
4684 			if( d2m > minlen2 ) /* line is not too small */
4685 				break;
4686 			pge = xge;
4687 		}
4688 
4689 		/* now we have a sequence of small fragments in pge...nge (inclusive) */
4690 
4691 		if(ISDBG(FCONCISE))  {
4692 			fprintf(stderr, "glyph %s has very small fragments(%x..%x..%x)\n",
4693 			g->name, pge, ge, nge);
4694 			dumppaths(g, pge, nge);
4695 		}
4696 
4697 		/* reduce whole sequence to one part and remember the middle point */
4698 		if(pge != nge) {
4699 			while(1) {
4700 				xge = pge->frwd;
4701 				if(xge == nge) {
4702 					pge->fx1 = pge->fx2 = pge->fx3;
4703 					pge->fx3 = nge->fx3;
4704 					pge->fy1 = pge->fy2 = pge->fy3;
4705 					pge->fy3 = nge->fy3;
4706 					pge->type = GE_CURVE;
4707 					freethisge(nge);
4708 					break;
4709 				}
4710 				if(xge == nge->bkwd) {
4711 					pge->fx1 = pge->fx2 = (pge->fx3+xge->fx3)/2.;
4712 					pge->fx3 = nge->fx3;
4713 					pge->fy1 = pge->fy2 = (pge->fy3+xge->fy3)/2.;
4714 					pge->fy3 = nge->fy3;
4715 					pge->type = GE_CURVE;
4716 					freethisge(nge);
4717 					freethisge(xge);
4718 					break;
4719 				}
4720 				freethisge(pge); pge = xge;
4721 				xge = nge->bkwd; freethisge(nge); nge = xge;
4722 			}
4723 		}
4724 		ge = pge;
4725 
4726 		/* check if the whole sequence is small */
4727 		dx = ge->fx3 - ge->prev->fx3;
4728 		dy = ge->fy3 - ge->prev->fy3;
4729 		d2 = dx*dx + dy*dy;
4730 
4731 		if( d2 > minlen2 ) { /* no, it is not */
4732 			double b, d;
4733 
4734 			WARNING_3 fprintf(stderr, "glyph %s had a sequence of fragments < %g points each, reduced to one curve\n",
4735 				g->name, minlen);
4736 
4737 			/* check that we did not create a monstrosity spanning quadrants */
4738 			if(fsign(ge->fx1 - ge->prev->fx1) * fsign(ge->fx3 - ge->fx1) < 0
4739 			|| fsign(ge->fy1 - ge->prev->fy1) * fsign(ge->fy3 - ge->fy1) < 0 ) {
4740 				/* yes, we did; are both parts of this thing big enough ? */
4741 				dx = ge->fx1 - ge->prev->fx3;
4742 				dy = ge->fy1 - ge->prev->fy3;
4743 				d2 = dx*dx + dy*dy;
4744 
4745 				dx = ge->fx3 - ge->fx1;
4746 				dy = ge->fy3 - ge->fy1;
4747 				d2m = dx*dx + dy*dy;
4748 
4749 				if(d2 > minlen2 && d2m > minlen2) { /* make two straights */
4750 					nge = newgentry(GEF_FLOAT);
4751 					*nge = *ge;
4752 
4753 					for(i=0; i<2; i++) {
4754 						ge->fpoints[i][2] = ge->fpoints[i][0];
4755 						b = nge->fpoints[i][0];
4756 						d = nge->fpoints[i][2] - b;
4757 						nge->fpoints[i][0] = b + 0.1*d;
4758 						nge->fpoints[i][1] = b + 0.9*d;
4759 					}
4760 				}
4761 				for(i=0; i<2; i++) { /* make one straight or first of two straights */
4762 					b = ge->prev->fpoints[i][2];
4763 					d = ge->fpoints[i][2] - b;
4764 					ge->fpoints[i][0] = b + 0.1*d;
4765 					ge->fpoints[i][1] = b + 0.9*d;
4766 				}
4767 			}
4768 			continue;
4769 		}
4770 
4771 		if(ge->frwd == ge) { /* points to itself, just remove the path completely */
4772 			WARNING_3 fprintf(stderr, "glyph %s had a path made of fragments < %g points each, removed\n",
4773 				g->name, minlen);
4774 
4775 			next = freethisge(ge);
4776 			continue;
4777 		}
4778 
4779 		/* now close the gap by x and y */
4780 		for(i=0; i<2; i++) {
4781 			double gap;
4782 
4783 			gap = ge->fpoints[i][2] - ge->prev->fpoints[i][2];
4784 			if( fclosegap(ge, ge, i, gap, NULL) != 0.0 ) {
4785 				double scale, base;
4786 
4787 				/* not good, as the last resort just scale the next line */
4788 				gap = ge->fpoints[i][2] - ge->prev->fpoints[i][2];
4789 
4790 				if(ISDBG(FCONCISE))
4791 					fprintf(stderr, "    last resort on %c: closing next by %g\n",
4792 					(i==0 ? 'x' : 'y'), gap);
4793 
4794 				nge = ge->frwd;
4795 				base = nge->fpoints[i][2];
4796 				dx = ge->fpoints[i][2] - base;
4797 				if(fabs(dx) < FEPS)
4798 					continue;
4799 
4800 				scale = ((dx-gap) / dx);
4801 
4802 				if(nge->type == GE_CURVE)
4803 					for(k = 0; k<2; k++)
4804 						nge->fpoints[i][k] = base +
4805 							scale * (nge->fpoints[i][k] - base);
4806 
4807 				ge->fpoints[i][2] -= gap;
4808 			}
4809 		}
4810 
4811 		/* OK, the gap is closed - remove this useless GENTRY */
4812 		freethisge(ge);
4813 	}
4814 #undef TIMESLARGER
4815 }
4816 
4817 /* find the point where two rays continuing vectors cross
4818  * returns 1 if they cross, 0 if they don't
4819  * If they cross optionally (if the pointers are not NULL) returns
4820  * the maximal scales for both vectors and also optionally the point
4821  * where the rays cross (twice).
4822  * Expects that the curves are normalized.
4823  *
4824  * For convenience there are 2 front-end functions taking
4825  * arguments in different formats
4826  */
4827 
4828 struct ray {
4829 	double x1, y1, x2, y2;
4830 	int isvert;
4831 	double k, b; /* lines are represented as y = k*x + b */
4832 	double *maxp;
4833 };
4834 static struct ray ray[3];
4835 
4836 /* the back-end doing the actual work
4837  * the rays are defined in the static array ray[]
4838  */
4839 
4840 static int
fcrossraysxx(double crossdot[2][2])4841 fcrossraysxx(
4842 	double crossdot[2][2]
4843 )
4844 {
4845 	double x, y, max;
4846 	int i;
4847 
4848 	for(i=0; i<2; i++) {
4849 		if(ray[i].x1 == ray[i].x2)
4850 			ray[i].isvert = 1;
4851 		else {
4852 			ray[i].isvert = 0;
4853 			ray[i].k = (ray[i].y2 - ray[i].y1) / (ray[i].x2 - ray[i].x1);
4854 			ray[i].b = ray[i].y2 - ray[i].k * ray[i].x2;
4855 		}
4856 	}
4857 
4858 	if(ray[0].isvert && ray[1].isvert) {
4859 		if(ISDBG(FCONCISE)) fprintf(stderr, "crossrays: both vertical\n");
4860 		return 0; /* both vertical, don't cross */
4861 	}
4862 
4863 	if(ray[1].isvert) {
4864 		ray[2] = ray[0]; /* exchange them */
4865 		ray[0] = ray[1];
4866 		ray[1] = ray[2];
4867 	}
4868 
4869 	if(ray[0].isvert) {
4870 		x = ray[0].x1;
4871 	} else {
4872 		if( fabs(ray[0].k - ray[1].k) < FEPS) {
4873 			if(ISDBG(FCONCISE)) fprintf(stderr, "crossrays: parallel lines, k = %g, %g\n",
4874 				ray[0].k, ray[1].k);
4875 			return 0; /* parallel lines */
4876 		}
4877 		x = (ray[1].b - ray[0].b) / (ray[0].k - ray[1].k) ;
4878 	}
4879 	y = ray[1].k * x + ray[1].b;
4880 
4881 	for(i=0; i<2; i++) {
4882 		if(ray[i].isvert)
4883 			max = (y - ray[i].y1) / (ray[i].y2 - ray[i].y1);
4884 		else
4885 			max = (x - ray[i].x1) / (ray[i].x2 - ray[i].x1);
4886 		/* check if wrong sides of rays cross */
4887 		if( max < 0 ) {
4888 			if(ISDBG(FCONCISE)) fprintf(stderr, "crossrays: %c scale=%g @(%g,%g) (%g,%g)<-(%g,%g)\n",
4889 				(i?'Y':'X'), max, x, y, ray[i].x2, ray[i].y2, ray[i].x1, ray[i].y1);
4890 			return 0;
4891 		}
4892 		if(ray[i].maxp)
4893 			*ray[i].maxp = max;
4894 	}
4895 	if(crossdot != 0) {
4896 		crossdot[0][0] = crossdot[1][0] = x;
4897 		crossdot[0][1] = crossdot[1][1] = y;
4898 	}
4899 	return 1;
4900 }
4901 
4902 /* the front-end getting the arguments from 4 dots defining
4903  * a curve in the same format as for fapproxcurve():
4904  * rays are defined as beginning and end of the curve,
4905  * the crossdot is inserted as the two middle dots of the curve
4906  */
4907 
4908 int
fcrossrayscv(double curve[4][2],double * max1,double * max2)4909 fcrossrayscv(
4910 	double curve[4][2 /*X,Y*/],
4911 	double *max1,
4912 	double *max2
4913 )
4914 {
4915 	ray[0].x1 = curve[0][X];
4916 	ray[0].y1 = curve[0][Y];
4917 	ray[0].x2 = curve[1][X];
4918 	ray[0].y2 = curve[1][Y];
4919 	ray[0].maxp = max1;
4920 
4921 	ray[1].x1 = curve[2][X];
4922 	ray[1].y1 = curve[2][Y];
4923 	ray[1].x2 = curve[3][X];
4924 	ray[1].y2 = curve[3][Y];
4925 	ray[1].maxp = max2;
4926 
4927 	return fcrossraysxx(&curve[1]);
4928 }
4929 
4930 /* the front-end getting the arguments from gentries:
4931  * rays are defined as beginning of curve1 and end of curve 2
4932  */
4933 
4934 int
fcrossraysge(GENTRY * ge1,GENTRY * ge2,double * max1,double * max2,double crossdot[2][2])4935 fcrossraysge(
4936 	GENTRY *ge1,
4937 	GENTRY *ge2,
4938 	double *max1,
4939 	double *max2,
4940 	double crossdot[2][2]
4941 )
4942 {
4943 	ray[0].x1 = ge1->prev->fx3;
4944 	ray[0].y1 = ge1->prev->fy3;
4945 	ray[0].x2 = ge1->fpoints[X][ge1->ftg];
4946 	ray[0].y2 = ge1->fpoints[Y][ge1->ftg];
4947 	ray[0].maxp = max1;
4948 
4949 	ray[1].x1 = ge2->fx3;
4950 	ray[1].y1 = ge2->fy3;
4951 	if(ge2->rtg < 0) {
4952 		ray[1].x2 = ge2->prev->fx3;
4953 		ray[1].y2 = ge2->prev->fy3;
4954 	} else {
4955 		ray[1].x2 = ge2->fpoints[X][ge2->rtg];
4956 		ray[1].y2 = ge2->fpoints[Y][ge2->rtg];
4957 	}
4958 	ray[1].maxp = max2;
4959 
4960 	return fcrossraysxx(crossdot);
4961 }
4962 
4963 /* debugging printout functions */
4964 
4965 #if defined(DEBUG_DOTSEG) || defined(DEBUG_DOTCURVE) || defined(DEBUG_APPROXCV)
4966 
4967 /* for debugging */
4968 static
printdot(double dot[2])4969 printdot(
4970 	double dot[2]
4971 )
4972 {
4973 	fprintf(stderr, "(%g,%g)", dot[0], dot[1]);
4974 }
4975 
4976 static
printseg(double seg[2][2])4977 printseg(
4978 	double seg[2][2]
4979 )
4980 {
4981 	putc('[', stderr);
4982 	printdot(seg[0]);
4983 	putc(' ', stderr);
4984 	printdot(seg[1]);
4985 	putc(']', stderr);
4986 }
4987 
4988 #endif /* DEBUG_* */
4989 
4990 /*
4991  * Find squared distance from a dot to a line segment
4992  */
4993 
4994 double
fdotsegdist2(double seg[2][2],double dot[2])4995 fdotsegdist2(
4996 	double seg[2][2 /*X,Y*/],
4997 	double dot[2 /*X,Y*/]
4998 )
4999 {
5000 #define x1	seg[0][X]
5001 #define y1	seg[0][Y]
5002 #define x2	seg[1][X]
5003 #define y2	seg[1][Y]
5004 #define xdot	dot[X]
5005 #define ydot	dot[Y]
5006 
5007 	double dx, dy; /* segment dimensions */
5008 	double kline, bline; /* segment line formula is y=k*x+b */
5009 	double kperp, bperp; /* perpendicular from the dot to the line */
5010 	double xcross, ycross; /* where the perpendicular crosses the segment */
5011 
5012 /* handle the situation where the nearest point of the segment is its end */
5013 #define HANDLE_LIMITS(less12, lesscr1, lesscr2)	\
5014 	if( less12 ) { \
5015 		if( lesscr1 ) { \
5016 			xcross = x1; \
5017 			ycross = y1; \
5018 		} else if( !(lesscr2) ) { \
5019 			xcross = x2; \
5020 			ycross = y2; \
5021 		} \
5022 	} else { \
5023 		if( !(lesscr1) ) { \
5024 			xcross = x1; \
5025 			ycross = y1; \
5026 		} else if( lesscr2 ) { \
5027 			xcross = x2; \
5028 			ycross = y2; \
5029 		} \
5030 	} \
5031 	/* end of macro */
5032 
5033 
5034 	dx = x2 - x1;
5035 	dy = y2 - y1;
5036 
5037 	if(fabs(dx) < FEPS) {
5038 		/* special case - vertical line */
5039 #ifdef DEBUG_DOTSEG
5040 		printf("vertical line!\n");
5041 #endif
5042 		xcross = x1;
5043 		ycross = ydot;
5044 		HANDLE_LIMITS( y1 < y2, ycross < y1, ycross < y2);
5045 	} else if(fabs(dy) < FEPS) {
5046 		/* special case - horizontal line */
5047 #ifdef DEBUG_DOTSEG
5048 		printf("horizontal line!\n");
5049 #endif
5050 		xcross = xdot;
5051 		ycross = y1;
5052 		HANDLE_LIMITS( x1 < x2, xcross < x1, xcross < x2)
5053 	} else {
5054 		kline = dy/dx;
5055 		bline = y1 - x1*kline;
5056 		kperp = -1./kline;
5057 		bperp = ydot - xdot*kperp;
5058 
5059 		xcross = (bline-bperp) / (kperp-kline);
5060 		ycross = kline*xcross + bline;
5061 
5062 		HANDLE_LIMITS( x1 < x2, xcross < x1, xcross < x2)
5063 	}
5064 #ifdef DEBUG_DOTSEG
5065 	printf("crossover at (%g,%g)\n", xcross, ycross);
5066 #endif
5067 
5068 	dx = xdot-xcross;
5069 	dy = ydot-ycross;
5070 	return dx*dx+dy*dy;
5071 #undef x1
5072 #undef y1
5073 #undef x2
5074 #undef y2
5075 #undef xdot
5076 #undef ydot
5077 #undef HANDLE_LIMITS
5078 }
5079 
5080 /* find the weighted quadratic average for the distance of a set
5081  * of dots from the curve; also fills out the individual distances
5082  * for each dot; if maxp!=NULL then returns the maximal squared
5083  * distance in there
5084  */
5085 
5086 double
fdotcurvdist2(double curve[4][2],struct dot_dist * dots,int ndots,double * maxp)5087 fdotcurvdist2(
5088 	double curve[4][2 /*X,Y*/ ],
5089 	struct dot_dist *dots,
5090 	int ndots, /* number of entries in dots */
5091 	double *maxp
5092 )
5093 {
5094 	/* a curve is approximated by this many straight segments */
5095 #define NAPSECT	16
5096 	/* a curve is divided into this many sections with equal weight each */
5097 #define NWSECT	4
5098 	/* table of coefficients for finding the dots on the curve */
5099 	/* tt[0] is left unused */
5100 	static double tt[NAPSECT][4];
5101 	static int havett = 0; /* flag: tt is initialized */
5102 	/* dots on the curve */
5103 	double cvd[NAPSECT+1][2 /*X,Y*/];
5104 	/* sums by sections */
5105 	double sum[NWSECT];
5106 	/* counts by sections */
5107 	double count[NWSECT];
5108 	int d, i, j;
5109 	int id1, id2;
5110 	double dist1, dist2, dist3, dx, dy, x, y;
5111 	double max = 0.;
5112 
5113 	if(!havett) {
5114 		double t, nt, t2, nt2, step;
5115 
5116 		havett++;
5117 		step = 1. / NAPSECT;
5118 		t = 0;
5119 		for(i=1; i<NAPSECT; i++) {
5120 			t += step;
5121 			nt = 1 - t;
5122 			t2 = t*t;
5123 			nt2 = nt*nt;
5124 			tt[i][0] = nt2*nt; /* (1-t)^3 */
5125 			tt[i][1] = 3*nt2*t; /* 3*(1-t)^2*t */
5126 			tt[i][2] = 3*nt*t2; /* 3*(1-t)*t^2 */
5127 			tt[i][3] = t2*t; /* t^3 */
5128 		}
5129 	}
5130 
5131 	for(i=0; i<NWSECT; i++) {
5132 		sum[i] = 0.;
5133 		count[i] = 0;
5134 	}
5135 
5136 	/* split the curve into segments */
5137 	for(d=0; d<2; d++) { /* X and Y */
5138 		cvd[0][d] = curve[0][d]; /* endpoints */
5139 		cvd[NAPSECT][d] = curve[3][d];
5140 		for(i=1; i<NAPSECT; i++) {
5141 			cvd[i][d] = curve[0][d] * tt[i][0]
5142 				+ curve[1][d] * tt[i][1]
5143 				+ curve[2][d] * tt[i][2]
5144 				+ curve[3][d] * tt[i][3];
5145 		}
5146 	}
5147 
5148 	for(d=0; d<ndots; d++) {
5149 #ifdef DEBUG_DOTCURVE
5150 		printf("dot %d ", d); printdot(dots[d].p); printf(":\n");
5151 
5152 		/* for debugging */
5153 		for(i=0; i< NAPSECT; i++) {
5154 			dist1 = fdotsegdist2(&cvd[i], dots[d].p);
5155 			printf("  seg %d ",i); printseg(&cvd[i]); printf(" dist=%g\n", sqrt(dist1));
5156 		}
5157 #endif
5158 
5159 		x = dots[d].p[X];
5160 		y = dots[d].p[Y];
5161 
5162 		/* find the nearest dot on the curve
5163 		 * there may be up to 2 local minimums - so we start from the
5164 		 * ends of curve and go to the center
5165 		 */
5166 
5167 		id1 = 0;
5168 		dx = x - cvd[0][X];
5169 		dy = y - cvd[0][Y];
5170 		dist1 = dx*dx + dy*dy;
5171 #ifdef DEBUG_DOTCURVE
5172 		printf("  dot 0 "); printdot(cvd[id1]); printf(" dist=%g\n", sqrt(dist1));
5173 #endif
5174 		for(i = 1; i<=NAPSECT; i++) {
5175 			dx = x - cvd[i][X];
5176 			dy = y - cvd[i][Y];
5177 			dist3 = dx*dx + dy*dy;
5178 #ifdef DEBUG_DOTCURVE
5179 			printf("  dot %d ",i); printdot(cvd[i]); printf(" dist=%g\n", sqrt(dist3));
5180 #endif
5181 			if(dist3 < dist1) {
5182 				dist1 = dist3;
5183 				id1 = i;
5184 			} else
5185 				break;
5186 		}
5187 
5188 		if(id1 < NAPSECT-1) {
5189 			id2 = NAPSECT;
5190 			dx = x - cvd[NAPSECT][X];
5191 			dy = y - cvd[NAPSECT][Y];
5192 			dist2 = dx*dx + dy*dy;
5193 #ifdef DEBUG_DOTCURVE
5194 			printf("  +dot %d ", id2); printdot(cvd[id2]); printf(" dist=%g\n", sqrt(dist2));
5195 #endif
5196 			for(i = NAPSECT-1; i>id1+1; i--) {
5197 				dx = x - cvd[i][X];
5198 				dy = y - cvd[i][Y];
5199 				dist3 = dx*dx + dy*dy;
5200 #ifdef DEBUG_DOTCURVE
5201 				printf("  dot %d ",i); printdot(cvd[i]); printf(" dist=%g\n", sqrt(dist3));
5202 #endif
5203 				if(dist3 < dist2) {
5204 					dist2 = dist3;
5205 					id2 = i;
5206 				} else
5207 					break;
5208 			}
5209 
5210 			/* now find which of the local minimums is smaller */
5211 			if(dist2 < dist1) {
5212 				id1 = id2;
5213 			}
5214 		}
5215 
5216 		/* the nearest segment must include the nearest dot */
5217 		if(id1==0) {
5218 			dots[d].seg = 0;
5219 			dots[d].dist2 = fdotsegdist2(&cvd[0], dots[d].p);
5220 		} else if(id1==NAPSECT) {
5221 			dots[d].seg = NAPSECT-1;
5222 			dots[d].dist2 = fdotsegdist2(&cvd[NAPSECT-1], dots[d].p);
5223 		} else {
5224 			dist1 = fdotsegdist2(&cvd[id1], dots[d].p);
5225 			dist2 = fdotsegdist2(&cvd[id1-1], dots[d].p);
5226 			if(dist2 < dist1) {
5227 				dots[d].seg = id1-1;
5228 				dots[d].dist2 = dist2;
5229 			} else {
5230 				dots[d].seg = id1;
5231 				dots[d].dist2 = dist1;
5232 			}
5233 		}
5234 
5235 		i = dots[d].seg % NWSECT;
5236 		sum[i] += dots[d].dist2;
5237 		if(dots[d].dist2 > max)
5238 			max = dots[d].dist2;
5239 		count[i]++;
5240 #ifdef DEBUG_DOTCURVE
5241 		printf(" best seg %d sect %d dist=%g\n", dots[d].seg, i, sqrt(dots[d].dist2));
5242 #endif
5243 	}
5244 
5245 	/* calculate the weighted average */
5246 	id1=0;
5247 	dist1=0.;
5248 	for(i=0; i<NWSECT; i++) {
5249 		if(count[i]==0)
5250 			continue;
5251 		id1++;
5252 		dist1 += sum[i]/count[i];
5253 	}
5254 	if(maxp)
5255 		*maxp = max;
5256 	if(id1==0) /* no dots, strange */
5257 		return 0.;
5258 	else
5259 		return dist1/id1; /* to get the average distance apply sqrt() */
5260 }
5261 
5262 /*
5263  * Approximate a curve matching the giving set of points and with
5264  * middle reference points going along the given segments (and no farther
5265  * than these segments).
5266  */
5267 
5268 void
fapproxcurve(double cv[4][2],struct dot_dist * dots,int ndots)5269 fapproxcurve(
5270 	double cv[4][2 /*X,Y*/ ], /* points 0-3 are passed in, points 1,2 - out */
5271 	struct dot_dist *dots, /* the dots to approximate - distances returned
5272 		* there may be invalid */
5273 	int ndots
5274 )
5275 {
5276 	/* b and c are the middle control points */
5277 #define	B	0
5278 #define	C	1
5279 	/* maximal number of sections on each axis - used for the first step */
5280 #define MAXSECT	2
5281 	/* number of sections used for the other steps */
5282 #define NORMSECT 2
5283 	/* when the steps become less than this many points, it's time to stop */
5284 #define STEPEPS	1.
5285 	double from[2 /*B,C*/], to[2 /*B,C*/];
5286 	double middf[2 /*B,C*/][2 /*X,Y*/], df;
5287 	double coef[2 /*B,C*/][MAXSECT];
5288 	double res[MAXSECT][MAXSECT], thisres, bestres, goodres;
5289 	int ncoef[2 /*B,C*/], best[2 /*B,C*/], good[2 /*B,C*/];
5290 	int i, j, k, keepsym;
5291 	char bc[]="BC";
5292 	char xy[]="XY";
5293 
5294 #ifdef DEBUG_APPROXCV
5295 	fprintf(stderr, "Curve points:");
5296 	for(i=0; i<4; i++) {
5297 		fprintf(stderr, " ");
5298 		printdot(cv[i]);
5299 	}
5300 	fprintf(stderr, "\nDots:");
5301 	for(i=0; i<ndots; i++) {
5302 		fprintf(stderr, " ");
5303 		printdot(dots[i].p);
5304 	}
5305 	fprintf(stderr, "\n");
5306 #endif
5307 
5308 	/* load the endpoints and calculate differences */
5309 	for(i=0; i<2; i++) {
5310 		/* i is X, Y */
5311 		middf[B][i] = cv[1][i]-cv[0][i];
5312 		middf[C][i] = cv[2][i]-cv[3][i];
5313 
5314 		/* i is B, C */
5315 		from[i] = 0.;
5316 		to[i] = 1.;
5317 		ncoef[i] = MAXSECT;
5318 	}
5319 
5320 	while(ncoef[B] != 1 || ncoef[C] != 1) {
5321 		/* prepare the values of coefficients */
5322 		for(i=0; i<2; i++) { /*B,C*/
5323 #ifdef DEBUG_APPROXCV
5324 			fprintf(stderr, "Coefficients by %c(%g,%g):", bc[i], from[i], to[i]);
5325 #endif
5326 			df = (to[i]-from[i]) / (ncoef[i]*2);
5327 			for(j=0; j<ncoef[i]; j++) {
5328 				coef[i][j] = from[i] + df*(2*j+1);
5329 #ifdef DEBUG_APPROXCV
5330 				fprintf(stderr, " %g", coef[i][j]);
5331 #endif
5332 			}
5333 #ifdef DEBUG_APPROXCV
5334 			fprintf(stderr, "\n");
5335 #endif
5336 		}
5337 		bestres = FBIGVAL;
5338 		best[B] = best[C] = 0;
5339 		/* i iterates by ncoef[B], j iterates by ncoef[C] */
5340 		for(i=0; i<ncoef[B]; i++) {
5341 			for(j=0; j<ncoef[C]; j++) {
5342 				for(k=0; k<2; k++) { /*X, Y*/
5343 					cv[1][k] = cv[0][k] + middf[B][k]*coef[B][i];
5344 					cv[2][k] = cv[3][k] + middf[C][k]*coef[C][j];
5345 				}
5346 				res[i][j] = thisres = fdotcurvdist2(cv, dots, ndots, NULL);
5347 				if(thisres < bestres) {
5348 					goodres = bestres;
5349 					good[B] = best[B];
5350 					good[C] = best[C];
5351 					bestres = thisres;
5352 					best[B] = i;
5353 					best[C] = j;
5354 				} else if(thisres < goodres) {
5355 					goodres = thisres;
5356 					good[B] = i;
5357 					good[C] = j;
5358 				}
5359 #ifdef DEBUG_APPROXCV
5360 				fprintf(stderr, " at (%g,%g) dist=%g %s\n", coef[B][i], coef[C][j], sqrt(thisres),
5361 					(best[B]==i && best[C]==j)? "(BEST)":"");
5362 #endif
5363 			}
5364 		}
5365 #ifdef DEBUG_APPROXCV
5366 		fprintf(stderr, " best: at (%g, %g) dist=%g\n",
5367 			coef[B][best[B]], coef[C][best[C]], sqrt(bestres));
5368 		fprintf(stderr, " B:%d,%d C:%d,%d -- 2nd best: at (%g, %g) dist=%g\n",
5369 			best[B], good[B], best[C], good[C], coef[B][good[B]], coef[C][good[C]], sqrt(goodres));
5370 #endif
5371 
5372 		if(bestres < (0.1*0.1)) { /* consider it close enough */
5373 			/* calculate the coordinates to return */
5374 			for(k=0; k<2; k++) { /*X, Y*/
5375 				cv[1][k] = cv[0][k] + middf[B][k]*coef[B][best[B]];
5376 				cv[2][k] = cv[3][k] + middf[C][k]*coef[C][best[C]];
5377 			}
5378 #ifdef DEBUG_APPROXCV
5379 			fprintf(stderr, "quick approximated middle points "); printdot(cv[1]);
5380 			fprintf(stderr, " "); printdot(cv[2]); fprintf(stderr, "\n");
5381 #endif
5382 			return;
5383 		}
5384 		keepsym = 0;
5385 		if(best[B] != best[C] && best[B]-best[C] == good[C]-good[B]) {
5386 			keepsym = 1;
5387 #ifdef DEBUG_APPROXCV
5388 			fprintf(stderr, "keeping symmetry!\n");
5389 #endif
5390 		}
5391 		for(i=0; i<2; i++) { /*B,C*/
5392 			if(ncoef[i]==1)
5393 				continue;
5394 			if(keepsym) {
5395 				/* try to keep the symmetry */
5396 				if(best[i] < good[i]) {
5397 					from[i] = coef[i][best[i]];
5398 					to[i] = coef[i][good[i]];
5399 				} else {
5400 					from[i] = coef[i][good[i]];
5401 					to[i] = coef[i][best[i]];
5402 				}
5403 			} else {
5404 				df = (to[i]-from[i]) / ncoef[i];
5405 				from[i] += df*best[i];
5406 				to[i] = from[i] + df;
5407 			}
5408 			if( fabs(df*middf[i][0]) < STEPEPS && fabs(df*middf[i][1]) < STEPEPS) {
5409 				/* this side has converged */
5410 				from[i] = to[i] = (from[i]+to[i]) / 2.;
5411 				ncoef[i] = 1;
5412 			} else
5413 				ncoef[i] = NORMSECT;
5414 		}
5415 
5416 	}
5417 	/* calculate the coordinates to return */
5418 	for(k=0; k<2; k++) { /*X, Y*/
5419 		cv[1][k] = cv[0][k] + middf[B][k]*from[B];
5420 		cv[2][k] = cv[3][k] + middf[C][k]*from[C];
5421 	}
5422 #ifdef DEBUG_APPROXCV
5423 	fprintf(stderr, "approximated middle points "); printdot(cv[1]);
5424 	fprintf(stderr, " "); printdot(cv[2]); fprintf(stderr, "\n");
5425 #endif
5426 #undef B
5427 #undef C
5428 #undef MAXSECT
5429 #undef NORMSECT
5430 #undef STEPEPS
5431 }
5432 
5433 /*
5434  * Find the squared value of the sinus of the angle between the
5435  * end of ge1 and the beginning of ge2
5436  * The curve must be normalized.
5437  */
5438 
5439 static double
fjointsin2(GENTRY * ge1,GENTRY * ge2)5440 fjointsin2(
5441 	GENTRY *ge1,
5442 	GENTRY *ge2
5443 )
5444 {
5445 	double d[3][2 /*X,Y*/];
5446 	double scale1, scale2, len1, len2;
5447 	int axis;
5448 
5449 	if(ge1->rtg < 0) {
5450 		d[1][X] = ge1->fx3 - ge1->prev->fx3;
5451 		d[1][Y] = ge1->fy3 - ge1->prev->fy3;
5452 	} else {
5453 		d[1][X] = ge1->fx3 - ge1->fpoints[X][ge1->rtg];
5454 		d[1][Y] = ge1->fy3 - ge1->fpoints[Y][ge1->rtg];
5455 	}
5456 	d[2][X] = ge2->fpoints[X][ge2->ftg] - ge2->prev->fx3;
5457 	d[2][Y] = ge2->fpoints[Y][ge2->ftg] - ge2->prev->fy3;
5458 
5459 	len1 = sqrt( d[1][X]*d[1][X] + d[1][Y]*d[1][Y] );
5460 	len2 = sqrt( d[2][X]*d[2][X] + d[2][Y]*d[2][Y] );
5461 	/* scale the 2nd segment to the length of 1
5462 	 * and to make sure that the 1st segment is longer scale it to
5463 	 * the length of 2 and extend to the same distance backwards
5464 	 */
5465 	scale1 = 2./len1;
5466 	scale2 = 1./len2;
5467 
5468 	for(axis=0; axis <2; axis++) {
5469 		d[0][axis] = -( d[1][axis] *= scale1 );
5470 		d[2][axis] *= scale2;
5471 	}
5472 	return fdotsegdist2(d, d[2]);
5473 }
5474 
5475 #if 0
5476 /* find the area covered by the curve
5477  * (limited by the projections to the X axis)
5478  */
5479 
5480 static double
5481 fcvarea(
5482 	GENTRY *ge
5483 )
5484 {
5485 	double Ly, My, Ny, Py, Qx, Rx, Sx;
5486 	double area;
5487 
5488 	/* y = Ly*t^3 + My*t^2 + Ny*t + Py */
5489 	Ly = -ge->prev->fy3 + 3*(ge->fy1 - ge->fy2) + ge->fy3;
5490 	My = 3*ge->prev->fy3 - 6*ge->fy1 + 3*ge->fy2;
5491 	Ny = 3*(-ge->prev->fy3 + ge->fy1);
5492 	Py = ge->prev->fy3;
5493 
5494 	/* dx/dt = Qx*t^2 + Rx*t + Sx */
5495 	Qx = 3*(-ge->prev->fx3 + 3*(ge->fx1 - ge->fx2) + ge->fx3);
5496 	Rx = 6*(ge->prev->fx3 - 2*ge->fx1 + ge->fx2);
5497 	Sx = 3*(-ge->prev->fx3 + ge->fx1);
5498 
5499 	/* area is integral[from 0 to 1]( y(t) * dx(t)/dt *dt) */
5500 	area = 1./6.*(Ly*Qx) + 1./5.*(Ly*Rx + My*Qx)
5501 		+ 1./4.*(Ly*Sx + My*Rx + Ny*Qx) + 1./3.*(My*Sx + Ny*Rx + Py*Qx)
5502 		+ 1./2.*(Ny*Sx + Py*Rx) + Py*Sx;
5503 
5504 	return area;
5505 }
5506 #endif
5507 
5508 /* find the value of point on the curve at the given parameter t,
5509  * along the given axis (0 - X, 1 - Y).
5510  */
5511 
5512 static double
fcvval(GENTRY * ge,int axis,double t)5513 fcvval(
5514 	GENTRY *ge,
5515 	int axis,
5516 	double t
5517 )
5518 {
5519 	double t2, mt, mt2;
5520 
5521 	/* val = A*(1-t)^3 + 3*B*(1-t)^2*t + 3*C*(1-t)*t^2 + D*t^3 */
5522 	t2 = t*t;
5523 	mt = 1-t;
5524 	mt2 = mt*mt;
5525 
5526 	return ge->prev->fpoints[axis][2]*mt2*mt
5527 		+ 3*(ge->fpoints[axis][0]*mt2*t + ge->fpoints[axis][1]*mt*t2)
5528 		+ ge->fpoints[axis][2]*t*t2;
5529 }
5530 
5531 /*
5532  * Find ndots equally spaced dots on a curve or line and fill
5533  * their coordinates into the dots array
5534  */
5535 
5536 static void
fsampledots(GENTRY * ge,double dots[][2],int ndots)5537 fsampledots(
5538 	GENTRY *ge,
5539 	double dots[][2], /* the dots to fill */
5540 	int ndots
5541 )
5542 {
5543 	int i, axis;
5544 	double t, nf, dx, d[2];
5545 
5546 	nf = ndots+1;
5547 	if(ge->type == GE_CURVE) {
5548 		for(i=0; i<ndots; i++) {
5549 			t = (i+1)/nf;
5550 			for(axis=0; axis<2; axis++)
5551 				dots[i][axis] = fcvval(ge, axis, t);
5552 		}
5553 	} else { /* line */
5554 		d[0] = ge->fx3 - ge->prev->fx3;
5555 		d[1] = ge->fy3 - ge->prev->fy3;
5556 		for(i=0; i<ndots; i++) {
5557 			t = (i+1)/nf;
5558 			for(axis=0; axis<2; axis++)
5559 				dots[i][axis] = ge->prev->fpoints[axis][2]
5560 					+ t*d[axis];
5561 		}
5562 	}
5563 }
5564 
5565 /*
5566  * Allocate a structure gex_con
5567  */
5568 
5569 static void
alloc_gex_con(GENTRY * ge)5570 alloc_gex_con(
5571 	GENTRY *ge
5572 )
5573 {
5574 	ge->ext = (void*)calloc(1, sizeof(GEX_CON));
5575 	if(ge->ext == 0) {
5576 		fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
5577 		exit(255);
5578 	}
5579 }
5580 
5581 /*
5582  * Normalize a gentry for fforceconcise() : find the points that
5583  * can be used to calculate the tangents.
5584  */
5585 
5586 static void
fnormalizege(GENTRY * ge)5587 fnormalizege(
5588 	GENTRY *ge
5589 )
5590 {
5591 	int midsame, frontsame, rearsame;
5592 
5593 	if(ge->type == GE_LINE) {
5594 		ge->ftg = 2;
5595 		ge->rtg = -1;
5596 	} else { /* assume it's a curve */
5597 		midsame = (fabs(ge->fx1-ge->fx2)<FEPS && fabs(ge->fy1-ge->fy2)<FEPS);
5598 		frontsame = (fabs(ge->fx1-ge->prev->fx3)<FEPS && fabs(ge->fy1-ge->prev->fy3)<FEPS);
5599 		rearsame = (fabs(ge->fx3-ge->fx2)<FEPS && fabs(ge->fy3-ge->fy2)<FEPS);
5600 
5601 		if(midsame && (frontsame || rearsame) ) {
5602 			/* essentially a line */
5603 			ge->ftg = 2;
5604 			ge->rtg = -1;
5605 		} else {
5606 			if(frontsame) {
5607 				ge->ftg = 1;
5608 			} else {
5609 				ge->ftg = 0;
5610 			}
5611 			if(rearsame) {
5612 				ge->rtg = 0;
5613 			} else {
5614 				ge->rtg = 1;
5615 			}
5616 		}
5617 	}
5618 }
5619 
5620 /* various definition for the processing of outlines */
5621 
5622 /* maximal average quadratic distance from the original curve
5623  * (in dots) to consider the joined curve good
5624  */
5625 #define CVEPS	1.5
5626 #define CVEPS2	(CVEPS*CVEPS)
5627 /* squared sinus of the maximal angle that we consider a smooth joint */
5628 #define SMOOTHSIN2 0.25 /* 0.25==sin(30 degrees)^2 */
5629 /* squared line length that we consider small */
5630 #define SMALL_LINE2 (15.*15.)
5631 /* how many times a curve must be bigger than a line to join, squared */
5632 #define TIMES_LINE2 (3.*3.)
5633 
5634 /*
5635  * Normalize and analyse a gentry for fforceconcise() and fill out the gex_con
5636  * structure
5637  */
5638 
5639 static void
fanalyzege(GENTRY * ge)5640 fanalyzege(
5641 	GENTRY *ge
5642 )
5643 {
5644 	int i, ix, iy;
5645 	double avsd2, dots[3][2 /*X,Y*/];
5646 	GEX_CON *gex;
5647 
5648 	gex = X_CON(ge);
5649 	memset(gex, 0, sizeof *gex);
5650 
5651 	gex->len2 = 0;
5652 	for(i=0; i<2; i++) {
5653 		avsd2 = gex->d[i] = ge->fpoints[i][2] - ge->prev->fpoints[i][2];
5654 		gex->len2 += avsd2*avsd2;
5655 	}
5656 	gex->sin2 = fjointsin2(ge, ge->frwd);
5657 	if(ge->type == GE_CURVE) {
5658 		ge->dir = fgetcvdir(ge);
5659 		for(i=0; i<2; i++) {
5660 			dots[0][i] = ge->prev->fpoints[i][2];
5661 			dots[1][i] = ge->fpoints[i][2];
5662 			dots[2][i] = fcvval(ge, i, 0.5);
5663 		}
5664 		avsd2 = fdotsegdist2(dots, dots[2]);
5665 		if(avsd2 <= CVEPS2) {
5666 			gex->flags |= GEXF_FLAT;
5667 		}
5668 	} else {
5669 		ge->dir = CVDIR_FEQUAL|CVDIR_REQUAL;
5670 		gex->flags |= GEXF_FLAT;
5671 	}
5672 	if(gex->flags & GEXF_FLAT) {
5673 		if( fabs(gex->d[X]) > FEPS && fabs(gex->d[Y]) < 5.
5674 		&& fabs(gex->d[Y] / gex->d[X]) < 0.2)
5675 			gex->flags |= GEXF_HOR;
5676 		else if( fabs(gex->d[Y]) > FEPS && fabs(gex->d[X]) < 5.
5677 		&& fabs(gex->d[X] / gex->d[Y]) < 0.2)
5678 			gex->flags |= GEXF_VERT;
5679 	}
5680 	ix = gex->isd[X] = fsign(gex->d[X]);
5681 	iy = gex->isd[Y] = fsign(gex->d[Y]);
5682 	if(ix <= 0) {
5683 		if(iy <= 0)
5684 			gex->flags |= GEXF_QDL;
5685 		if(iy >= 0)
5686 			gex->flags |= GEXF_QUL;
5687 		if(gex->flags & GEXF_HOR)
5688 			gex->flags |= GEXF_IDQ_L;
5689 	}
5690 	if(ix >= 0) {
5691 		if(iy <= 0)
5692 			gex->flags |= GEXF_QDR;
5693 		if(iy >= 0)
5694 			gex->flags |= GEXF_QUR;
5695 		if(gex->flags & GEXF_HOR)
5696 			gex->flags |= GEXF_IDQ_R;
5697 	}
5698 	if(gex->flags & GEXF_VERT) {
5699 		if(iy <= 0) {
5700 			gex->flags |= GEXF_IDQ_U;
5701 		} else { /* supposedly there is no 0-sized entry */
5702 			gex->flags |= GEXF_IDQ_D;
5703 		}
5704 	}
5705 }
5706 
5707 /*
5708  * Analyse a joint between this and following gentry for fforceconcise()
5709  * and fill out the corresponding parts of the gex_con structure
5710  * Bothe entries must be analyzed first.
5711  */
5712 
5713 static void
fanalyzejoint(GENTRY * ge)5714 fanalyzejoint(
5715 	GENTRY *ge
5716 )
5717 {
5718 	GENTRY *nge = ge->frwd;
5719 	GENTRY tge;
5720 	GEX_CON *gex, *ngex;
5721 	double avsd2, dots[3][2 /*X,Y*/];
5722 	int i;
5723 
5724 	gex = X_CON(ge); ngex = X_CON(nge);
5725 
5726 	/* look if they can be joined honestly */
5727 
5728 	/* if any is flat, they should join smoothly */
5729 	if( (gex->flags & GEXF_FLAT || ngex->flags & GEXF_FLAT)
5730 	&& gex->sin2 > SMOOTHSIN2)
5731 		goto try_flatboth;
5732 
5733 	if(ge->type == GE_LINE) {
5734 		if(nge->type == GE_LINE) {
5735 			if(gex->len2 > SMALL_LINE2 || ngex->len2 > SMALL_LINE2)
5736 				goto try_flatboth;
5737 		} else {
5738 			if(gex->len2*TIMES_LINE2 > ngex->len2)
5739 				goto try_flatboth;
5740 		}
5741 	} else if(nge->type == GE_LINE) {
5742 		if(ngex->len2*TIMES_LINE2 > gex->len2)
5743 			goto try_flatboth;
5744 	}
5745 
5746 	/* if curve changes direction */
5747 	if( gex->isd[X]*ngex->isd[X]<0 || gex->isd[Y]*ngex->isd[Y]<0)
5748 		goto try_idealone;
5749 
5750 	/* if would create a zigzag */
5751 	if( ((ge->dir&CVDIR_FRONT)-CVDIR_FEQUAL) * ((nge->dir&CVDIR_REAR)-CVDIR_REQUAL) < 0 )
5752 		goto try_flatone;
5753 
5754 	if( fcrossraysge(ge, nge, NULL, NULL, NULL) )
5755 		gex->flags |= GEXF_JGOOD;
5756 
5757 try_flatone:
5758 	/* look if they can be joined by flatting out one of the entries */
5759 
5760 	/* at this point we know that the general direction of the
5761 	 * gentries is OK
5762 	 */
5763 
5764 	if( gex->flags & GEXF_FLAT ) {
5765 		tge = *ge;
5766 		tge.fx1 = tge.fx3;
5767 		tge.fy1 = tge.fy3;
5768 		fnormalizege(&tge);
5769 		if( fcrossraysge(&tge, nge, NULL, NULL, NULL) )
5770 			gex->flags |= GEXF_JFLAT|GEXF_JFLAT1;
5771 	}
5772 	if( ngex->flags & GEXF_FLAT ) {
5773 		tge = *nge;
5774 		tge.fx2 = ge->fx3;
5775 		tge.fy2 = ge->fy3;
5776 		fnormalizege(&tge);
5777 		if( fcrossraysge(ge, &tge, NULL, NULL, NULL) )
5778 			gex->flags |= GEXF_JFLAT|GEXF_JFLAT2;
5779 	}
5780 
5781 try_idealone:
5782 	/* look if one of the entries can be brought to an idealized
5783 	 * horizontal or vertical position and then joined
5784 	 */
5785 	if( gex->flags & GEXF_HOR && gex->isd[X]*ngex->isd[X]>=0 ) {
5786 		tge = *ge;
5787 		tge.fx1 = tge.fx3;
5788 		tge.fy1 = ge->prev->fy3; /* force horizontal */
5789 		fnormalizege(&tge);
5790 		if( fcrossraysge(&tge, nge, NULL, NULL, NULL) )
5791 			gex->flags |= GEXF_JID|GEXF_JID1;
5792 	} else if( gex->flags & GEXF_VERT && gex->isd[Y]*ngex->isd[Y]>=0 ) {
5793 		tge = *ge;
5794 		tge.fx1 = ge->prev->fx3; /* force vertical */
5795 		tge.fy1 = tge.fy3;
5796 		fnormalizege(&tge);
5797 		if( fcrossraysge(&tge, nge, NULL, NULL, NULL) )
5798 			gex->flags |= GEXF_JID|GEXF_JID1;
5799 	}
5800 	if( ngex->flags & GEXF_HOR && gex->isd[X]*ngex->isd[X]>=0 ) {
5801 		tge = *nge;
5802 		tge.fx2 = ge->fx3;
5803 		tge.fy2 = nge->fy3; /* force horizontal */
5804 		fnormalizege(&tge);
5805 		if( fcrossraysge(ge, &tge, NULL, NULL, NULL) )
5806 			gex->flags |= GEXF_JID|GEXF_JID2;
5807 	} else if( ngex->flags & GEXF_VERT && gex->isd[Y]*ngex->isd[Y]>=0 ) {
5808 		tge = *nge;
5809 		tge.fx2 = nge->fx3; /* force vertical */
5810 		tge.fy2 = ge->fy3;
5811 		fnormalizege(&tge);
5812 		if( fcrossraysge(ge, &tge, NULL, NULL, NULL) )
5813 			gex->flags |= GEXF_JID|GEXF_JID2;
5814 	}
5815 
5816 try_flatboth:
5817 	/* look if we can change them to one line */
5818 	if(gex->flags & GEXF_FLAT && ngex->flags & GEXF_FLAT) {
5819 		for(i=0; i<2; i++) {
5820 			dots[0][i] = ge->prev->fpoints[i][2];
5821 			dots[1][i] = nge->fpoints[i][2];
5822 			dots[2][i] = ge->fpoints[i][2];
5823 		}
5824 		if( fdotsegdist2(dots, dots[2]) <= CVEPS2)
5825 			gex->flags |= GEXF_JLINE;
5826 	}
5827 }
5828 
5829 /*
5830  * Force conciseness of one contour in the glyph,
5831  * the contour is indicated by one entry from it.
5832  */
5833 
5834 static void
fconcisecontour(GLYPH * g,GENTRY * startge)5835 fconcisecontour(
5836 	GLYPH *g,
5837 	GENTRY *startge
5838 )
5839 {
5840 /* initial maximal number of dots to be used as reference */
5841 #define MAXDOTS	((NREFDOTS+1)*12)
5842 
5843 	GENTRY *ge, *pge, *nge, *ige;
5844 	GEX_CON *gex, *pgex, *ngex, *nngex;
5845 	GENTRY tpge, tnge;
5846 	int quad, qq, i, j, ndots, maxdots;
5847 	int found[2];
5848 	int joinmask, pflag, nflag;
5849 	struct dot_dist *dots;
5850 	double avsd2, maxd2, eps2;
5851 	double apcv[4][2];
5852 
5853 	if(startge == 0) {
5854 		fprintf(stderr, "WARNING: assertion in %s line %d, please report it to the ttf2pt1 project\n",
5855 			__FILE__, __LINE__);
5856 		fprintf(stderr, "Strange contour in glyph %s\n", g->name);
5857 		dumppaths(g, NULL, NULL);
5858 		return;
5859 	}
5860 
5861 	if(startge->type != GE_CURVE && startge->type != GE_LINE)
5862 		return; /* probably a degenerate contour */
5863 
5864 	if(ISDBG(FCONCISE))
5865 		fprintf(stderr, "processing contour 0x%p of glyph %s\n", startge, g->name);
5866 
5867 	maxdots = MAXDOTS;
5868 	dots = (struct dot_dist *)malloc(sizeof(*dots)*maxdots);
5869 	if(dots == NULL) {
5870 		fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
5871 		exit(255);
5872 	}
5873 
5874 	ge = startge;
5875 	joinmask = GEXF_JGOOD;
5876 	while(1) {
5877 	restart:
5878 		gex = X_CON(ge);
5879 		if((gex->flags & GEXF_JMASK) > ((joinmask<<1)-1)) {
5880 			if(ISDBG(FCONCISE))
5881 				fprintf(stderr, "found higher flag (%x>%x) at 0x%p\n",
5882 					gex->flags & GEXF_JMASK, ((joinmask<<1)-1), ge);
5883 			joinmask <<= 1;
5884 			startge = ge; /* have to redo the pass */
5885 			continue;
5886 		}
5887 		if(( gex->flags & joinmask )==0)
5888 			goto next;
5889 
5890 		/* if we happen to be in the middle of a string of
5891 		 * joinable entries, find its beginning
5892 		 */
5893 		if( gex->flags & (GEXF_JCVMASK^GEXF_JID) )
5894 			quad = gex->flags & X_CON_F(ge->frwd) & GEXF_QMASK;
5895 		else if( gex->flags & GEXF_JID2 )
5896 			quad = gex->flags & GEXF_QFROM_IDEAL(X_CON_F(ge->frwd)) & GEXF_QMASK;
5897 		else /* must be GEXF_JID1 */
5898 			quad = GEXF_QFROM_IDEAL(gex->flags) & X_CON_F(ge->frwd) & GEXF_QMASK;
5899 
5900 		pge = ge;
5901 		pgex = X_CON(pge->bkwd);
5902 
5903 		if(ISDBG(FCONCISE))
5904 			fprintf(stderr, "ge %p prev -> 0x%p ", ge, pge);
5905 
5906 		while(pgex->flags & GEXF_JCVMASK) {
5907 			if( !(pgex->flags & ((GEXF_JCVMASK^GEXF_JID)|GEXF_JID2)) )
5908 				qq = GEXF_QFROM_IDEAL(pgex->flags);
5909 			else
5910 				qq = pgex->flags & GEXF_QMASK;
5911 
5912 			if(ISDBG(FCONCISE))
5913 				fprintf(stderr, "(%x?%x)", quad, qq);
5914 
5915 			if( !(quad & qq) ) {
5916 				if( !(X_CON_F(pge) & (GEXF_JCVMASK^GEXF_JID))
5917 				&& pgex->flags & (GEXF_JCVMASK^GEXF_JID) ) {
5918 					/* the previos entry is definitely a better match */
5919 					if(pge == ge) {
5920 						if(ISDBG(FCONCISE))
5921 							fprintf(stderr, "\nprev is a better match at %p\n", pge);
5922 						startge = ge;
5923 						goto next;
5924 					} else
5925 						pge = pge->frwd;
5926 				}
5927 				break;
5928 			}
5929 
5930 			quad &= qq;
5931 			pge = pge->bkwd;
5932 			pgex = X_CON(pge->bkwd);
5933 			if(ISDBG(FCONCISE))
5934 				fprintf(stderr, "0x%p ", pge);
5935 		}
5936 
5937 		/* collect as many entries for joining as possible */
5938 		nge = ge->frwd;
5939 		ngex = X_CON(nge);
5940 		nngex = X_CON(nge->frwd);
5941 
5942 		if(ISDBG(FCONCISE))
5943 			fprintf(stderr, ": 0x%x\nnext -> 0x%p ", pge, nge);
5944 
5945 		while(ngex->flags & GEXF_JCVMASK) {
5946 			if( !(ngex->flags & ((GEXF_JCVMASK^GEXF_JID)|GEXF_JID1)) )
5947 				qq = GEXF_QFROM_IDEAL(nngex->flags);
5948 			else
5949 				qq = nngex->flags & GEXF_QMASK;
5950 
5951 			if(ISDBG(FCONCISE))
5952 				fprintf(stderr, "(%x?%x)", quad, qq);
5953 			if( !(quad & qq) ) {
5954 				if( !(X_CON_F(nge->bkwd) & (GEXF_JCVMASK^GEXF_JID))
5955 				&& ngex->flags & (GEXF_JCVMASK^GEXF_JID) ) {
5956 					/* the next-next entry is definitely a better match */
5957 					if(nge == ge->frwd) {
5958 						if(ISDBG(FCONCISE))
5959 							fprintf(stderr, "\nnext %x is a better match than %x at %p (jmask %x)\n",
5960 								ngex->flags & GEXF_JCVMASK, gex->flags & GEXF_JCVMASK, nge, joinmask);
5961 						goto next;
5962 					} else
5963 						nge = nge->bkwd;
5964 				}
5965 				break;
5966 			}
5967 
5968 			quad &= qq;
5969 			nge = nge->frwd;
5970 			ngex = nngex;
5971 			nngex = X_CON(nge->frwd);
5972 			if(ISDBG(FCONCISE))
5973 				fprintf(stderr, "0x%p ", nge);
5974 		}
5975 
5976 		if(ISDBG(FCONCISE))
5977 			fprintf(stderr, ": 0x%x\n", nge);
5978 
5979 		/* XXX add splitting of last entries if neccessary */
5980 
5981 		/* make sure that all the reference dots are valid */
5982 		for(ige = pge; ige != nge->frwd; ige = ige->frwd) {
5983 			nngex = X_CON(ige);
5984 			if( !(nngex->flags & GEXF_VDOTS) ) {
5985 				fsampledots(ige, nngex->dots, NREFDOTS);
5986 				nngex->flags |= GEXF_VDOTS;
5987 			}
5988 		}
5989 
5990 		/* do the actual joining */
5991 		while(1) {
5992 			pgex = X_CON(pge);
5993 			ngex = X_CON(nge->bkwd);
5994 			/* now the segments to be joined are pge...nge */
5995 
5996 			ndots = 0;
5997 			for(ige = pge; ige != nge->frwd; ige = ige->frwd) {
5998 				if(maxdots < ndots+(NREFDOTS+1)) {
5999 					maxdots += MAXDOTS;
6000 					dots = (struct dot_dist *)realloc((void *)dots, sizeof(*dots)*maxdots);
6001 					if(dots == NULL) {
6002 						fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
6003 						exit(255);
6004 					}
6005 				}
6006 				nngex = X_CON(ige);
6007 				for(i=0; i<NREFDOTS; i++) {
6008 					for(j=0; j<2; j++)
6009 						dots[ndots].p[j] = nngex->dots[i][j];
6010 					ndots++;
6011 				}
6012 				for(j=0; j<2; j++)
6013 					dots[ndots].p[j] = ige->fpoints[j][2];
6014 				ndots++;
6015 			}
6016 			ndots--; /* the last point is not interesting */
6017 
6018 			tpge = *pge;
6019 			pflag = pgex->flags;
6020 			if(pflag & (GEXF_JGOOD|GEXF_JFLAT2|GEXF_JID2)) {
6021 				/* nothing */
6022 			} else if(pflag & GEXF_JFLAT) {
6023 				tpge.fx1 = tpge.fx3;
6024 				tpge.fy1 = tpge.fy3;
6025 			} else if(pflag & GEXF_JID) {
6026 				if(pflag & GEXF_HOR)
6027 					tpge.fy1 = tpge.bkwd->fy3;
6028 				else
6029 					tpge.fx1 = tpge.bkwd->fx3;
6030 			}
6031 
6032 			tnge = *nge;
6033 			nflag = ngex->flags;
6034 			if(nflag & (GEXF_JGOOD|GEXF_JFLAT1|GEXF_JID)
6035 			&& !(nflag & GEXF_JID2)) {
6036 				/* nothing */
6037 			} else if(nflag & GEXF_JFLAT) {
6038 				tnge.fx2 = tnge.bkwd->fx3;
6039 				tnge.fy2 = tnge.bkwd->fy3;
6040 			} else if(nflag & GEXF_JID) {
6041 				if(X_CON_F(nge) & GEXF_HOR)
6042 					tnge.fy2 = tnge.fy3;
6043 				else
6044 					tnge.fx2 = tnge.fx3;
6045 			}
6046 
6047 			fnormalizege(&tpge);
6048 			fnormalizege(&tnge);
6049 			if( fcrossraysge(&tpge, &tnge, NULL, NULL, &apcv[1]) ) {
6050 				apcv[0][X] = tpge.bkwd->fx3;
6051 				apcv[0][Y] = tpge.bkwd->fy3;
6052 				/* apcv[1] and apcv[2] were filled by fcrossraysge() */
6053 				apcv[3][X] = tnge.fx3;
6054 				apcv[3][Y] = tnge.fy3;
6055 
6056 				/* calculate the precision depending on the smaller dimension of the curve */
6057 				maxd2 = apcv[3][X]-apcv[0][X];
6058 				maxd2 *= maxd2;
6059 				eps2 = apcv[3][Y]-apcv[0][Y];
6060 				eps2 *= eps2;
6061 				if(maxd2 < eps2)
6062 					eps2 = maxd2;
6063 				eps2 *= (CVEPS2*4.) / (400.*400.);
6064 				if(eps2 < CVEPS2)
6065 					eps2 = CVEPS2;
6066 				else if(eps2 > CVEPS2*4.)
6067 					eps2 = CVEPS2*4.;
6068 
6069 				fapproxcurve(apcv, dots, ndots);
6070 
6071 				avsd2 = fdotcurvdist2(apcv, dots, ndots, &maxd2);
6072 				if(ISDBG(FCONCISE))
6073 					fprintf(stderr, "avsd = %g, maxd = %g, ", sqrt(avsd2), sqrt(maxd2));
6074 				if(avsd2 <= eps2 && maxd2 <= eps2*2.) {
6075 					/* we've guessed a curve that is close enough */
6076 					ggoodcv++; ggoodcvdots += ndots;
6077 
6078 					if(ISDBG(FCONCISE)) {
6079 						fprintf(stderr, "in %s joined %p-%p to ", g->name, pge, nge);
6080 						for(i=0; i<4; i++) {
6081 							fprintf(stderr, " (%g, %g)", apcv[i][X], apcv[i][Y]);
6082 						}
6083 						fprintf(stderr, " from\n");
6084 						dumppaths(g, pge, nge);
6085 					}
6086 					for(i=0; i<3; i++) {
6087 						pge->fxn[i] = apcv[i+1][X];
6088 						pge->fyn[i] = apcv[i+1][Y];
6089 					}
6090 					pge->type = GE_CURVE;
6091 					ge = pge;
6092 					for(ige = pge->frwd; ; ige = pge->frwd) {
6093 						if(ige == pge) {
6094 							fprintf(stderr, "WARNING: assertion in %s line %d, please report it to the ttf2pt1 project\n",
6095 								__FILE__, __LINE__);
6096 							free(dots);
6097 							return;
6098 						}
6099 						if(startge == ige)
6100 							startge = pge;
6101 						free(ige->ext);
6102 						freethisge(ige);
6103 						if(ige == nge)
6104 							break;
6105 					}
6106 					fnormalizege(ge);
6107 					if(ISDBG(FCONCISE)) {
6108 						fprintf(stderr, "normalized ");
6109 						for(i=0; i<3; i++) {
6110 							fprintf(stderr, " (%g, %g)", ge->fpoints[X][i], ge->fpoints[Y][i]);
6111 						}
6112 						fprintf(stderr, "\n");
6113 					}
6114 					fanalyzege(ge);
6115 					fanalyzejoint(ge);
6116 					fanalyzege(ge->bkwd);
6117 					fanalyzejoint(ge->bkwd);
6118 
6119 					/* the results of this join will have to be reconsidered */
6120 					startge = ge = ge->frwd;
6121 					goto restart;
6122 				} else {
6123 					gbadcv++; gbadcvdots += ndots;
6124 				}
6125 			}
6126 
6127 			/* if we're down to 2 entries then the join has failed */
6128 			if(pge->frwd == nge) {
6129 				pgex->flags &= ~joinmask;
6130 				if(ISDBG(FCONCISE))
6131 					fprintf(stderr, "no match\n");
6132 				goto next;
6133 			}
6134 
6135 			/* reduce the number of entries by dropping one at some end,
6136 			 * should never drop the original ge from the range
6137 			 */
6138 
6139 			if(nge->bkwd == ge
6140 			|| pge != ge && (pgex->flags & GEXF_JCVMASK) <= (ngex->flags & GEXF_JCVMASK) ) {
6141 				pge = pge->frwd;
6142 			} else {
6143 				nge = nge->bkwd;
6144 			}
6145 			if(ISDBG(FCONCISE))
6146 				fprintf(stderr, "next try: %p to %p\n", pge, nge);
6147 		}
6148 
6149 next:
6150 		ge = ge->frwd;
6151 		if(ge == startge) {
6152 			joinmask = (joinmask >> 1) & GEXF_JCVMASK;
6153 			if(joinmask == 0)
6154 				break;
6155 		}
6156 	}
6157 
6158 	/* join flat segments into lines */
6159 	/* here ge==startge */
6160 	while(1) {
6161 		gex = X_CON(ge);
6162 		if( !(gex->flags & GEXF_JLINE) )
6163 			goto next2;
6164 
6165 		ndots = 0;
6166 		dots[ndots].p[X] = ge->fx3;
6167 		dots[ndots].p[Y] = ge->fy3;
6168 		ndots++;
6169 
6170 		pge = ge->bkwd;
6171 		nge = ge->frwd;
6172 
6173 		if(ISDBG(FCONCISE))
6174 			fprintf(stderr, "joining LINE from %p-%p\n", ge, nge);
6175 
6176 		while(pge!=nge) {
6177 			pgex = X_CON(pge);
6178 			ngex = X_CON(nge);
6179 			if(ISDBG(FCONCISE))
6180 				fprintf(stderr, "(p=%p/%x n=0x%x/%x) ", pge, pgex->flags & GEXF_JLINE,
6181 					nge, ngex->flags & GEXF_JLINE);
6182 			if( !((pgex->flags | ngex->flags) & GEXF_JLINE) ) {
6183 				if(ISDBG(FCONCISE))
6184 					fprintf(stderr, "(end p=%p n=%p) ", pge, nge);
6185 				break;
6186 			}
6187 
6188 			if(maxdots < ndots+2) {
6189 				maxdots += MAXDOTS;
6190 				dots = (struct dot_dist *)realloc((void *)dots, sizeof(*dots)*maxdots);
6191 				if(dots == NULL) {
6192 					fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
6193 					exit(255);
6194 				}
6195 			}
6196 			if( pgex->flags & GEXF_JLINE ) {
6197 				for(i=0; i<2; i++) {
6198 					apcv[0][i] = pge->bkwd->fpoints[i][2];
6199 					apcv[1][i] = nge->fpoints[i][2];
6200 					dots[ndots].p[i] = pge->fpoints[i][2];
6201 				}
6202 				ndots++;
6203 				for(i=0; i<ndots; i++) {
6204 					avsd2 = fdotsegdist2(apcv, dots[i].p);
6205 					if(avsd2 > CVEPS2)
6206 						break;
6207 				}
6208 				if(i<ndots) { /* failed to join */
6209 					if(ISDBG(FCONCISE))
6210 						fprintf(stderr, "failed to join prev %p ", pge);
6211 					ndots--;
6212 					pgex->flags &= ~GEXF_JLINE;
6213 				} else {
6214 					pge = pge->bkwd;
6215 					if(pge == nge) {
6216 						if(ISDBG(FCONCISE))
6217 							fprintf(stderr, "intersected at prev %p ", pge);
6218 						break; /* oops, tried to self-intersect */
6219 					}
6220 				}
6221 			} else if(ISDBG(FCONCISE))
6222 				fprintf(stderr, "(p=%p) ", pge);
6223 
6224 			if( ngex->flags & GEXF_JLINE ) {
6225 				for(i=0; i<2; i++) {
6226 					apcv[0][i] = pge->fpoints[i][2]; /* pge points before the 1st segment */
6227 					apcv[1][i] = nge->frwd->fpoints[i][2];
6228 					dots[ndots].p[i] = nge->fpoints[i][2];
6229 				}
6230 				ndots++;
6231 				for(i=0; i<ndots; i++) {
6232 					avsd2 = fdotsegdist2(apcv, dots[i].p);
6233 					if(avsd2 > CVEPS2)
6234 						break;
6235 				}
6236 				if(i<ndots) { /* failed to join */
6237 					if(ISDBG(FCONCISE))
6238 						fprintf(stderr, "failed to join next %p ", nge->frwd);
6239 					ndots--;
6240 					ngex->flags &= ~GEXF_JLINE;
6241 				} else {
6242 					nge = nge->frwd;
6243 				}
6244 			} else if(ISDBG(FCONCISE))
6245 				fprintf(stderr, "(n=%p) ", nge);
6246 		}
6247 
6248 		pge = pge->frwd;  /* now the limits are pge...nge inclusive */
6249 		if(pge == nge) /* a deeply perversive contour */
6250 			break;
6251 
6252 		if(ISDBG(FCONCISE)) {
6253 			fprintf(stderr, "\nin %s joined LINE %p-%p from\n", g->name, pge, nge);
6254 			dumppaths(g, pge, nge);
6255 		}
6256 		pge->type = GE_LINE;
6257 		for(i=0; i<2; i++) {
6258 			pge->fpoints[i][2] = nge->fpoints[i][2];
6259 		}
6260 		fnormalizege(pge);
6261 		X_CON_F(pge) &= ~GEXF_JLINE;
6262 
6263 		ge = pge;
6264 		for(ige = pge->frwd; ; ige = pge->frwd) {
6265 			if(ige == pge) {
6266 				fprintf(stderr, "WARNING: assertion in %s line %d, please report it to the ttf2pt1 project\n",
6267 					__FILE__, __LINE__);
6268 				free(dots);
6269 				return;
6270 			}
6271 			if(startge == ige)
6272 				startge = pge;
6273 			free(ige->ext);
6274 			freethisge(ige);
6275 			if(ige == nge)
6276 				break;
6277 		}
6278 next2:
6279 		ge = ge->frwd;
6280 		if(ge == startge)
6281 			break;
6282 	}
6283 
6284 	free(dots);
6285 }
6286 
6287 /* force conciseness: substitute 2 or more curves going in the
6288 ** same quadrant with one curve
6289 ** in floating point
6290 */
6291 
6292 void
fforceconcise(GLYPH * g)6293 fforceconcise(
6294 	     GLYPH * g
6295 )
6296 {
6297 
6298 	GENTRY         *ge, *nge, *endge, *xge;
6299 
6300 	assertisfloat(g, "enforcing conciseness");
6301 
6302 	fdelsmall(g, 0.05);
6303 	assertpath(g->entries, __FILE__, __LINE__, g->name);
6304 
6305 	if(ISDBG(FCONCISE))
6306 		dumppaths(g, NULL, NULL);
6307 
6308 	/* collect more information about each gentry and their joints */
6309 	for (ge = g->entries; ge != 0; ge = ge->next)
6310 		if (ge->type == GE_CURVE || ge->type == GE_LINE)
6311 			fnormalizege(ge);
6312 
6313 	for (ge = g->entries; ge != 0; ge = ge->next)
6314 		if (ge->type == GE_CURVE || ge->type == GE_LINE) {
6315 			alloc_gex_con(ge);
6316 			fanalyzege(ge);
6317 		}
6318 
6319 	/* see what we can do about joining */
6320 	for (ge = g->entries; ge != 0; ge = ge->next)
6321 		if (ge->type == GE_CURVE || ge->type == GE_LINE)
6322 			fanalyzejoint(ge);
6323 
6324 	/* now do the joining */
6325 	for (ge = g->entries; ge != 0; ge = ge->next)
6326 		if(ge->type == GE_MOVE)
6327 			fconcisecontour(g, ge->next);
6328 
6329 	for (ge = g->entries; ge != 0; ge = ge->next)
6330 		if (ge->type == GE_CURVE || ge->type == GE_LINE)
6331 			free(ge->ext);
6332 }
6333 
6334 void
print_glyph(int glyphno)6335 print_glyph(
6336 	   int glyphno
6337 )
6338 {
6339 	GLYPH          *g;
6340 	GENTRY         *ge;
6341 	int             x = 0, y = 0;
6342 	int             i;
6343 	int             grp, lastgrp= -1;
6344 
6345 	if(ISDBG(FCONCISE) && glyphno == 0) {
6346 		fprintf(stderr, "Guessed curves: bad %d/%d good %d/%d\n",
6347 			gbadcv, gbadcvdots, ggoodcv, ggoodcvdots);
6348 	}
6349 
6350 	g = &glyph_list[glyphno];
6351 
6352 	fprintf(pfa_file, "/%s { \n", g->name);
6353 
6354 	/* consider widths >MAXLEGALWIDTH as bugs */
6355 	if( g->scaledwidth <= MAXLEGALWIDTH ) {
6356 		fprintf(pfa_file, "0 %d hsbw\n", g->scaledwidth);
6357 	} else {
6358 		fprintf(pfa_file, "0 1000 hsbw\n");
6359 		WARNING_2 fprintf(stderr, "glyph %s: width %d seems to be buggy, set to 1000\n",
6360 			g->name, g->scaledwidth);
6361 	}
6362 
6363 #if 0
6364 	fprintf(pfa_file, "%% contours: ");
6365 	for (i = 0; i < g->ncontours; i++)
6366 		fprintf(pfa_file, "%s(%d,%d) ", (g->contours[i].direction == DIR_OUTER ? "out" : "in"),
6367 			g->contours[i].xofmin, g->contours[i].ymin);
6368 	fprintf(pfa_file, "\n");
6369 
6370 	if (g->rymin < 5000)
6371 		fprintf(pfa_file, "%d lower%s\n", g->rymin, (g->flatymin ? "flat" : "curve"));
6372 	if (g->rymax > -5000)
6373 		fprintf(pfa_file, "%d upper%s\n", g->rymax, (g->flatymax ? "flat" : "curve"));
6374 #endif
6375 
6376 	if (g->hstems)
6377 		for (i = 0; i < g->nhs; i += 2) {
6378 			if (g->hstems[i].flags & ST_3) {
6379 				fprintf(pfa_file, "%d %d %d %d %d %d hstem3\n",
6380 					g->hstems[i].value,
6381 				g->hstems[i + 1].value - g->hstems[i].value,
6382 					g->hstems[i + 2].value,
6383 					g->hstems[i + 3].value - g->hstems[i + 2].value,
6384 					g->hstems[i + 4].value,
6385 					g->hstems[i + 5].value - g->hstems[i + 4].value
6386 					);
6387 				i += 4;
6388 			} else {
6389 				fprintf(pfa_file, "%d %d hstem\n", g->hstems[i].value,
6390 				g->hstems[i + 1].value - g->hstems[i].value);
6391 			}
6392 		}
6393 
6394 	if (g->vstems)
6395 		for (i = 0; i < g->nvs; i += 2) {
6396 			if (g->vstems[i].flags & ST_3) {
6397 				fprintf(pfa_file, "%d %d %d %d %d %d vstem3\n",
6398 					g->vstems[i].value,
6399 				g->vstems[i + 1].value - g->vstems[i].value,
6400 					g->vstems[i + 2].value,
6401 					g->vstems[i + 3].value - g->vstems[i + 2].value,
6402 					g->vstems[i + 4].value,
6403 					g->vstems[i + 5].value - g->vstems[i + 4].value
6404 					);
6405 				i += 4;
6406 			} else {
6407 				fprintf(pfa_file, "%d %d vstem\n", g->vstems[i].value,
6408 				g->vstems[i + 1].value - g->vstems[i].value);
6409 			}
6410 		}
6411 
6412 	for (ge = g->entries; ge != 0; ge = ge->next) {
6413 		if(g->nsg>0) {
6414 			grp=ge->stemid;
6415 			if(grp >= 0 && grp != lastgrp)  {
6416 				fprintf(pfa_file, "%d 4 callsubr\n", grp+g->firstsubr);
6417 				lastgrp=grp;
6418 			}
6419 		}
6420 
6421 		switch (ge->type) {
6422 		case GE_MOVE:
6423 			if (absolute)
6424 				fprintf(pfa_file, "%d %d amoveto\n", ge->ix3, ge->iy3);
6425 			else
6426 				rmoveto(ge->ix3 - x, ge->iy3 - y);
6427 			if (0)
6428 				fprintf(stderr, "Glyph %s: print moveto(%d, %d)\n",
6429 					g->name, ge->ix3, ge->iy3);
6430 			x = ge->ix3;
6431 			y = ge->iy3;
6432 			break;
6433 		case GE_LINE:
6434 			if (absolute)
6435 				fprintf(pfa_file, "%d %d alineto\n", ge->ix3, ge->iy3);
6436 			else
6437 				rlineto(ge->ix3 - x, ge->iy3 - y);
6438 			x = ge->ix3;
6439 			y = ge->iy3;
6440 			break;
6441 		case GE_CURVE:
6442 			if (absolute)
6443 				fprintf(pfa_file, "%d %d %d %d %d %d arcurveto\n",
6444 					ge->ix1, ge->iy1, ge->ix2, ge->iy2, ge->ix3, ge->iy3);
6445 			else
6446 				rrcurveto(ge->ix1 - x, ge->iy1 - y,
6447 					  ge->ix2 - ge->ix1, ge->iy2 - ge->iy1,
6448 					  ge->ix3 - ge->ix2, ge->iy3 - ge->iy2);
6449 			x = ge->ix3;
6450 			y = ge->iy3;
6451 			break;
6452 		case GE_PATH:
6453 			closepath();
6454 			break;
6455 		default:
6456 			WARNING_1 fprintf(stderr, "**** Glyph %s: unknown entry type '%c'\n",
6457 				g->name, ge->type);
6458 			break;
6459 		}
6460 	}
6461 
6462 	fprintf(pfa_file, "endchar } ND\n");
6463 }
6464 
6465 /* print the subroutines for this glyph, returns the number of them */
6466 int
print_glyph_subs(int glyphno,int startid)6467 print_glyph_subs(
6468 	   int glyphno,
6469 	   int startid /* start numbering subroutines from this id */
6470 )
6471 {
6472 	GLYPH *g;
6473 	int i, grp;
6474 
6475 	g = &glyph_list[glyphno];
6476 
6477 	if(!hints || !subhints || g->nsg<1)
6478 		return 0;
6479 
6480 	g->firstsubr=startid;
6481 
6482 #if 0
6483 	fprintf(pfa_file, "%% %s %d\n", g->name, g->nsg);
6484 #endif
6485 	for(grp=0; grp<g->nsg; grp++) {
6486 		fprintf(pfa_file, "dup %d {\n", startid++);
6487 		for(i= (grp==0)? 0 : g->nsbs[grp-1]; i<g->nsbs[grp]; i++)
6488 			fprintf(pfa_file, "\t%d %d %cstem\n", g->sbstems[i].low,
6489 				g->sbstems[i].high-g->sbstems[i].low,
6490 				g->sbstems[i].isvert ? 'v' : 'h');
6491 		fprintf(pfa_file, "\treturn\n\t} NP\n");
6492 	}
6493 
6494 	return g->nsg;
6495 }
6496 
6497 void
print_glyph_metrics(int code,int glyphno)6498 print_glyph_metrics(
6499 	   int code,
6500 	   int glyphno
6501 )
6502 {
6503 	GLYPH *g;
6504 
6505 	g = &glyph_list[glyphno];
6506 
6507 	if(transform)
6508 	  fprintf(afm_file, "C %d ; WX %d ; N %s ; B %d %d %d %d ;\n",
6509 		  code, g->scaledwidth, g->name,
6510 		  iscale(g->xMin), iscale(g->yMin), iscale(g->xMax), iscale(g->yMax));
6511 	else
6512 	  fprintf(afm_file, "C %d ; WX %d ; N %s ; B %d %d %d %d ;\n",
6513 		  code, g->scaledwidth, g->name,
6514 		  g->xMin, g->yMin, g->xMax, g->yMax);
6515 }
6516 
6517 /*
6518  SB:
6519  An important note about the BlueValues.
6520 
6521  The Adobe documentation says that the maximal width of a Blue zone
6522  is connected to the value of BlueScale, which is by default 0.039625.
6523  The BlueScale value defines, at which point size the overshoot
6524  suppression be disabled.
6525 
6526  The formula for it that is given in the manual is:
6527 
6528   BlueScale=point_size/240, for a 300dpi device
6529 
6530  that makes us wonder what is this 240 standing for. Incidentally
6531  240=72*1000/300, where 72 is the relation between inches and points,
6532  1000 is the size of the glyph matrix, and 300dpi is the resolution of
6533  the output device. Knowing that we can recalculate the formula for
6534  the font size in pixels rather than points:
6535 
6536   BlueScale=pixel_size/1000
6537 
6538  That looks a lot simpler than the original formula, does not it ?
6539  And the limitation about the maximal width of zone also looks
6540  a lot simpler after the transformation:
6541 
6542   max_width < 1000/pixel_size
6543 
6544  that ensures that even at the maximal pixel size when the overshoot
6545  suppression is disabled the zone width will be less than one pixel.
6546  This is important, failure to comply to this limit will result in
6547  really ugly fonts (been there, done that). But knowing the formula
6548  for the pixel width, we see that in fact we can use the maximal width
6549  of 24, not 23 as specified in the manual.
6550 
6551 */
6552 
6553 #define MAXBLUEWIDTH (24)
6554 
6555 /*
6556  * Find the indexes of the most frequent values
6557  * in the hystogram, sort them in ascending order, and save which one
6558  * was the best one (if asked).
6559  * Returns the number of values found (may be less than maximal because
6560  * we ignore the zero values)
6561  */
6562 
6563 #define MAXHYST	(2000)		/* size of the hystogram */
6564 #define HYSTBASE 500
6565 
6566 static int
besthyst(int * hyst,int base,int * best,int nbest,int width,int * bestindp)6567 besthyst(
6568 	 int *hyst,		/* the hystogram */
6569 	 int base,		/* the base point of the hystogram */
6570 	 int *best,		/* the array for indexes of best values */
6571 	 int nbest,		/* its allocated size */
6572 	 int width,		/* minimal difference between indexes */
6573 	 int *bestindp		/* returned top point */
6574 )
6575 {
6576 	unsigned char   hused[MAXHYST / 8 + 1];
6577 	int             i, max, j, w, last = 0;
6578 	int             nf = 0;
6579 
6580 	width--;
6581 
6582 	memset(hused, 0 , sizeof hused);
6583 
6584 	max = 1;
6585 	for (i = 0; i < nbest && max != 0; i++) {
6586 		best[i] = 0;
6587 		max = 0;
6588 		for (j = 1; j < MAXHYST - 1; j++) {
6589 			w = hyst[j];
6590 
6591 			if (w > max && (hused[j>>3] & (1 << (j & 0x07))) == 0) {
6592 				best[i] = j;
6593 				max = w;
6594 			}
6595 		}
6596 		if (max != 0) {
6597 			if (max < last/2) {
6598 				/* do not pick the too low values */
6599 				break;
6600 			}
6601 			for (j = best[i] - width; j <= best[i] + width; j++) {
6602 				if (j >= 0 && j < MAXHYST)
6603 					hused[j >> 3] |= (1 << (j & 0x07));
6604 			}
6605 			last = max;
6606 			best[i] -= base;
6607 			nf = i + 1;
6608 		}
6609 	}
6610 
6611 	if (bestindp)
6612 		*bestindp = best[0];
6613 
6614 	/* sort the indexes in ascending order */
6615 	for (i = 0; i < nf; i++) {
6616 		for (j = i + 1; j < nf; j++)
6617 			if (best[j] < best[i]) {
6618 				w = best[i];
6619 				best[i] = best[j];
6620 				best[j] = w;
6621 			}
6622 	}
6623 
6624 	return nf;
6625 }
6626 
6627 /*
6628  * Find the next best Blue zone in the hystogram.
6629  * Return the weight of the found zone.
6630  */
6631 
6632 static int
bestblue(short * zhyst,short * physt,short * ozhyst,int * bluetab)6633 bestblue(
6634 	 short *zhyst,		/* the zones hystogram */
6635 	 short *physt,		/* the points hystogram */
6636 	 short *ozhyst,		/* the other zones hystogram */
6637 	 int *bluetab		/* where to put the found zone */
6638 )
6639 {
6640 	int             i, j, w, max, ind, first, last;
6641 
6642 	/* find the highest point in the zones hystogram */
6643 	/* if we have a plateau, take its center */
6644 	/* if we have multiple peaks, take the first one */
6645 
6646 	max = -1;
6647 	first = last = -10;
6648 	for (i = 0; i <= MAXHYST - MAXBLUEWIDTH; i++) {
6649 		w = zhyst[i];
6650 		if (w > max) {
6651 			first = last = i;
6652 			max = w;
6653 		} else if (w == max) {
6654 			if (last == i - 1)
6655 				last = i;
6656 		}
6657 	}
6658 	ind = (first + last) / 2;
6659 
6660 	if (max == 0)		/* no zones left */
6661 		return 0;
6662 
6663 	/* now we reuse `first' and `last' as inclusive borders of the zone */
6664 	first = ind;
6665 	last = ind + (MAXBLUEWIDTH - 1);
6666 
6667 	/* our maximal width is far too big, so we try to make it narrower */
6668 	w = max;
6669 	j = (w & 1);		/* a pseudo-random bit */
6670 	while (1) {
6671 		while (physt[first] == 0)
6672 			first++;
6673 		while (physt[last] == 0)
6674 			last--;
6675 		if (last - first < (MAXBLUEWIDTH * 2 / 3) || (max - w) * 10 > max)
6676 			break;
6677 
6678 		if (physt[first] < physt[last]
6679 		    || physt[first] == physt[last] && j) {
6680 			if (physt[first] * 20 > w)	/* if weight is >5%,
6681 							 * stop */
6682 				break;
6683 			w -= physt[first];
6684 			first++;
6685 			j = 0;
6686 		} else {
6687 			if (physt[last] * 20 > w)	/* if weight is >5%,
6688 							 * stop */
6689 				break;
6690 			w -= physt[last];
6691 			last--;
6692 			j = 1;
6693 		}
6694 	}
6695 
6696 	/* save our zone */
6697 	bluetab[0] = first - HYSTBASE;
6698 	bluetab[1] = last - HYSTBASE;
6699 
6700 	/* invalidate all the zones overlapping with this one */
6701 	/* the constant of 2 is determined by the default value of BlueFuzz */
6702 	for (i = first - (MAXBLUEWIDTH - 1) - 2; i <= last + 2; i++)
6703 		if (i >= 0 && i < MAXHYST) {
6704 			zhyst[i] = 0;
6705 			ozhyst[i] = 0;
6706 		}
6707 	return w;
6708 }
6709 
6710 /*
6711  * Try to find the Blue Values, bounding box and italic angle
6712  */
6713 
6714 void
findblues(void)6715 findblues(void)
6716 {
6717 	/* hystograms for upper and lower zones */
6718 	short           hystl[MAXHYST];
6719 	short           hystu[MAXHYST];
6720 	short           zuhyst[MAXHYST];
6721 	short           zlhyst[MAXHYST];
6722 	int             nchars;
6723 	int             i, j, k, w, max;
6724 	GENTRY         *ge;
6725 	GLYPH          *g;
6726 	double          ang;
6727 
6728 	/* find the lowest and highest points of glyphs */
6729 	/* and by the way build the values for FontBBox */
6730 	/* and build the hystogram for the ItalicAngle */
6731 
6732 	/* re-use hystl for the hystogram of italic angle */
6733 
6734 	bbox[0] = bbox[1] = 5000;
6735 	bbox[2] = bbox[3] = -5000;
6736 
6737 	for (i = 0; i < MAXHYST; i++)
6738 		hystl[i] = 0;
6739 
6740 	nchars = 0;
6741 
6742 	for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6743 		if (g->flags & GF_USED) {
6744 			nchars++;
6745 
6746 			g->rymin = 5000;
6747 			g->rymax = -5000;
6748 			for (ge = g->entries; ge != 0; ge = ge->next) {
6749 				if (ge->type == GE_LINE) {
6750 
6751 					j = ge->iy3 - ge->prev->iy3;
6752 					k = ge->ix3 - ge->prev->ix3;
6753 					if (j > 0)
6754 						ang = atan2(-k, j) * 180.0 / M_PI;
6755 					else
6756 						ang = atan2(k, -j) * 180.0 / M_PI;
6757 
6758 					k /= 100;
6759 					j /= 100;
6760 					if (ang > -45.0 && ang < 45.0) {
6761 						/*
6762 						 * be careful to not overflow
6763 						 * the counter
6764 						 */
6765 						hystl[HYSTBASE + (int) (ang * 10.0)] += (k * k + j * j) / 4;
6766 					}
6767 					if (ge->iy3 == ge->prev->iy3) {
6768 						if (ge->iy3 <= g->rymin) {
6769 							g->rymin = ge->iy3;
6770 							g->flatymin = 1;
6771 						}
6772 						if (ge->iy3 >= g->rymax) {
6773 							g->rymax = ge->iy3;
6774 							g->flatymax = 1;
6775 						}
6776 					} else {
6777 						if (ge->iy3 < g->rymin) {
6778 							g->rymin = ge->iy3;
6779 							g->flatymin = 0;
6780 						}
6781 						if (ge->iy3 > g->rymax) {
6782 							g->rymax = ge->iy3;
6783 							g->flatymax = 0;
6784 						}
6785 					}
6786 				} else if (ge->type == GE_CURVE) {
6787 					if (ge->iy3 < g->rymin) {
6788 						g->rymin = ge->iy3;
6789 						g->flatymin = 0;
6790 					}
6791 					if (ge->iy3 > g->rymax) {
6792 						g->rymax = ge->iy3;
6793 						g->flatymax = 0;
6794 					}
6795 				}
6796 				if (ge->type == GE_LINE || ge->type == GE_CURVE) {
6797 					if (ge->ix3 < bbox[0])
6798 						bbox[0] = ge->ix3;
6799 					if (ge->ix3 > bbox[2])
6800 						bbox[2] = ge->ix3;
6801 					if (ge->iy3 < bbox[1])
6802 						bbox[1] = ge->iy3;
6803 					if (ge->iy3 > bbox[3])
6804 						bbox[3] = ge->iy3;
6805 				}
6806 			}
6807 		}
6808 	}
6809 
6810 	/* get the most popular angle */
6811 	max = 0;
6812 	w = 0;
6813 	for (i = 0; i < MAXHYST; i++) {
6814 		if (hystl[i] > w) {
6815 			w = hystl[i];
6816 			max = i;
6817 		}
6818 	}
6819 	ang = (double) (max - HYSTBASE) / 10.0;
6820 	WARNING_2 fprintf(stderr, "Guessed italic angle: %f\n", ang);
6821 	if (italic_angle == 0.0)
6822 		italic_angle = ang;
6823 
6824 	/* build the hystogram of the lower points */
6825 	for (i = 0; i < MAXHYST; i++)
6826 		hystl[i] = 0;
6827 
6828 	for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6829 		if ((g->flags & GF_USED)
6830 		    && g->rymin + HYSTBASE >= 0 && g->rymin < MAXHYST - HYSTBASE) {
6831 			hystl[g->rymin + HYSTBASE]++;
6832 		}
6833 	}
6834 
6835 	/* build the hystogram of the upper points */
6836 	for (i = 0; i < MAXHYST; i++)
6837 		hystu[i] = 0;
6838 
6839 	for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6840 		if ((g->flags & GF_USED)
6841 		    && g->rymax + HYSTBASE >= 0 && g->rymax < MAXHYST - HYSTBASE) {
6842 			hystu[g->rymax + HYSTBASE]++;
6843 		}
6844 	}
6845 
6846 	/* build the hystogram of all the possible lower zones with max width */
6847 	for (i = 0; i < MAXHYST; i++)
6848 		zlhyst[i] = 0;
6849 
6850 	for (i = 0; i <= MAXHYST - MAXBLUEWIDTH; i++) {
6851 		for (j = 0; j < MAXBLUEWIDTH; j++)
6852 			zlhyst[i] += hystl[i + j];
6853 	}
6854 
6855 	/* build the hystogram of all the possible upper zones with max width */
6856 	for (i = 0; i < MAXHYST; i++)
6857 		zuhyst[i] = 0;
6858 
6859 	for (i = 0; i <= MAXHYST - MAXBLUEWIDTH; i++) {
6860 		for (j = 0; j < MAXBLUEWIDTH; j++)
6861 			zuhyst[i] += hystu[i + j];
6862 	}
6863 
6864 	/* find the baseline */
6865 	w = bestblue(zlhyst, hystl, zuhyst, &bluevalues[0]);
6866 	if (0)
6867 		fprintf(stderr, "BaselineBlue zone %d%% %d...%d\n", w * 100 / nchars,
6868 				bluevalues[0], bluevalues[1]);
6869 
6870 	if (w == 0)		/* no baseline, something weird */
6871 		return;
6872 
6873 	/* find the upper zones */
6874 	for (nblues = 2; nblues < 14; nblues += 2) {
6875 		w = bestblue(zuhyst, hystu, zlhyst, &bluevalues[nblues]);
6876 
6877 		if (0)
6878 			fprintf(stderr, "Blue zone %d%% %d...%d\n", w * 100 / nchars,
6879 				bluevalues[nblues], bluevalues[nblues+1]);
6880 
6881 		if (w * 20 < nchars)
6882 			break;	/* don't save this zone */
6883 	}
6884 
6885 	/* find the lower zones */
6886 	for (notherb = 0; notherb < 10; notherb += 2) {
6887 		w = bestblue(zlhyst, hystl, zuhyst, &otherblues[notherb]);
6888 
6889 		if (0)
6890 			fprintf(stderr, "OtherBlue zone %d%% %d...%d\n", w * 100 / nchars,
6891 				otherblues[notherb], otherblues[notherb+1]);
6892 
6893 
6894 		if (w * 20 < nchars)
6895 			break;	/* don't save this zone */
6896 	}
6897 
6898 }
6899 
6900 /*
6901  * Find the actual width of the glyph and modify the
6902  * description to reflect it. Not guaranteed to do
6903  * any good, may make character spacing too wide.
6904  */
6905 
6906 void
docorrectwidth(void)6907 docorrectwidth(void)
6908 {
6909 	int             i;
6910 	GENTRY         *ge;
6911 	GLYPH          *g;
6912 	int             xmin, xmax;
6913 	int             maxwidth, minsp;
6914 
6915 	/* enforce this minimal spacing,
6916 	 * we limit the amount of the enforced spacing to avoid
6917 	 * spacing the bold wonts too widely
6918 	 */
6919 	minsp = (stdhw>60 || stdhw<10)? 60 : stdhw;
6920 
6921 	for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6922 		g->oldwidth=g->scaledwidth; /* save the old width, will need for AFM */
6923 
6924 		if (correctwidth && g->flags & GF_USED) {
6925 			xmin = 5000;
6926 			xmax = -5000;
6927 			for (ge = g->entries; ge != 0; ge = ge->next) {
6928 				if (ge->type != GE_LINE && ge->type != GE_CURVE)
6929 					continue;
6930 
6931 				if (ge->ix3 <= xmin) {
6932 					xmin = ge->ix3;
6933 				}
6934 				if (ge->ix3 >= xmax) {
6935 					xmax = ge->ix3;
6936 				}
6937 			}
6938 
6939 			maxwidth=xmax+minsp;
6940 			if( g->scaledwidth < maxwidth ) {
6941 				g->scaledwidth = maxwidth;
6942 				WARNING_3 fprintf(stderr, "glyph %s: extended from %d to %d\n",
6943 					g->name, g->oldwidth, g->scaledwidth );
6944 			}
6945 		}
6946 	}
6947 
6948 }
6949 
6950 /*
6951  * Try to find the typical stem widths
6952  */
6953 
6954 void
stemstatistics(void)6955 stemstatistics(void)
6956 {
6957 #define MINDIST	10 /* minimal distance between the widths */
6958 	int             hyst[MAXHYST+MINDIST*2];
6959 	int             best[12];
6960 	int             i, j, k, w;
6961 	int             nchars;
6962 	int             ns;
6963 	STEM           *s;
6964 	GLYPH          *g;
6965 
6966 	/* start with typical stem width */
6967 
6968 	nchars=0;
6969 
6970 	/* build the hystogram of horizontal stem widths */
6971 	memset(hyst, 0, sizeof hyst);
6972 
6973 	for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6974 		if (g->flags & GF_USED) {
6975 			nchars++;
6976 			s = g->hstems;
6977 			for (j = 0; j < g->nhs; j += 2) {
6978 				if ((s[j].flags | s[j + 1].flags) & ST_END)
6979 					continue;
6980 				w = s[j + 1].value - s[j].value+1;
6981 				if(w==20) /* split stems should not be counted */
6982 					continue;
6983 				if (w > 0 && w < MAXHYST - 1) {
6984 					/*
6985 					 * handle some fuzz present in
6986 					 * converted fonts
6987 					 */
6988 					hyst[w+MINDIST] += MINDIST-1;
6989 					for(k=1; k<MINDIST-1; k++) {
6990 						hyst[w+MINDIST + k] += MINDIST-1-k;
6991 						hyst[w+MINDIST - k] += MINDIST-1-k;
6992 					}
6993 				}
6994 			}
6995 		}
6996 	}
6997 
6998 	/* find 12 most frequent values */
6999 	ns = besthyst(hyst+MINDIST, 0, best, 12, MINDIST, &stdhw);
7000 
7001 	/* store data in stemsnaph */
7002 	for (i = 0; i < ns; i++)
7003 		stemsnaph[i] = best[i];
7004 	if (ns < 12)
7005 		stemsnaph[ns] = 0;
7006 
7007 	/* build the hystogram of vertical stem widths */
7008 	memset(hyst, 0, sizeof hyst);
7009 
7010 	for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
7011 		if (g->flags & GF_USED) {
7012 			s = g->vstems;
7013 			for (j = 0; j < g->nvs; j += 2) {
7014 				if ((s[j].flags | s[j + 1].flags) & ST_END)
7015 					continue;
7016 				w = s[j + 1].value - s[j].value+1;
7017 				if (w > 0 && w < MAXHYST - 1) {
7018 					/*
7019 					 * handle some fuzz present in
7020 					 * converted fonts
7021 					 */
7022 					hyst[w+MINDIST] += MINDIST-1;
7023 					for(k=1; k<MINDIST-1; k++) {
7024 						hyst[w+MINDIST + k] += MINDIST-1-k;
7025 						hyst[w+MINDIST - k] += MINDIST-1-k;
7026 					}
7027 				}
7028 			}
7029 		}
7030 	}
7031 
7032 	/* find 12 most frequent values */
7033 	ns = besthyst(hyst+MINDIST, 0, best, 12, MINDIST, &stdvw);
7034 
7035 	/* store data in stemsnaph */
7036 	for (i = 0; i < ns; i++)
7037 		stemsnapv[i] = best[i];
7038 	if (ns < 12)
7039 		stemsnapv[ns] = 0;
7040 
7041 #undef MINDIST
7042 }
7043 
7044 /*
7045  * SB
7046  * A funny thing: TTF paths are going in reverse direction compared
7047  * to Type1. So after all (because the rest of logic uses TTF
7048  * path directions) we have to reverse the paths.
7049  *
7050  * It was a big headache to discover that.
7051  */
7052 
7053 /* works on both int and float paths */
7054 
7055 void
reversepathsfromto(GENTRY * from,GENTRY * to)7056 reversepathsfromto(
7057 		   GENTRY * from,
7058 		   GENTRY * to
7059 )
7060 {
7061 	GENTRY         *ge, *nge, *pge;
7062 	GENTRY         *cur, *next;
7063 	int i, n, ilast[2];
7064 	double flast[2], f;
7065 
7066 	for (ge = from; ge != 0 && ge != to; ge = ge->next) {
7067 		if(ge->type == GE_LINE || ge->type == GE_CURVE) {
7068 			if (ISDBG(REVERSAL))
7069 				fprintf(stderr, "reverse path 0x%x <- 0x%x, 0x%x\n", ge, ge->prev, ge->bkwd);
7070 
7071 			/* cut out the path itself */
7072 			pge = ge->prev; /* GE_MOVE */
7073 			if (pge == 0) {
7074 				fprintf(stderr, "**! No MOVE before line !!! Fatal. ****\n");
7075 				exit(1);
7076 			}
7077 			nge = ge->bkwd->next; /* GE_PATH */
7078 			pge->next = nge;
7079 			nge->prev = pge;
7080 			ge->bkwd->next = 0; /* mark end of chain */
7081 
7082 			/* remember the starting point */
7083 			if(ge->flags & GEF_FLOAT) {
7084 				flast[0] = pge->fx3;
7085 				flast[1] = pge->fy3;
7086 			} else {
7087 				ilast[0] = pge->ix3;
7088 				ilast[1] = pge->iy3;
7089 			}
7090 
7091 			/* then reinsert them in backwards order */
7092 			for(cur = ge; cur != 0; cur = next ) {
7093 				next = cur->next; /* or addgeafter() will screw it up */
7094 				if(cur->flags & GEF_FLOAT) {
7095 					for(i=0; i<2; i++) {
7096 						/* reverse the direction of path element */
7097 						f = cur->fpoints[i][0];
7098 						cur->fpoints[i][0] = cur->fpoints[i][1];
7099 						cur->fpoints[i][1] = f;
7100 						f = flast[i];
7101 						flast[i] = cur->fpoints[i][2];
7102 						cur->fpoints[i][2] = f;
7103 					}
7104 				} else {
7105 					for(i=0; i<2; i++) {
7106 						/* reverse the direction of path element */
7107 						n = cur->ipoints[i][0];
7108 						cur->ipoints[i][0] = cur->ipoints[i][1];
7109 						cur->ipoints[i][1] = n;
7110 						n = ilast[i];
7111 						ilast[i] = cur->ipoints[i][2];
7112 						cur->ipoints[i][2] = n;
7113 					}
7114 				}
7115 				addgeafter(pge, cur);
7116 			}
7117 
7118 			/* restore the starting point */
7119 			if(ge->flags & GEF_FLOAT) {
7120 				pge->fx3 = flast[0];
7121 				pge->fy3 = flast[1];
7122 			} else {
7123 				pge->ix3 = ilast[0];
7124 				pge->iy3 = ilast[1];
7125 			}
7126 
7127 			ge = nge;
7128 		}
7129 
7130 	}
7131 }
7132 
7133 void
reversepaths(GLYPH * g)7134 reversepaths(
7135 	     GLYPH * g
7136 )
7137 {
7138 	reversepathsfromto(g->entries, NULL);
7139 }
7140 
7141 /* add a kerning pair information, scales the value */
7142 
7143 void
addkernpair(unsigned id1,unsigned id2,int unscval)7144 addkernpair(
7145 	unsigned id1,
7146 	unsigned id2,
7147 	int unscval
7148 )
7149 {
7150 	static unsigned char *bits = 0;
7151 	static int lastid;
7152 	GLYPH *g = &glyph_list[id1];
7153 	int i, n;
7154 	struct kern *p;
7155 
7156 	if(unscval == 0 || id1 >= numglyphs || id2 >= numglyphs)
7157 		return;
7158 
7159 	if( (glyph_list[id1].flags & GF_USED)==0
7160 	|| (glyph_list[id2].flags & GF_USED)==0 )
7161 		return;
7162 
7163 	if(bits == 0) {
7164 		bits = calloc( BITMAP_BYTES(numglyphs), 1);
7165 		if (bits == NULL) {
7166 			fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
7167 			exit(255);
7168 		}
7169 		lastid = id1;
7170 	}
7171 
7172 	if(lastid != id1) {
7173 		/* refill the bitmap cache */
7174 		memset(bits, 0,BITMAP_BYTES(numglyphs));
7175 		p = g->kern;
7176 		for(i=g->kerncount; i>0; i--) {
7177 			n = (p++)->id;
7178 			SET_BITMAP(bits, n);
7179 		}
7180 		lastid = id1;
7181 	}
7182 
7183 	if(IS_BITMAP(bits, id2))
7184 		return; /* duplicate */
7185 
7186 	if(g->kerncount <= g->kernalloc) {
7187 		g->kernalloc += 8;
7188 		p = realloc(g->kern, sizeof(struct kern) * g->kernalloc);
7189 		if(p == 0) {
7190 			fprintf (stderr, "** realloc failed, kerning data will be incomplete\n");
7191 		}
7192 		g->kern = p;
7193 	}
7194 
7195 	SET_BITMAP(bits, id2);
7196 	p = &g->kern[g->kerncount];
7197 	p->id = id2;
7198 	p->val = iscale(unscval) - (g->scaledwidth - g->oldwidth);
7199 	g->kerncount++;
7200 	kerning_pairs++;
7201 }
7202 
7203 /* print out the kerning information */
7204 
7205 void
print_kerning(FILE * afm_file)7206 print_kerning(
7207 	FILE *afm_file
7208 )
7209 {
7210 	int	i, j, n;
7211 	GLYPH *g;
7212 	struct kern *p;
7213 
7214 	if( kerning_pairs == 0 )
7215 		return;
7216 
7217 	fprintf(afm_file, "StartKernData\n");
7218 	fprintf(afm_file, "StartKernPairs %hd\n", kerning_pairs);
7219 
7220 	for(i=0; i<numglyphs; i++)  {
7221 		g = &glyph_list[i];
7222 		if( (g->flags & GF_USED) ==0)
7223 			continue;
7224 		p = g->kern;
7225 		for(j=g->kerncount; j>0; j--, p++) {
7226 			fprintf(afm_file, "KPX %s %s %d\n", g->name,
7227 				glyph_list[ p->id ].name, p->val );
7228 		}
7229 	}
7230 
7231 	fprintf(afm_file, "EndKernPairs\n");
7232 	fprintf(afm_file, "EndKernData\n");
7233 }
7234 
7235 
7236 #if 0
7237 
7238 /*
7239 ** This function is commented out because the information
7240 ** collected by it is not used anywhere else yet. Now
7241 ** it only collects the directions of contours. And the
7242 ** direction of contours gets fixed already in draw_glyf().
7243 **
7244 ***********************************************
7245 **
7246 ** Here we expect that the paths are already closed.
7247 ** We also expect that the contours do not intersect
7248 ** and that curves doesn't cross any border of quadrant.
7249 **
7250 ** Find which contours go inside which and what is
7251 ** their proper direction. Then fix the direction
7252 ** to make it right.
7253 **
7254 */
7255 
7256 #define MAXCONT	1000
7257 
7258 void
7259 fixcontours(
7260 	    GLYPH * g
7261 )
7262 {
7263 	CONTOUR         cont[MAXCONT];
7264 	short           ymax[MAXCONT];	/* the highest point */
7265 	short           xofmax[MAXCONT];	/* X-coordinate of any point
7266 						 * at ymax */
7267 	short           ymin[MAXCONT];	/* the lowest point */
7268 	short           xofmin[MAXCONT];	/* X-coordinate of any point
7269 						 * at ymin */
7270 	short           count[MAXCONT];	/* count of lines */
7271 	char            dir[MAXCONT];	/* in which direction they must go */
7272 	GENTRY         *start[MAXCONT], *minptr[MAXCONT], *maxptr[MAXCONT];
7273 	int             ncont;
7274 	int             i;
7275 	int             dx1, dy1, dx2, dy2;
7276 	GENTRY         *ge, *nge;
7277 
7278 	/* find the contours and their most upper/lower points */
7279 	ncont = 0;
7280 	ymax[0] = -5000;
7281 	ymin[0] = 5000;
7282 	for (ge = g->entries; ge != 0; ge = ge->next) {
7283 		if (ge->type == GE_LINE || ge->type == GE_CURVE) {
7284 			if (ge->iy3 > ymax[ncont]) {
7285 				ymax[ncont] = ge->iy3;
7286 				xofmax[ncont] = ge->ix3;
7287 				maxptr[ncont] = ge;
7288 			}
7289 			if (ge->iy3 < ymin[ncont]) {
7290 				ymin[ncont] = ge->iy3;
7291 				xofmin[ncont] = ge->ix3;
7292 				minptr[ncont] = ge;
7293 			}
7294 		}
7295 		if (ge->frwd != ge->next) {
7296 			start[ncont++] = ge->frwd;
7297 			ymax[ncont] = -5000;
7298 			ymin[ncont] = 5000;
7299 		}
7300 	}
7301 
7302 	/* determine the directions of contours */
7303 	for (i = 0; i < ncont; i++) {
7304 		ge = minptr[i];
7305 		nge = ge->frwd;
7306 
7307 		if (ge->type == GE_CURVE) {
7308 			dx1 = ge->ix3 - ge->ix2;
7309 			dy1 = ge->iy3 - ge->iy2;
7310 
7311 			if (dx1 == 0 && dy1 == 0) {	/* a pathological case */
7312 				dx1 = ge->ix3 - ge->ix1;
7313 				dy1 = ge->iy3 - ge->iy1;
7314 			}
7315 			if (dx1 == 0 && dy1 == 0) {	/* a more pathological
7316 							 * case */
7317 				dx1 = ge->ix3 - ge->prev->ix3;
7318 				dy1 = ge->iy3 - ge->prev->iy3;
7319 			}
7320 		} else {
7321 			dx1 = ge->ix3 - ge->prev->ix3;
7322 			dy1 = ge->iy3 - ge->prev->iy3;
7323 		}
7324 		if (nge->type == GE_CURVE) {
7325 			dx2 = ge->ix3 - nge->ix1;
7326 			dy2 = ge->iy3 - nge->iy1;
7327 			if (dx1 == 0 && dy1 == 0) {	/* a pathological case */
7328 				dx2 = ge->ix3 - nge->ix2;
7329 				dy2 = ge->iy3 - nge->iy2;
7330 			}
7331 			if (dx1 == 0 && dy1 == 0) {	/* a more pathological
7332 							 * case */
7333 				dx2 = ge->ix3 - nge->ix3;
7334 				dy2 = ge->iy3 - nge->iy3;
7335 			}
7336 		} else {
7337 			dx2 = ge->ix3 - nge->ix3;
7338 			dy2 = ge->iy3 - nge->iy3;
7339 		}
7340 
7341 		/* compare angles */
7342 		cont[i].direction = DIR_INNER;
7343 		if (dy1 == 0) {
7344 			if (dx1 < 0)
7345 				cont[i].direction = DIR_OUTER;
7346 		} else if (dy2 == 0) {
7347 			if (dx2 > 0)
7348 				cont[i].direction = DIR_OUTER;
7349 		} else if (dx2 * dy1 < dx1 * dy2)
7350 			cont[i].direction = DIR_OUTER;
7351 
7352 		cont[i].ymin = ymin[i];
7353 		cont[i].xofmin = xofmin[i];
7354 	}
7355 
7356 	/* save the information that may be needed further */
7357 	g->ncontours = ncont;
7358 	if (ncont > 0) {
7359 		g->contours = malloc(sizeof(CONTOUR) * ncont);
7360 		if (g->contours == 0) {
7361 			fprintf(stderr, "***** Memory allocation error *****\n");
7362 			exit(255);
7363 		}
7364 		memcpy(g->contours, cont, sizeof(CONTOUR) * ncont);
7365 	}
7366 }
7367 
7368 #endif
7369 
7370 /*
7371  *
7372  */
7373 
7374