1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "splineutil.h"
31 
32 #include "cvundoes.h"
33 #include "dumppfa.h"
34 #include "encoding.h"
35 #include "ffglib.h"
36 #include "fontforgevw.h"
37 #include "fvfonts.h"
38 #include "fvimportbdf.h"
39 #include "glif_name_hash.h"
40 #include "mm.h"
41 #include "namelist.h"
42 #include "parsepfa.h"
43 #include "parsettf.h"
44 #include "psfont.h"
45 #include "psread.h"
46 #include "sfd1.h" // This has the extended SplineFont type SplineFont1 for old file versions.
47 #include "spiro.h"
48 #include "splinefill.h"
49 #include "splineorder2.h"
50 #include "splinerefigure.h"
51 #include "splineutil2.h"
52 #include "tottf.h"
53 #include "ustring.h"
54 #include "utype.h"
55 #include "views.h"		/* for FindSel structure */
56 
57 #include <locale.h>
58 
59 #include <math.h>
60 #ifdef HAVE_IEEEFP_H
61 # include <ieeefp.h>		/* Solaris defines isnan in ieeefp rather than math.h */
62 #endif
63 
64 /*#define DEBUG 1*/
65 
66 typedef struct quartic {
67     bigreal a,b,c,d,e;
68 } Quartic;
69 
70 /* In an attempt to make allocation more efficient I just keep preallocated */
71 /*  lists of certain common sizes. It doesn't seem to make much difference */
72 /*  when allocating stuff, but does when freeing. If the extra complexity */
73 /*  is bad then put:							  */
74 /*	#define chunkalloc(size)	calloc(1,size)			  */
75 /*	#define chunkfree(item,size)	free(item)			  */
76 /*  into splinefont.h after (or instead of) the definition of chunkalloc()*/
77 
78 #define ALLOC_CHUNK	100		/* Number of small chunks to malloc at a time */
79 #ifndef FONTFORGE_CONFIG_USE_DOUBLE
80 # define CHUNK_MAX	100		/* Maximum size (in chunk units) that we are prepared to allocate */
81 					/* The size of our data structures */
82 #else
83 # define CHUNK_MAX	129
84 #endif
85 # define CHUNK_UNIT	sizeof(void *)	/*  will vary with the word size of */
86 					/*  the machine. if pointers are 64 bits*/
87 					/*  we may need twice as much space as for 32 bits */
88 
89 #ifdef FLAG
90 #undef FLAG
91 #define FLAG 0xbadcafe
92 #endif
93 
94 #ifdef CHUNKDEBUG
95 static int chunkdebug = 0;	/* When this is set we never free anything, insuring that each chunk is unique */
96 #endif
97 
98 #if ALLOC_CHUNK>1
99 struct chunk { struct chunk *next; };
100 struct chunk2 { struct chunk2 *next; int flag; };
101 #endif
102 
103 #if defined(FLAG) && ALLOC_CHUNK>1
chunktest(void)104 void chunktest(void) {
105     int i;
106     struct chunk2 *c;
107 
108     for ( i=2; i<CHUNK_MAX; ++i )
109 	for ( c=(struct chunk2 *) chunklists[i]; c!=NULL; c=c->next )
110 	    if ( c->flag!=FLAG ) {
111 		fprintf( stderr, "Chunk memory list has been corrupted\n" );
112 		abort();
113 	    }
114 }
115 #endif
116 
strconcat(const char * str1,const char * str2)117 char *strconcat(const char *str1,const char *str2) {
118     char *ret;
119     int len1 = strlen(str1);
120     if ( (ret=malloc(len1+strlen(str2)+1))!=NULL ) {
121 	strcpy(ret,str1);
122 	strcpy(ret+len1,str2);
123     }
124     return( ret );
125 }
126 
strconcat3(const char * str1,const char * str2,const char * str3)127 char *strconcat3(const char *str1,const char *str2, const char *str3) {
128     char *ret;
129     int len1 = strlen(str1), len2 = strlen(str2);
130     if ( (ret=malloc(len1+len2+strlen(str3)+1))!=NULL ) {
131 	strcpy(ret,str1);
132 	strcpy(ret+len1,str2);
133 	strcpy(ret+len1+len2,str3);
134     }
135     return( ret );
136 }
137 
LineListFree(LineList * ll)138 void LineListFree(LineList *ll) {
139     LineList *next;
140 
141     while ( ll!=NULL ) {
142 	next = ll->next;
143 	chunkfree(ll,sizeof(LineList));
144 	ll = next;
145     }
146 }
147 
LinearApproxFree(LinearApprox * la)148 void LinearApproxFree(LinearApprox *la) {
149     LinearApprox *next;
150 
151     while ( la!=NULL ) {
152 	next = la->next;
153 	LineListFree(la->lines);
154 	chunkfree(la,sizeof(LinearApprox));
155 	la = next;
156     }
157 }
158 
SplineFree(Spline * spline)159 void SplineFree(Spline *spline) {
160     LinearApproxFree(spline->approx);
161     chunkfree(spline,sizeof(Spline));
162 }
163 
SplinePointCreate(real x,real y)164 SplinePoint *SplinePointCreate(real x, real y) {
165     SplinePoint *sp;
166     if ( (sp=chunkalloc(sizeof(SplinePoint)))!=NULL ) {
167 	sp->me.x = x; sp->me.y = y;
168 	sp->nextcp = sp->prevcp = sp->me;
169 	sp->nonextcp = sp->noprevcp = true;
170 	sp->nextcpdef = sp->prevcpdef = false;
171 	sp->ttfindex = sp->nextcpindex = 0xfffe;
172 	sp->name = NULL;
173     }
174     return( sp );
175 }
176 
SplineMake3(SplinePoint * from,SplinePoint * to)177 Spline *SplineMake3(SplinePoint *from, SplinePoint *to) {
178     Spline *spline = chunkalloc(sizeof(Spline));
179 
180     spline->from = from; spline->to = to;
181     from->next = to->prev = spline;
182     SplineRefigure3(spline);
183 return( spline );
184 }
185 
SplinePointFree(SplinePoint * sp)186 void SplinePointFree(SplinePoint *sp) {
187     chunkfree(sp->hintmask,sizeof(HintMask));
188 	free(sp->name);
189     chunkfree(sp,sizeof(SplinePoint));
190 }
191 
SplinePointMDFree(SplineChar * sc,SplinePoint * sp)192 void SplinePointMDFree(SplineChar *sc, SplinePoint *sp) {
193     MinimumDistance *md, *prev, *next;
194 
195     if ( sc!=NULL ) {
196 	prev = NULL;
197 	for ( md = sc->md; md!=NULL; md = next ) {
198 	    next = md->next;
199 	    if ( md->sp1==sp || md->sp2==sp ) {
200 		if ( prev==NULL )
201 		    sc->md = next;
202 		else
203 		    prev->next = next;
204 		chunkfree(md,sizeof(MinimumDistance));
205 	    } else
206 		prev = md;
207 	}
208     }
209 
210     chunkfree(sp->hintmask,sizeof(HintMask));
211 	free(sp->name);
212     chunkfree(sp,sizeof(SplinePoint));
213 }
214 
SplinePointsFree(SplinePointList * spl)215 void SplinePointsFree(SplinePointList *spl) {
216     Spline *first, *spline, *next;
217     int nonext;
218 
219     if ( spl==NULL )
220       return;
221     if ( spl->first!=NULL ) {
222 	nonext = spl->first->next==NULL; // If there is no spline, we set a flag.
223 	first = NULL;
224         // We start on the first spline if it exists.
225 	for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
226 	    next = spline->to->next; // Cache the location of the next spline.
227 	    SplinePointFree(spline->to); // Free the destination point.
228 	    SplineFree(spline); // Free the spline.
229 	    if ( first==NULL ) first = spline; // We want to avoid repeating the circuit.
230 	}
231         // If the path is open or has no splines, free the starting point.
232 	if ( spl->last!=spl->first || nonext )
233 	    SplinePointFree(spl->first);
234     }
235 }
236 
SplineSetBeziersClear(SplinePointList * spl)237 void SplineSetBeziersClear(SplinePointList *spl) {
238 
239     if ( spl==NULL ) return;
240     SplinePointsFree(spl);
241     spl->first = spl->last = NULL;
242     spl->start_offset = 0;
243 }
244 
SplinePointListFree(SplinePointList * spl)245 void SplinePointListFree(SplinePointList *spl) {
246 
247     if ( spl==NULL ) return;
248     SplinePointsFree(spl);
249     free(spl->spiros);
250     free(spl->contour_name);
251     chunkfree(spl,sizeof(SplinePointList));
252 }
253 
SplinePointListMDFree(SplineChar * sc,SplinePointList * spl)254 void SplinePointListMDFree(SplineChar *sc,SplinePointList *spl) {
255     Spline *first, *spline, *next;
256     int freefirst;
257 
258     if ( spl==NULL )
259 return;
260     if ( spl->first!=NULL ) {
261 	first = NULL;
262 	freefirst = ( spl->last!=spl->first || spl->first->next==NULL );
263 	for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
264 	    next = spline->to->next;
265 	    SplinePointMDFree(sc,spline->to);
266 	    SplineFree(spline);
267 	    if ( first==NULL ) first = spline;
268 	}
269 	if ( freefirst )
270 	    SplinePointMDFree(sc,spl->first);
271     }
272     free(spl->spiros);
273     free(spl->contour_name);
274     chunkfree(spl,sizeof(SplinePointList));
275 }
276 
SplinePointListsMDFree(SplineChar * sc,SplinePointList * spl)277 void SplinePointListsMDFree(SplineChar *sc,SplinePointList *spl) {
278     SplinePointList *next;
279 
280     while ( spl!=NULL ) {
281 	next = spl->next;
282 	SplinePointListMDFree(sc,spl);
283 	spl = next;
284     }
285 }
286 
SplinePointListsFree(SplinePointList * spl)287 void SplinePointListsFree(SplinePointList *spl) {
288     SplinePointList *next;
289 
290     while ( spl!=NULL ) {
291 	next = spl->next;
292 	SplinePointListFree(spl);
293 	spl = next;
294     }
295 }
296 
SplineSetSpirosClear(SplineSet * spl)297 void SplineSetSpirosClear(SplineSet *spl) {
298     free(spl->spiros);
299     spl->spiros = NULL;
300     spl->spiro_cnt = spl->spiro_max = 0;
301 }
302 
ImageListsFree(ImageList * imgs)303 void ImageListsFree(ImageList *imgs) {
304     ImageList *inext;
305 
306     while ( imgs!=NULL ) {
307 	inext = imgs->next;
308 	chunkfree(imgs,sizeof(ImageList));
309 	imgs = inext;
310     }
311 }
312 
RefCharFree(RefChar * ref)313 void RefCharFree(RefChar *ref) {
314     int i;
315 
316     if ( ref==NULL )
317 return;
318     for ( i=0; i<ref->layer_cnt; ++i ) {
319 	SplinePointListsFree(ref->layers[i].splines);
320 	ImageListsFree(ref->layers[i].images);
321 	GradientFree(ref->layers[i].fill_brush.gradient);
322 	GradientFree(ref->layers[i].stroke_pen.brush.gradient);
323 	PatternFree(ref->layers[i].fill_brush.pattern);
324 	PatternFree(ref->layers[i].stroke_pen.brush.pattern);
325     }
326     free(ref->layers);
327     chunkfree(ref,sizeof(RefChar));
328 }
329 
RefCharCreate(void)330 RefChar *RefCharCreate(void) {
331     RefChar *ref = chunkalloc(sizeof(RefChar));
332     ref->layer_cnt = 1;
333     ref->layers = calloc(1,sizeof(struct reflayer));
334     ref->layers[0].fill_brush.opacity = ref->layers[0].stroke_pen.brush.opacity = 1.0;
335     ref->layers[0].fill_brush.col = ref->layers[0].stroke_pen.brush.col = COLOR_INHERITED;
336     ref->layers[0].stroke_pen.width = WIDTH_INHERITED;
337     ref->layers[0].stroke_pen.linecap = lc_inherited;
338     ref->layers[0].stroke_pen.linejoin = lj_inherited;
339     ref->layers[0].dofill = true;
340     ref->round_translation_to_grid = true;
341 return( ref );
342 }
343 
RefCharsFree(RefChar * ref)344 void RefCharsFree(RefChar *ref) {
345     RefChar *rnext;
346 
347     while ( ref!=NULL ) {
348 	rnext = ref->next;
349 	RefCharFree(ref);
350 	ref = rnext;
351     }
352 }
353 
354 /* Remove line segments which are just one point long */
355 /* Merge colinear line segments */
356 /* Merge two segments each of which involves a single pixel change in one dimension (cut corners) */
SimplifyLineList(LineList * prev)357 static void SimplifyLineList(LineList *prev) {
358     LineList *next, *lines;
359 
360     if ( prev->next==NULL )
361 return;
362     lines = prev->next;
363     while ( (next = lines->next)!=NULL ) {
364 	if ( (prev->here.x==lines->here.x && prev->here.y == lines->here.y ) ||
365 		( prev->here.x==lines->here.x && lines->here.x==next->here.x ) ||
366 		( prev->here.y==lines->here.y && lines->here.y==next->here.y ) ||
367 		(( prev->here.x==next->here.x+1 || prev->here.x==next->here.x-1 ) &&
368 		 ( prev->here.y==next->here.y+1 || prev->here.y==next->here.y-1 )) ) {
369 	    lines->here = next->here;
370 	    lines->next = next->next;
371 	    chunkfree(next,sizeof(*next));
372 	} else {
373 	    prev = lines;
374 	    lines = next;
375 	}
376     }
377     if ( prev!=NULL &&
378 	    prev->here.x==lines->here.x && prev->here.y == lines->here.y ) {
379 	prev->next = lines->next;
380 	chunkfree(lines,sizeof(*lines));
381 	lines = prev->next;
382     }
383 
384     if ( lines!=NULL ) while ( (next = lines->next)!=NULL ) {
385 	if ( prev->here.x!=next->here.x ) {
386 	    bigreal slope = (next->here.y-prev->here.y) / (bigreal) (next->here.x-prev->here.x);
387 	    bigreal inter = prev->here.y - slope*prev->here.x;
388 	    int y = rint(lines->here.x*slope + inter);
389 	    if ( y == lines->here.y ) {
390 		lines->here = next->here;
391 		lines->next = next->next;
392 		chunkfree(next,sizeof(*next));
393 	    } else
394 		lines = next;
395 	} else
396 	    lines = next;
397     }
398 }
399 
400 typedef struct spline1 {
401     Spline1D sp;
402     real s0, s1;
403     real c0, c1;
404 } Spline1;
405 
FigureSpline1(Spline1 * sp1,bigreal t0,bigreal t1,Spline1D * sp)406 static void FigureSpline1(Spline1 *sp1,bigreal t0, bigreal t1, Spline1D *sp ) {
407     bigreal s = (t1-t0);
408     if ( sp->a==0 && sp->b==0 ) {
409 	sp1->sp.d = sp->d + t0*sp->c;
410 	sp1->sp.c = s*sp->c;
411 	sp1->sp.b = sp1->sp.a = 0;
412     } else {
413 	sp1->sp.d = sp->d + t0*(sp->c + t0*(sp->b + t0*sp->a));
414 	sp1->sp.c = s*(sp->c + t0*(2*sp->b + 3*sp->a*t0));
415 	sp1->sp.b = s*s*(sp->b+3*sp->a*t0);
416 	sp1->sp.a = s*s*s*sp->a;
417     }
418     sp1->c0 = sp1->sp.c/3 + sp1->sp.d;
419     sp1->c1 = sp1->c0 + (sp1->sp.b+sp1->sp.c)/3;
420 }
421 
SplineSegApprox(LineList * last,Spline * spline,bigreal start,bigreal end,real scale)422 static LineList *SplineSegApprox(LineList *last, Spline *spline, bigreal start, bigreal end, real scale) {
423     /* Divide into n equal segments */
424     /* (first point is already on the line list) */
425     /* what's a good value for n? Perhaps the normal distance of the control */
426     /*  points to the line between the end points. */
427     int i,n;
428     bigreal t, diff, len;
429     bigreal x,y;
430     LineList *cur;
431     BasePoint startp, endp, slope, off;
432     bigreal temp;
433 
434     n = 6;
435     if ( start==0 && end==1 ) {
436 	/* No different from the latter case, except we can optimize here */
437 	/*  and it's easier to understand what is happening in the simple */
438 	/*  case */
439 	slope.x = spline->to->me.x - spline->from->me.x;
440 	slope.y = spline->to->me.y - spline->from->me.y;
441 	len = slope.x*slope.x + slope.y*slope.y;
442 	if ( len==0 )
443 return( last );
444 	len = sqrt(len);
445 	slope.x /= len; slope.y /= len;
446 	off.x = spline->from->nextcp.x - spline->from->me.x;
447 	off.y = spline->from->nextcp.y - spline->from->me.y;
448 	temp = (off.x*slope.y - off.y*slope.x) * scale;
449 	if ( temp<0 ) temp = -temp;
450 	if ( temp>n ) n = temp;
451 	off.x = spline->to->prevcp.x - spline->from->me.x;
452 	off.y = spline->to->prevcp.y - spline->from->me.y;
453 	temp = (off.x*slope.y - off.y*slope.x) * scale;
454 	if ( temp<0 ) temp = -temp;
455 	if ( temp>n ) n = temp;
456     } else {
457 	Spline1 xsp, ysp;
458 	startp.x = ((spline->splines[0].a*start+spline->splines[0].b)*start+spline->splines[0].c)*start + spline->splines[0].d;
459 	startp.y = ((spline->splines[1].a*start+spline->splines[1].b)*start+spline->splines[1].c)*start + spline->splines[1].d;
460 	endp.x = ((spline->splines[0].a*end+spline->splines[0].b)*end+spline->splines[0].c)*end + spline->splines[0].d;
461 	endp.y = ((spline->splines[1].a*end+spline->splines[1].b)*end+spline->splines[1].c)*end + spline->splines[1].d;
462 	slope.x = endp.x - startp.x;
463 	slope.y = endp.y - startp.y;
464 	FigureSpline1(&xsp,start,end,&spline->splines[0]);
465 	FigureSpline1(&ysp,start,end,&spline->splines[1]);
466 	len = slope.x*slope.x + slope.y*slope.y;
467 	if ( len==0 )
468 return( last );
469 	len = sqrt(len);
470 	slope.x /= len; slope.y /= len;
471 	off.x = xsp.c0 - startp.x;
472 	off.y = ysp.c0 - startp.y;
473 	temp = (off.x*slope.y - off.y*slope.x) * scale;
474 	if ( temp<0 ) temp = -temp;
475 	if ( temp>n ) n = temp;
476 	off.x = xsp.c1 - endp.x;
477 	off.y = ysp.c1 - endp.y;
478 	temp = (off.x*slope.y - off.y*slope.x) * scale;
479 	if ( temp<0 ) temp = -temp;
480 	if ( temp>n ) n = temp;
481     }
482 
483     diff = (end-start)/n;
484     for ( t=start+diff, i=1; i<=n; ++i, t+=diff ) {
485 	if ( i==n ) t = end;		/* Avoid rounding errors */
486 	cur = chunkalloc(sizeof(LineList) );
487 	x = ((spline->splines[0].a*t+spline->splines[0].b)*t+spline->splines[0].c)*t + spline->splines[0].d;
488 	y = ((spline->splines[1].a*t+spline->splines[1].b)*t+spline->splines[1].c)*t + spline->splines[1].d;
489 	cur->here.x = rint(x*scale);
490 	cur->here.y = rint(y*scale);
491 	last->next = cur;
492 	last = cur;
493     }
494 return( last );
495 }
496 
SplineApproximate(Spline * spline,real scale)497 LinearApprox *SplineApproximate(Spline *spline, real scale) {
498     LinearApprox *test;
499     LineList *cur, *last=NULL;
500     extended poi[2], lastt;
501     int i,n;
502 
503     for ( test = spline->approx; test!=NULL && test->scale!=scale; test = test->next );
504     if ( test!=NULL )
505 return( test );
506 
507     test = chunkalloc(sizeof(LinearApprox));
508     test->scale = scale;
509     test->next = spline->approx;
510     spline->approx = test;
511 
512     cur = chunkalloc(sizeof(LineList) );
513     cur->here.x = rint(spline->from->me.x*scale);
514     cur->here.y = rint(spline->from->me.y*scale);
515     test->lines = last = cur;
516 
517     if ( spline->knownlinear ) {
518 	cur = chunkalloc(sizeof(LineList) );
519 	cur->here.x = rint(spline->to->me.x*scale);
520 	cur->here.y = rint(spline->to->me.y*scale);
521 	last->next = cur;
522     } else if ( spline->isquadratic ) {
523 	last = SplineSegApprox(last,spline,0,1,scale);
524     } else {
525 	n = Spline2DFindPointsOfInflection(spline,poi);
526 	lastt=0;
527 	for ( i=0; i<n; ++i ) {
528 	    last = SplineSegApprox(last,spline,lastt,poi[i],scale);
529 	    lastt = poi[i];
530 	}
531 	last = SplineSegApprox(last,spline,lastt,1,scale);
532     }
533     SimplifyLineList(test->lines);
534     if ( test->lines->next==NULL ) {
535 	test->oneline = 1;
536 	test->onepoint = 1;
537     } else if ( test->lines->next->next == NULL ) {
538 	test->oneline = 1;
539     }
540 return( test );
541 }
542 
SplineFindBounds(const Spline * sp,DBounds * bounds)543 static void SplineFindBounds(const Spline *sp, DBounds *bounds) {
544     real t, b2_fourac, v;
545     real min, max;
546     const Spline1D *sp1;
547     int i;
548 
549     /* first try the end points */
550     for ( i=0; i<2; ++i ) {
551 	sp1 = &sp->splines[i];
552 	if ( i==0 ) {
553 	    if ( sp->to->me.x<bounds->minx ) bounds->minx = sp->to->me.x;
554 	    if ( sp->to->me.x>bounds->maxx ) bounds->maxx = sp->to->me.x;
555 	    min = bounds->minx; max = bounds->maxx;
556 	} else {
557 	    if ( sp->to->me.y<bounds->miny ) bounds->miny = sp->to->me.y;
558 	    if ( sp->to->me.y>bounds->maxy ) bounds->maxy = sp->to->me.y;
559 	    min = bounds->miny; max = bounds->maxy;
560 	}
561 
562 	/* then try the extrema of the spline (assuming they are between t=(0,1) */
563 	/* (I don't bother fixing up for tiny rounding errors here. they don't matter */
564 	/* But we could call CheckExtremaForSingleBitErrors */
565 	if ( sp1->a!=0 ) {
566 	    b2_fourac = 4*sp1->b*sp1->b - 12*sp1->a*sp1->c;
567 	    if ( b2_fourac>=0 ) {
568 		b2_fourac = sqrt(b2_fourac);
569 		t = (-2*sp1->b + b2_fourac) / (6*sp1->a);
570 		if ( t>0 && t<1 ) {
571 		    v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d;
572 		    if ( v<min ) min = v;
573 		    if ( v>max ) max = v;
574 		}
575 		t = (-2*sp1->b - b2_fourac) / (6*sp1->a);
576 		if ( t>0 && t<1 ) {
577 		    v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d;
578 		    if ( v<min ) min = v;
579 		    if ( v>max ) max = v;
580 		}
581 	    }
582 	} else if ( sp1->b!=0 ) {
583 	    t = -sp1->c/(2.0*sp1->b);
584 	    if ( t>0 && t<1 ) {
585 		v = (sp1->b*t+sp1->c)*t + sp1->d;
586 		if ( v<min ) min = v;
587 		if ( v>max ) max = v;
588 	    }
589 	}
590 	if ( i==0 ) {
591 	    bounds->minx = min; bounds->maxx = max;
592 	} else {
593 	    bounds->miny = min; bounds->maxy = max;
594 	}
595     }
596 }
597 
_SplineSetFindBounds(const SplinePointList * spl,DBounds * bounds)598 static void _SplineSetFindBounds(const SplinePointList *spl, DBounds *bounds) {
599     Spline *spline, *first;
600     /* Ignore contours consisting of a single point (used for hinting, anchors */
601     /*  for mark to base, etc. */
602 
603     for ( ; spl!=NULL; spl = spl->next ) if ( spl->first->next!=NULL && spl->first->next->to != spl->first ) {
604 	first = NULL;
605 	if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) {
606 	    bounds->minx = bounds->maxx = spl->first->me.x;
607 	    bounds->miny = bounds->maxy = spl->first->me.y;
608 	} else {
609 	    if ( spl->first->me.x<bounds->minx ) bounds->minx = spl->first->me.x;
610 	    if ( spl->first->me.x>bounds->maxx ) bounds->maxx = spl->first->me.x;
611 	    if ( spl->first->me.y<bounds->miny ) bounds->miny = spl->first->me.y;
612 	    if ( spl->first->me.y>bounds->maxy ) bounds->maxy = spl->first->me.y;
613 	}
614 	for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
615 	    SplineFindBounds(spline,bounds);
616 	    if ( first==NULL ) first = spline;
617 	}
618     }
619 }
620 
_SplineSetFindClippedBounds(const SplinePointList * spl,DBounds * bounds,DBounds * clipb)621 static void _SplineSetFindClippedBounds(const SplinePointList *spl, DBounds *bounds,DBounds *clipb) {
622     Spline *spline, *first;
623     /* Ignore contours consisting of a single point (used for hinting, anchors */
624     /*  for mark to base, etc. */
625 
626     for ( ; spl!=NULL; spl = spl->next ) if ( spl->first->next!=NULL && spl->first->next->to != spl->first ) {
627 	first = NULL;
628 	if ( !spl->is_clip_path ) {
629 	    if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) {
630 		bounds->minx = bounds->maxx = spl->first->me.x;
631 		bounds->miny = bounds->maxy = spl->first->me.y;
632 	    } else {
633 		if ( spl->first->me.x<bounds->minx ) bounds->minx = spl->first->me.x;
634 		if ( spl->first->me.x>bounds->maxx ) bounds->maxx = spl->first->me.x;
635 		if ( spl->first->me.y<bounds->miny ) bounds->miny = spl->first->me.y;
636 		if ( spl->first->me.y>bounds->maxy ) bounds->maxy = spl->first->me.y;
637 	    }
638 	    for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
639 		SplineFindBounds(spline,bounds);
640 		if ( first==NULL ) first = spline;
641 	    }
642 	} else {
643 	    if ( clipb->minx==0 && clipb->maxx==0 && clipb->miny==0 && clipb->maxy == 0 ) {
644 		clipb->minx = clipb->maxx = spl->first->me.x;
645 		clipb->miny = clipb->maxy = spl->first->me.y;
646 	    } else {
647 		if ( spl->first->me.x<clipb->minx ) clipb->minx = spl->first->me.x;
648 		if ( spl->first->me.x>clipb->maxx ) clipb->maxx = spl->first->me.x;
649 		if ( spl->first->me.y<clipb->miny ) clipb->miny = spl->first->me.y;
650 		if ( spl->first->me.y>clipb->maxy ) clipb->maxy = spl->first->me.y;
651 	    }
652 	    for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
653 		SplineFindBounds(spline,clipb);
654 		if ( first==NULL ) first = spline;
655 	    }
656 	}
657     }
658 }
659 
SplineSetFindBounds(const SplinePointList * spl,DBounds * bounds)660 void SplineSetFindBounds(const SplinePointList *spl, DBounds *bounds) {
661     DBounds clipb;
662     memset(bounds,'\0',sizeof(*bounds));
663     memset(&clipb,'\0',sizeof(clipb));
664     _SplineSetFindClippedBounds(spl, bounds,&clipb);
665     if ( clipb.minx!=0 || clipb.miny!=0 || clipb.maxx!=0 || clipb.maxy!=0 ) {
666 	if ( bounds->minx<clipb.minx ) bounds->minx = clipb.minx;
667 	if ( bounds->miny<clipb.miny ) bounds->miny = clipb.miny;
668 	if ( bounds->maxx>clipb.maxx ) bounds->maxx = clipb.maxx;
669 	if ( bounds->maxy>clipb.maxy ) bounds->maxy = clipb.maxy;
670     }
671 }
672 
_ImageFindBounds(ImageList * img,DBounds * bounds)673 static void _ImageFindBounds(ImageList *img,DBounds *bounds) {
674     if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
675 	*bounds = img->bb;
676     else if ( img->bb.minx!=0 || img->bb.maxx != 0 || img->bb.maxy != 0 || img->bb.miny!=0 ) {
677 	if ( img->bb.minx < bounds->minx ) bounds->minx = img->bb.minx;
678 	if ( img->bb.miny < bounds->miny ) bounds->miny = img->bb.miny;
679 	if ( img->bb.maxx > bounds->maxx ) bounds->maxx = img->bb.maxx;
680 	if ( img->bb.maxy > bounds->maxy ) bounds->maxy = img->bb.maxy;
681     }
682 }
683 
_SplineCharLayerFindBounds(SplineChar * sc,int layer,DBounds * bounds)684 static void _SplineCharLayerFindBounds(SplineChar *sc,int layer, DBounds *bounds) {
685     RefChar *rf;
686     ImageList *img;
687     real e;
688     DBounds b, clipb;
689 
690     for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next ) {
691 	if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
692 	    *bounds = rf->bb;
693 	else if ( rf->bb.minx!=0 || rf->bb.maxx != 0 || rf->bb.maxy != 0 || rf->bb.miny!=0 ) {
694 	    if ( rf->bb.minx < bounds->minx ) bounds->minx = rf->bb.minx;
695 	    if ( rf->bb.miny < bounds->miny ) bounds->miny = rf->bb.miny;
696 	    if ( rf->bb.maxx > bounds->maxx ) bounds->maxx = rf->bb.maxx;
697 	    if ( rf->bb.maxy > bounds->maxy ) bounds->maxy = rf->bb.maxy;
698 	}
699     }
700     memset(&b,0,sizeof(b));
701     memset(&clipb,0,sizeof(clipb));
702     _SplineSetFindClippedBounds(sc->layers[layer].splines,&b,&clipb);
703     for ( img=sc->layers[layer].images; img!=NULL; img=img->next )
704 	_ImageFindBounds(img,bounds);
705     if ( sc->layers[layer].dostroke ) {
706 	if ( sc->layers[layer].stroke_pen.width!=WIDTH_INHERITED )
707 	    e = sc->layers[layer].stroke_pen.width*sc->layers[layer].stroke_pen.trans[0];
708 	else
709 	    e = sc->layers[layer].stroke_pen.trans[0];
710 	b.minx -= e; b.maxx += e;
711 	b.miny -= e; b.maxy += e;
712     }
713     if ( clipb.minx!=0 || clipb.miny!=0 || clipb.maxx!=0 || clipb.maxy!=0 ) {
714 	if ( b.minx<clipb.minx ) b.minx = clipb.minx;
715 	if ( b.miny<clipb.miny ) b.miny = clipb.miny;
716 	if ( b.maxx>clipb.maxx ) b.maxx = clipb.maxx;
717 	if ( b.maxy>clipb.maxy ) b.maxy = clipb.maxy;
718     }
719     if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
720 	*bounds = b;
721     else if ( b.minx!=0 || b.maxx != 0 || b.maxy != 0 || b.miny!=0 ) {
722 	if ( b.minx < bounds->minx ) bounds->minx = b.minx;
723 	if ( b.miny < bounds->miny ) bounds->miny = b.miny;
724 	if ( b.maxx > bounds->maxx ) bounds->maxx = b.maxx;
725 	if ( b.maxy > bounds->maxy ) bounds->maxy = b.maxy;
726     }
727 
728     if ( sc->parent!=NULL && sc->parent->strokedfont &&
729 	    (bounds->minx!=bounds->maxx || bounds->miny!=bounds->maxy)) {
730 	real sw = sc->parent->strokewidth;
731 	bounds->minx -= sw; bounds->miny -= sw;
732 	bounds->maxx += sw; bounds->maxy += sw;
733     }
734 }
735 
SplineCharLayerFindBounds(SplineChar * sc,int layer,DBounds * bounds)736 void SplineCharLayerFindBounds(SplineChar *sc,int layer,DBounds *bounds) {
737 
738     if ( sc->parent!=NULL && sc->parent->multilayer ) {
739 	SplineCharFindBounds(sc,bounds);
740 return;
741     }
742 
743     /* a char with no splines (ie. a space) must have an lbearing of 0 */
744     bounds->minx = bounds->maxx = 0;
745     bounds->miny = bounds->maxy = 0;
746 
747     _SplineCharLayerFindBounds(sc,layer,bounds);
748 }
749 
SplineCharFindBounds(SplineChar * sc,DBounds * bounds)750 void SplineCharFindBounds(SplineChar *sc,DBounds *bounds) {
751     int i;
752     int first,last;
753 
754     /* a char with no splines (ie. a space) must have an lbearing of 0 */
755     bounds->minx = bounds->maxx = 0;
756     bounds->miny = bounds->maxy = 0;
757 
758     first = last = ly_fore;
759     if ( sc->parent!=NULL )
760 	last = sc->layer_cnt-1;
761     for ( i=first; i<=last; ++i )
762 	_SplineCharLayerFindBounds(sc,i,bounds);
763 }
764 
SplineFontLayerFindBounds(SplineFont * sf,int layer,DBounds * bounds)765 void SplineFontLayerFindBounds(SplineFont *sf,int layer,DBounds *bounds) {
766     int i, k, first, last;
767 
768     if ( sf->multilayer ) {
769 	SplineFontFindBounds(sf,bounds);
770 return;
771     }
772 
773     bounds->minx = bounds->maxx = 0;
774     bounds->miny = bounds->maxy = 0;
775 
776     for ( i = 0; i<sf->glyphcnt; ++i ) {
777 	SplineChar *sc = sf->glyphs[i];
778 	if ( sc!=NULL ) {
779 	    first = last = ly_fore;
780 	    if ( sc->parent != NULL && sc->parent->multilayer )
781 		last = sc->layer_cnt-1;
782 	    for ( k=first; k<=last; ++k )
783 		_SplineCharLayerFindBounds(sc,k,bounds);
784 	}
785     }
786 }
787 
SplineFontFindBounds(SplineFont * sf,DBounds * bounds)788 void SplineFontFindBounds(SplineFont *sf,DBounds *bounds) {
789     int i, k, first, last;
790 
791     bounds->minx = bounds->maxx = 0;
792     bounds->miny = bounds->maxy = 0;
793 
794     for ( i = 0; i<sf->glyphcnt; ++i ) {
795 	SplineChar *sc = sf->glyphs[i];
796 	if ( sc!=NULL ) {
797 	    first = last = ly_fore;
798 	    if ( sf->multilayer )
799 		last = sc->layer_cnt-1;
800 	    for ( k=first; k<=last; ++k )
801 		_SplineCharLayerFindBounds(sc,k,bounds);
802 	}
803     }
804 }
805 
CIDLayerFindBounds(SplineFont * cidmaster,int layer,DBounds * bounds)806 void CIDLayerFindBounds(SplineFont *cidmaster,int layer,DBounds *bounds) {
807     SplineFont *sf;
808     int i;
809     DBounds b;
810     real factor;
811 
812     if ( cidmaster->cidmaster )
813 	cidmaster = cidmaster->cidmaster;
814     if ( cidmaster->subfonts==NULL ) {
815 	SplineFontLayerFindBounds(cidmaster,layer,bounds);
816 return;
817     }
818 
819     sf = cidmaster->subfonts[0];
820     SplineFontLayerFindBounds(sf,layer,bounds);
821     factor = 1000.0/(sf->ascent+sf->descent);
822     bounds->maxx *= factor; bounds->minx *= factor; bounds->miny *= factor; bounds->maxy *= factor;
823     for ( i=1; i<cidmaster->subfontcnt; ++i ) {
824 	sf = cidmaster->subfonts[i];
825 	SplineFontLayerFindBounds(sf,layer,&b);
826 	factor = 1000.0/(sf->ascent+sf->descent);
827 	b.maxx *= factor; b.minx *= factor; b.miny *= factor; b.maxy *= factor;
828 	if ( b.maxx>bounds->maxx ) bounds->maxx = b.maxx;
829 	if ( b.maxy>bounds->maxy ) bounds->maxy = b.maxy;
830 	if ( b.miny<bounds->miny ) bounds->miny = b.miny;
831 	if ( b.minx<bounds->minx ) bounds->minx = b.minx;
832     }
833 }
834 
_SplineSetFindTop(SplineSet * ss,BasePoint * top)835 static void _SplineSetFindTop(SplineSet *ss,BasePoint *top) {
836     SplinePoint *sp;
837 
838     for ( ; ss!=NULL; ss=ss->next ) {
839 	for ( sp=ss->first; ; ) {
840 	    if ( sp->me.y > top->y ) *top = sp->me;
841 	    if ( sp->next==NULL )
842 	break;
843 	    sp = sp->next->to;
844 	    if ( sp==ss->first )
845 	break;
846 	}
847     }
848 }
849 
SplineSetQuickBounds(SplineSet * ss,DBounds * b)850 void SplineSetQuickBounds(SplineSet *ss,DBounds *b) {
851     SplinePoint *sp;
852 
853     b->minx = b->miny = 1e10;
854     b->maxx = b->maxy = -1e10;
855     for ( ; ss!=NULL; ss=ss->next ) {
856 	for ( sp=ss->first; ; ) {
857 	    if ( sp->me.y < b->miny ) b->miny = sp->me.y;
858 	    if ( sp->me.x < b->minx ) b->minx = sp->me.x;
859 	    if ( sp->me.y > b->maxy ) b->maxy = sp->me.y;
860 	    if ( sp->me.x > b->maxx ) b->maxx = sp->me.x;
861 	    // Frank added the control points to the calculation since,
862 	    // according to Adam Twardoch,
863 	    // the OpenType values that rely upon this function
864 	    // expect control points to be included.
865 	    if ( !sp->noprevcp ) {
866 	      if ( sp->prevcp.y < b->miny ) b->miny = sp->prevcp.y;
867 	      if ( sp->prevcp.x < b->minx ) b->minx = sp->prevcp.x;
868 	      if ( sp->prevcp.y > b->maxy ) b->maxy = sp->prevcp.y;
869 	      if ( sp->prevcp.x > b->maxx ) b->maxx = sp->prevcp.x;
870 	    }
871 	    if ( !sp->nonextcp ) {
872 	      if ( sp->nextcp.y < b->miny ) b->miny = sp->nextcp.y;
873 	      if ( sp->nextcp.x < b->minx ) b->minx = sp->nextcp.x;
874 	      if ( sp->nextcp.y > b->maxy ) b->maxy = sp->nextcp.y;
875 	      if ( sp->nextcp.x > b->maxx ) b->maxx = sp->nextcp.x;
876 	    }
877 	    if ( sp->next==NULL )
878 	break;
879 	    sp = sp->next->to;
880 	    if ( sp==ss->first )
881 	break;
882 	}
883     }
884     if ( b->minx>65536 ) b->minx = 0;
885     if ( b->miny>65536 ) b->miny = 0;
886     if ( b->maxx<-65536 ) b->maxx = 0;
887     if ( b->maxy<-65536 ) b->maxy = 0;
888 }
889 
SplineCharQuickBounds(SplineChar * sc,DBounds * b)890 void SplineCharQuickBounds(SplineChar *sc, DBounds *b) {
891     RefChar *ref;
892     int i,first, last;
893     DBounds temp;
894     real e;
895     ImageList *img;
896 
897     b->minx = b->miny = 1e10;
898     b->maxx = b->maxy = -1e10;
899     first = last = ly_fore;
900     if ( sc->parent!=NULL && sc->parent->multilayer )
901 	last = sc->layer_cnt-1;
902     for ( i=first; i<=last; ++i ) {
903 	SplineSetQuickBounds(sc->layers[i].splines,&temp);
904 	for ( img=sc->layers[i].images; img!=NULL; img=img->next )
905 	    _ImageFindBounds(img,b);
906 	if ( sc->layers[i].dostroke && sc->layers[i].splines!=NULL ) {
907 	    if ( sc->layers[i].stroke_pen.width!=WIDTH_INHERITED )
908 		e = sc->layers[i].stroke_pen.width*sc->layers[i].stroke_pen.trans[0];
909 	    else
910 		e = sc->layers[i].stroke_pen.trans[0];
911 	    temp.minx -= e; temp.maxx += e;
912 	    temp.miny -= e; temp.maxy += e;
913 	}
914 	if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
915 	    if ( temp.minx < b->minx ) b->minx = temp.minx;
916 	    if ( temp.miny < b->miny ) b->miny = temp.miny;
917 	    if ( temp.maxx > b->maxx ) b->maxx = temp.maxx;
918 	    if ( temp.maxy > b->maxy ) b->maxy = temp.maxy;
919 	}
920 	for ( ref = sc->layers[i].refs; ref!=NULL; ref = ref->next ) {
921 	    /*SplineSetQuickBounds(ref->layers[0].splines,&temp);*/
922 	    if ( b->minx==0 && b->maxx==0 && b->miny==0 && b->maxy == 0 )
923 		*b = ref->bb;
924 	    else if ( ref->bb.minx!=0 || ref->bb.maxx != 0 || ref->bb.maxy != 0 || ref->bb.miny!=0 ) {
925 		if ( ref->bb.minx < b->minx ) b->minx = ref->bb.minx;
926 		if ( ref->bb.miny < b->miny ) b->miny = ref->bb.miny;
927 		if ( ref->bb.maxx > b->maxx ) b->maxx = ref->bb.maxx;
928 		if ( ref->bb.maxy > b->maxy ) b->maxy = ref->bb.maxy;
929 	    }
930 	}
931     }
932     if ( sc->parent!=NULL && sc->parent->strokedfont &&
933 	    (b->minx!=b->maxx || b->miny!=b->maxy)) {
934 	real sw = sc->parent->strokewidth;
935 	b->minx -= sw; b->miny -= sw;
936 	b->maxx += sw; b->maxy += sw;
937     }
938     if ( b->minx>1e9 )
939 	memset(b,0,sizeof(*b));
940 }
941 
SplineCharLayerQuickBounds(SplineChar * sc,int layer,DBounds * bounds)942 void SplineCharLayerQuickBounds(SplineChar *sc,int layer,DBounds *bounds) {
943     RefChar *ref;
944     DBounds temp;
945 
946     if ( sc->parent!=NULL && sc->parent->multilayer ) {
947 	SplineCharQuickBounds(sc,bounds);
948 return;
949     }
950 
951     bounds->minx = bounds->miny = 1e10;
952     bounds->maxx = bounds->maxy = -1e10;
953 
954     SplineSetQuickBounds(sc->layers[layer].splines,bounds);
955 
956     for ( ref = sc->layers[layer].refs; ref!=NULL; ref = ref->next ) {
957 	SplineSetQuickBounds(ref->layers[0].splines,&temp);
958 	if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
959 	    *bounds = temp;
960 	else if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
961 	    if ( temp.minx < bounds->minx ) bounds->minx = temp.minx;
962 	    if ( temp.miny < bounds->miny ) bounds->miny = temp.miny;
963 	    if ( temp.maxx > bounds->maxx ) bounds->maxx = temp.maxx;
964 	    if ( temp.maxy > bounds->maxy ) bounds->maxy = temp.maxy;
965 	}
966     }
967     /* a char with no splines (ie. a space) must have an lbearing of 0 */
968     if ( bounds->minx>1e9 )
969 	memset(bounds,0,sizeof(*bounds));
970 }
971 
SplineSetQuickConservativeBounds(SplineSet * ss,DBounds * b)972 void SplineSetQuickConservativeBounds(SplineSet *ss,DBounds *b) {
973     SplinePoint *sp;
974 
975     b->minx = b->miny = 1e10;
976     b->maxx = b->maxy = -1e10;
977     for ( ; ss!=NULL; ss=ss->next ) {
978 	for ( sp=ss->first; ; ) {
979 	    if ( sp->me.y < b->miny ) b->miny = sp->me.y;
980 	    if ( sp->me.x < b->minx ) b->minx = sp->me.x;
981 	    if ( sp->me.y > b->maxy ) b->maxy = sp->me.y;
982 	    if ( sp->me.x > b->maxx ) b->maxx = sp->me.x;
983 	    if ( sp->nextcp.y < b->miny ) b->miny = sp->nextcp.y;
984 	    if ( sp->nextcp.x < b->minx ) b->minx = sp->nextcp.x;
985 	    if ( sp->nextcp.y > b->maxy ) b->maxy = sp->nextcp.y;
986 	    if ( sp->nextcp.x > b->maxx ) b->maxx = sp->nextcp.x;
987 	    if ( sp->prevcp.y < b->miny ) b->miny = sp->prevcp.y;
988 	    if ( sp->prevcp.x < b->minx ) b->minx = sp->prevcp.x;
989 	    if ( sp->prevcp.y > b->maxy ) b->maxy = sp->prevcp.y;
990 	    if ( sp->prevcp.x > b->maxx ) b->maxx = sp->prevcp.x;
991 	    if ( sp->next==NULL )
992 	break;
993 	    sp = sp->next->to;
994 	    if ( sp==ss->first )
995 	break;
996 	}
997     }
998     if ( b->minx>65536 ) b->minx = 0;
999     if ( b->miny>65536 ) b->miny = 0;
1000     if ( b->maxx<-65536 ) b->maxx = 0;
1001     if ( b->maxy<-65536 ) b->maxy = 0;
1002 }
1003 
SplineCharQuickConservativeBounds(SplineChar * sc,DBounds * b)1004 void SplineCharQuickConservativeBounds(SplineChar *sc, DBounds *b) {
1005     RefChar *ref;
1006     int i, first,last;
1007     DBounds temp;
1008     real e;
1009     ImageList *img;
1010 
1011     memset(b,0,sizeof(*b));
1012     first = last = ly_fore;
1013     if ( sc->parent!=NULL && sc->parent->multilayer )
1014 	last = sc->layer_cnt-1;
1015     for ( i=first; i<=last; ++i ) {
1016 	SplineSetQuickConservativeBounds(sc->layers[i].splines,&temp);
1017 	for ( img=sc->layers[i].images; img!=NULL; img=img->next )
1018 	    _ImageFindBounds(img,b);
1019 	if ( sc->layers[i].dostroke && sc->layers[i].splines!=NULL ) {
1020 	    if ( sc->layers[i].stroke_pen.width!=WIDTH_INHERITED )
1021 		e = sc->layers[i].stroke_pen.width*sc->layers[i].stroke_pen.trans[0];
1022 	    else
1023 		e = sc->layers[i].stroke_pen.trans[0];
1024 	    temp.minx -= e; temp.maxx += e;
1025 	    temp.miny -= e; temp.maxy += e;
1026 	}
1027 	if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
1028 	    if ( temp.minx < b->minx ) b->minx = temp.minx;
1029 	    if ( temp.miny < b->miny ) b->miny = temp.miny;
1030 	    if ( temp.maxx > b->maxx ) b->maxx = temp.maxx;
1031 	    if ( temp.maxy > b->maxy ) b->maxy = temp.maxy;
1032 	}
1033 	for ( ref = sc->layers[i].refs; ref!=NULL; ref = ref->next ) {
1034 	    /*SplineSetQuickConservativeBounds(ref->layers[0].splines,&temp);*/
1035 	    if ( b->minx==0 && b->maxx==0 && b->miny==0 && b->maxy == 0 )
1036 		*b = ref->bb;
1037 	    else if ( ref->bb.minx!=0 || ref->bb.maxx != 0 || ref->bb.maxy != 0 || ref->bb.miny!=0 ) {
1038 		if ( ref->bb.minx < b->minx ) b->minx = ref->bb.minx;
1039 		if ( ref->bb.miny < b->miny ) b->miny = ref->bb.miny;
1040 		if ( ref->bb.maxx > b->maxx ) b->maxx = ref->bb.maxx;
1041 		if ( ref->bb.maxy > b->maxy ) b->maxy = ref->bb.maxy;
1042 	    }
1043 	}
1044     }
1045     if ( sc->parent->strokedfont && (b->minx!=b->maxx || b->miny!=b->maxy)) {
1046 	real sw = sc->parent->strokewidth;
1047 	b->minx -= sw; b->miny -= sw;
1048 	b->maxx += sw; b->maxy += sw;
1049     }
1050 }
1051 
SplineFontQuickConservativeBounds(SplineFont * sf,DBounds * b)1052 void SplineFontQuickConservativeBounds(SplineFont *sf,DBounds *b) {
1053     DBounds bb;
1054     int i;
1055 
1056     b->minx = b->miny = 1e10;
1057     b->maxx = b->maxy = -1e10;
1058     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1059 	SplineCharQuickConservativeBounds(sf->glyphs[i],&bb);
1060 	if ( bb.minx < b->minx ) b->minx = bb.minx;
1061 	if ( bb.miny < b->miny ) b->miny = bb.miny;
1062 	if ( bb.maxx > b->maxx ) b->maxx = bb.maxx;
1063 	if ( bb.maxy > b->maxy ) b->maxy = bb.maxy;
1064     }
1065     if ( b->minx>65536 ) b->minx = 0;
1066     if ( b->miny>65536 ) b->miny = 0;
1067     if ( b->maxx<-65536 ) b->maxx = 0;
1068     if ( b->maxy<-65536 ) b->maxy = 0;
1069 }
1070 
SplinePointCategory(SplinePoint * sp)1071 static int SplinePointCategory(SplinePoint *sp) {
1072     enum pointtype pt;
1073 
1074     pt = pt_corner;
1075     if ( sp->next==NULL && sp->prev==NULL )
1076 	;
1077     else if ( (sp->next!=NULL && sp->next->to->me.x==sp->me.x && sp->next->to->me.y==sp->me.y) ||
1078 	    (sp->prev!=NULL && sp->prev->from->me.x==sp->me.x && sp->prev->from->me.y==sp->me.y ))
1079 	;
1080     else if ( sp->next==NULL ) {
1081 	pt = sp->noprevcp ? pt_corner : pt_curve;
1082     } else if ( sp->prev==NULL ) {
1083 	pt = sp->nonextcp ? pt_corner : pt_curve;
1084     } else if ( sp->nonextcp && sp->noprevcp ) {
1085 	;
1086     } else {
1087 	BasePoint ndir, ncdir, ncunit, pdir, pcdir, pcunit;
1088 	bigreal nlen, nclen, plen, pclen;
1089 	bigreal cross, bounds;
1090 
1091 	ncdir.x = sp->nextcp.x - sp->me.x; ncdir.y = sp->nextcp.y - sp->me.y;
1092 	pcdir.x = sp->prevcp.x - sp->me.x; pcdir.y = sp->prevcp.y - sp->me.y;
1093 	ndir.x = ndir.y = pdir.x = pdir.y = 0;
1094 	if ( sp->next!=NULL ) {
1095 	    ndir.x = sp->next->to->me.x - sp->me.x; ndir.y = sp->next->to->me.y - sp->me.y;
1096 	}
1097 	if ( sp->prev!=NULL ) {
1098 	    pdir.x = sp->prev->from->me.x - sp->me.x; pdir.y = sp->prev->from->me.y - sp->me.y;
1099 	}
1100 	nclen = sqrt(ncdir.x*ncdir.x + ncdir.y*ncdir.y);
1101 	pclen = sqrt(pcdir.x*pcdir.x + pcdir.y*pcdir.y);
1102 	nlen = sqrt(ndir.x*ndir.x + ndir.y*ndir.y);
1103 	plen = sqrt(pdir.x*pdir.x + pdir.y*pdir.y);
1104 	ncunit = ncdir; pcunit = pcdir;
1105 	if ( nclen!=0 ) { ncunit.x /= nclen; ncunit.y /= nclen; }
1106 	if ( pclen!=0 ) { pcunit.x /= pclen; pcunit.y /= pclen; }
1107 	if ( nlen!=0 ) { ndir.x /= nlen; ndir.y /= nlen; }
1108 	if ( plen!=0 ) { pdir.x /= plen; pdir.y /= plen; }
1109 
1110 	/* find out which side has the shorter control vector. Cross that vector */
1111 	/*  with the normal of the unit vector on the other side. If the */
1112 	/*  result is less than 1 em-unit then we've got colinear control points */
1113 	/*  (within the resolution of the integer grid) */
1114 	/* Not quite... they could point in the same direction */
1115         if ( sp->pointtype==pt_curve )
1116             bounds = 4.0;
1117         else
1118             bounds = 1.0;
1119 	if ( nclen!=0 && pclen!=0 &&
1120 		((nclen>=pclen && (cross = pcdir.x*ncunit.y - pcdir.y*ncunit.x)<bounds && cross>-bounds ) ||
1121 		 (pclen>nclen && (cross = ncdir.x*pcunit.y - ncdir.y*pcunit.x)<bounds && cross>-bounds )) &&
1122 		 ncdir.x*pcdir.x + ncdir.y*pcdir.y < 0 )
1123 	    pt = pt_curve;
1124 	/* Cross product of control point with unit vector normal to line in */
1125 	/*  opposite direction should be less than an em-unit for a tangent */
1126 	else if (    (   nclen==0 && pclen!=0
1127 	              && (cross = pcdir.x*ndir.y-pcdir.y*ndir.x)<bounds
1128 	              && cross>-bounds && (pcdir.x*ndir.x+pcdir.y*ndir.y)<0 )
1129 	          ||
1130 	             (   pclen==0 && nclen!=0
1131 	              && (cross = ncdir.x*pdir.y-ncdir.y*pdir.x)<bounds
1132 	              && cross>-bounds && (ncdir.x*pdir.x+ncdir.y*pdir.y)<0 ) )
1133 	    pt = pt_tangent;
1134 
1135 	if (pt == pt_curve &&
1136 		((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) ||
1137 		 (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x)))
1138 	    pt = pt_hvcurve;
1139     }
1140     return pt;
1141 }
1142 
SplinePointIsACorner(SplinePoint * sp)1143 int SplinePointIsACorner(SplinePoint *sp) {
1144 	return SplinePointCategory(sp) == pt_corner;
1145 }
1146 
SplinePointDowngrade(int current,int geom)1147 static enum pointtype SplinePointDowngrade(int current, int geom) {
1148 	enum pointtype np = current;
1149 
1150 	if ( current==pt_curve && geom!=pt_curve ) {
1151 		if ( geom==pt_hvcurve )
1152 			np = pt_curve;
1153 		else
1154 			np = pt_corner;
1155 	} else if ( current==pt_hvcurve && geom!=pt_hvcurve ) {
1156 		if ( geom==pt_curve )
1157 			np = pt_curve;
1158 		else
1159 			np = pt_corner;
1160 	} else if ( current==pt_tangent && geom!=pt_tangent ) {
1161 		np = pt_corner;
1162 	}
1163 
1164 	return np;
1165 }
1166 
1167 // Assumes flag combinations are already verified. Only returns false
1168 // when called with check_compat
_SplinePointCategorize(SplinePoint * sp,int flags)1169 int _SplinePointCategorize(SplinePoint *sp, int flags) {
1170 	enum pointtype geom, dg, cur;
1171 
1172 	if ( flags & pconvert_flag_none )
1173 		// No points selected for conversion -- keep type as is
1174 		return true;
1175 	if ( flags & pconvert_flag_smooth && sp->pointtype == pt_corner )
1176 		// Convert only "smooth" points, not corners
1177 		return true;
1178 
1179 	geom = SplinePointCategory(sp);
1180 	dg = SplinePointDowngrade(sp->pointtype, geom);
1181 
1182 	if ( flags & pconvert_flag_incompat && sp->pointtype == dg )
1183 		// Only convert points incompatible with current type
1184 		return true;
1185 
1186 	if ( flags & pconvert_flag_by_geom ) {
1187 		if ( ! ( flags & pconvert_flag_hvcurve ) && geom == pt_hvcurve )
1188 			sp->pointtype = pt_curve;
1189 		else
1190 			sp->pointtype = geom;
1191 	} else if ( flags & pconvert_flag_downgrade ) {
1192 		sp->pointtype = dg;
1193 	} else if ( flags & pconvert_flag_force_type ) {
1194 		if ( sp->pointtype != dg ) {
1195 			cur = sp->pointtype;
1196 			sp->pointtype = dg;
1197 			SPChangePointType(sp,cur);
1198 		}
1199 	} else if ( flags & pconvert_flag_check_compat ) {
1200 		if ( sp->pointtype != dg )
1201 			return false;
1202 	}
1203 	return true;
1204 }
1205 
SplinePointCategorize(SplinePoint * sp)1206 void SplinePointCategorize(SplinePoint *sp) {
1207 	_SplinePointCategorize(sp, pconvert_flag_all|pconvert_flag_by_geom);
1208 }
1209 
1210 // _SplinePointCategorize only returns false when called with check_compat flag,
1211 // in which case no point values are altered and the "early" return will not leave
1212 // splines partially adjusted.
_SPLCategorizePoints(SplinePointList * spl,int flags)1213 int _SPLCategorizePoints(SplinePointList *spl, int flags) {
1214     Spline *spline, *first, *last=NULL;
1215     int ok = true;
1216 
1217     for ( ; spl!=NULL; spl = spl->next ) {
1218 	first = NULL;
1219 	for ( spline = spl->first->next; spline!=NULL && spline!=first && ok; spline=spline->to->next ) {
1220 	    ok = _SplinePointCategorize(spline->from, flags);
1221 	    last = spline;
1222 	    if ( first==NULL ) first = spline;
1223 	}
1224 	if ( spline==NULL && last!=NULL && ok )
1225 	    _SplinePointCategorize(last->to, flags);
1226     }
1227     return ok;
1228 }
1229 
SPLCategorizePoints(SplinePointList * spl)1230 void SPLCategorizePoints(SplinePointList *spl) {
1231 	_SPLCategorizePoints(spl, pconvert_flag_all|pconvert_flag_by_geom);
1232 }
1233 
SCCategorizePoints(SplineChar * sc)1234 void SCCategorizePoints(SplineChar *sc) {
1235     int i;
1236     for ( i=ly_fore; i<sc->layer_cnt; ++i )
1237 	SPLCategorizePoints(sc->layers[i].splines);
1238 }
1239 
CharsNotInEncoding(FontDict * fd)1240 static int CharsNotInEncoding(FontDict *fd) {
1241     int i, cnt, j;
1242 
1243     for ( i=cnt=0; i<fd->chars->cnt; ++i ) {
1244 	if ( fd->chars->keys[i]!=NULL ) {
1245 	    for ( j=0; j<256; ++j )
1246 		if ( fd->encoding[j]!=NULL &&
1247 			strcmp(fd->encoding[j],fd->chars->keys[i])==0 )
1248 	    break;
1249 	    if ( j==256 )
1250 		++cnt;
1251 	}
1252     }
1253     /* And for type 3 fonts... */
1254     if ( fd->charprocs!=NULL ) for ( i=0; i<fd->charprocs->cnt; ++i ) {
1255 	if ( fd->charprocs->keys[i]!=NULL ) {
1256 	    for ( j=0; j<256; ++j )
1257 		if ( fd->encoding[j]!=NULL &&
1258 			strcmp(fd->encoding[j],fd->charprocs->keys[i])==0 )
1259 	    break;
1260 	    if ( j==256 )
1261 		++cnt;
1262 	}
1263     }
1264 return( cnt );
1265 }
1266 
LookupCharString(char * encname,struct pschars * chars)1267 static int LookupCharString(char *encname,struct pschars *chars) {
1268     int k;
1269 
1270     if ( encname==NULL ) encname = ".notdef";	/* In case of an incomplete encoding array */
1271 
1272     for ( k=0; k<chars->cnt; ++k ) {
1273 	if ( chars->keys[k]!=NULL )
1274 	    if ( strcmp(encname,chars->keys[k])==0 )
1275 return( k );
1276     }
1277 return( -1 );
1278 }
1279 
SplinePointListCopy1(const SplinePointList * spl)1280 SplinePointList *SplinePointListCopy1(const SplinePointList *spl) {
1281     SplinePointList *cur;
1282     const SplinePoint *pt; SplinePoint *cpt;
1283     Spline *spline;
1284 
1285     cur = chunkalloc(sizeof(SplinePointList));
1286     cur->is_clip_path = spl->is_clip_path;
1287     cur->spiro_cnt = cur->spiro_max = 0;
1288     cur->spiros = 0;
1289     if (spl->contour_name != NULL) cur->contour_name = copy(spl->contour_name);
1290     for ( pt=spl->first; ;  ) {
1291 	cpt = SplinePointCreate( 0, 0 );
1292 	*cpt = *pt;
1293 	if ( pt->hintmask!=NULL ) {
1294 	    cpt->hintmask = chunkalloc(sizeof(HintMask));
1295 	    memcpy(cpt->hintmask,pt->hintmask,sizeof(HintMask));
1296 	}
1297 	if ( pt->name!=NULL ) {
1298 		cpt->name = copy(pt->name);
1299 	}
1300 	cpt->next = cpt->prev = NULL;
1301 	if ( cur->first==NULL ) {
1302 	    cur->first = cur->last = cpt;
1303 	    cur->start_offset = 0;
1304 	} else {
1305 	    spline = chunkalloc(sizeof(Spline));
1306 	    *spline = *pt->prev;
1307 	    spline->from = cur->last;
1308 	    cur->last->next = spline;
1309 	    cpt->prev = spline;
1310 	    spline->to = cpt;
1311 	    spline->approx = NULL;
1312 	    cur->last = cpt;
1313 	}
1314 	if ( pt->next==NULL )
1315     break;
1316 	pt = pt->next->to;
1317 	if ( pt==spl->first )
1318     break;
1319     }
1320     if ( spl->first->prev!=NULL ) {
1321 	cpt = cur->first;
1322 	spline = chunkalloc(sizeof(Spline));
1323 	*spline = *pt->prev;
1324 	spline->from = cur->last;
1325 	cur->last->next = spline;
1326 	cpt->prev = spline;
1327 	spline->to = cpt;
1328 	spline->approx = NULL;
1329 	cur->last = cpt;
1330     }
1331     if ( spl->spiro_cnt!=0 ) {
1332 	cur->spiro_cnt = cur->spiro_max = spl->spiro_cnt;
1333 	cur->spiros = malloc(cur->spiro_cnt*sizeof(spiro_cp));
1334 	memcpy(cur->spiros,spl->spiros,cur->spiro_cnt*sizeof(spiro_cp));
1335     }
1336 return( cur );
1337 }
1338 
1339 /* If this routine is called we are guarenteed that:
1340     at least one point on the splineset is selected
1341     not all points on the splineset are selected
1342 */
SplinePointListCopySelected1(SplinePointList * spl)1343 static SplinePointList *SplinePointListCopySelected1(SplinePointList *spl) {
1344     SplinePointList *head=NULL, *last=NULL, *cur;
1345     SplinePoint *cpt, *first, *start;
1346     Spline *spline;
1347 
1348     start = spl->first;
1349     if ( spl->first==spl->last ) {
1350 	/* If it's a closed contour and the start point is selected then we */
1351 	/*  don't know where that selection began (and we have to keep it with */
1352 	/*  the things that precede it when we make the new splinesets), so */
1353 	/*  loop until we find something unselected */
1354 	while ( start->selected )
1355 	    start = start->next->to;
1356     }
1357     first = NULL;
1358     while ( start != NULL && start!=first ) {
1359 	while ( start!=NULL && start!=first && !start->selected ) {
1360 	    if ( first==NULL ) first = start;
1361 	    if ( start->next==NULL ) {
1362 		start = NULL;
1363 	break;
1364 	    }
1365 	    start = start->next->to;
1366 	}
1367 	if ( start==NULL || start==first )
1368     break;
1369 	cur = chunkalloc(sizeof(SplinePointList));
1370 	if ( head==NULL )
1371 	    head = cur;
1372 	else
1373 	    last->next = cur;
1374 	last = cur;
1375 
1376 	while ( start!=NULL && start->selected && start!=first ) {
1377 	    cpt = chunkalloc(sizeof(SplinePoint));
1378 	    *cpt = *start;
1379 	    cpt->hintmask = NULL;
1380 		cpt->name = NULL;
1381 	    cpt->next = cpt->prev = NULL;
1382 	    if ( cur->first==NULL ) {
1383 		cur->first = cur->last = cpt;
1384 		cur->start_offset = 0;
1385 	    } else {
1386 		spline = chunkalloc(sizeof(Spline));
1387 		*spline = *start->prev;
1388 		spline->from = cur->last;
1389 		cur->last->next = spline;
1390 		cpt->prev = spline;
1391 		spline->to = cpt;
1392 		spline->approx = NULL;
1393 		cur->last = cpt;
1394 	    }
1395 	    if ( first==NULL ) first = start;
1396 	    if ( start->next==NULL ) {
1397 		start = NULL;
1398 	break;
1399 	    }
1400 	    start = start->next->to;
1401 	}
1402     }
1403 return( head );
1404 }
1405 
1406 /* If this routine is called we are guarenteed that:
1407     at least one point on the splineset is selected
1408     not all points on the splineset are selected
1409 */
SplinePointListCopySpiroSelected1(SplinePointList * spl)1410 static SplinePointList *SplinePointListCopySpiroSelected1(SplinePointList *spl) {
1411     SplinePointList *head=NULL, *last=NULL, *cur;
1412     int i,j;
1413     spiro_cp *list = spl->spiros, *freeme = NULL, *temp = NULL;
1414 
1415     if ( !SPIRO_SPL_OPEN(spl)) {
1416 	/* If it's a closed contour and the start point is selected then we */
1417 	/*  don't know where that selection began (and we have to keep it with */
1418 	/*  the things that precede it when we make the new splinesets), so */
1419 	/*  loop until we find something unselected */
1420 	for ( i=0 ; i<spl->spiro_cnt-1; ++i )
1421 	    if ( !(SPIRO_SELECTED(&list[i])) )
1422 	break;
1423 	if ( i!=0 ) {
1424 	    freeme = malloc(spl->spiro_cnt*sizeof(spiro_cp));
1425 	    memcpy(freeme,list+i,(spl->spiro_cnt-1-i)*sizeof(spiro_cp));
1426 	    memcpy(freeme+(spl->spiro_cnt-1-i),list,i*sizeof(spiro_cp));
1427 	    /* And copy the list terminator */
1428 	    memcpy(freeme+spl->spiro_cnt-1,list+spl->spiro_cnt-1,sizeof(spiro_cp));
1429 	    list = freeme;
1430 	}
1431     }
1432     for ( i=0 ; i<spl->spiro_cnt-1; ) {
1433 	/* Skip unselected things */
1434 	for ( ; i<spl->spiro_cnt-1 && !SPIRO_SELECTED(&list[i]); ++i );
1435 	if ( i==spl->spiro_cnt-1 )
1436     break;
1437 	for ( j=i; j<spl->spiro_cnt-1 && SPIRO_SELECTED(&list[j]); ++j );
1438 	temp = malloc((j-i+2)*sizeof(spiro_cp));
1439 	memcpy(temp,list+i,(j-i)*sizeof(spiro_cp));
1440 	temp[0].ty = SPIRO_OPEN_CONTOUR;
1441 	memset(temp+(j-i),0,sizeof(spiro_cp));
1442 	temp[j-i].ty = SPIRO_END;
1443 	cur = SpiroCP2SplineSet( temp );
1444 	if ( head==NULL )
1445 	    head = cur;
1446 	else
1447 	    last->next = cur;
1448 	last = cur;
1449 	i = j;
1450     }
1451 return( head );
1452 }
1453 
SplinePointListCheckSelected1(const SplinePointList * base,bool spiro,bool * allsel,bool skip_spiro_end)1454 bool SplinePointListCheckSelected1(const SplinePointList *base, bool spiro, bool *allsel, bool skip_spiro_end) {
1455     bool anysel = false;
1456     if (allsel) {
1457         *allsel = true;
1458     }
1459     if (spiro) {
1460         for (int i = 0; i < base->spiro_cnt-(skip_spiro_end?1:0); ++i) {
1461             if (SPIRO_SELECTED(&base->spiros[i])) {
1462                 anysel = true;
1463                 if (!allsel) {
1464                     return anysel;
1465                 }
1466             } else if (allsel) {
1467                 *allsel = false;
1468             }
1469         }
1470     } else {
1471         SplinePoint *first = NULL, *pt;
1472         for (pt = base->first; pt != NULL && pt != first; pt = pt->next->to) {
1473             if (pt->selected) {
1474                 anysel = true;
1475                 if (!allsel) {
1476                     return anysel;
1477                 }
1478             } else if (allsel) {
1479                 *allsel = false;
1480             }
1481             if (first == NULL)
1482                 first = pt;
1483             if (pt->next == NULL)
1484                 break;
1485         }
1486     }
1487     return anysel;
1488 }
1489 
SplinePointListCopy(const SplinePointList * base)1490 SplinePointList *SplinePointListCopy(const SplinePointList *base) {
1491     SplinePointList *head=NULL, *last=NULL, *cur;
1492 
1493     for ( ; base!=NULL; base = base->next ) {
1494 	cur = SplinePointListCopy1(base);
1495 	if ( head==NULL )
1496 	    head = cur;
1497 	else
1498 	    last->next = cur;
1499 	last = cur;
1500     }
1501 return( head );
1502 }
1503 
SplinePointListCopySelected(SplinePointList * base)1504 SplinePointList *SplinePointListCopySelected(SplinePointList *base) {
1505     SplinePointList *head=NULL, *last=NULL, *cur=NULL;
1506     SplinePoint *pt, *first;
1507     bool anysel, allsel;
1508 
1509     for ( ; base!=NULL; base = base->next ) {
1510 	anysel = SplinePointListCheckSelected1(base, false, &allsel, false);
1511 	if ( allsel )
1512 	    cur = SplinePointListCopy1(base);
1513 	else if ( anysel )
1514 	    cur = SplinePointListCopySelected1(base);
1515 	if ( anysel ) {
1516 	    if ( head==NULL )
1517 		head = cur;
1518 	    else
1519 		last->next = cur;
1520 	    for ( last = cur; last->next ; last = last->next );
1521 	}
1522     }
1523 return( head );
1524 }
1525 
SplinePointListCopySpiroSelected(SplinePointList * base)1526 SplinePointList *SplinePointListCopySpiroSelected(SplinePointList *base) {
1527     SplinePointList *head=NULL, *last=NULL, *cur=NULL;
1528     bool anysel, allsel;
1529     int i;
1530 
1531     for ( ; base!=NULL; base = base->next ) {
1532 	anysel = SplinePointListCheckSelected1(base, true, &allsel, true);
1533 	if ( allsel )
1534 	    cur = SplinePointListCopy1(base);
1535 	else if ( anysel )
1536 	    cur = SplinePointListCopySpiroSelected1(base);
1537 	if ( anysel ) {
1538 	    if ( head==NULL )
1539 		head = cur;
1540 	    else
1541 		last->next = cur;
1542 	    for ( last = cur; last->next ; last = last->next );
1543 	}
1544     }
1545 return( head );
1546 }
1547 
SplinePointListSplitSpiros(SplineChar * sc,SplinePointList * spl)1548 static SplinePointList *SplinePointListSplitSpiros(SplineChar *sc,SplinePointList *spl) {
1549     SplinePointList *head=NULL, *last=NULL, *cur;
1550     int i;
1551     spiro_cp *list = spl->spiros, *freeme = NULL, *temp = NULL;
1552 
1553     if ( !SPIRO_SPL_OPEN(spl)) {
1554 	/* If it's a closed contour and the start point is selected then we */
1555 	/*  don't know where that selection began (and we have to keep it with */
1556 	/*  the things that precede it when we make the new splinesets), so */
1557 	/*  loop until we find something unselected */
1558 	for ( i=0 ; i<spl->spiro_cnt-1; ++i )
1559 	    if ( !(SPIRO_SELECTED(&list[i])) )
1560 	break;
1561 	if ( i!=0 ) {
1562 	    freeme = malloc(spl->spiro_cnt*sizeof(spiro_cp));
1563 	    memcpy(freeme,list+i,(spl->spiro_cnt-1-i)*sizeof(spiro_cp));
1564 	    memcpy(freeme+(spl->spiro_cnt-1-i),list,i*sizeof(spiro_cp));
1565 	    /* And copy the list terminator */
1566 	    memcpy(freeme+spl->spiro_cnt-1,list+spl->spiro_cnt-1,sizeof(spiro_cp));
1567 	    list = freeme;
1568 	}
1569     }
1570     for ( i=0 ; i<spl->spiro_cnt-1; ) {
1571 	int start = i;
1572 	/* Retain unselected things */
1573 	for ( ; i<spl->spiro_cnt-1 && !SPIRO_SELECTED(&list[i]); ++i );
1574 	if ( i!=start ) {
1575 	    temp = malloc((i-start+2)*sizeof(spiro_cp));
1576 	    memcpy(temp,list+start,(i-start)*sizeof(spiro_cp));
1577 	    temp[0].ty = SPIRO_OPEN_CONTOUR;
1578 	    memset(temp+(i-start),0,sizeof(spiro_cp));
1579 	    temp[i-start].ty = SPIRO_END;
1580 	    cur = SpiroCP2SplineSet( temp );
1581 	    if ( head==NULL )
1582 		head = cur;
1583 	    else
1584 		last->next = cur;
1585 	    last = cur;
1586 	}
1587 	for ( ; i<spl->spiro_cnt-1 && SPIRO_SELECTED(&list[i]); ++i );
1588     }
1589     SplinePointListFree(spl);
1590 return( head );
1591 }
1592 
SplinePointListSplit(SplineChar * sc,SplinePointList * spl)1593 static SplinePointList *SplinePointListSplit(SplineChar *sc,SplinePointList *spl) {
1594     SplinePointList *head=NULL, *last=NULL, *cur;
1595     SplinePoint *first, *start, *next;
1596 
1597     start = spl->first;
1598     if ( spl->first==spl->last ) {
1599 	/* If it's a closed contour and the start point is selected then we */
1600 	/*  don't know where that selection began (and we have to keep it with */
1601 	/*  the things that precede it when we make the new splinesets), so */
1602 	/*  loop until we find something unselected */
1603 	while ( !start->selected )
1604 	    start = start->next->to;
1605     }
1606     first = NULL;
1607     while ( start != NULL && start!=first ) {
1608 	while ( start!=NULL && start!=first && start->selected ) {
1609 	    if ( first==NULL ) first = start;
1610 	    if ( start->prev!=NULL ) {
1611 		start->prev->from->next = NULL;
1612 		SplineFree(start->prev);
1613 	    }
1614 	    if ( start->next!=NULL ) {
1615 		next = start->next->to;
1616 		next->prev = NULL;
1617 		SplineFree(start->next);
1618 	    } else
1619 		next = NULL;
1620 	    SplinePointMDFree(sc,start);
1621 	    start = next;
1622 	}
1623 	if ( start==NULL || start==first )
1624     break;
1625 	if ( head==NULL ) {
1626 	    head = cur = spl;
1627 	    spl->first = spl->last = NULL;
1628 	    spl->start_offset = 0;
1629 	} else {
1630 	    cur = chunkalloc(sizeof(SplinePointList));
1631 	    last->next = cur;
1632 	}
1633 	last = cur;
1634 
1635 	while ( start!=NULL && !start->selected && start!=first ) {
1636 	    if ( cur->first==NULL ) {
1637 		cur->first = start;
1638 		cur->start_offset = 0;
1639 	    }
1640 	    cur->last = start;
1641 	    if ( start->next!=NULL ) {
1642 		next = start->next->to;
1643 		if ( next->selected ) {
1644 		    SplineFree(start->next);
1645 		    start->next = NULL;
1646 		    next->prev = NULL;
1647 		}
1648 	    } else
1649 		next = NULL;
1650 	    if ( first==NULL ) first = start;
1651 	    start = next;
1652 	}
1653     }
1654 return( last );
1655 }
1656 
SplinePointListRemoveSelected(SplineChar * sc,SplinePointList * base)1657 SplinePointList *SplinePointListRemoveSelected(SplineChar *sc,SplinePointList *base) {
1658     SplinePointList *head=NULL, *last=NULL, *next;
1659     SplinePoint *pt, *first;
1660     bool anysel, allsel;
1661 
1662     for ( ; base!=NULL; base = next ) {
1663 	next = base->next;
1664 	anysel = SplinePointListCheckSelected1(base, sc->inspiro && hasspiro(), &allsel, false);
1665 	if ( allsel ) {
1666 	    SplinePointListMDFree(sc,base);
1667     continue;
1668 	}
1669 	if ( !sc->inspiro || !anysel || !hasspiro()) {
1670 	    if ( head==NULL )
1671 		head = base;
1672 	    else
1673 		last->next = base;
1674 	    last = base;
1675 	    if ( anysel )
1676 		last = SplinePointListSplit(sc,base);
1677 	} else {
1678 	    SplineSet *ret;
1679 	    ret = SplinePointListSplitSpiros(sc,base);
1680 	    if ( head==NULL )
1681 		head = ret;
1682 	    else
1683 		last->next = ret;
1684 	    if ( ret!=NULL )
1685 		for ( last=ret; last->next!=NULL; last=last->next );
1686 	}
1687     }
1688     if ( last!=NULL ) last->next = NULL;
1689 return( head );
1690 }
1691 
ImageListCopy(ImageList * cimg)1692 ImageList *ImageListCopy(ImageList *cimg) {
1693     ImageList *head=NULL, *last=NULL, *new;
1694 
1695     for ( ; cimg!=NULL; cimg=cimg->next ) {
1696 	new = chunkalloc(sizeof(ImageList));
1697 	*new = *cimg;
1698 	new->next = NULL;
1699 	if ( last==NULL )
1700 	    head = last = new;
1701 	else {
1702 	    last->next = new;
1703 	    last = new;
1704 	}
1705     }
1706 return( head );
1707 }
1708 
ImageListTransform(ImageList * img,real transform[6],int everything)1709 ImageList *ImageListTransform(ImageList *img, real transform[6],int everything) {
1710     ImageList *head = img;
1711 
1712 	/* Don't support rotating, flipping or skewing images */;
1713     if ( transform[0]!=0 && transform[3]!=0 ) {
1714 	while ( img!=NULL ) {
1715 	    if ( everything || (!everything && img->selected)) {
1716 		bigreal x = img->xoff;
1717 		img->xoff = transform[0]*x + transform[2]*img->yoff + transform[4];
1718 		img->yoff = transform[1]*x + transform[3]*img->yoff + transform[5];
1719 		if (( img->xscale *= transform[0])<0 ) {
1720 		    img->xoff += img->xscale *
1721 			(img->image->list_len==0?img->image->u.image:img->image->u.images[0])->width;
1722 		    img->xscale = -img->xscale;
1723 		}
1724 		if (( img->yscale *= transform[3])<0 ) {
1725 		    img->yoff += img->yscale *
1726 			(img->image->list_len==0?img->image->u.image:img->image->u.images[0])->height;
1727 		    img->yscale = -img->yscale;
1728 		}
1729 		img->bb.minx = img->xoff; img->bb.maxy = img->yoff;
1730 		img->bb.maxx = img->xoff + GImageGetWidth(img->image)*img->xscale;
1731 		img->bb.miny = img->yoff - GImageGetHeight(img->image)*img->yscale;
1732 	    }
1733 	    img = img->next;
1734 	}
1735     }
1736 return( head );
1737 }
1738 
_BpTransform(BasePoint * to,BasePoint * from,real transform[6],enum transformPointMask tpmask)1739 static void _BpTransform(BasePoint *to, BasePoint *from, real transform[6], enum transformPointMask tpmask) {
1740     BasePoint p;
1741     p.x = transform[0]*from->x + transform[2]*from->y + transform[4];
1742     p.y = transform[1]*from->x + transform[3]*from->y + transform[5];
1743     if ( ! (tpmask & tpmask_dontTrimValues ) ) {
1744 	to->x = rint(1024*p.x)/1024;
1745 	to->y = rint(1024*p.y)/1024;
1746     } else {
1747 	to->x = p.x;
1748 	to->y = p.y;
1749     }
1750 }
1751 
BpTransform(BasePoint * to,BasePoint * from,real transform[6])1752 void BpTransform(BasePoint *to, BasePoint *from, real transform[6]) {
1753     _BpTransform(to, from, transform, 0);
1754 }
1755 
ApTransform(AnchorPoint * ap,real transform[6])1756 void ApTransform(AnchorPoint *ap, real transform[6]) {
1757     BpTransform(&ap->me,&ap->me,transform);
1758 }
1759 
TransformPointExtended(SplinePoint * sp,real transform[6],enum transformPointMask tpmask)1760 static void TransformPointExtended(SplinePoint *sp, real transform[6], enum transformPointMask tpmask )
1761 {
1762     /**
1763      * If we are to transform selected BCP instead of their base splinepoint
1764      * then lets do that.
1765      */
1766     if( tpmask & tpmask_operateOnSelectedBCP
1767 	&& (sp->nextcpselected || sp->prevcpselected ))
1768     {
1769 	if( sp->nextcpselected )
1770 	{
1771 	    int order2 = sp->next ? sp->next->order2 : 0;
1772 	    _BpTransform(&sp->nextcp,&sp->nextcp,transform,tpmask);
1773 	    SPTouchControl( sp, &sp->nextcp, order2 );
1774 	}
1775 	else if( sp->prevcpselected )
1776 	{
1777 	    int order2 = sp->next ? sp->next->order2 : 0;
1778 	    _BpTransform(&sp->prevcp,&sp->prevcp,transform,tpmask);
1779 	    SPTouchControl( sp, &sp->prevcp, order2 );
1780 	}
1781     }
1782     else
1783     {
1784 	/**
1785 	 * Transform the base splinepoints.
1786 	 */
1787 	_BpTransform(&sp->me,&sp->me,transform,tpmask);
1788 
1789 	if ( !sp->nonextcp )
1790 	{
1791 	    _BpTransform(&sp->nextcp,&sp->nextcp,transform,tpmask);
1792 	}
1793 	else
1794 	{
1795 	    sp->nextcp = sp->me;
1796 	}
1797 
1798 	if ( !sp->noprevcp )
1799 	{
1800 	    _BpTransform(&sp->prevcp,&sp->prevcp,transform,tpmask);
1801 	}
1802 	else
1803 	{
1804 	    sp->prevcp = sp->me;
1805 	}
1806     }
1807 
1808 
1809 
1810     if ( sp->pointtype == pt_hvcurve )
1811     {
1812 	if(
1813 	    ((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) ||
1814 	     (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x)))
1815 	{
1816 	    /* Do Nothing */;
1817 	}
1818 	else
1819 	{
1820 	    sp->pointtype = pt_curve;
1821 	}
1822     }
1823 }
1824 
TransformPoint(SplinePoint * sp,real transform[6])1825 static void TransformPoint(SplinePoint *sp, real transform[6])
1826 {
1827     TransformPointExtended( sp, transform, 0 );
1828 }
1829 
TransformSpiro(spiro_cp * cp,real transform[6])1830 static void TransformSpiro(spiro_cp *cp, real transform[6]) {
1831     bigreal x;
1832 
1833     x = transform[0]*cp->x + transform[2]*cp->y + transform[4];
1834     cp->y = transform[1]*cp->x + transform[3]*cp->y + transform[5];
1835     cp->x = x;
1836 }
1837 
TransformPTsInterpolateCPs(BasePoint * fromorig,Spline * spline,BasePoint * toorig,real transform[6],enum transformPointMask tpmask)1838 static void TransformPTsInterpolateCPs(BasePoint *fromorig,Spline *spline,
1839 	BasePoint *toorig,real transform[6], enum transformPointMask tpmask ) {
1840     BasePoint totrans, temp;
1841     bigreal fraction;
1842 
1843     /* Normally the "from" point will already have been translated, and the "to" */
1844     /*  point will need to be. But if we have a closed contour then on the */
1845     /*  last spline both from and to will have been transform. We can detect */
1846     /*  this because toorig will be different from &spline->to->me */
1847     if ( spline->to->selected && toorig==&spline->to->me )
1848 	_BpTransform(&totrans,&spline->to->me,transform,tpmask);
1849     else
1850 	totrans = spline->to->me;
1851 
1852     /* None of the control points will have been transformed yet */
1853     if ( fromorig->x!=toorig->x ) {
1854 	fraction = (spline->from->nextcp.x-fromorig->x)/( toorig->x-fromorig->x );
1855 	spline->from->nextcp.x = spline->from->me.x + fraction*( totrans.x-spline->from->me.x );
1856 	fraction = (spline->to->prevcp.x-fromorig->x)/( toorig->x-fromorig->x );
1857 	spline->to->prevcp.x = spline->from->me.x + fraction*( totrans.x-spline->from->me.x );
1858     } else {
1859 	_BpTransform(&temp,&spline->from->nextcp,transform,tpmask);
1860 	spline->from->nextcp.x = temp.x;
1861 	_BpTransform(&temp,&spline->to->prevcp,transform,tpmask);
1862 	spline->to->prevcp.x = temp.x;
1863     }
1864     if ( fromorig->y!=toorig->y ) {
1865 	fraction = (spline->from->nextcp.y-fromorig->y)/( toorig->y-fromorig->y );
1866 	spline->from->nextcp.y = spline->from->me.y + fraction*( totrans.y-spline->from->me.y );
1867 	fraction = (spline->to->prevcp.y-fromorig->y)/( toorig->y-fromorig->y );
1868 	spline->to->prevcp.y = spline->from->me.y + fraction*( totrans.y-spline->from->me.y );
1869     } else {
1870 	_BpTransform(&temp,&spline->from->nextcp,transform,tpmask);
1871 	spline->from->nextcp.y = temp.y;
1872 	_BpTransform(&temp,&spline->to->prevcp,transform,tpmask);
1873 	spline->to->prevcp.y = temp.y;
1874     }
1875 
1876     if ( spline->to->selected )
1877 	spline->to->me = totrans;
1878 }
1879 
1880 
SplinePointListTransformExtended(SplinePointList * base,real transform[6],enum transformPointType tpt,enum transformPointMask tpmask)1881 SplinePointList *SplinePointListTransformExtended(SplinePointList *base, real transform[6],
1882 						  enum transformPointType tpt, enum transformPointMask tpmask ) {
1883     Spline *spline, *first;
1884     SplinePointList *spl;
1885     SplinePoint *spt, *pfirst;
1886     int allsel, anysel, alldone=true;
1887     BasePoint lastpointorig, firstpointorig, orig;
1888 
1889     for ( spl = base; spl!=NULL; spl = spl->next ) {
1890 	pfirst = NULL; first = NULL;
1891 	allsel = true; anysel=false;
1892 	if ( tpt==tpt_OnlySelectedInterpCPs && spl->first->next!=NULL && !spl->first->next->order2 ) {
1893 	    lastpointorig = firstpointorig = spl->first->me;
1894 	    printf("SplinePointListTransformExtended() spl->first->selected %d\n", spl->first->selected );
1895 	    if ( spl->first->selected ) {
1896 		anysel = true;
1897 		_BpTransform(&spl->first->me,&spl->first->me,transform,tpmask);
1898 	    } else
1899 		allsel = false;
1900 	    for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1901 		if ( first==NULL ) first = spline;
1902 		orig = spline->to->me;
1903 		if ( spline->from->selected || spline->to->selected )
1904 		{
1905 		    TransformPTsInterpolateCPs( &lastpointorig, spline,
1906 						spl->first==spline->to? &firstpointorig : &spline->to->me,
1907 						transform, tpmask );
1908 		}
1909 		lastpointorig = orig;
1910 		if ( spline->to->selected ) anysel = true; else allsel = false;
1911 	    }
1912 
1913 	} else {
1914 	    for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to ) {
1915 		if ( pfirst==NULL ) pfirst = spt;
1916 		if ( tpt==tpt_AllPoints || spt->selected ) {
1917 		    TransformPointExtended(spt,transform,tpmask);
1918 		    if ( tpt!=tpt_AllPoints ) {
1919 			if ( spt->next!=NULL && spt->next->order2 && !spt->next->to->selected && spt->next->to->ttfindex==0xffff ) {
1920 			    SplinePoint *to = spt->next->to;
1921 			    to->prevcp = spt->nextcp;
1922 			    to->me.x = (to->prevcp.x+to->nextcp.x)/2;
1923 			    to->me.y = (to->prevcp.y+to->nextcp.y)/2;
1924 			}
1925 			if ( spt->prev!=NULL && spt->prev->order2 && !spt->prev->from->selected && spt->prev->from->ttfindex==0xffff ) {
1926 			    SplinePoint *from = spt->prev->from;
1927 			    from->nextcp = spt->prevcp;
1928 			    from->me.x = (from->prevcp.x+from->nextcp.x)/2;
1929 			    from->me.y = (from->prevcp.y+from->nextcp.y)/2;
1930 			}
1931 		    }
1932 		    anysel = true;
1933 		} else
1934 		    allsel = alldone = false;
1935 		if ( spt->next==NULL )
1936 	    break;
1937 	    }
1938 	}
1939 	if ( !anysel )		/* This splineset had no selected points it's unchanged */
1940     continue;
1941 
1942 	/* If we changed all the points, then transform the spiro version too */
1943 	/*  otherwise if we just changed some points, throw away the spiro */
1944 	if ( allsel ) {
1945 	    int i;
1946 	    for ( i=0; i<spl->spiro_cnt-1; ++i )
1947 		TransformSpiro(&spl->spiros[i], transform);
1948 	} else
1949 	    SplineSetSpirosClear(spl);
1950 
1951 	/* if we changed all the points then the control points are right */
1952 	/*  otherwise those near the edges may be wonky, fix 'em up */
1953 	/* Figuring out where the edges of the selection are is difficult */
1954 	/*  so let's just tweak all points, it shouldn't matter */
1955 	/* It does matter. Let's tweak all default points */
1956 	if( !(tpmask & tpmask_dontFixControlPoints))
1957 	{
1958 	    if ( tpt!=tpt_AllPoints && !allsel && spl->first->next!=NULL && !spl->first->next->order2 )
1959 	    {
1960 		pfirst = NULL;
1961 		for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to )
1962 		{
1963 		    if ( pfirst==NULL ) pfirst = spt;
1964 		    if ( spt->selected && spt->prev!=NULL && !spt->prev->from->selected &&
1965 			 spt->prev->from->pointtype == pt_tangent )
1966 			SplineCharTangentPrevCP(spt->prev->from);
1967 		    if ( spt->selected && spt->next!=NULL && !spt->next->to->selected &&
1968 			 spt->next->to->pointtype == pt_tangent )
1969 			SplineCharTangentNextCP(spt->next->to);
1970 		    if ( spt->prev!=NULL && spt->prevcpdef && tpt==tpt_OnlySelected )
1971 			SplineCharDefaultPrevCP(spt);
1972 		    if ( spt->next==NULL )
1973 			break;
1974 		    if ( spt->nextcpdef && tpt==tpt_OnlySelected )
1975 			SplineCharDefaultNextCP(spt);
1976 		}
1977 	    }
1978 	}
1979 	first = NULL;
1980 	for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1981 	    if ( !alldone ) SplineRefigureFixup(spline); else SplineRefigure(spline);
1982 	    if ( first==NULL ) first = spline;
1983 	}
1984     }
1985 return( base );
1986 }
1987 
SplinePointListTransform(SplinePointList * base,real transform[6],enum transformPointType tpt)1988 SplinePointList *SplinePointListTransform( SplinePointList *base, real transform[6],
1989 					   enum transformPointType tpt )
1990 {
1991     enum transformPointMask tpmask = 0;
1992     return SplinePointListTransformExtended( base, transform, tpt, tpmask );
1993 }
1994 
SplinePointListSpiroTransform(SplinePointList * base,real transform[6],int allpoints)1995 SplinePointList *SplinePointListSpiroTransform(SplinePointList *base, real transform[6], int allpoints ) {
1996     SplinePointList *spl;
1997     bool allsel, anysel;
1998     int i;
1999 
2000 
2001     if ( allpoints )
2002 return( SplinePointListTransform(base,transform,tpt_AllPoints));
2003 
2004     for ( spl = base; spl!=NULL; spl = spl->next ) {
2005 	anysel = SplinePointListCheckSelected1(spl, true, &allsel, true);
2006 	if ( !anysel )
2007     continue;
2008 	if ( allsel ) {
2009 	    SplinePointList *next = spl->next;
2010 	    /* If we are transforming everything, then we can just transform */
2011 	    /*  the beziers too */
2012 	    spl->next = NULL;
2013 	    SplinePointListTransform(spl,transform,tpt_AllPoints);
2014 	    spl->next = next;
2015     continue;
2016 	}
2017 	/* If we are transformings some things, then we need to transform the */
2018 	/*  selected spiros and then regenerate the beziers */
2019 	for ( i=0; i<spl->spiro_cnt-1; ++i )
2020 	    if ( spl->spiros[i].ty & 0x80 )
2021 		TransformSpiro(&spl->spiros[i], transform);
2022 	SSRegenerateFromSpiros(spl);
2023     }
2024 return( base );
2025 }
2026 
SplinePointListShift(SplinePointList * base,real xoff,enum transformPointType allpoints)2027 SplinePointList *SplinePointListShift(SplinePointList *base,real xoff,enum transformPointType allpoints ) {
2028     real transform[6];
2029     if ( xoff==0 )
2030 return( base );
2031     transform[0] = transform[3] = 1;
2032     transform[1] = transform[2] = transform[5] = 0;
2033     transform[4] = xoff;
2034 return( SplinePointListTransform(base,transform,allpoints));
2035 }
2036 
HintMaskFromTransformedRef(RefChar * ref,BasePoint * trans,SplineChar * basesc,HintMask * hm)2037 HintMask *HintMaskFromTransformedRef(RefChar *ref,BasePoint *trans,
2038 	SplineChar *basesc,HintMask *hm) {
2039     StemInfo *st, *st2;
2040     int hst_cnt, bcnt;
2041     real start, width;
2042     int i;
2043 
2044     if ( ref->transform[1]!=0 || ref->transform[2]!=0 )
2045 return(NULL);
2046 
2047     memset(hm,0,sizeof(HintMask));
2048     for ( st = ref->sc->hstem; st!=NULL; st=st->next ) {
2049 	start = st->start*ref->transform[3] + ref->transform[5] + trans->y;
2050 	width = st->width*ref->transform[3];
2051 	for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ )
2052 	    if ( st2->start == start && st2->width == width )
2053 	break;
2054 	if ( st2!=NULL )
2055 	    (*hm)[bcnt>>3] |= (0x80>>(bcnt&7));
2056     }
2057     for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ );
2058 
2059     for ( st = ref->sc->vstem; st!=NULL; st=st->next ) {
2060 	start = st->start*ref->transform[0] + ref->transform[4] + trans->x;
2061 	width = st->width*ref->transform[0];
2062 	for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ )
2063 	    if ( st2->start == start && st2->width == width )
2064 	break;
2065 	if ( st2!=NULL )
2066 	    (*hm)[bcnt>>3] |= (0x80>>(bcnt&7));
2067     }
2068     for ( i=0; i<HntMax/8; ++i )
2069 	if ( (*hm)[i]!=0 )
2070 return( hm );
2071 
2072 return( NULL );
2073 }
2074 
HintMaskTransform(HintMask * oldhm,real transform[6],SplineChar * basesc,SplineChar * subsc)2075 static HintMask *HintMaskTransform(HintMask *oldhm,real transform[6],
2076 	SplineChar *basesc,SplineChar *subsc) {
2077     HintMask *newhm;
2078     StemInfo *st, *st2;
2079     int cnt, hst_cnt, bcnt;
2080     real start, width;
2081 
2082     if ( transform[1]!=0 || transform[2]!=0 )
2083 return( NULL );
2084 
2085     newhm = chunkalloc(sizeof(HintMask));
2086     for ( st = subsc->hstem,cnt = 0; st!=NULL; st=st->next, cnt++ ) {
2087 	if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) {
2088 	    start = st->start*transform[3] + transform[5];
2089 	    width = st->width*transform[3];
2090 	    for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ )
2091 		if ( st2->start == start && st2->width == width )
2092 	    break;
2093 	    if ( st2!=NULL )
2094 		(*newhm)[bcnt>>3] |= (0x80>>(bcnt&7));
2095 	}
2096     }
2097     for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ );
2098 
2099     for ( st = subsc->vstem; st!=NULL; st=st->next, cnt++ ) {
2100 	if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) {
2101 	    start = st->start*transform[0] + transform[4];
2102 	    width = st->width*transform[0];
2103 	    for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ )
2104 		if ( st2->start == start && st2->width == width )
2105 	    break;
2106 	    if ( st2!=NULL )
2107 		(*newhm)[bcnt>>3] |= (0x80>>(bcnt&7));
2108 	}
2109     }
2110 return( newhm );
2111 }
2112 
SPLCopyTranslatedHintMasks(SplinePointList * base,SplineChar * basesc,SplineChar * subsc,BasePoint * trans)2113 SplinePointList *SPLCopyTranslatedHintMasks(SplinePointList *base,
2114 	SplineChar *basesc, SplineChar *subsc, BasePoint *trans ) {
2115     SplinePointList *spl, *spl2, *head;
2116     SplinePoint *spt, *spt2, *pfirst;
2117     real transform[6];
2118     Spline *s, *first;
2119 
2120     head = SplinePointListCopy(base);
2121 
2122     transform[0] = transform[3] = 1; transform[1] = transform[2] = 0;
2123     transform[4] = trans->x; transform[5] = trans->y;
2124 
2125     for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2 = spl2->next ) {
2126 	pfirst = NULL;
2127 	for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) {
2128 	    if ( pfirst==NULL ) pfirst = spt;
2129 	    TransformPoint(spt,transform);
2130 	    if ( spt2->hintmask ) {
2131 		chunkfree(spt->hintmask,sizeof(HintMask));
2132 		spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc);
2133 	    }
2134 	    if ( spt->next==NULL )
2135 	break;
2136 	}
2137 	first = NULL;
2138 	for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
2139 	    SplineRefigure(s);
2140 	    if ( first==NULL ) first = s;
2141 	}
2142     }
2143 return( head );
2144 }
2145 
_SPLCopyTransformedHintMasks(SplineChar * subsc,int layer,real transform[6],SplineChar * basesc)2146 static SplinePointList *_SPLCopyTransformedHintMasks(SplineChar *subsc,int layer,
2147 	real transform[6], SplineChar *basesc ) {
2148     SplinePointList *spl, *spl2, *head, *last=NULL, *cur, *base;
2149     SplinePoint *spt, *spt2, *pfirst;
2150     Spline *s, *first;
2151     real trans[6];
2152     RefChar *rf;
2153 
2154     base = subsc->layers[layer].splines;
2155     head = SplinePointListCopy(base);
2156     if ( head!=NULL )
2157 	for ( last = head; last->next!=NULL; last=last->next );
2158 
2159     for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2=spl2->next ) {
2160 	pfirst = NULL;
2161 	for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) {
2162 	    if ( pfirst==NULL ) pfirst = spt;
2163 	    TransformPoint(spt,transform);
2164 	    if ( spt2->hintmask ) {
2165 		chunkfree(spt->hintmask,sizeof(HintMask));
2166 		spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc);
2167 	    }
2168 	    if ( spt->next==NULL )
2169 	break;
2170 	}
2171 	first = NULL;
2172 	for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
2173 	    SplineRefigure(s);
2174 	    if ( first==NULL ) first = s;
2175 	}
2176     }
2177     for ( rf=subsc->layers[layer].refs; rf!=NULL; rf=rf->next ) {
2178 	trans[0] = rf->transform[0]*transform[0] +
2179 		    rf->transform[1]*transform[2];
2180 	trans[1] = rf->transform[0]*transform[1] +
2181 		    rf->transform[1]*transform[3];
2182 	trans[2] = rf->transform[2]*transform[0] +
2183 		    rf->transform[3]*transform[2];
2184 	trans[3] = rf->transform[2]*transform[1] +
2185 		    rf->transform[3]*transform[3];
2186 	trans[4] = rf->transform[4]*transform[0] +
2187 		    rf->transform[5]*transform[2] +
2188 		    transform[4];
2189 	trans[5] = rf->transform[4]*transform[1] +
2190 		    rf->transform[5]*transform[3] +
2191 		    transform[5];
2192 	cur = _SPLCopyTransformedHintMasks(rf->sc,layer,trans,basesc);
2193 	if ( head==NULL )
2194 	    head = cur;
2195 	else
2196 	    last->next = cur;
2197 	if ( cur!=NULL ) {
2198 	    while ( cur->next!=NULL ) cur = cur->next;
2199 	    last = cur;
2200 	}
2201     }
2202 return( head );
2203 }
2204 
SPLCopyTransformedHintMasks(RefChar * r,SplineChar * basesc,BasePoint * trans,int layer)2205 SplinePointList *SPLCopyTransformedHintMasks(RefChar *r,
2206 	SplineChar *basesc, BasePoint *trans,int layer ) {
2207     real transform[6];
2208 
2209     memcpy(transform,r->transform,sizeof(transform));
2210     transform[4] += trans->x; transform[5] += trans->y;
2211 return( _SPLCopyTransformedHintMasks(r->sc,layer,transform,basesc));
2212 }
2213 
SplinePointListClearCPSel(SplinePointList * spl)2214 void SplinePointListClearCPSel(SplinePointList *spl) {
2215     Spline *spline, *first;
2216 
2217     for ( ; spl!=NULL; spl = spl->next ) {
2218 	first = NULL;
2219 	spl->first->nextcpselected = false;
2220 	spl->first->prevcpselected = false;
2221 	for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
2222 	     spline->to->nextcpselected = false;
2223 	     spline->to->prevcpselected = false;
2224 	    if ( first==NULL ) first = spline;
2225 	}
2226     }
2227 }
2228 
SplinePointListSelect(SplinePointList * spl,int sel)2229 void SplinePointListSelect(SplinePointList *spl,int sel) {
2230     Spline *spline, *first;
2231 
2232     for ( ; spl!=NULL; spl = spl->next ) {
2233 	first = NULL;
2234 	spl->first->selected = sel;
2235 	for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
2236 	    spline->to->selected = sel;
2237 	    if ( first==NULL ) first = spline;
2238 	}
2239     }
2240 }
2241 
SCMakeDependent(SplineChar * dependent,SplineChar * base)2242 void SCMakeDependent(SplineChar *dependent,SplineChar *base) {
2243     struct splinecharlist *dlist;
2244 
2245     if ( dependent->searcherdummy )
2246 return;
2247 
2248     for ( dlist=base->dependents; dlist!=NULL && dlist->sc!=dependent; dlist = dlist->next);
2249     if ( dlist==NULL ) {
2250 	dlist = chunkalloc(sizeof(struct splinecharlist));
2251 	dlist->sc = dependent;
2252 	dlist->next = base->dependents;
2253 	base->dependents = dlist;
2254     }
2255 }
2256 
InstanciateReference(SplineFont * sf,RefChar * topref,RefChar * refs,real transform[6],SplineChar * dsc,int layer)2257 static void InstanciateReference(SplineFont *sf, RefChar *topref, RefChar *refs,
2258 	real transform[6], SplineChar *dsc, int layer) {
2259     real trans[6];
2260     RefChar *rf;
2261     SplineChar *rsc;
2262     SplinePointList *spl, *new;
2263     int i;
2264 
2265     if ( !refs->checked ) {
2266 	if ( refs->sc!=NULL )
2267 	    i = refs->sc->orig_pos;		/* Can happen in type3 fonts */
2268 	else for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2269 	    if ( strcmp(sf->glyphs[i]->name,AdobeStandardEncoding[refs->adobe_enc])==0 )
2270 	break;
2271 	if ( i!=sf->glyphcnt && !sf->glyphs[i]->ticked ) {
2272 	    refs->checked = true;
2273 	    refs->sc = rsc = sf->glyphs[i];
2274 	    refs->orig_pos = rsc->orig_pos;
2275 	    refs->unicode_enc = rsc->unicodeenc;
2276 	    SCMakeDependent(dsc,rsc);
2277 	} else {
2278 	    LogError( _("Couldn't find referenced character \"%s\" in %s\n"),
2279 		    AdobeStandardEncoding[refs->adobe_enc], dsc->name);
2280 return;
2281 	}
2282     } else if ( refs->sc->ticked )
2283 return;
2284 
2285     rsc = refs->sc;
2286     rsc->ticked = true;
2287 
2288     for ( rf=rsc->layers[ly_fore].refs; rf!=NULL; rf = rf->next ) {
2289 	trans[0] = rf->transform[0]*transform[0] +
2290 		    rf->transform[1]*transform[2];
2291 	trans[1] = rf->transform[0]*transform[1] +
2292 		    rf->transform[1]*transform[3];
2293 	trans[2] = rf->transform[2]*transform[0] +
2294 		    rf->transform[3]*transform[2];
2295 	trans[3] = rf->transform[2]*transform[1] +
2296 		    rf->transform[3]*transform[3];
2297 	trans[4] = rf->transform[4]*transform[0] +
2298 		    rf->transform[5]*transform[2] +
2299 		    transform[4];
2300 	trans[5] = rf->transform[4]*transform[1] +
2301 		    rf->transform[5]*transform[3] +
2302 		    transform[5];
2303 	InstanciateReference(sf,topref,rf,trans,rsc,layer);
2304     }
2305     rsc->ticked = false;
2306 
2307     if ( sf->multilayer ) {
2308 	int lbase = topref->layer_cnt;
2309 	if ( topref->layer_cnt==0 ) {
2310 	    topref->layers = calloc(rsc->layer_cnt-1,sizeof(struct reflayer));
2311 	    topref->layer_cnt = rsc->layer_cnt-1;
2312 	} else {
2313 	    topref->layer_cnt += rsc->layer_cnt-1;
2314 	    topref->layers = realloc(topref->layers,topref->layer_cnt*sizeof(struct reflayer));
2315 	    memset(topref->layers+lbase,0,(rsc->layer_cnt-1)*sizeof(struct reflayer));
2316 	}
2317 	for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
2318 	    topref->layers[i-ly_fore+lbase].splines = SplinePointListTransform(SplinePointListCopy(rsc->layers[i].splines),transform,tpt_AllPoints);
2319 	    BrushCopy(&topref->layers[i-ly_fore+lbase].fill_brush, &rsc->layers[i].fill_brush,transform);
2320 	    PenCopy(&topref->layers[i-ly_fore+lbase].stroke_pen, &rsc->layers[i].stroke_pen,transform);
2321 	    topref->layers[i-ly_fore+lbase].dofill = rsc->layers[i].dofill;
2322 	    topref->layers[i-ly_fore+lbase].dostroke = rsc->layers[i].dostroke;
2323 	    topref->layers[i-ly_fore+lbase].fillfirst = rsc->layers[i].fillfirst;
2324 	    /* ??? and images?  */
2325 	}
2326     } else {
2327 	if ( topref->layer_cnt==0 ) {
2328 	    topref->layers = calloc(1,sizeof(struct reflayer));
2329 	    topref->layer_cnt = 1;
2330 	}
2331 	new = SplinePointListTransform(SplinePointListCopy(rsc->layers[layer].splines),transform,tpt_AllPoints);
2332 	if ( new!=NULL ) {
2333 	    for ( spl = new; spl->next!=NULL; spl = spl->next );
2334 	    spl->next = topref->layers[0].splines;
2335 	    topref->layers[0].splines = new;
2336 	}
2337     }
2338 }
2339 
copyparse(char * str)2340 static char *copyparse(char *str) {
2341     char *ret, *rpt;
2342     int ch,i;
2343 
2344     if ( str==NULL )
2345 return( str );
2346 
2347     rpt=ret=malloc(strlen(str)+1);
2348     while ( *str ) {
2349 	if ( *str=='\\' ) {
2350 	    ++str;
2351 	    if ( *str=='n' ) ch = '\n';
2352 	    else if ( *str=='r' ) ch = '\r';
2353 	    else if ( *str=='t' ) ch = '\t';
2354 	    else if ( *str=='b' ) ch = '\b';
2355 	    else if ( *str=='f' ) ch = '\f';
2356 	    else if ( *str=='\\' ) ch = '\\';
2357 	    else if ( *str=='(' ) ch = '(';
2358 	    else if ( *str==')' ) ch = ')';
2359 	    else if ( *str>='0' && *str<='7' ) {
2360 		for ( i=ch = 0; i<3 && *str>='0' && *str<='7'; ++i )
2361 		    ch = (ch<<3) + *str++-'0';
2362 		--str;
2363 	    } else
2364 		ch = *str;
2365 	    ++str;
2366 	    *rpt++ = ch;
2367 	} else
2368 	    *rpt++ = *str++;
2369     }
2370     *rpt = '\0';
2371     if ( !utf8_valid(ret)) {
2372 	/* Assume latin1, convert to utf8 */
2373 	rpt = latin1_2_utf8_copy(ret);
2374 	free(ret);
2375 	ret = rpt;
2376     }
2377     if ( !AllAscii(ret)) {
2378 	rpt = StripToASCII(ret);
2379 	free(ret);
2380 	ret = rpt;
2381     }
2382 return(ret);
2383 }
2384 
XUIDFromFD(int xuid[20])2385 char *XUIDFromFD(int xuid[20]) {
2386     int i;
2387     char *ret=NULL;
2388 
2389     for ( i=19; i>=0 && xuid[i]==0; --i );
2390     if ( i>=0 ) {
2391 	int j; char *pt;
2392 	ret = malloc(2+20*(i+1));
2393 	pt = ret;
2394 	*pt++ = '[';
2395 	for ( j=0; j<=i; ++j ) {
2396 	    sprintf(pt,"%d ", xuid[j]);
2397 	    pt += strlen(pt);
2398 	}
2399 	pt[-1] = ']';
2400     }
2401 return( ret );
2402 }
2403 
SplineFontMetaData(SplineFont * sf,struct fontdict * fd)2404 static void SplineFontMetaData(SplineFont *sf,struct fontdict *fd) {
2405     int em;
2406 
2407     if ( fd->cidfontname || fd->fontname ) sf->fontname = utf8_verify_copy(fd->cidfontname?fd->cidfontname:fd->fontname);
2408     sf->display_size = -default_fv_font_size;
2409     sf->display_antialias = default_fv_antialias;
2410     if ( fd->fontinfo!=NULL ) {
2411 	if ( sf->fontname==NULL && fd->fontinfo->fullname!=NULL ) {
2412 	    sf->fontname = EnforcePostScriptName(fd->fontinfo->fullname);
2413 	}
2414 	if ( sf->fontname==NULL && fd->fontinfo->familyname!=NULL ){
2415 		sf->fontname = EnforcePostScriptName(fd->fontinfo->familyname);
2416 	}
2417 	sf->fullname = copyparse(fd->fontinfo->fullname);
2418 	sf->familyname = copyparse(fd->fontinfo->familyname);
2419 	sf->weight = copyparse(fd->fontinfo->weight);
2420 	sf->version = copyparse(fd->fontinfo->version);
2421 	sf->copyright = copyparse(fd->fontinfo->notice);
2422 	sf->italicangle = fd->fontinfo->italicangle;
2423 	sf->upos = fd->fontinfo->underlineposition;
2424 	sf->uwidth = fd->fontinfo->underlinethickness;
2425 	sf->strokedfont = fd->painttype==2;
2426 	sf->strokewidth = fd->strokewidth;
2427 	sf->ascent = fd->fontinfo->ascent;
2428 	sf->descent = fd->fontinfo->descent;
2429     }
2430     if ( sf->uniqueid==0 ) sf->uniqueid = fd->uniqueid;
2431     if ( sf->fontname==NULL ) sf->fontname = GetNextUntitledName();
2432     if ( sf->fullname==NULL ) sf->fullname = copy(sf->fontname);
2433     if ( sf->familyname==NULL ) sf->familyname = copy(sf->fontname);
2434     if ( sf->weight==NULL ) sf->weight = copy("");
2435     if ( fd->modificationtime!=0 ) {
2436 	sf->modificationtime = fd->modificationtime;
2437 	sf->creationtime = fd->creationtime;
2438     }
2439     sf->cidversion = fd->cidversion;
2440     sf->xuid = XUIDFromFD(fd->xuid);
2441     /*sf->wasbinary = fd->wasbinary;*/
2442     if ( fd->fontmatrix[0]==0 )
2443 	em = 1000;
2444     else
2445 	em = rint(1/fd->fontmatrix[0]);
2446     if ( sf->ascent==0 && sf->descent!=0 )
2447 	sf->ascent = em-sf->descent;
2448     else if ( fd->fontbb[3]-fd->fontbb[1]==em ) {
2449 	if ( sf->ascent==0 ) sf->ascent = fd->fontbb[3];
2450 	if ( sf->descent==0 ) sf->descent = fd->fontbb[1];
2451     } else if ( sf->ascent==0 )
2452 	sf->ascent = 8*em/10;
2453     sf->descent = em-sf->ascent;
2454 
2455     sf->private = fd->private->private; fd->private->private = NULL;
2456     PSDictRemoveEntry(sf->private, "OtherSubrs");
2457 
2458     sf->cidregistry = copy(fd->registry);
2459     sf->ordering = copy(fd->ordering);
2460     sf->supplement = fd->supplement;
2461     sf->pfminfo.fstype = fd->fontinfo->fstype;
2462     if ( sf->ordering!=NULL ) {
2463 	if ( strnmatch(sf->ordering,"Japan",5)==0 )
2464 	    sf->uni_interp = ui_japanese;
2465 	else if ( strnmatch(sf->ordering,"Korea",5)==0 )
2466 	    sf->uni_interp = ui_korean;
2467 	else if ( strnmatch(sf->ordering,"CNS",3)==0 )
2468 	    sf->uni_interp = ui_trad_chinese;
2469 	else if ( strnmatch(sf->ordering,"GB",2)==0 )
2470 	    sf->uni_interp = ui_simp_chinese;
2471     }
2472 }
2473 
TransByFontMatrix(SplineFont * sf,real fontmatrix[6])2474 static void TransByFontMatrix(SplineFont *sf,real fontmatrix[6]) {
2475     real trans[6];
2476     int em = sf->ascent+sf->descent, i;
2477     SplineChar *sc;
2478     RefChar *refs;
2479 
2480     if ( fontmatrix[0]==fontmatrix[3] &&
2481 	    fontmatrix[1]==0 && fontmatrix[2]==0 &&
2482 	    fontmatrix[4]==0 && fontmatrix[5]==0 )
2483 return;		/* It's just the expected matrix */
2484 
2485     trans[0] = 1;
2486     if ( fontmatrix[0]==fontmatrix[3] ) trans[3] = 1;
2487     else trans[3] = rint(fontmatrix[3]*em);
2488     trans[1] = fontmatrix[1]*em;
2489     trans[2] = fontmatrix[2]*em;
2490     trans[4] = rint(fontmatrix[4]*em);
2491     trans[5] = rint(fontmatrix[5]*em);
2492 
2493     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
2494 	SplinePointListTransform(sc->layers[ly_fore].splines,trans,tpt_AllPoints);
2495 	for ( refs=sc->layers[ly_fore].refs; refs!=NULL; refs=refs->next ) {
2496 	    /* Just scale the offsets. we'll do all the base characters */
2497 	    real temp = refs->transform[4]*trans[0] +
2498 			refs->transform[5]*trans[2] +
2499 			/*transform[4]*/0;
2500 	    refs->transform[5] = refs->transform[4]*trans[1] +
2501 			refs->transform[5]*trans[3] +
2502 			/*transform[5]*/0;
2503 	    refs->transform[4] = temp;
2504 	}
2505 	sc->changedsincelasthinted = true;
2506 	sc->manualhints = false;
2507     }
2508     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
2509 	for ( refs=sc->layers[ly_fore].refs; refs!=NULL; refs=refs->next )
2510 	    SCReinstanciateRefChar(sc,refs,ly_fore);
2511     }
2512 }
2513 
SFInstanciateRefs(SplineFont * sf)2514 void SFInstanciateRefs(SplineFont *sf) {
2515     int i, layer;
2516     RefChar *refs, *next, *pr;
2517 
2518     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2519 	sf->glyphs[i]->ticked = false;
2520 
2521     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2522 	SplineChar *sc = sf->glyphs[i];
2523 
2524 	for ( layer=ly_back; layer<sc->layer_cnt; ++layer ) {
2525 	    for ( pr=NULL, refs = sc->layers[layer].refs; refs!=NULL; refs=next ) {
2526 		next = refs->next;
2527 		sc->ticked = true;
2528 		InstanciateReference(sf, refs, refs, refs->transform,sc,layer);
2529 		if ( refs->sc!=NULL ) {
2530 		    SplineSetFindBounds(refs->layers[0].splines,&refs->bb);
2531 		    sc->ticked = false;
2532 		    pr = refs;
2533 		} else {
2534 		    /* In some mal-formed postscript fonts we can have a reference */
2535 		    /*  to a character that is not actually in the font. I even */
2536 		    /*  generated one by mistake once... */
2537 		    if ( pr==NULL )
2538 			sc->layers[layer].refs = next;
2539 		    else
2540 			pr->next = next;
2541 		    refs->next = NULL;
2542 		    RefCharsFree(refs);
2543 		}
2544 	    }
2545 	}
2546     }
2547 }
2548 
2549 /* Also handles type3s */
_SplineFontFromType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2550 static void _SplineFontFromType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
2551     int i, j, notdefpos;
2552     RefChar *refs, *next;
2553     int istype2 = fd->fonttype==2;		/* Easy enough to deal with even though it will never happen... */
2554     int istype3 = fd->charprocs->next!=0;
2555     EncMap *map;
2556 
2557     if ( istype2 )
2558 	fd->private->subrs->bias = fd->private->subrs->cnt<1240 ? 107 :
2559 	    fd->private->subrs->cnt<33900 ? 1131 : 32768;
2560     sf->glyphmax = sf->glyphcnt = istype3 ? fd->charprocs->next : fd->chars->next;
2561     if ( sf->map==NULL ) {
2562 	sf->map = map = EncMapNew(256+CharsNotInEncoding(fd),sf->glyphcnt,fd->encoding_name);
2563     } else
2564 	map = sf->map;
2565     sf->glyphs = calloc(map->backmax,sizeof(SplineChar *));
2566     if ( istype3 )	/* We read a type3 */
2567 	sf->multilayer = true;
2568     if ( istype3 )
2569 	notdefpos = LookupCharString(".notdef",(struct pschars *) (fd->charprocs));
2570     else
2571 	notdefpos = LookupCharString(".notdef",fd->chars);
2572     for ( i=0; i<256; ++i ) {
2573 	int k;
2574 	if ( istype3 ) {
2575 	    k = LookupCharString(fd->encoding[i],(struct pschars *) (fd->charprocs));
2576 	} else {
2577 	    k = LookupCharString(fd->encoding[i],fd->chars);
2578 	}
2579 	if ( k==-1 ) k = notdefpos;
2580 	map->map[i] = k;
2581 	if ( k!=-1 && map->backmap[k]==-1 )
2582 	    map->backmap[k] = i;
2583     }
2584     if ( map->enccount>256 ) {
2585 	int k, j;
2586 	for ( k=0; k<fd->chars->cnt; ++k ) {
2587 	    if ( fd->chars->keys[k]!=NULL ) {
2588 		for ( j=0; j<256; ++j )
2589 		    if ( fd->encoding[j]!=NULL &&
2590 			    strcmp(fd->encoding[j],fd->chars->keys[k])==0 )
2591 		break;
2592 		if ( j==256 ) {
2593 		    map->map[i] = k;
2594 		    if ( map->backmap[k]==-1 )
2595 			map->backmap[k] = i;
2596 		    ++i;
2597 		}
2598 	    }
2599 	}
2600 	/* And for type3s */
2601 	for ( k=0; k<fd->charprocs->cnt; ++k ) {
2602 	    if ( fd->charprocs->keys[k]!=NULL ) {
2603 		for ( j=0; j<256; ++j )
2604 		    if ( fd->encoding[j]!=NULL &&
2605 			    strcmp(fd->encoding[j],fd->charprocs->keys[k])==0 )
2606 		break;
2607 		if ( j==256 ) {
2608 		    map->map[i] = k;
2609 		    if ( map->backmap[k]==-1 )
2610 			map->backmap[k] = i;
2611 		    ++i;
2612 		}
2613 	    }
2614 	}
2615     }
2616     for ( i=0; i<map->enccount; ++i ) if ( map->map[i]==-1 )
2617 	map->map[i] = notdefpos;
2618 
2619     for ( i=0; i<sf->glyphcnt; ++i ) {
2620 	if ( !istype3 )
2621 	    sf->glyphs[i] = PSCharStringToSplines(fd->chars->values[i],fd->chars->lens[i],
2622 		    pscontext,fd->private->subrs,NULL,fd->chars->keys[i]);
2623 	else
2624 	    sf->glyphs[i] = fd->charprocs->values[i];
2625 	if ( sf->glyphs[i]!=NULL ) {
2626 	    sf->glyphs[i]->orig_pos = i;
2627 	    sf->glyphs[i]->vwidth = sf->ascent+sf->descent;
2628 	    sf->glyphs[i]->unicodeenc = UniFromName(sf->glyphs[i]->name,sf->uni_interp,map->enc);
2629 	    sf->glyphs[i]->parent = sf;
2630 	    /* SCLigDefault(sf->glyphs[i]);*/		/* Also reads from AFM file, but it probably doesn't exist */
2631 	}
2632 	ff_progress_next();
2633     }
2634     SFInstanciateRefs(sf);
2635     if ( fd->metrics!=NULL ) {
2636 	for ( i=0; i<fd->metrics->next; ++i ) {
2637 	    int width = strtol(fd->metrics->values[i],NULL,10);
2638 	    for ( j=sf->glyphcnt-1; j>=0; --j ) {
2639 		if ( sf->glyphs[j]!=NULL && sf->glyphs[j]->name!=NULL &&
2640 			strcmp(fd->metrics->keys[i],sf->glyphs[j]->name)==0 ) {
2641 		    sf->glyphs[j]->width = width;
2642 	    break;
2643 		}
2644 	    }
2645 	}
2646     }
2647     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2648 	    for ( refs = sf->glyphs[i]->layers[ly_fore].refs; refs!=NULL; refs=next ) {
2649 	next = refs->next;
2650 	if ( refs->adobe_enc==' ' && refs->layers[0].splines==NULL ) {
2651 	    /* When I have a link to a single character I will save out a */
2652 	    /*  seac to that character and a space (since I can only make */
2653 	    /*  real char links), so if we find a space link, get rid of*/
2654 	    /*  it. It's an artifact */
2655 	    SCRefToSplines(sf->glyphs[i],refs,ly_fore);
2656 	}
2657     }
2658     /* sometimes (some apple oblique fonts) the fontmatrix is not just a */
2659     /*  formality, it acutally contains a skew. So be ready */
2660     if ( fd->fontmatrix[0]!=0 )
2661 	TransByFontMatrix(sf,fd->fontmatrix);
2662     AltUniFigure(sf,sf->map,true);
2663 }
2664 
SplineFontFromType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2665 static void SplineFontFromType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
2666     int i;
2667     SplineChar *sc;
2668 
2669     _SplineFontFromType1(sf,fd,pscontext);
2670 
2671     /* Clean up the hint masks, We create an initial hintmask whether we need */
2672     /*  it or not */
2673     for ( i=0; i<sf->glyphcnt; ++i ) {
2674 	if ( (sc = sf->glyphs[i])!=NULL && !sc->hconflicts && !sc->vconflicts &&
2675 		sc->layers[ly_fore].splines!=NULL ) {
2676 	    chunkfree( sc->layers[ly_fore].splines->first->hintmask,sizeof(HintMask) );
2677 	    sc->layers[ly_fore].splines->first->hintmask = NULL;
2678 	}
2679     }
2680 }
2681 
SplineFontFromMMType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2682 static SplineFont *SplineFontFromMMType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
2683     char *pt, *end, *origweight;
2684     MMSet *mm;
2685     int ipos, apos, ppos, item, i;
2686     real blends[12];	/* At most twelve points/axis in a blenddesignmap */
2687     real designs[12];
2688     EncMap *map;
2689 
2690     if ( fd->weightvector==NULL || fd->fontinfo->blenddesignpositions==NULL ||
2691 	    fd->fontinfo->blenddesignmap==NULL || fd->fontinfo->blendaxistypes==NULL ) {
2692 	ff_post_error(_("Bad Multiple Master Font"),_("Bad Multiple Master Font"));
2693 	SplineFontFree(sf);
2694 return( NULL );
2695     }
2696 
2697     mm = chunkalloc(sizeof(MMSet));
2698 
2699     pt = fd->weightvector;
2700     while ( *pt==' ' || *pt=='[' ) ++pt;
2701     while ( *pt!=']' && *pt!='\0' ) {
2702 	pscontext->blend_values[ pscontext->instance_count ] =
2703 		g_ascii_strtod(pt,&end);
2704 	if ( pt==end )
2705     break;
2706 	++(pscontext->instance_count);
2707 	if ( pscontext->instance_count>=sizeof(pscontext->blend_values)/sizeof(pscontext->blend_values[0])) {
2708 	    LogError( _("Multiple master font with more than 16 instances\n") );
2709     break;
2710 	}
2711 	for ( pt = end; *pt==' '; ++pt );
2712     }
2713 
2714     mm->instance_count = pscontext->instance_count;
2715     mm->instances = malloc(pscontext->instance_count*sizeof(SplineFont *));
2716     mm->defweights = malloc(mm->instance_count*sizeof(real));
2717     memcpy(mm->defweights,pscontext->blend_values,mm->instance_count*sizeof(real));
2718     mm->normal = sf;
2719     _SplineFontFromType1(mm->normal,fd,pscontext);
2720     map = sf->map;
2721     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2722 	sf->glyphs[i]->blended = true;
2723     sf->mm = mm;
2724 
2725     pt = fd->fontinfo->blendaxistypes;
2726     while ( *pt==' ' || *pt=='[' ) ++pt;
2727     while ( *pt!=']' && *pt!='\0' ) {
2728 	if ( *pt=='/' ) ++pt;
2729 	for ( end=pt; *end!=' ' && *end!=']' && *end!='\0'; ++end );
2730 	if ( pt==end )
2731     break;
2732 	if ( mm->axis_count>=sizeof(mm->axes)/sizeof(mm->axes[0])) {
2733 	    LogError( _("Multiple master font with more than 4 axes\n") );
2734     break;
2735 	}
2736 	mm->axes[ mm->axis_count++ ] = copyn( pt,end-pt );
2737 	for ( pt = end; *pt==' '; ++pt );
2738     }
2739 
2740     if ( mm->instance_count < (1<<mm->axis_count) )
2741 	ff_post_error(_("Bad Multiple Master Font"),_("This multiple master font has %1$d instance fonts, but it needs at least %2$d master fonts for %3$d axes. FontForge will not be able to edit this correctly"),mm->instance_count,1<<mm->axis_count,mm->axis_count);
2742     else if ( mm->instance_count > (1<<mm->axis_count) )
2743 	ff_post_error(_("Bad Multiple Master Font"),_("This multiple master font has %1$d instance fonts, but FontForge can only handle %2$d master fonts for %3$d axes. FontForge will not be able to edit this correctly"),mm->instance_count,1<<mm->axis_count,mm->axis_count);
2744     mm->positions = calloc(mm->axis_count*mm->instance_count,sizeof(real));
2745     pt = fd->fontinfo->blenddesignpositions;
2746     while ( *pt==' ' ) ++pt;
2747     if ( *pt=='[' ) ++pt;
2748     ipos = 0;
2749     while ( *pt!=']' && *pt!='\0' ) {
2750 	while ( *pt==' ' ) ++pt;
2751 	if ( *pt==']' || *pt=='\0' )
2752     break;
2753 	if ( ipos>=mm->instance_count )
2754     break;
2755 	if ( *pt=='[' ) {
2756 	    ++pt;
2757 	    apos=0;
2758 	    while ( *pt!=']' && *pt!='\0' ) {
2759 		if ( apos>=mm->axis_count ) {
2760 		    LogError( _("Too many axis positions specified in /BlendDesignPositions.\n") );
2761 	    break;
2762 		}
2763 		mm->positions[ipos*mm->axis_count+apos] =
2764 			g_ascii_strtod(pt,&end);
2765 		if ( pt==end )
2766 	    break;
2767 		++apos;
2768 		for ( pt = end; *pt==' '; ++pt );
2769 	    }
2770 	    if ( *pt==']' ) ++pt;
2771 	    ++ipos;
2772 	} else
2773 	    ++pt;
2774     }
2775 
2776     mm->axismaps = calloc(mm->axis_count,sizeof(struct axismap));
2777     pt = fd->fontinfo->blenddesignmap;
2778     while ( *pt==' ' ) ++pt;
2779     if ( *pt=='[' ) ++pt;
2780     apos = 0;
2781     while ( *pt!=']' && *pt!='\0' ) {
2782 	while ( *pt==' ' ) ++pt;
2783 	if ( *pt==']' || *pt=='\0' )
2784     break;
2785 	if ( apos>=mm->axis_count )
2786     break;
2787 	if ( *pt=='[' ) {
2788 	    ++pt;
2789 	    ppos=0;
2790 	    while ( *pt!=']' && *pt!='\0' ) {
2791 		if ( ppos>=12 ) {
2792 		    LogError( _("Too many mapping data points specified in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2793 	    break;
2794 		}
2795 		while ( *pt==' ' ) ++pt;
2796 		if ( *pt=='[' ) {
2797 		    ++pt;
2798 		    designs[ppos] = g_ascii_strtod(pt,&end);
2799 		    blends[ppos] = g_ascii_strtod(end,&end);
2800 		    if ( blends[ppos]<0 || blends[ppos]>1 ) {
2801 			LogError( _("Bad value for blend in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2802 			if ( blends[ppos]<0 ) blends[ppos] = 0;
2803 			if ( blends[ppos]>1 ) blends[ppos] = 1;
2804 		    }
2805 		    pt = end;
2806 		    while ( *pt!=']' && *pt!='\0' ) ++pt;
2807 		    ppos ++;
2808 		}
2809 		++pt;
2810 		while ( *pt==' ' ) ++pt;
2811 	    }
2812 	    if ( *pt==']' ) ++pt;
2813 	    if ( ppos<2 )
2814 		LogError( _("Bad few values in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2815 	    mm->axismaps[apos].points = ppos;
2816 	    mm->axismaps[apos].blends = malloc(ppos*sizeof(real));
2817 	    mm->axismaps[apos].designs = malloc(ppos*sizeof(real));
2818 	    memcpy(mm->axismaps[apos].blends,blends,ppos*sizeof(real));
2819 	    memcpy(mm->axismaps[apos].designs,designs,ppos*sizeof(real));
2820 	    ++apos;
2821 	} else
2822 	    ++pt;
2823     }
2824 
2825     mm->cdv = copy(fd->cdv);
2826     mm->ndv = copy(fd->ndv);
2827 
2828     origweight = fd->fontinfo->weight;
2829 
2830     /* Now figure out the master designs, being careful to interpolate */
2831     /* BlueValues, ForceBold, UnderlinePosition etc. We need to copy private */
2832     /* generate a font name */
2833     for ( ipos = 0; ipos<mm->instance_count; ++ipos ) {
2834 	free(fd->fontname);
2835 	free(fd->fontinfo->fullname);
2836 	fd->fontname = MMMakeMasterFontname(mm,ipos,&fd->fontinfo->fullname);
2837 	fd->fontinfo->weight = MMGuessWeight(mm,ipos,copy(origweight));
2838 	if ( fd->blendfontinfo!=NULL ) {
2839 	    for ( item=0; item<3; ++item ) {
2840 		static char *names[] = { "ItalicAngle", "UnderlinePosition", "UnderlineThickness" };
2841 		pt = PSDictHasEntry(fd->blendfontinfo,names[item]);
2842 		if ( pt!=NULL ) {
2843 		    pt = MMExtractNth(pt,ipos);
2844 		    if ( pt!=NULL ) {
2845 			bigreal val = g_ascii_strtod(pt,NULL);
2846 			free(pt);
2847 			switch ( item ) {
2848 			  case 0: fd->fontinfo->italicangle = val; break;
2849 			  case 1: fd->fontinfo->underlineposition = val; break;
2850 			  case 2: fd->fontinfo->underlinethickness = val; break;
2851 			}
2852 		    }
2853 		}
2854 	    }
2855 	}
2856 	fd->private->private = PSDictCopy(sf->private);
2857 	if ( fd->blendprivate!=NULL ) {
2858 	    static char *arrnames[] = { "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", "StemSnapH", "StemSnapV", NULL };
2859 	    static char *scalarnames[] = { "ForceBold", "BlueFuzz", "BlueScale", "BlueShift", NULL };
2860 	    for ( item=0; scalarnames[item]!=NULL; ++item ) {
2861 		pt = PSDictHasEntry(fd->blendprivate,scalarnames[item]);
2862 		if ( pt!=NULL ) {
2863 		    pt = MMExtractNth(pt,ipos);
2864 		    PSDictChangeEntry(fd->private->private,scalarnames[item],pt);
2865 		    free(pt);
2866 		}
2867 	    }
2868 	    for ( item=0; arrnames[item]!=NULL; ++item ) {
2869 		pt = PSDictHasEntry(fd->blendprivate,arrnames[item]);
2870 		if ( pt!=NULL ) {
2871 		    pt = MMExtractArrayNth(pt,ipos);
2872 		    PSDictChangeEntry(fd->private->private,arrnames[item],pt);
2873 		    free(pt);
2874 		}
2875 	    }
2876 	}
2877 	for ( item=0; item<mm->instance_count; ++item )
2878 	    pscontext->blend_values[item] = 0;
2879 	pscontext->blend_values[ipos] = 1;
2880 
2881 	mm->instances[ipos] = SplineFontEmpty();
2882 	SplineFontMetaData(mm->instances[ipos],fd);
2883 	free(fd->fontinfo->weight);
2884 	mm->instances[ipos]->map = map;
2885 	_SplineFontFromType1(mm->instances[ipos],fd,pscontext);
2886 	mm->instances[ipos]->mm = mm;
2887     }
2888     fd->fontinfo->weight = origweight;
2889 
2890     /* Clean up hintmasks. We always create a hintmask on the first point */
2891     /*  only keep them if we actually have conflicts.			  */
2892     for ( i=0; i<mm->normal->glyphcnt; ++i )
2893 	    if ( mm->normal->glyphs[i]!=NULL &&
2894 		    mm->normal->glyphs[i]->layers[ly_fore].splines != NULL ) {
2895 	for ( item=0; item<mm->instance_count; ++item )
2896 	    if ( mm->instances[item]->glyphs[i]->vconflicts ||
2897 		    mm->instances[item]->glyphs[i]->hconflicts )
2898 	break;
2899 	if ( item==mm->instance_count ) {	/* No conflicts */
2900 	    for ( item=0; item<mm->instance_count; ++item ) {
2901 		chunkfree( mm->instances[item]->glyphs[i]->layers[ly_fore].splines->first->hintmask, sizeof(HintMask) );
2902 		mm->instances[item]->glyphs[i]->layers[ly_fore].splines->first->hintmask = NULL;
2903 	    }
2904 	    chunkfree( mm->normal->glyphs[i]->layers[ly_fore].splines->first->hintmask, sizeof(HintMask) );
2905 	    mm->normal->glyphs[i]->layers[ly_fore].splines->first->hintmask = NULL;
2906 	}
2907     }
2908 
2909 return( sf );
2910 }
2911 
SplineFontFromCIDType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2912 static SplineFont *SplineFontFromCIDType1(SplineFont *sf, FontDict *fd,
2913 	struct pscontext *pscontext) {
2914     int i,j,k, bad, uni;
2915     SplineChar **chars;
2916     char buffer[100];
2917     struct cidmap *map;
2918     SplineFont *_sf;
2919     SplineChar *sc;
2920     EncMap *encmap;
2921 
2922     bad = 0x80000000;
2923     for ( i=0; i<fd->fdcnt; ++i )
2924 	if ( fd->fds[i]->fonttype!=1 && fd->fds[i]->fonttype!=2 )
2925 	    bad = fd->fds[i]->fonttype;
2926     if ( bad!=0x80000000 || fd->cidfonttype!=0 ) {
2927 	LogError( _("Could not parse a CID font, %sCIDFontType %d, %sfonttype %d\n"),
2928 		( fd->cidfonttype!=0 ) ? "unexpected " : "",
2929 		( bad!=0x80000000 ) ? "unexpected " : "",
2930 		fd->cidfonttype, bad );
2931 	SplineFontFree(sf);
2932 return( NULL );
2933     }
2934     if ( fd->cidstrs==NULL || fd->cidcnt==0 ) {
2935 	LogError( _("CID format doesn't contain what we expected it to.\n") );
2936 	SplineFontFree(sf);
2937 return( NULL );
2938     }
2939 
2940     encmap = EncMap1to1(fd->cidcnt);
2941 
2942     sf->subfontcnt = fd->fdcnt;
2943     sf->subfonts = malloc((sf->subfontcnt+1)*sizeof(SplineFont *));
2944     for ( i=0; i<fd->fdcnt; ++i ) {
2945 	if ( fd->fontmatrix[0]!=0 ) {
2946 	    MatMultiply(fd->fontmatrix,fd->fds[i]->fontmatrix,fd->fds[i]->fontmatrix);
2947 	}
2948 	sf->subfonts[i] = SplineFontEmpty();
2949 	SplineFontMetaData(sf->subfonts[i],fd->fds[i]);
2950 	sf->subfonts[i]->cidmaster = sf;
2951 	sf->subfonts[i]->uni_interp = sf->uni_interp;
2952 	sf->subfonts[i]->map = encmap;
2953 	if ( fd->fds[i]->fonttype==2 )
2954 	    fd->fds[i]->private->subrs->bias =
2955 		    fd->fds[i]->private->subrs->cnt<1240 ? 107 :
2956 		    fd->fds[i]->private->subrs->cnt<33900 ? 1131 : 32768;
2957     }
2958 
2959     map = FindCidMap(sf->cidregistry,sf->ordering,sf->supplement,sf);
2960 
2961     chars = calloc(fd->cidcnt,sizeof(SplineChar *));
2962     for ( i=0; i<fd->cidcnt; ++i ) if ( fd->cidlens[i]>0 ) {
2963 	j = fd->cidfds[i];		/* We get font indexes of 255 for non-existant chars */
2964 	uni = CID2NameUni(map,i,buffer,sizeof(buffer));
2965 	pscontext->is_type2 = fd->fds[j]->fonttype==2;
2966 	chars[i] = PSCharStringToSplines(fd->cidstrs[i],fd->cidlens[i],
2967 		    pscontext,fd->fds[j]->private->subrs,
2968 		    NULL,buffer);
2969 	chars[i]->vwidth = sf->subfonts[j]->ascent+sf->subfonts[j]->descent;
2970 	chars[i]->unicodeenc = uni;
2971 	chars[i]->orig_pos = i;
2972 	chars[i]->altuni = CIDSetAltUnis(map,i);
2973 	/* There better not be any references (seac's) because we have no */
2974 	/*  encoding on which to base any fixups */
2975 	if ( chars[i]->layers[ly_fore].refs!=NULL )
2976 	    IError( "Reference found in CID font. Can't fix it up");
2977 	sf->subfonts[j]->glyphcnt = sf->subfonts[j]->glyphmax = i+1;
2978 	ff_progress_next();
2979     }
2980     for ( i=0; i<fd->fdcnt; ++i )
2981 	sf->subfonts[i]->glyphs = calloc(sf->subfonts[i]->glyphcnt,sizeof(SplineChar *));
2982     for ( i=0; i<fd->cidcnt; ++i ) if ( chars[i]!=NULL ) {
2983 	j = fd->cidfds[i];
2984 	if ( j<sf->subfontcnt ) {
2985 	    sf->subfonts[j]->glyphs[i] = chars[i];
2986 	    chars[i]->parent = sf->subfonts[j];
2987 	}
2988     }
2989     free(chars);
2990 
2991     /* Clean up the hint masks, We create an initial hintmask whether we */
2992     /*  need it or not */
2993     k=0;
2994     do {
2995 	_sf = k<sf->subfontcnt?sf->subfonts[k]:sf;
2996 	for ( i=0; i<_sf->glyphcnt; ++i ) {
2997 	    if ( (sc = _sf->glyphs[i])!=NULL && !sc->hconflicts && !sc->vconflicts &&
2998 		    sc->layers[ly_fore].splines!=NULL ) {
2999 		chunkfree( sc->layers[ly_fore].splines->first->hintmask,sizeof(HintMask) );
3000 		sc->layers[ly_fore].splines->first->hintmask = NULL;
3001 	    }
3002 	}
3003 	++k;
3004     } while ( k<sf->subfontcnt );
3005 return( sf );
3006 }
3007 
SplineFontFromPSFont(FontDict * fd)3008 SplineFont *SplineFontFromPSFont(FontDict *fd) {
3009     SplineFont *sf;
3010     struct pscontext pscontext;
3011 
3012     if ( fd->sf!=NULL )
3013 	sf = fd->sf;
3014     else {
3015 	memset(&pscontext,0,sizeof(pscontext));
3016 	pscontext.is_type2 = fd->fonttype==2;
3017 	pscontext.painttype = fd->painttype;
3018 
3019 	sf = SplineFontEmpty();
3020 	SplineFontMetaData(sf,fd);
3021 	if ( fd->wascff ) {
3022 	    SplineFontFree(sf);
3023 	    sf = fd->sf;
3024 	} else if ( fd->fdcnt!=0 )
3025 	    sf = SplineFontFromCIDType1(sf,fd,&pscontext);
3026 	else if ( fd->weightvector!=NULL )
3027 	    SplineFontFromMMType1(sf,fd,&pscontext);
3028 	else
3029 	    SplineFontFromType1(sf,fd,&pscontext);
3030 	if ( loaded_fonts_same_as_new && new_fonts_are_order2 &&
3031 		fd->weightvector==NULL )
3032 	    SFConvertToOrder2(sf);
3033     }
3034     if ( sf->multilayer )
3035 	SFCheckPSBitmap(sf);
3036 return( sf );
3037 }
3038 
LayerToRefLayer(struct reflayer * rl,Layer * layer,real transform[6])3039 static void LayerToRefLayer(struct reflayer *rl,Layer *layer, real transform[6]) {
3040     BrushCopy(&rl->fill_brush, &layer->fill_brush,transform);
3041     PenCopy(&rl->stroke_pen, &layer->stroke_pen,transform);
3042     rl->dofill = layer->dofill;
3043     rl->dostroke = layer->dostroke;
3044     rl->fillfirst = layer->fillfirst;
3045 }
3046 
RefLayerFindBaseLayerIndex(RefChar * rf,int layer)3047 static int RefLayerFindBaseLayerIndex(RefChar *rf, int layer) {
3048 	// Note that most of the logic below is copied and lightly modified from SCReinstanciateRefChar.
3049 	SplineChar *rsc = rf->sc;
3050 	int i = 0, j = 0, cnt = 0;
3051 	RefChar *subref;
3052 	for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
3053 	    if ( rsc->layers[i].splines!=NULL || rsc->layers[i].images!=NULL ) {
3054 	        if (cnt == layer) return i;
3055 		++cnt;
3056 	    }
3057 	    for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next ) {
3058 		for ( j=0; j<subref->layer_cnt; ++j ) if ( subref->layers[j].images!=NULL || subref->layers[j].splines!=NULL ) {
3059 		    if (cnt == layer) return i;
3060 		    ++cnt;
3061 		}
3062 	    }
3063 	}
3064 	return -1;
3065 }
3066 
RefCharFindBounds(RefChar * rf)3067 void RefCharFindBounds(RefChar *rf) {
3068     int i;
3069     SplineChar *rsc = rf->sc;
3070     real extra=0,e;
3071 
3072     memset(&rf->bb,'\0',sizeof(rf->bb));
3073     rf->top.y = -1e10;
3074     for ( i=0; i<rf->layer_cnt; ++i ) {
3075 	_SplineSetFindBounds(rf->layers[i].splines,&rf->bb);
3076 	_SplineSetFindTop(rf->layers[i].splines,&rf->top);
3077 	int baselayer = RefLayerFindBaseLayerIndex(rf, i);
3078 	if ( baselayer >= 0 && rsc->layers[baselayer].dostroke ) {
3079 	    if ( rf->layers[i].stroke_pen.width!=WIDTH_INHERITED )
3080 		e = rf->layers[i].stroke_pen.width*rf->layers[i].stroke_pen.trans[0];
3081 	    else
3082 		e = rf->layers[i].stroke_pen.trans[0];
3083 	    if ( e>extra ) extra = e;
3084 	}
3085     }
3086     if ( rf->top.y < -65536 ) rf->top.y = rf->top.x = 0;
3087     rf->bb.minx -= extra; rf->bb.miny -= extra;
3088     rf->bb.maxx += extra; rf->bb.maxy += extra;
3089 }
3090 
SCReinstanciateRefChar(SplineChar * sc,RefChar * rf,int layer)3091 void SCReinstanciateRefChar(SplineChar *sc,RefChar *rf,int layer) {
3092     SplinePointList *new, *last;
3093     RefChar *refs;
3094     int i,j;
3095     SplineChar *rsc = rf->sc;
3096     real extra=0,e;
3097 
3098     for ( i=0; i<rf->layer_cnt; ++i ) {
3099 	SplinePointListsFree(rf->layers[i].splines);
3100 	GradientFree(rf->layers[i].fill_brush.gradient);
3101 	PatternFree(rf->layers[i].fill_brush.pattern);
3102 	GradientFree(rf->layers[i].stroke_pen.brush.gradient);
3103 	PatternFree(rf->layers[i].stroke_pen.brush.pattern);
3104     }
3105     free( rf->layers );
3106     rf->layers = NULL;
3107     rf->layer_cnt = 0;
3108     if ( rsc==NULL )
3109 return;
3110     /* Can be called before sc->parent is set, but only when reading a ttf */
3111     /*  file which won't be multilayer */
3112     if ( sc->parent!=NULL && sc->parent->multilayer ) {
3113 	int cnt = 0;
3114 	RefChar *subref;
3115 	for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
3116 	    if ( rsc->layers[i].splines!=NULL || rsc->layers[i].images!=NULL )
3117 		++cnt;
3118 	    for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next )
3119 		cnt += subref->layer_cnt;
3120 	}
3121 
3122 	rf->layer_cnt = cnt;
3123 	rf->layers = calloc(cnt,sizeof(struct reflayer));
3124 	cnt = 0;
3125 	for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
3126 	    if ( rsc->layers[i].splines!=NULL || rsc->layers[i].images!=NULL ) {
3127 		rf->layers[cnt].splines =
3128 			SplinePointListTransform(
3129 			 SplinePointListCopy(rsc->layers[i].splines),rf->transform,tpt_AllPoints);
3130 		rf->layers[cnt].images =
3131 			ImageListTransform(
3132 			 ImageListCopy(rsc->layers[i].images),rf->transform,true);
3133 		LayerToRefLayer(&rf->layers[cnt],&rsc->layers[i],rf->transform);
3134 		++cnt;
3135 	    }
3136 	    for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next ) {
3137 		for ( j=0; j<subref->layer_cnt; ++j ) if ( subref->layers[j].images!=NULL || subref->layers[j].splines!=NULL ) {
3138 		    rf->layers[cnt] = subref->layers[j];
3139 		    rf->layers[cnt].splines =
3140 			    SplinePointListTransform(
3141 			     SplinePointListCopy(subref->layers[j].splines),rf->transform,tpt_AllPoints);
3142 		    rf->layers[cnt].images =
3143 			    ImageListTransform(
3144 			     ImageListCopy(subref->layers[j].images),rf->transform,true);
3145 		    ++cnt;
3146 		}
3147 	    }
3148 	}
3149 
3150 	memset(&rf->bb,'\0',sizeof(rf->bb));
3151 	rf->top.y = -1e10;
3152 	for ( i=0; i<rf->layer_cnt; ++i ) {
3153 	    _SplineSetFindBounds(rf->layers[i].splines,&rf->bb);
3154 	    _SplineSetFindTop(rf->layers[i].splines,&rf->top);
3155 	    int baselayer = RefLayerFindBaseLayerIndex(rf, i);
3156 	    if ( baselayer >= 0 && rsc->layers[baselayer].dostroke ) {
3157 		if ( rf->layers[i].stroke_pen.width!=WIDTH_INHERITED )
3158 		    e = rf->layers[i].stroke_pen.width*rf->layers[i].stroke_pen.trans[0];
3159 		else
3160 		    e = rf->layers[i].stroke_pen.trans[0];
3161 		if ( e>extra ) extra = e;
3162 	    }
3163 	}
3164 	if ( rf->top.y < -65536 ) rf->top.y = rf->top.x = 0;
3165 	rf->bb.minx -= extra; rf->bb.miny -= extra;
3166 	rf->bb.maxx += extra; rf->bb.maxy += extra;
3167     } else {
3168 	if ( rf->layer_cnt>0 ) {
3169 	    SplinePointListsFree(rf->layers[0].splines);
3170 	    rf->layers[0].splines = NULL;
3171 	}
3172 	rf->layers = calloc(1,sizeof(struct reflayer));
3173 	rf->layer_cnt = 1;
3174 	rf->layers[0].dofill = true;
3175 	new = SplinePointListTransform(SplinePointListCopy(rf->sc->layers[layer].splines),rf->transform,tpt_AllPoints);
3176 	rf->layers[0].splines = new;
3177 	last = NULL;
3178 	if ( new!=NULL )
3179 	    for ( last = new; last->next!=NULL; last = last->next );
3180 	for ( refs = rf->sc->layers[layer].refs; refs!=NULL; refs = refs->next ) {
3181 	    new = SplinePointListTransform(SplinePointListCopy(refs->layers[0].splines),rf->transform,tpt_AllPoints);
3182 	    if ( last!=NULL )
3183 		last->next = new;
3184 	    else
3185 		rf->layers[0].splines = new;
3186 	    if ( new!=NULL )
3187 		for ( last = new; last->next!=NULL; last = last->next );
3188 	}
3189     }
3190     RefCharFindBounds(rf);
3191 }
3192 
_SFReinstanciateRefs(SplineFont * sf)3193 static void _SFReinstanciateRefs(SplineFont *sf) {
3194     int i, undone, undoable, j, cnt;
3195     RefChar *ref;
3196 
3197     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
3198 	sf->glyphs[i]->ticked = false;
3199 
3200     undone = true;
3201     cnt = 0;
3202     while ( undone && cnt<200) {
3203 	undone = false;
3204 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked ) {
3205 	    undoable = false;
3206 	    for ( j=0; j<sf->glyphs[i]->layer_cnt; ++j ) {
3207 		for ( ref=sf->glyphs[i]->layers[j].refs; ref!=NULL; ref=ref->next ) {
3208 		    if ( !ref->sc->ticked )
3209 			undoable = true;
3210 		}
3211 	    }
3212 	    if ( undoable )
3213 		undone = true;
3214 	    else {
3215 		for ( j=0; j<sf->glyphs[i]->layer_cnt; ++j ) {
3216 		    for ( ref=sf->glyphs[i]->layers[j].refs; ref!=NULL; ref=ref->next )
3217 			SCReinstanciateRefChar(sf->glyphs[i],ref,j);
3218 		}
3219 		sf->glyphs[i]->ticked = true;
3220 	    }
3221 	}
3222 	++cnt;
3223     }
3224 }
3225 
SFReinstanciateRefs(SplineFont * sf)3226 void SFReinstanciateRefs(SplineFont *sf) {
3227     int i;
3228 
3229     if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
3230 	if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
3231 	for ( i=0; i<sf->subfontcnt; ++i )
3232 	    _SFReinstanciateRefs(sf->subfonts[i]);
3233     } else
3234 	_SFReinstanciateRefs(sf);
3235 }
3236 
SCReinstanciateRef(SplineChar * sc,SplineChar * rsc,int layer)3237 void SCReinstanciateRef(SplineChar *sc,SplineChar *rsc,int layer) {
3238     RefChar *rf;
3239 
3240     for ( rf=sc->layers[layer].refs; rf!=NULL; rf=rf->next ) if ( rf->sc==rsc ) {
3241 	SCReinstanciateRefChar(sc,rf,layer);
3242     }
3243 }
3244 
SCRemoveDependent(SplineChar * dependent,RefChar * rf,int layer)3245 void SCRemoveDependent(SplineChar *dependent,RefChar *rf,int layer) {
3246     struct splinecharlist *dlist, *pd;
3247     RefChar *prev;
3248     int i;
3249 
3250     if ( dependent->layers[layer].refs==rf )
3251 	dependent->layers[layer].refs = rf->next;
3252     else {
3253 	for ( prev = dependent->layers[layer].refs; prev->next!=rf; prev=prev->next );
3254 	prev->next = rf->next;
3255     }
3256     /* Check for multiple dependencies (colon has two refs to period) */
3257     /* Also check other layers (they may include references to the same glyph as well */
3258     /*  if there are none, then remove dependent from ref->sc's dependents list */
3259     for ( i=0; i<dependent->layer_cnt; i++ ) {
3260 	for ( prev = dependent->layers[i].refs; prev!=NULL && (prev==rf || prev->sc!=rf->sc); prev = prev->next );
3261     }
3262     if ( prev==NULL ) {
3263 	dlist = rf->sc->dependents;
3264 	if ( dlist==NULL )
3265 	    /* Do nothing */;
3266 	else if ( dlist->sc==dependent ) {
3267 	    rf->sc->dependents = dlist->next;
3268 	} else {
3269 	    for ( pd=dlist, dlist = pd->next; dlist!=NULL && dlist->sc!=dependent; pd=dlist, dlist = pd->next );
3270 	    if ( dlist!=NULL )
3271 		pd->next = dlist->next;
3272 	}
3273 	chunkfree(dlist,sizeof(struct splinecharlist));
3274     }
3275     RefCharFree(rf);
3276 }
3277 
SCRemoveLayerDependents(SplineChar * dependent,int layer)3278 void SCRemoveLayerDependents(SplineChar *dependent,int layer) {
3279     RefChar *rf, *next;
3280 
3281     for ( rf=dependent->layers[layer].refs; rf!=NULL; rf=next ) {
3282 	next = rf->next;
3283 	SCRemoveDependent(dependent,rf,layer);
3284     }
3285     dependent->layers[layer].refs = NULL;
3286 }
3287 
SCRemoveDependents(SplineChar * dependent)3288 void SCRemoveDependents(SplineChar *dependent) {
3289     int layer;
3290 
3291     for ( layer=ly_fore; layer<dependent->layer_cnt; ++layer )
3292 	SCRemoveLayerDependents(dependent,layer);
3293 }
3294 
SCRefToSplines(SplineChar * sc,RefChar * rf,int layer)3295 void SCRefToSplines(SplineChar *sc,RefChar *rf,int layer) {
3296     SplineSet *spl;
3297     int rlayer;
3298 
3299     if ( sc->parent->multilayer ) {
3300 	Layer *old = sc->layers;
3301 	sc->layers = realloc(sc->layers,(sc->layer_cnt+rf->layer_cnt)*sizeof(Layer));
3302 	for ( rlayer = 0; rlayer<rf->layer_cnt; ++rlayer ) {
3303 	    LayerDefault(&sc->layers[sc->layer_cnt+rlayer]);
3304 	    sc->layers[sc->layer_cnt+rlayer].splines = rf->layers[rlayer].splines;
3305 	    rf->layers[rlayer].splines = NULL;
3306 	    sc->layers[sc->layer_cnt+rlayer].images = rf->layers[rlayer].images;
3307 	    rf->layers[rlayer].images = NULL;
3308 	    sc->layers[sc->layer_cnt+rlayer].refs = NULL;
3309 	    sc->layers[sc->layer_cnt+rlayer].undoes = NULL;
3310 	    sc->layers[sc->layer_cnt+rlayer].redoes = NULL;
3311 	    BrushCopy(&sc->layers[sc->layer_cnt+rlayer].fill_brush, &rf->layers[rlayer].fill_brush,rf->transform);
3312 	    PenCopy(&sc->layers[sc->layer_cnt+rlayer].stroke_pen, &rf->layers[rlayer].stroke_pen,rf->transform);
3313 	    sc->layers[sc->layer_cnt+rlayer].dofill = rf->layers[rlayer].dofill;
3314 	    sc->layers[sc->layer_cnt+rlayer].dostroke = rf->layers[rlayer].dostroke;
3315 	    sc->layers[sc->layer_cnt+rlayer].fillfirst = rf->layers[rlayer].fillfirst;
3316 	}
3317 	sc->layer_cnt += rf->layer_cnt;
3318 	SCMoreLayers(sc,old);
3319     } else {
3320 	if ( (spl = rf->layers[0].splines)!=NULL ) {
3321 	    while ( spl->next!=NULL )
3322 		spl = spl->next;
3323 	    spl->next = sc->layers[layer].splines;
3324 	    sc->layers[layer].splines = rf->layers[0].splines;
3325 	    rf->layers[0].splines = NULL;
3326 	    if ( sc->layers[layer].order2 && !sc->layers[layer].background )
3327 		SCClearInstrsOrMark(sc,layer,true);
3328 	}
3329     }
3330     SCRemoveDependent(sc,rf,layer);
3331 }
3332 
3333 /* This returns all real solutions, even those out of bounds */
3334 /* I use -999999 as an error flag, since we're really only interested in */
3335 /*  solns near 0 and 1 that should be ok. -1 is perhaps a little too close */
3336 /* Sigh. When solutions are near 0, the rounding errors are appalling. */
_CubicSolve(const Spline1D * sp,bigreal sought,extended ts[3])3337 int _CubicSolve(const Spline1D *sp,bigreal sought, extended ts[3]) {
3338     extended d, xN, yN, delta2, temp, delta, h, t2, t3, theta;
3339     extended sa=sp->a, sb=sp->b, sc=sp->c, sd=sp->d-sought;
3340     int i=0;
3341 
3342     ts[0] = ts[1] = ts[2] = -999999;
3343     if ( sd==0 && sa!=0 ) {
3344 	/* one of the roots is 0, the other two are the soln of a quadratic */
3345 	ts[0] = 0;
3346 	if ( sc==0 ) {
3347 	    ts[1] = -sb/(extended) sa;	/* two zero roots */
3348 	} else {
3349 	    temp = sb*(extended) sb-4*(extended) sa*sc;
3350 	    if ( RealNear(temp,0))
3351 		ts[1] = -sb/(2*(extended) sa);
3352 	    else if ( temp>=0 ) {
3353 		temp = sqrt(temp);
3354 		ts[1] = (-sb+temp)/(2*(extended) sa);
3355 		ts[2] = (-sb-temp)/(2*(extended) sa);
3356 	    }
3357 	}
3358     } else if ( sa!=0 ) {
3359     /* http://www.m-a.org.uk/eb/mg/mg077ch.pdf */
3360     /* this nifty solution to the cubic neatly avoids complex arithmatic */
3361 	xN = -sb/(3*(extended) sa);
3362 	yN = ((sa*xN + sb)*xN+sc)*xN + sd;
3363 
3364 	delta2 = (sb*(extended) sb-3*(extended) sa*sc)/(9*(extended) sa*sa);
3365 	/*if ( RealWithin(delta2,0,.00000001) ) delta2 = 0;*/
3366 
3367 	/* the descriminant is yN^2-h^2, but delta might be <0 so avoid using h */
3368 	d = yN*yN - 4*sa*sa*delta2*delta2*delta2;
3369 	if ( ((yN>.01 || yN<-.01) && RealNear(d/yN,0)) || ((yN<=.01 && yN>=-.01) && RealNear(d,0)) )
3370 	    d = 0;
3371 	if ( d>0 ) {
3372 	    temp = sqrt(d);
3373 	    t2 = (-yN-temp)/(2*sa);
3374 	    t2 = (t2==0) ? 0 : (t2<0) ? -pow(-t2,1./3.) : pow(t2,1./3.);
3375 	    t3 = (-yN+temp)/(2*sa);
3376 	    t3 = t3==0 ? 0 : (t3<0) ? -pow(-t3,1./3.) : pow(t3,1./3.);
3377 	    ts[0] = xN + t2 + t3;
3378 	} else if ( d<0 ) {
3379 	    if ( delta2>=0 ) {
3380 		delta = sqrt(delta2);
3381 		h = 2*sa*delta2*delta;
3382 		temp = -yN/h;
3383 		if ( temp>=-1.0001 && temp<=1.0001 ) {
3384 		    if ( temp<-1 ) temp = -1; else if ( temp>1 ) temp = 1;
3385 		    theta = acos(temp)/3;
3386 		    ts[i++] = xN+2*delta*cos(theta);
3387 		    ts[i++] = xN+2*delta*cos(2.0943951+theta);	/* 2*pi/3 */
3388 		    ts[i++] = xN+2*delta*cos(4.1887902+theta);	/* 4*pi/3 */
3389 		}
3390 	    }
3391 	} else if ( /* d==0 && */ delta2!=0 ) {
3392 	    delta = yN/(2*sa);
3393 	    delta = delta==0 ? 0 : delta>0 ? pow(delta,1./3.) : -pow(-delta,1./3.);
3394 	    ts[i++] = xN + delta;	/* this root twice, but that's irrelevant to me */
3395 	    ts[i++] = xN - 2*delta;
3396 	} else if ( /* d==0 && */ delta2==0 ) {
3397 	    if ( xN>=-0.0001 && xN<=1.0001 ) ts[0] = xN;
3398 	}
3399     } else if ( sb!=0 ) {
3400 	extended d = sc*(extended) sc-4*(extended) sb*sd;
3401 	if ( d<0 && RealNear(d,0)) d=0;
3402 	if ( d<0 )
3403 return(false);		/* All roots imaginary */
3404 	d = sqrt(d);
3405 	ts[0] = (-sc-d)/(2*(extended) sb);
3406 	ts[1] = (-sc+d)/(2*(extended) sb);
3407     } else if ( sc!=0 ) {
3408 	ts[0] = -sd/(extended) sc;
3409     } else {
3410 	/* If it's a point then either everything is a solution, or nothing */
3411     }
3412 return( ts[0]!=-999999 );
3413 }
3414 
CubicSolve(const Spline1D * sp,bigreal sought,extended ts[3])3415 int CubicSolve(const Spline1D *sp,bigreal sought, extended ts[3]) {
3416     extended t;
3417     extended ts2[3];
3418     int i,j;
3419     /* This routine gives us all solutions between [0,1] with -1 as an error flag */
3420     /* http://mathforum.org/dr.math/faq/faq.cubic.equations.html */
3421 
3422     ts[0] = ts[1] = ts[2] = -1;
3423     if ( !_CubicSolve(sp,sought,ts2)) {
3424 return( false );
3425     }
3426 
3427     for ( i=j=0; i<3; ++i ) {
3428 	if ( ts2[i]>-.0001 && ts2[i]<1.0001 ) {
3429 	    if ( ts2[i]<0 ) ts[j++] = 0;
3430 	    else if ( ts2[i]>1 ) ts[j++] = 1;
3431 	    else
3432 		ts[j++] = ts2[i];
3433 	}
3434     }
3435     if ( j==0 )
3436 return( false );
3437 
3438     if ( ts[0]>ts[2] && ts[2]!=-1 ) {
3439 	t = ts[0]; ts[0] = ts[2]; ts[2] = t;
3440     }
3441     if ( ts[0]>ts[1] && ts[1]!=-1 ) {
3442 	t = ts[0]; ts[0] = ts[1]; ts[1] = t;
3443     }
3444     if ( ts[1]>ts[2] && ts[2]!=-1 ) {
3445 	t = ts[1]; ts[1] = ts[2]; ts[2] = t;
3446     }
3447 return( true );
3448 }
3449 
_QuarticSolve(Quartic * q,extended ts[4])3450 static int _QuarticSolve(Quartic *q,extended ts[4]) {
3451     extended extrema[5];
3452     Spline1D sp;
3453     int ecnt = 0, i, zcnt;
3454 
3455     /* Two special cases */
3456     if ( q->a==0 ) {	/* It's really a cubic */
3457 	sp.a = q->b;
3458 	sp.b = q->c;
3459 	sp.c = q->d;
3460 	sp.d = q->e;
3461 	ts[3] = -999999;
3462 return( _CubicSolve(&sp,0,ts));
3463     } else if ( q->e==0 ) {	/* we can factor out a zero root */
3464 	sp.a = q->a;
3465 	sp.b = q->b;
3466 	sp.c = q->c;
3467 	sp.d = q->d;
3468 	ts[0] = 0;
3469 return( _CubicSolve(&sp,0,ts+1)+1);
3470     }
3471 
3472     sp.a = 4*q->a;
3473     sp.b = 3*q->b;
3474     sp.c = 2*q->c;
3475     sp.d = q->d;
3476     if ( _CubicSolve(&sp,0,extrema)) {
3477 	ecnt = 1;
3478 	if ( extrema[1]!=-999999 ) {
3479 	    ecnt = 2;
3480 	    if ( extrema[1]<extrema[0] ) {
3481 		extended temp = extrema[1]; extrema[1] = extrema[0]; extrema[0]=temp;
3482 	    }
3483 	    if ( extrema[2]!=-999999 ) {
3484 		ecnt = 3;
3485 		if ( extrema[2]<extrema[0] ) {
3486 		    extended temp = extrema[2]; extrema[2] = extrema[0]; extrema[0]=temp;
3487 		}
3488 		if ( extrema[2]<extrema[1] ) {
3489 		    extended temp = extrema[2]; extrema[2] = extrema[1]; extrema[1]=temp;
3490 		}
3491 	    }
3492 	}
3493     }
3494     for ( i=ecnt-1; i>=0 ; --i )
3495 	extrema[i+1] = extrema[i];
3496     /* Upper and lower bounds within which we'll search */
3497     extrema[0] = -999;
3498     extrema[ecnt+1] = 999;
3499     ecnt += 2;
3500     /* divide into monotonic sections & use binary search to find zeroes */
3501     for ( i=zcnt=0; i<ecnt-1; ++i ) {
3502 	extended top, bottom, val;
3503 	extended topt, bottomt, t;
3504 	topt = extrema[i+1];
3505 	bottomt = extrema[i];
3506 	top = (((q->a*topt+q->b)*topt+q->c)*topt+q->d)*topt+q->e;
3507 	bottom = (((q->a*bottomt+q->b)*bottomt+q->c)*bottomt+q->d)*bottomt+q->e;
3508 	if ( top<bottom ) {
3509 	    extended temp = top; top = bottom; bottom = temp;
3510 	    temp = topt; topt = bottomt; bottomt = temp;
3511 	}
3512 	if ( bottom>.001 )	/* this monotonic is all above 0 */
3513     continue;
3514 	if ( top<-.001 )	/* this monotonic is all below 0 */
3515     continue;
3516 	if ( bottom>0 ) {
3517 	    ts[zcnt++] = bottomt;
3518     continue;
3519 	}
3520 	if ( top<0 ) {
3521 	    ts[zcnt++] = topt;
3522     continue;
3523 	}
3524 	for (;;) {
3525 	    t = (topt+bottomt)/2;
3526 	    if ( t==topt || t==bottomt ) {
3527 		ts[zcnt++] = t;
3528 	break;
3529 	    }
3530 
3531 	    val = (((q->a*t+q->b)*t+q->c)*t+q->d)*t+q->e;
3532 	    if ( val>-.0001 && val<.0001 ) {
3533 		ts[zcnt++] = t;
3534 	break;
3535 	    } else if ( val>0 ) {
3536 		top = val;
3537 		topt = t;
3538 	    } else {
3539 		bottom = val;
3540 		bottomt = t;
3541 	    }
3542 	}
3543     }
3544     for ( i=zcnt; i<4; ++i )
3545 	ts[i] = -999999;
3546 return( zcnt );
3547 }
3548 
SplineSolve(const Spline1D * sp,real tmin,real tmax,extended sought)3549 extended SplineSolve(const Spline1D *sp, real tmin, real tmax, extended sought) {
3550     /* We want to find t so that spline(t) = sought */
3551     /*  the curve must be monotonic */
3552     /* returns t which is near sought or -1 */
3553     extended ts[3];
3554     int i;
3555     extended t;
3556 
3557     CubicSolve(sp,sought,ts);
3558     if ( tmax<tmin ) { t = tmax; tmax = tmin; tmin = t; }
3559     for ( i=0; i<3; ++i )
3560 	if ( ts[i]>=tmin && ts[i]<=tmax )
3561 return( ts[i] );
3562 
3563 return( -1 );
3564 }
3565 
3566 /* An IEEE double has 52 bits of precision. So one unit of rounding error will be */
3567 /*  the number divided by 2^51 */
3568 # define D_RE_Factor	(1024.0*1024.0*1024.0*1024.0*1024.0*2.0)
3569 /* But that's not going to work near 0, so, since the t values we care about */
3570 /*  are [0,1], let's use 1.0/D_RE_Factor */
3571 
SplineSolveFixup(const Spline1D * sp,real tmin,real tmax,extended sought)3572 extended SplineSolveFixup(const Spline1D *sp, real tmin, real tmax, extended sought) {
3573     extended ts[3];
3574     int i;
3575     bigreal factor;
3576     extended t;
3577     extended val, valp, valm;
3578 
3579     CubicSolve(sp,sought,ts);
3580     if ( tmax<tmin ) { t = tmax; tmax = tmin; tmin = t; }
3581     for ( i=0; i<3; ++i )
3582 	if ( ts[i]>=tmin && ts[i]<=tmax )
3583     break;
3584     if ( i==3 ) {
3585 	/* nothing in range, but ... */
3586 	/* did a rounding error take a solution just outside the bounds? */
3587 	extended bestd = .0001; int besti = -1;
3588 	extended off;
3589 	for ( i=0; i<3 && ts[i]!=-1; ++i ) {
3590 	    if ( ts[i]<tmin )
3591 		off = tmin-ts[i];
3592 	    else
3593 		off = ts[i]-tmax;
3594 	    if ( off<bestd ) {
3595 		bestd = off;
3596 		besti = i;
3597 	    }
3598 	}
3599 	if ( besti==-1 )
3600 return( -1 );
3601 	i = besti;
3602     }
3603     t = ts[i];
3604 
3605     if ((val = (((sp->a*t+sp->b)*t+sp->c)*t+sp->d) - sought)<0 )
3606 	val=-val;
3607     if ( val!=0 ) {
3608 	for ( factor=1024.0*1024.0*1024.0*1024.0*1024.0; factor>.5; factor/=2.0 ) {
3609 	    extended tp = t + (factor*t)/D_RE_Factor;
3610 	    extended tm = t - (factor*t)/D_RE_Factor;
3611 	    if ( (valp = (((sp->a*tp+sp->b)*tp+sp->c)*tp+sp->d) - sought)<0 )
3612 		valp = -valp;
3613 	    if ( (valm = (((sp->a*tm+sp->b)*tm+sp->c)*tm+sp->d) - sought)<0 )
3614 		valm = -valm;
3615 	    if ( valp<val && valp<valm ) {
3616 		if ( factor==1024.0*1024.0*1024.0*1024*1024 ) {
3617 		    bigreal it = IterateSplineSolve(sp,tmin,tmax,sought);
3618 		    printf( "Used %g: orig-t: %g, new-t: %g iter-t: %g\n", (double) factor, (double) t, (double) tp, (double) it );
3619 		}
3620 		t = tp;
3621 		val = valp;
3622 	    } else if ( valm<val ) {
3623 		if ( factor==1024.0*1024.0*1024.0*1024*1024 ) {
3624 		    bigreal it = IterateSplineSolve(sp,tmin,tmax,sought);
3625 		    printf( "Used -%g: orig-t: %g, new-t: %g iter-t: %g\n", (double) factor, (double) t, (double) tm, (double) it );
3626 		}
3627 		t = tm;
3628 		val = valm;
3629 	    }
3630 	}
3631     }
3632     if ( t>=tmin && t<=tmax )
3633 return( t );
3634 
3635 return( -1 );
3636 }
3637 
IterateSplineSolve(const Spline1D * sp,extended tmin,extended tmax,extended sought)3638 extended IterateSplineSolve(const Spline1D *sp, extended tmin, extended tmax,
3639 	extended sought) {
3640     extended t, low, high, test;
3641     Spline1D temp;
3642     /* Now the closed form CubicSolver can have rounding errors so if we know */
3643     /*  the spline to be monotonic, an iterative approach is more accurate */
3644 
3645     if ( tmin>tmax ) {
3646 	t=tmin; tmin=tmax; tmax=t;
3647     }
3648 
3649     temp = *sp;
3650     temp.d -= sought;
3651 
3652     if ( temp.a==0 && temp.b==0 && temp.c!=0 ) {
3653 	t = -temp.d/(extended) temp.c;
3654 	if ( t<tmin || t>tmax )
3655 return( -1 );
3656 return( t );
3657     }
3658 
3659     low = ((temp.a*tmin+temp.b)*tmin+temp.c)*tmin+temp.d;
3660     high = ((temp.a*tmax+temp.b)*tmax+temp.c)*tmax+temp.d;
3661     if ( low==0 )
3662 return(tmin);
3663     if ( high==0 )
3664 return(tmax);
3665     if (( low<0 && high>0 ) ||
3666 	    ( low>0 && high<0 )) {
3667 
3668 	for (;;) {
3669 	    t = (tmax+tmin)/2;
3670 	    if ( t==tmax || t==tmin )
3671 return( t );
3672 	    test = ((temp.a*t+temp.b)*t+temp.c)*t+temp.d;
3673 	    if ( test==0 )	/* someone complained that this test relied on exact arithmetic. In fact this test will almost never be hit, the real exit test is the line above, when tmin/tmax are so close that there is no space between them in the floating representation */
3674 return( t );
3675 	    if ( (low<0 && test<0) || (low>0 && test>0) )
3676 		tmin=t;
3677 	    else
3678 		tmax = t;
3679 	}
3680     } else if ( low<.0001 && low>-.0001 )
3681 return( tmin );			/* Rounding errors */
3682     else if ( high<.0001 && high>-.0001 )
3683 return( tmax );
3684 
3685 return( -1 );
3686 }
3687 
IterateSplineSolveFixup(const Spline1D * sp,extended tmin,extended tmax,extended sought)3688 extended IterateSplineSolveFixup(const Spline1D *sp, extended tmin, extended tmax,
3689 	extended sought) {
3690     // Search between tmin and tmax for a t-value at which the spline outputs sought.
3691     extended t;
3692     bigreal factor;
3693     extended val, valp, valm;
3694 
3695     if ( tmin>tmax ) {
3696 	t=tmin; tmin=tmax; tmax=t;
3697     }
3698 
3699     t = IterateSplineSolve(sp,tmin,tmax,sought);
3700 
3701     if ( t==-1 )
3702 return( -1 );
3703 
3704     if ((val = (((sp->a*t+sp->b)*t+sp->c)*t+sp->d) - sought)<0 )
3705 	val=-val;
3706     if ( val!=0 ) {
3707 	for ( factor=1024.0*1024.0*1024.0*1024.0*1024.0; factor>.5; factor/=2.0 ) {
3708 	    extended tp = t + (factor*t)/D_RE_Factor;
3709 	    extended tm = t - (factor*t)/D_RE_Factor;
3710 	    if ( tp>tmax ) tp=tmax;
3711 	    if ( tm<tmin ) tm=tmin;
3712 	    if ( (valp = (((sp->a*tp+sp->b)*tp+sp->c)*tp+sp->d) - sought)<0 )
3713 		valp = -valp;
3714 	    if ( (valm = (((sp->a*tm+sp->b)*tm+sp->c)*tm+sp->d) - sought)<0 )
3715 		valm = -valm;
3716 	    if ( valp<val && valp<valm ) {
3717 		t = tp;
3718 		val = valp;
3719 	    } else if ( valm<val ) {
3720 		t = tm;
3721 		val = valm;
3722 	    }
3723 	}
3724     }
3725     if ( t==0 && !Within16RoundingErrors(sought,sought+val))
3726 return( -1 );
3727     /* if t!=0 then we we get the chance of far worse rounding errors */
3728     else if ( t==tmax || t==tmin ) {
3729 	if ( Within16RoundingErrors(sought,sought+val) ||
3730 		Within16RoundingErrors(sp->a,sp->a+val) ||
3731 		Within16RoundingErrors(sp->b,sp->b+val) ||
3732 		Within16RoundingErrors(sp->c,sp->c+val) ||
3733 		Within16RoundingErrors(sp->c,sp->c+val) ||
3734 		Within16RoundingErrors(sp->d,sp->d+val))
3735 return( t );
3736 	else
3737 return( -1 );
3738     }
3739 
3740     if ( t>=tmin && t<=tmax )
3741 return( t );
3742 
3743     /* I don't think this can happen... */
3744 return( -1 );
3745 }
3746 
CheckExtremaForSingleBitErrors(const Spline1D * sp,double t,double othert)3747 double CheckExtremaForSingleBitErrors(const Spline1D *sp, double t, double othert) {
3748     double u1, um1;
3749     double slope, slope1, slopem1;
3750     int err;
3751     double diff, factor;
3752 
3753     if ( t<0 || t>1 )
3754 return( t );
3755 
3756     factor = t*0x40000/D_RE_Factor;
3757     if ( (diff = t-othert)<0 ) diff= -diff;
3758     if ( factor>diff/4 && diff!=0 )		/* This little check is to insure we don't skip beyond the well of this extremum into the next */
3759 	factor = diff/4;
3760 
3761     slope = (3*(double) sp->a*t+2*sp->b)*t+sp->c;
3762     if ( slope<0 ) slope = -slope;
3763 
3764     for ( err = 0x40000; err!=0; err>>=1 ) {
3765 	u1 = t+factor;
3766 	slope1 = (3*(double) sp->a*u1+2*sp->b)*u1+sp->c;
3767 	if ( slope1<0 ) slope1 = -slope1;
3768 
3769 	um1 = t-factor;
3770 	slopem1 = (3*(double) sp->a*um1+2*sp->b)*um1+sp->c;
3771 	if ( slopem1<0 ) slopem1 = -slopem1;
3772 
3773 	if ( slope1<slope && slope1<=slopem1 && u1<=1.0 ) {
3774 	    t = u1;
3775 	} else if ( slopem1<slope && slopem1<=slope1 && um1>=0.0 ) {
3776 	    t = um1;
3777 	}
3778 	factor /= 2.0;
3779     }
3780     /* that seems as good as it gets */
3781 
3782 return( t );
3783 }
3784 
_SplineFindExtrema(const Spline1D * sp,extended * _t1,extended * _t2)3785 static void _SplineFindExtrema(const Spline1D *sp, extended *_t1, extended *_t2 ) {
3786     extended t1= -1, t2= -1;
3787     extended b2_fourac;
3788 
3789     /* Find the extreme points on the curve */
3790     /*  Set to -1 if there are none or if they are outside the range [0,1] */
3791     /*  Order them so that t1<t2 */
3792     /*  If only one valid extremum it will be t1 */
3793     /*  (Does not check the end points unless they have derivative==0) */
3794     /*  (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
3795     if ( sp->a!=0 ) {
3796 	/* cubic, possibly 2 extrema (possibly none) */
3797 	b2_fourac = 4*(extended)sp->b*sp->b - 12*(extended)sp->a*sp->c;
3798 	if ( b2_fourac>=0 ) {
3799 	    b2_fourac = sqrt(b2_fourac);
3800 	    t1 = (-2*sp->b - b2_fourac) / (6*sp->a);
3801 	    t2 = (-2*sp->b + b2_fourac) / (6*sp->a);
3802 	    t1 = CheckExtremaForSingleBitErrors(sp,t1,t2);
3803 	    t2 = CheckExtremaForSingleBitErrors(sp,t2,t1);
3804 	    if ( t1>t2 ) { extended temp = t1; t1 = t2; t2 = temp; }
3805 	    else if ( t1==t2 ) t2 = -1;
3806 	    if ( RealNear(t1,0)) t1=0; else if ( RealNear(t1,1)) t1=1;
3807 	    if ( RealNear(t2,0)) t2=0; else if ( RealNear(t2,1)) t2=1;
3808 	}
3809     } else if ( sp->b!=0 ) {
3810 	/* Quadratic, at most one extremum */
3811 	t1 = -sp->c/(2.0*(extended) sp->b);
3812     } else /*if ( sp->c!=0 )*/ {
3813 	/* linear, no extrema */
3814     }
3815     *_t1 = t1; *_t2 = t2;
3816 }
3817 
SplineFindExtrema(const Spline1D * sp,extended * _t1,extended * _t2)3818 void SplineFindExtrema(const Spline1D *sp, extended *_t1, extended *_t2 ) {
3819     extended t1= -1, t2= -1;
3820     extended b2_fourac;
3821 
3822     /* Find the extreme points on the curve */
3823     /*  Set to -1 if there are none or if they are outside the range [0,1] */
3824     /*  Order them so that t1<t2 */
3825     /*  If only one valid extremum it will be t1 */
3826     /*  (Does not check the end points unless they have derivative==0) */
3827     /*  (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
3828     if ( sp->a!=0 ) {
3829 	/* cubic, possibly 2 extrema (possibly none) */
3830 	b2_fourac = 4*(extended) sp->b*sp->b - 12*(extended) sp->a*sp->c;
3831 	if ( b2_fourac>=0 ) {
3832 	    b2_fourac = sqrt(b2_fourac);
3833 	    t1 = (-2*sp->b - b2_fourac) / (6*sp->a);
3834 	    t2 = (-2*sp->b + b2_fourac) / (6*sp->a);
3835 	    t1 = CheckExtremaForSingleBitErrors(sp,t1,t2);
3836 	    t2 = CheckExtremaForSingleBitErrors(sp,t2,t1);
3837 	    if ( t1>t2 ) { extended temp = t1; t1 = t2; t2 = temp; }
3838 	    else if ( t1==t2 ) t2 = -1;
3839 	    if ( RealNear(t1,0)) t1=0; else if ( RealNear(t1,1)) t1=1;
3840 	    if ( RealNear(t2,0)) t2=0; else if ( RealNear(t2,1)) t2=1;
3841 	    if ( t2<=0 || t2>=1 ) t2 = -1;
3842 	    if ( t1<=0 || t1>=1 ) { t1 = t2; t2 = -1; }
3843 	}
3844     } else if ( sp->b!=0 ) {
3845 	/* Quadratic, at most one extremum */
3846 	t1 = -sp->c/(2.0*(extended) sp->b);
3847 	if ( t1<=0 || t1>=1 ) t1 = -1;
3848     } else /*if ( sp->c!=0 )*/ {
3849 	/* linear, no extrema */
3850     }
3851     *_t1 = t1; *_t2 = t2;
3852 }
3853 
SplineCurvature(Spline * s,bigreal t)3854 bigreal SplineCurvature(Spline *s, bigreal t) {
3855 	/* Kappa = (x'y'' - y'x'') / (x'^2 + y'^2)^(3/2) */
3856     bigreal dxdt, dydt, d2xdt2, d2ydt2, denom, numer;
3857 
3858     if ( s==NULL )
3859 return( CURVATURE_ERROR );
3860 
3861     dxdt = (3*s->splines[0].a*t+2*s->splines[0].b)*t+s->splines[0].c;
3862     dydt = (3*s->splines[1].a*t+2*s->splines[1].b)*t+s->splines[1].c;
3863     d2xdt2 = 6*s->splines[0].a*t + 2*s->splines[0].b;
3864     d2ydt2 = 6*s->splines[1].a*t + 2*s->splines[1].b;
3865     denom = pow( dxdt*dxdt + dydt*dydt, 3.0/2.0 );
3866     numer = dxdt*d2ydt2 - dydt*d2xdt2;
3867 
3868     if ( numer==0 )
3869 return( 0 );
3870     if ( denom==0 )
3871 return( CURVATURE_ERROR );
3872 
3873 return( numer/denom );
3874 }
3875 
SplineAtInflection(Spline1D * sp,bigreal t)3876 int SplineAtInflection(Spline1D *sp, bigreal t ) {
3877     /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2==0 */
3878 return ( RealNear( (3*sp->a*t + 2*sp->b)*t + sp->c,0) &&
3879 	    RealNear( 6*sp->a*t + 2*sp->b, 0));
3880 }
3881 
SplineAtMinMax(Spline1D * sp,bigreal t)3882 int SplineAtMinMax(Spline1D *sp, bigreal t ) {
3883     /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2!=0 */
3884 return ( RealNear( (3*sp->a*t + 2*sp->b)*t + sp->c,0) &&
3885 	    !RealNear( 6*sp->a*t + 2*sp->b, 0));
3886 }
3887 
Spline2DFindExtrema(const Spline * sp,extended extrema[4])3888 int Spline2DFindExtrema(const Spline *sp, extended extrema[4] ) {
3889     int i,j;
3890     BasePoint last, cur, mid;
3891 
3892     /* If the control points are at the end-points then this (1D) spline is */
3893     /*  basically a line. But rounding errors can give us very faint extrema */
3894     /*  if we look for them */
3895     if ( !Spline1DCantExtremeX(sp) )
3896 	SplineFindExtrema(&sp->splines[0],&extrema[0],&extrema[1]);
3897     else
3898 	extrema[0] = extrema[1] = -1;
3899     if ( !Spline1DCantExtremeY(sp) )
3900 	SplineFindExtrema(&sp->splines[1],&extrema[2],&extrema[3]);
3901     else
3902 	extrema[2] = extrema[3] = -1;
3903 
3904     for ( i=0; i<3; ++i ) for ( j=i+1; j<4; ++j ) {
3905 	if ( (extrema[i]==-1 && extrema[j]!=-1) || (extrema[i]>extrema[j] && extrema[j]!=-1) ) {
3906 	    extended temp = extrema[i];
3907 	    extrema[i] = extrema[j];
3908 	    extrema[j] = temp;
3909 	}
3910     }
3911     for ( i=j=0; i<3 && extrema[i]!=-1; ++i ) {
3912 	if ( extrema[i]==extrema[i+1] ) {
3913 	    for ( j=i+1; j<3; ++j )
3914 		extrema[j] = extrema[j+1];
3915 	    extrema[3] = -1;
3916 	}
3917     }
3918 
3919     /* Extrema which are too close together are not interesting */
3920     last = sp->from->me;
3921     for ( i=0; i<4 && extrema[i]!=-1; ++i ) {
3922 	cur.x = ((sp->splines[0].a*extrema[i]+sp->splines[0].b)*extrema[i]+
3923 		sp->splines[0].c)*extrema[i]+sp->splines[0].d;
3924 	cur.y = ((sp->splines[1].a*extrema[i]+sp->splines[1].b)*extrema[i]+
3925 		sp->splines[1].c)*extrema[i]+sp->splines[1].d;
3926 	mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2;
3927 	if ( (mid.x==last.x || mid.x==cur.x) &&
3928 		(mid.y==last.y || mid.y==cur.y)) {
3929 	    for ( j=i; j<3; ++j )
3930 		extrema[j] = extrema[j+1];
3931 	    extrema[3] = -1;
3932 	    --i;
3933 	} else
3934 	    last = cur;
3935     }
3936     if ( extrema[0]!=-1 ) {
3937 	mid.x = (last.x+sp->to->me.x)/2; mid.y = (last.y+sp->to->me.y)/2;
3938 	if ( (mid.x==last.x || mid.x==cur.x) &&
3939 		(mid.y==last.y || mid.y==cur.y))
3940 	    extrema[i-1] = -1;
3941     }
3942     for ( i=0; i<4 && extrema[i]!=-1; ++i );
3943     if ( i!=0 ) {
3944 	cur = sp->to->me;
3945 	mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2;
3946 	if ( (mid.x==last.x || mid.x==cur.x) &&
3947 		(mid.y==last.y || mid.y==cur.y))
3948 	    extrema[--i] = -1;
3949     }
3950 
3951 return( i );
3952 }
3953 
Spline2DFindPointsOfInflection(const Spline * sp,extended poi[2])3954 int Spline2DFindPointsOfInflection(const Spline *sp, extended poi[2] ) {
3955     int cnt=0;
3956     extended a, b, c, b2_fourac, t;
3957     /* A POI happens when d2 y/dx2 is zero. This is not the same as d2y/dt2 / d2x/dt2 */
3958     /* d2 y/dx^2 = d/dt ( dy/dt / dx/dt ) / dx/dt */
3959     /*		 = ( (dx/dt) * d2 y/dt2 - ((dy/dt) * d2 x/dt2) )/ (dx/dt)^3 */
3960     /* (3ax*t^2+2bx*t+cx) * (6ay*t+2by) - (3ay*t^2+2by*t+cy) * (6ax*t+2bx) == 0 */
3961     /* (3ax*t^2+2bx*t+cx) * (3ay*t+by) - (3ay*t^2+2by*t+cy) * (3ax*t+bx) == 0 */
3962     /*   9*ax*ay*t^3 + (3ax*by+6bx*ay)*t^2 + (2bx*by+3cx*ay)*t + cx*by	   */
3963     /* -(9*ax*ay*t^3 + (3ay*bx+6by*ax)*t^2 + (2by*bx+3cy*ax)*t + cy*bx)==0 */
3964     /* 3*(ax*by-ay*bx)*t^2 + 3*(cx*ay-cy*ax)*t+ (cx*by-cy*bx) == 0	   */
3965 
3966     a = 3*((extended) sp->splines[1].a*sp->splines[0].b-(extended) sp->splines[0].a*sp->splines[1].b);
3967     b = 3*((extended) sp->splines[0].c*sp->splines[1].a - (extended) sp->splines[1].c*sp->splines[0].a);
3968     c = (extended) sp->splines[0].c*sp->splines[1].b-(extended) sp->splines[1].c*sp->splines[0].b;
3969     if ( !RealNear(a,0) ) {
3970 	b2_fourac = b*b - 4*a*c;
3971 	poi[0] = poi[1] = -1;
3972 	if ( b2_fourac<0 )
3973 return( 0 );
3974 	b2_fourac = sqrt( b2_fourac );
3975 	t = (-b+b2_fourac)/(2*a);
3976 	if ( t>=0 && t<=1.0 )
3977 	    poi[cnt++] = t;
3978 	t = (-b-b2_fourac)/(2*a);
3979 	if ( t>=0 && t<=1.0 ) {
3980 	    if ( cnt==1 && poi[0]>t ) {
3981 		poi[1] = poi[0];
3982 		poi[0] = t;
3983 		++cnt;
3984 	    } else
3985 		poi[cnt++] = t;
3986 	}
3987     } else if ( !RealNear(b,0) ) {
3988 	t = -c/b;
3989 	if ( t>=0 && t<=1.0 )
3990 	    poi[cnt++] = t;
3991     }
3992     if ( cnt<2 )
3993 	poi[cnt] = -1;
3994 
3995 return( cnt );
3996 }
3997 
3998 /* Ok, if the above routine finds an extremum that less than 1 unit */
3999 /*  from an endpoint or another extremum, then many things are */
4000 /*  just going to skip over it, and other things will be confused by this */
4001 /*  so just remove it. It should be so close the difference won't matter */
SplineRemoveExtremaTooClose(Spline1D * sp,extended * _t1,extended * _t2)4002 void SplineRemoveExtremaTooClose(Spline1D *sp, extended *_t1, extended *_t2 ) {
4003     extended last, test;
4004     extended t1= *_t1, t2 = *_t2;
4005 
4006     if ( t1>t2 && t2!=-1 ) {
4007 	t1 = t2;
4008 	t2 = *_t1;
4009     }
4010     last = sp->d;
4011     if ( t1!=-1 ) {
4012 	test = ((sp->a*t1+sp->b)*t1+sp->c)*t1+sp->d;
4013 	if ( (test-last)*(test-last)<1 )
4014 	    t1 = -1;
4015 	else
4016 	    last = test;
4017     }
4018     if ( t2!=-1 ) {
4019 	test = ((sp->a*t2+sp->b)*t2+sp->c)*t2+sp->d;
4020 	if ( (test-last)*(test-last)<1 )
4021 	    t2 = -1;
4022 	else
4023 	    last = test;
4024     }
4025     test = sp->a+sp->b+sp->c+sp->d;
4026     if ( (test-last)*(test-last)<1 ) {
4027 	if ( t2!=-1 )
4028 	    t2 = -1;
4029 	else if ( t1!=-1 )
4030 	    t1 = -1;
4031 	else {
4032 	    /* Well we should just remove the whole spline? */
4033 	    ;
4034 	}
4035     }
4036     *_t1 = t1; *_t2 = t2;
4037 }
4038 
IntersectLines(BasePoint * inter,BasePoint * line1_1,BasePoint * line1_2,BasePoint * line2_1,BasePoint * line2_2)4039 int IntersectLines(BasePoint *inter,
4040 	BasePoint *line1_1, BasePoint *line1_2,
4041 	BasePoint *line2_1, BasePoint *line2_2) {
4042     // A lot of functions call this with the same address as an input and the output.
4043     // In order to avoid unexpected behavior, we delay writing to the output until the end.
4044     bigreal s1, s2;
4045     BasePoint _output;
4046     BasePoint * output = &_output;
4047     if ( line1_1->x == line1_2->x ) {
4048         // Line 1 is vertical.
4049 	output->x = line1_1->x;
4050 	if ( line2_1->x == line2_2->x ) {
4051             // Line 2 is vertical.
4052 	    if ( line2_1->x!=line1_1->x )
4053               return( false );		/* Parallel vertical lines */
4054 	    output->y = (line1_1->y+line2_1->y)/2;
4055 	} else {
4056 	    output->y = line2_1->y + (output->x-line2_1->x) * (line2_2->y - line2_1->y)/(line2_2->x - line2_1->x);
4057         }
4058         *inter = *output;
4059         return( true );
4060     } else if ( line2_1->x == line2_2->x ) {
4061         // Line 2 is vertical, but we know that line 1 is not.
4062 	output->x = line2_1->x;
4063 	output->y = line1_1->y + (output->x-line1_1->x) * (line1_2->y - line1_1->y)/(line1_2->x - line1_1->x);
4064         *inter = *output;
4065         return( true );
4066     } else {
4067         // Both lines are oblique.
4068 	s1 = (line1_2->y - line1_1->y)/(line1_2->x - line1_1->x);
4069 	s2 = (line2_2->y - line2_1->y)/(line2_2->x - line2_1->x);
4070 	if ( RealNear(s1,s2)) {
4071 	    if ( !RealNear(line1_1->y + (line2_1->x-line1_1->x) * s1,line2_1->y))
4072               return( false );
4073 	    output->x = (line1_2->x+line2_2->x)/2;
4074 	    output->y = (line1_2->y+line2_2->y)/2;
4075 	} else {
4076 	    output->x = (s1*line1_1->x - s2*line2_1->x - line1_1->y + line2_1->y)/(s1-s2);
4077 	    output->y = line1_1->y + (output->x-line1_1->x) * s1;
4078 	}
4079         *inter = *output;
4080         return( true );
4081     }
4082 }
4083 
IntersectLinesClip(BasePoint * inter,BasePoint * line1_1,BasePoint * line1_2,BasePoint * line2_1,BasePoint * line2_2)4084 int IntersectLinesClip(BasePoint *inter,
4085 	BasePoint *line1_1, BasePoint *line1_2,
4086 	BasePoint *line2_1, BasePoint *line2_2) {
4087     BasePoint old = *inter, unit;
4088     bigreal len, val;
4089 
4090     if ( !IntersectLines(inter,line1_1,line1_2,line2_1,line2_2))
4091 return( false );
4092     else {
4093 	unit.x = line2_2->x-line1_2->x;
4094 	unit.y = line2_2->y-line1_2->y;
4095 	len = sqrt(unit.x*unit.x + unit.y*unit.y);
4096 	if ( len==0 )
4097 return( false );
4098 	else {
4099 	    unit.x /= len; unit.y /= len;
4100 	    val = unit.x*(inter->x-line1_2->x) + unit.y*(inter->y-line1_2->y);
4101 	    if ( val<=0 || val>=len ) {
4102 		*inter = old;
4103 return( false );
4104 	    }
4105 	}
4106     }
4107 return( true );
4108 }
4109 
IntersectLinesSlopes(BasePoint * inter,BasePoint * line1,BasePoint * slope1,BasePoint * line2,BasePoint * slope2)4110 int IntersectLinesSlopes(BasePoint *inter,
4111 	BasePoint *line1, BasePoint *slope1,
4112 	BasePoint *line2, BasePoint *slope2) {
4113     bigreal denom = slope1->y*(bigreal) slope2->x - slope1->x*(bigreal) slope2->y;
4114     bigreal x,y;
4115 
4116     if ( denom == 0 )
4117 return( false );			/* Lines are colinear, no intersection */
4118     if ( line1->x==line2->x && line1->y==line2->y ) {
4119 	*inter = *line1;
4120 return( true );
4121     }
4122 
4123     x = (slope1->y*(bigreal) slope2->x*line1->x -
4124 	    slope2->y*(bigreal) slope1->x*line2->x +
4125 	    slope2->x*(bigreal) slope1->x*(line2->y - line1->y)) / denom;
4126     if ( slope1->x==0 )
4127 	y = slope2->y*(x-line2->x)/slope2->x + line2->y;
4128     else
4129 	y = slope1->y*(x-line1->x)/slope1->x + line1->y;
4130     if ( x<-16000 || x>16000 || y<-16000 || y>16000 )
4131 return( false );			/* Effectively parallel */
4132 
4133     inter->x = x;
4134     inter->y = y;
4135 return( true );
4136 }
4137 
AddPoint(extended x,extended y,extended t,extended s,BasePoint * pts,extended t1s[3],extended t2s[3],int soln)4138 static int AddPoint(extended x,extended y,extended t,extended s,BasePoint *pts,
4139 	extended t1s[3],extended t2s[3], int soln) {
4140     int i;
4141 
4142     for ( i=0; i<soln; ++i )
4143 	if ( x==pts[i].x && y==pts[i].y )
4144 return( soln );
4145     if ( soln>=9 )
4146 	IError( "Too many solutions!\n" );
4147     t1s[soln] = t;
4148     t2s[soln] = s;
4149     pts[soln].x = x;
4150     pts[soln].y = y;
4151 return( soln+1 );
4152 }
4153 
IterateSolve(const Spline1D * sp,extended ts[3])4154 static void IterateSolve(const Spline1D *sp,extended ts[3]) {
4155     /* The closed form solution has too many rounding errors for my taste... */
4156     int i,j;
4157 
4158     ts[0] = ts[1] = ts[2] = -1;
4159 
4160     if ( sp->a!=0 ) {
4161 	extended e[4];
4162 	e[0] = 0; e[1] = e[2] = e[3] = 1.0;
4163 	SplineFindExtrema(sp,&e[1],&e[2]);
4164 	if ( e[1]==-1 ) e[1] = 1;
4165 	if ( e[2]==-1 ) e[2] = 1;
4166 	for ( i=j=0; i<3; ++i ) {
4167 	    ts[j] = IterateSplineSolve(sp,e[i],e[i+1],0);
4168 	    if ( ts[j]!=-1 ) ++j;
4169 	    if ( e[i+1]==1.0 )
4170 	break;
4171 	}
4172     } else if ( sp->b!=0 ) {
4173 	extended b2_4ac = sp->c*(extended) sp->c - 4*sp->b*(extended) sp->d;
4174 	if ( b2_4ac>=0 ) {
4175 	    b2_4ac = sqrt(b2_4ac);
4176 	    ts[0] = (-sp->c-b2_4ac)/(2*sp->b);
4177 	    ts[1] = (-sp->c+b2_4ac)/(2*sp->b);
4178 	    if ( ts[0]>ts[1] ) { bigreal t = ts[0]; ts[0] = ts[1]; ts[1] = t; }
4179 	}
4180     } else if ( sp->c!=0 ) {
4181 	ts[0] = -sp->d/(extended) sp->c;
4182     } else {
4183 	/* No solutions, or all solutions */
4184 	;
4185     }
4186 
4187     for ( i=j=0; i<3; ++i )
4188 	if ( ts[i]>=0 && ts[i]<=1 )
4189 	    ts[j++] = ts[i];
4190     for ( i=0; i<j-1; ++i )
4191 	if ( ts[i]+.0000001>ts[i+1]) {
4192 	    ts[i] = (ts[i]+ts[i+1])/2;
4193 	    --j;
4194 	    for ( ++i; i<j; ++i )
4195 		ts[i] = ts[i+1];
4196 	}
4197     if ( j!=0 ) {
4198 	if ( ts[0]!=0 ) {
4199 	    extended d0 = sp->d;
4200 	    extended dt = ((sp->a*ts[0]+sp->b)*ts[0]+sp->c)*ts[0]+sp->d;
4201 	    if ( d0<0 ) d0=-d0;
4202 	    if ( dt<0 ) dt=-dt;
4203 	    if ( d0<dt )
4204 		ts[0] = 0;
4205 	}
4206 	if ( ts[j-1]!=1.0 ) {
4207 	    extended d1 = sp->a+(extended) sp->b+sp->c+sp->d;
4208 	    extended dt = ((sp->a*ts[j-1]+sp->b)*ts[j-1]+sp->c)*ts[j-1]+sp->d;
4209 	    if ( d1<0 ) d1=-d1;
4210 	    if ( dt<0 ) dt=-dt;
4211 	    if ( d1<dt )
4212 		ts[j-1] = 1;
4213 	}
4214     }
4215     for ( ; j<3; ++j )
4216 	ts[j] = -1;
4217 }
4218 
ISolveWithin(const Spline * spline,int major,extended val,extended tlow,extended thigh)4219 static extended ISolveWithin(const Spline *spline,int major,
4220 	extended val,extended tlow, extended thigh) {
4221     Spline1D temp;
4222     extended ts[3];
4223     const Spline1D *sp = &spline->splines[major];
4224     int i;
4225 
4226     /* Calculation for t=1 can yield rounding errors. Insist on the endpoints */
4227     /*  (the Spline1D is not a perfectly accurate description of the spline,  */
4228     /*   but the control points are right -- at least that's my defn.) */
4229     if ( tlow==0 && val==(&spline->from->me.x)[major] )
4230 return( 0 );
4231     if ( thigh==1.0 && val==(&spline->to->me.x)[major] )
4232 return( 1.0 );
4233 
4234     temp = *sp;
4235     temp.d -= val;
4236     IterateSolve(&temp,ts);
4237     if ( tlow<thigh ) {
4238 	for ( i=0; i<3; ++i )
4239 	    if ( ts[i]>=tlow && ts[i]<=thigh )
4240 return( ts[i] );
4241 	for ( i=0; i<3; ++i ) {
4242 	    if ( ts[i]>=tlow-1./1024. && ts[i]<=tlow )
4243 return( tlow );
4244 	    if ( ts[i]>=thigh && ts[i]<=thigh+1./1024 )
4245 return( thigh );
4246 	}
4247     } else {
4248 	for ( i=0; i<3; ++i )
4249 	    if ( ts[i]>=thigh && ts[i]<=tlow )
4250 return( ts[i] );
4251 	for ( i=0; i<3; ++i ) {
4252 	    if ( ts[i]>=thigh-1./1024. && ts[i]<=thigh )
4253 return( thigh );
4254 	    if ( ts[i]>=tlow && ts[i]<=tlow+1./1024 )
4255 return( tlow );
4256 	}
4257     }
4258 return( -1 );
4259 }
4260 
ICAddInter(int cnt,BasePoint * foundpos,extended * foundt1,extended * foundt2,const Spline * s1,const Spline * s2,extended t1,extended t2,int maxcnt)4261 static int ICAddInter(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2,
4262 	const Spline *s1,const Spline *s2,extended t1,extended t2, int maxcnt) {
4263 
4264     if ( cnt>=maxcnt )
4265 return( cnt );
4266 
4267     foundt1[cnt] = t1;
4268     foundt2[cnt] = t2;
4269     foundpos[cnt].x = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+
4270 			s1->splines[0].c)*t1+s1->splines[0].d;
4271     foundpos[cnt].y = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+
4272 			s1->splines[1].c)*t1+s1->splines[1].d;
4273 return( cnt+1 );
4274 }
4275 
ICBinarySearch(int cnt,BasePoint * foundpos,extended * foundt1,extended * foundt2,int other,const Spline * s1,const Spline * s2,extended t1low,extended t1high,extended t2low,extended t2high,int maxcnt)4276 static int ICBinarySearch(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2,
4277 	int other,
4278 	const Spline *s1,const Spline *s2,extended t1low,extended t1high,extended t2low,extended t2high,
4279 	int maxcnt) {
4280     int major;
4281     extended t1, t2;
4282     extended o1o, o2o, o1n, o2n, m;
4283 
4284     major = !other;
4285     o1o = ((s1->splines[other].a*t1low+s1->splines[other].b)*t1low+
4286 		    s1->splines[other].c)*t1low+s1->splines[other].d;
4287     o2o = ((s2->splines[other].a*t2low+s2->splines[other].b)*t2low+
4288 		    s2->splines[other].c)*t2low+s2->splines[other].d;
4289     for (;;) {
4290 	t1 = (t1low+t1high)/2;
4291 	m = ((s1->splines[major].a*t1+s1->splines[major].b)*t1+
4292 			s1->splines[major].c)*t1+s1->splines[major].d;
4293 	t2 = ISolveWithin(s2,major,m,t2low,t2high);
4294 	if ( t2==-1 )
4295 return( cnt );
4296 
4297 	o1n = ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
4298 			s1->splines[other].c)*t1+s1->splines[other].d;
4299 	o2n = ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
4300 			s2->splines[other].c)*t2+s2->splines[other].d;
4301 	if (( o1n-o2n<.001 && o1n-o2n>-.001) ||
4302 		(t1-t1low<.0001 && t1-t1low>-.0001))
4303 return( ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt));
4304 	if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n)) {
4305 	    t1high = t1;
4306 	    t2high = t2;
4307 	} else {
4308 	    t1low = t1;
4309 	    t2low = t2;
4310 	}
4311     }
4312 }
4313 
CubicsIntersect(const Spline * s1,extended lowt1,extended hight1,BasePoint * min1,BasePoint * max1,const Spline * s2,extended lowt2,extended hight2,BasePoint * min2,BasePoint * max2,BasePoint * foundpos,extended * foundt1,extended * foundt2,int maxcnt)4314 static int CubicsIntersect(const Spline *s1,extended lowt1,extended hight1,BasePoint *min1,BasePoint *max1,
4315 			    const Spline *s2,extended lowt2,extended hight2,BasePoint *min2,BasePoint *max2,
4316 			    BasePoint *foundpos,extended *foundt1,extended *foundt2,
4317 			    int maxcnt) {
4318     int major, other;
4319     BasePoint max, min;
4320     extended t1max, t1min, t2max, t2min, t1, t2, t1diff, oldt2;
4321     extended o1o, o2o, o1n, o2n, m;
4322     int cnt=0;
4323 
4324     if ( (min.x = min1->x)<min2->x ) min.x = min2->x;
4325     if ( (min.y = min1->y)<min2->y ) min.y = min2->y;
4326     if ( (max.x = max1->x)>max2->x ) max.x = max2->x;
4327     if ( (max.y = max1->y)>max2->y ) max.y = max2->y;
4328     if ( max.x<min.x || max.y<min.y )
4329 return( 0 );
4330     if ( max.x-min.x > max.y-min.y )
4331 	major = 0;
4332     else
4333 	major = 1;
4334     other = 1-major;
4335 
4336     t1max = ISolveWithin(s1,major,(&max.x)[major],lowt1,hight1);
4337     t1min = ISolveWithin(s1,major,(&min.x)[major],lowt1,hight1);
4338     t2max = ISolveWithin(s2,major,(&max.x)[major],lowt2,hight2);
4339     t2min = ISolveWithin(s2,major,(&min.x)[major],lowt2,hight2);
4340     if ( t1max==-1 || t1min==-1 || t2max==-1 || t2min==-1 )
4341 return( 0 );
4342     t1diff = (t1max-t1min)/64.0;
4343     if (RealNear(t1diff,0))
4344 return( 0 );
4345 
4346     t1 = t1min; t2 = t2min;
4347     o1o = t1==0   ? (&s1->from->me.x)[other] :
4348 	  t1==1.0 ? (&s1->to->me.x)[other] :
4349 	    ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
4350 		    s1->splines[other].c)*t1+s1->splines[other].d;
4351     o2o = t2==0   ? (&s2->from->me.x)[other] :
4352 	  t2==1.0 ? (&s2->to->me.x)[other] :
4353 	    ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
4354 		    s2->splines[other].c)*t2+s2->splines[other].d;
4355     if ( o1o==o2o )
4356 	cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt);
4357     for (;;) {
4358 	if ( cnt>=maxcnt )
4359     break;
4360 	t1 += t1diff;
4361 	if (( t1max>t1min && t1>t1max ) || (t1max<t1min && t1<t1max) || cnt>3 )
4362     break;
4363 	m =   t1==0   ? (&s1->from->me.x)[major] :
4364 	      t1==1.0 ? (&s1->to->me.x)[major] :
4365 		((s1->splines[major].a*t1+s1->splines[major].b)*t1+
4366 			s1->splines[major].c)*t1+s1->splines[major].d;
4367 	oldt2 = t2;
4368 	t2 = ISolveWithin(s2,major,m,lowt2,hight2);
4369 	if ( t2==-1 )
4370     continue;
4371 
4372 	o1n = t1==0   ? (&s1->from->me.x)[other] :
4373 	      t1==1.0 ? (&s1->to->me.x)[other] :
4374 		((s1->splines[other].a*t1+s1->splines[other].b)*t1+
4375 			s1->splines[other].c)*t1+s1->splines[other].d;
4376 	o2n = t2==0   ? (&s2->from->me.x)[other] :
4377 	      t2==1.0 ? (&s2->to->me.x)[other] :
4378 		((s2->splines[other].a*t2+s2->splines[other].b)*t2+
4379 			s2->splines[other].c)*t2+s2->splines[other].d;
4380 	if ( o1n==o2n )
4381 	    cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt);
4382 	if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n))
4383 	    cnt = ICBinarySearch(cnt,foundpos,foundt1,foundt2,other,
4384 		    s1,s2,t1-t1diff,t1,oldt2,t2,maxcnt);
4385 	o1o = o1n; o2o = o2n;
4386     }
4387 return( cnt );
4388 }
4389 
Closer(const Spline * s1,const Spline * s2,extended t1,extended t2,extended t1p,extended t2p)4390 static int Closer(const Spline *s1,const Spline *s2,extended t1,extended t2,extended t1p,extended t2p) {
4391     bigreal x1 = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+s1->splines[0].c)*t1+s1->splines[0].d;
4392     bigreal y1 = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+s1->splines[1].c)*t1+s1->splines[1].d;
4393     bigreal x2 = ((s2->splines[0].a*t2+s2->splines[0].b)*t2+s2->splines[0].c)*t2+s2->splines[0].d;
4394     bigreal y2 = ((s2->splines[1].a*t2+s2->splines[1].b)*t2+s2->splines[1].c)*t2+s2->splines[1].d;
4395     bigreal diff = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
4396     bigreal x1p = ((s1->splines[0].a*t1p+s1->splines[0].b)*t1p+s1->splines[0].c)*t1p+s1->splines[0].d;
4397     bigreal y1p = ((s1->splines[1].a*t1p+s1->splines[1].b)*t1p+s1->splines[1].c)*t1p+s1->splines[1].d;
4398     bigreal x2p = ((s2->splines[0].a*t2p+s2->splines[0].b)*t2p+s2->splines[0].c)*t2p+s2->splines[0].d;
4399     bigreal y2p = ((s2->splines[1].a*t2p+s2->splines[1].b)*t2p+s2->splines[1].c)*t2p+s2->splines[1].d;
4400     bigreal diffp = (x1p-x2p)*(x1p-x2p) + (y1p-y2p)*(y1p-y2p);
4401 
4402     if ( diff<diffp )
4403 return( false );
4404 
4405 return( true );
4406 }
4407 
4408 /* returns 0=>no intersection, 1=>at least one, location in pts, t1s, t2s */
4409 /*  -1 => We couldn't figure it out in a closed form, have to do a numerical */
4410 /*  approximation */
SplinesIntersect(const Spline * s1,const Spline * s2,BasePoint pts[9],extended t1s[10],extended t2s[10])4411 int SplinesIntersect(const Spline *s1, const Spline *s2, BasePoint pts[9],
4412 	extended t1s[10], extended t2s[10]) {	/* One extra for a trailing -1 */
4413     BasePoint min1, max1, min2, max2;
4414     int soln = 0;
4415     extended x,y,t, ac0, ac1;
4416     int i,j,found;
4417     Spline1D spline;
4418     extended tempts[4];	/* 3 solns for cubics, 4 for quartics */
4419     extended extrema1[6], extrema2[6];
4420     int ecnt1, ecnt2;
4421 
4422     t1s[0] = t1s[1] = t1s[2] = t1s[3] = -1;
4423     t2s[0] = t2s[1] = t2s[2] = t2s[3] = -1;
4424 
4425     if ( s1==s2 && !s1->knownlinear && !s1->isquadratic )
4426 	/* Special case see if it doubles back on itself anywhere */;
4427     else if ( s1==s2 )
4428 return( 0 );			/* Linear and quadratics can't double back, can't self-intersect */
4429     else if ( s1->splines[0].a == s2->splines[0].a &&
4430 	    s1->splines[0].b == s2->splines[0].b &&
4431 	    s1->splines[0].c == s2->splines[0].c &&
4432 	    s1->splines[0].d == s2->splines[0].d &&
4433 	    s1->splines[1].a == s2->splines[1].a &&
4434 	    s1->splines[1].b == s2->splines[1].b &&
4435 	    s1->splines[1].c == s2->splines[1].c &&
4436 	    s1->splines[1].d == s2->splines[1].d )
4437 return( -1 );			/* Same spline. Intersects everywhere */
4438 
4439     /* Ignore splines which are just a point */
4440     if ( s1->knownlinear && s1->splines[0].c==0 && s1->splines[1].c==0 )
4441 return( 0 );
4442     if ( s2->knownlinear && s2->splines[0].c==0 && s2->splines[1].c==0 )
4443 return( 0 );
4444 
4445     if ( s1->knownlinear )
4446 	/* Do Nothing */;
4447     else if ( s2->knownlinear || (!s1->isquadratic && s2->isquadratic)) {
4448 	const Spline *stemp = s1;
4449 	extended *ts = t1s;
4450 	t1s = t2s; t2s = ts;
4451 	s1 = s2; s2 = stemp;
4452     }
4453 
4454     min1 = s1->from->me; max1 = min1;
4455     min2 = s2->from->me; max2 = min2;
4456     if ( s1->from->nextcp.x>max1.x ) max1.x = s1->from->nextcp.x;
4457     else if ( s1->from->nextcp.x<min1.x ) min1.x = s1->from->nextcp.x;
4458     if ( s1->from->nextcp.y>max1.y ) max1.y = s1->from->nextcp.y;
4459     else if ( s1->from->nextcp.y<min1.y ) min1.y = s1->from->nextcp.y;
4460     if ( s1->to->prevcp.x>max1.x ) max1.x = s1->to->prevcp.x;
4461     else if ( s1->to->prevcp.x<min1.x ) min1.x = s1->to->prevcp.x;
4462     if ( s1->to->prevcp.y>max1.y ) max1.y = s1->to->prevcp.y;
4463     else if ( s1->to->prevcp.y<min1.y ) min1.y = s1->to->prevcp.y;
4464     if ( s1->to->me.x>max1.x ) max1.x = s1->to->me.x;
4465     else if ( s1->to->me.x<min1.x ) min1.x = s1->to->me.x;
4466     if ( s1->to->me.y>max1.y ) max1.y = s1->to->me.y;
4467     else if ( s1->to->me.y<min1.y ) min1.y = s1->to->me.y;
4468 
4469     if ( s2->from->nextcp.x>max2.x ) max2.x = s2->from->nextcp.x;
4470     else if ( s2->from->nextcp.x<min2.x ) min2.x = s2->from->nextcp.x;
4471     if ( s2->from->nextcp.y>max2.y ) max2.y = s2->from->nextcp.y;
4472     else if ( s2->from->nextcp.y<min2.y ) min2.y = s2->from->nextcp.y;
4473     if ( s2->to->prevcp.x>max2.x ) max2.x = s2->to->prevcp.x;
4474     else if ( s2->to->prevcp.x<min2.x ) min2.x = s2->to->prevcp.x;
4475     if ( s2->to->prevcp.y>max2.y ) max2.y = s2->to->prevcp.y;
4476     else if ( s2->to->prevcp.y<min2.y ) min2.y = s2->to->prevcp.y;
4477     if ( s2->to->me.x>max2.x ) max2.x = s2->to->me.x;
4478     else if ( s2->to->me.x<min2.x ) min2.x = s2->to->me.x;
4479     if ( s2->to->me.y>max2.y ) max2.y = s2->to->me.y;
4480     else if ( s2->to->me.y<min2.y ) min2.y = s2->to->me.y;
4481     if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y )
4482 return( false );		/* no intersection of bounding boxes */
4483 
4484     if ( s1->knownlinear ) {
4485 	spline.d = s1->splines[1].c*((bigreal) s2->splines[0].d-(bigreal) s1->splines[0].d)-
4486 		s1->splines[0].c*((bigreal) s2->splines[1].d-(bigreal) s1->splines[1].d);
4487 	spline.c = s1->splines[1].c*(bigreal) s2->splines[0].c - s1->splines[0].c*(bigreal) s2->splines[1].c;
4488 	spline.b = s1->splines[1].c*(bigreal) s2->splines[0].b - s1->splines[0].c*(bigreal) s2->splines[1].b;
4489 	spline.a = s1->splines[1].c*(bigreal) s2->splines[0].a - s1->splines[0].c*(bigreal) s2->splines[1].a;
4490 	IterateSolve(&spline,tempts);
4491 	if ( tempts[0]==-1 )
4492 return( false );
4493 	for ( i = 0; i<3 && tempts[i]!=-1; ++i ) {
4494 	    x = ((s2->splines[0].a*tempts[i]+s2->splines[0].b)*tempts[i]+
4495 		    s2->splines[0].c)*tempts[i]+s2->splines[0].d;
4496 	    y = ((s2->splines[1].a*tempts[i]+s2->splines[1].b)*tempts[i]+
4497 		    s2->splines[1].c)*tempts[i]+s2->splines[1].d;
4498 	    if ( s1->splines[0].c==0 )
4499 		x = s1->splines[0].d;
4500 	    if ( s1->splines[1].c==0 )
4501 		y = s1->splines[1].d;
4502 	    if ( (ac0 = s1->splines[0].c)<0 ) ac0 = -ac0;
4503 	    if ( (ac1 = s1->splines[1].c)<0 ) ac1 = -ac1;
4504 	    if ( ac0>ac1 )
4505 		t = (x-s1->splines[0].d)/s1->splines[0].c;
4506 	    else
4507 		t = (y-s1->splines[1].d)/s1->splines[1].c;
4508 	    if ( tempts[i]>.99996 && Closer(s1,s2,t,tempts[i],t,1)) {
4509 		tempts[i] = 1;
4510 		x = s2->to->me.x; y = s2->to->me.y;
4511 	    } else if ( tempts[i]<.00001 && Closer(s1,s2,t,tempts[i],t,0)) {
4512 		tempts[i] = 0;
4513 		x = s2->from->me.x; y = s2->from->me.y;
4514 	    }
4515 	    /* I know we just did this, but we might have changed x,y so redo */
4516 	    if ( ac0>ac1 )
4517 		t = (x-s1->splines[0].d)/s1->splines[0].c;
4518 	    else
4519 		t = (y-s1->splines[1].d)/s1->splines[1].c;
4520 	    if ( t>.99996 && t<1.001 && Closer(s1,s2,t,tempts[i],1,tempts[i])) {
4521 		t = 1;
4522 		x = s1->to->me.x; y = s1->to->me.y;
4523 	    } else if ( t<.00001 && t>-.001 && Closer(s1,s2,t,tempts[i],0,tempts[i])) {
4524 		t = 0;
4525 		x = s1->from->me.x; y = s1->from->me.y;
4526 	    }
4527 	    if ( t<-.001 || t>1.001 || x<min1.x-.01 || y<min1.y-.01 || x>max1.x+.01 || y>max1.y+.01 )
4528 	continue;
4529 	    if ( t<=0 ) {t=0; x=s1->from->me.x; y = s1->from->me.y; }
4530 	    else if ( t>=1 ) { t=1; x=s1->to->me.x; y = s1->to->me.y; }
4531 	    if ( s1->from->me.x==s1->to->me.x )		/* Avoid rounding errors */
4532 		x = s1->from->me.x;			/* on hor/vert lines */
4533 	    else if ( s1->from->me.y==s1->to->me.y )
4534 		y = s1->from->me.y;
4535 	    if ( s2->knownlinear ) {
4536 		if ( s2->from->me.x==s2->to->me.x )
4537 		    x = s2->from->me.x;
4538 		else if ( s2->from->me.y==s2->to->me.y )
4539 		    y = s2->from->me.y;
4540 	    }
4541 	    soln = AddPoint(x,y,t,tempts[i],pts,t1s,t2s,soln);
4542 	}
4543 return( soln!=0 );
4544     }
4545     /* if one of the splines is quadratic then we can get an expression */
4546     /*  relating c*t+d to poly(s^3), and substituting this back we get */
4547     /*  a poly of degree 6 in s which could be solved iteratively */
4548     /* however mixed quadratics and cubics are unlikely */
4549 
4550     /* but if both splines are degree 3, the t is expressed as the sqrt of */
4551     /*  a third degree poly, which must be substituted into a cubic, and */
4552     /*  then squared to get rid of the sqrts leaving us with an ?18? degree */
4553     /*  poly. Ick. */
4554 
4555     /* So let's do it the hard way... we break the splines into little bits */
4556     /*  where they are monotonic in both dimensions, then check these for */
4557     /*  possible intersections */
4558     extrema1[0] = extrema2[0] = 0;
4559     ecnt1 = Spline2DFindExtrema(s1,extrema1+1);
4560     ecnt2 = Spline2DFindExtrema(s2,extrema2+1);
4561     extrema1[++ecnt1] = 1.0;
4562     extrema2[++ecnt2] = 1.0;
4563     found=0;
4564     for ( i=0; i<ecnt1; ++i ) {
4565 	min1.x = ((s1->splines[0].a*extrema1[i]+s1->splines[0].b)*extrema1[i]+
4566 		s1->splines[0].c)*extrema1[i]+s1->splines[0].d;
4567 	min1.y = ((s1->splines[1].a*extrema1[i]+s1->splines[1].b)*extrema1[i]+
4568 		s1->splines[1].c)*extrema1[i]+s1->splines[1].d;
4569 	max1.x = ((s1->splines[0].a*extrema1[i+1]+s1->splines[0].b)*extrema1[i+1]+
4570 		s1->splines[0].c)*extrema1[i+1]+s1->splines[0].d;
4571 	max1.y = ((s1->splines[1].a*extrema1[i+1]+s1->splines[1].b)*extrema1[i+1]+
4572 		s1->splines[1].c)*extrema1[i+1]+s1->splines[1].d;
4573 	if ( max1.x<min1.x ) { extended temp = max1.x; max1.x = min1.x; min1.x = temp; }
4574 	if ( max1.y<min1.y ) { extended temp = max1.y; max1.y = min1.y; min1.y = temp; }
4575 	for ( j=(s1==s2)?i+1:0; j<ecnt2; ++j ) {
4576 	    min2.x = ((s2->splines[0].a*extrema2[j]+s2->splines[0].b)*extrema2[j]+
4577 		    s2->splines[0].c)*extrema2[j]+s2->splines[0].d;
4578 	    min2.y = ((s2->splines[1].a*extrema2[j]+s2->splines[1].b)*extrema2[j]+
4579 		    s2->splines[1].c)*extrema2[j]+s2->splines[1].d;
4580 	    max2.x = ((s2->splines[0].a*extrema2[j+1]+s2->splines[0].b)*extrema2[j+1]+
4581 		    s2->splines[0].c)*extrema2[j+1]+s2->splines[0].d;
4582 	    max2.y = ((s2->splines[1].a*extrema2[j+1]+s2->splines[1].b)*extrema2[j+1]+
4583 		    s2->splines[1].c)*extrema2[j+1]+s2->splines[1].d;
4584 	    if ( max2.x<min2.x ) { extended temp = max2.x; max2.x = min2.x; min2.x = temp; }
4585 	    if ( max2.y<min2.y ) { extended temp = max2.y; max2.y = min2.y; min2.y = temp; }
4586 	    if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y )
4587 		/* No possible intersection */;
4588 	    else if ( s1!=s2 )
4589 		found += CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1,
4590 				    s2,extrema2[j],extrema2[j+1],&min2,&max2,
4591 				    &pts[found],&t1s[found],&t2s[found],9-found);
4592 	    else {
4593 		int k,l;
4594 		int cnt = CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1,
4595 				    s2,extrema2[j],extrema2[j+1],&min2,&max2,
4596 				    &pts[found],&t1s[found],&t2s[found],9-found);
4597 		for ( k=0; k<cnt; ++k ) {
4598 		    if ( RealNear(t1s[found+k],t2s[found+k]) ) {
4599 			for ( l=k+1; l<cnt; ++l ) {
4600 			    pts[found+l-1] = pts[found+l];
4601 			    t1s[found+l-1] = t1s[found+l];
4602 			    t2s[found+l-1] = t2s[found+l];
4603 			}
4604 			--cnt; --k;
4605 		    }
4606 		}
4607 		found += cnt;
4608 	    }
4609 	    if ( found>=8 ) {
4610 		/* If the splines are colinear then we might get an unbounded */
4611 		/*  number of intersections */
4612 	break;
4613 	    }
4614 	}
4615     }
4616     t1s[found] = t2s[found] = -1;
4617 return( found!=0 );
4618 }
4619 
4620 /* Puts all the contours of the glyph together. Next routine undoes this */
LayerAllSplines(Layer * layer)4621 SplineSet *LayerAllSplines(Layer *layer) {
4622     SplineSet *head=NULL, *last=NULL;
4623     RefChar *r;
4624 
4625     head = layer->splines;
4626     if ( head!=NULL )
4627 	for ( last=head; last->next!=NULL; last = last->next );
4628     for ( r=layer->refs; r!=NULL; r=r->next ) {
4629 	if ( last!=NULL ) {
4630 	    last->next = r->layers[0].splines;
4631 	    for ( ; last->next!=NULL; last=last->next );
4632 	} else {
4633 	    head = r->layers[0].splines;
4634 	    if ( head!=NULL )
4635 		for ( last=head; last->next!=NULL; last = last->next );
4636 	}
4637     }
4638 return( head );
4639 }
4640 
LayerUnAllSplines(Layer * layer)4641 SplineSet *LayerUnAllSplines(Layer *layer) {
4642     SplineSet *spl = layer->splines;
4643     RefChar *r = layer->refs;
4644 
4645     if ( spl==NULL ) {
4646 	while ( r!=NULL && r->layers[0].splines==NULL )
4647 	    r = r->next;
4648 	if ( r==NULL )
4649 return( NULL );
4650 	spl = r->layers[0].splines;
4651 	do { r = r->next; } while ( r!=NULL && r->layers[0].splines==NULL );
4652     }
4653     while ( r!=NULL ) {
4654 	while ( spl!=NULL && spl->next!=r->layers[0].splines )
4655 	    spl = spl->next;
4656 	spl->next = NULL;
4657 	spl = r->layers[0].splines;
4658 	do { r = r->next; } while ( r!=NULL && r->layers[0].splines==NULL );
4659     }
4660 return( layer->splines );
4661 }
4662 
SplineSetIntersect(SplineSet * spl,Spline ** _spline,Spline ** _spline2)4663 int SplineSetIntersect(SplineSet *spl, Spline **_spline, Spline **_spline2) {
4664     BasePoint pts[9];
4665     extended t1s[10], t2s[10];
4666     int found = false,i;
4667     SplineSet *test, *test2;
4668     Spline *spline, *spline2, *first, *first2;
4669 
4670     for ( test=spl; test!=NULL ; test=test->next ) {
4671 	first = NULL;
4672 	for ( spline = test->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4673 	    if ( first==NULL ) first = spline;
4674 	    for ( test2=test; test2!=NULL; test2=test2->next ) {
4675 		first2 = test2==test && first!=spline ? first : NULL;
4676 		for ( spline2=(test2==test)?spline : test2->first->next;
4677 			spline2!=NULL && spline2!=first2; spline2 = spline2->to->next ) {
4678 		    if ( first2==NULL ) first2 = spline2;
4679 		    if ( SplinesIntersect(spline,spline2,pts,t1s,t2s)) {
4680 			if ( spline->to->next!=spline2 && spline->from->prev!=spline2 )
4681 			    found = true;
4682 			else for ( i=0; i<10 && t1s[i]!=-1; ++i ) {
4683 			    if ( (t1s[i]<.999 && t1s[i]>.001) || (t2s[i]<.999 && t2s[i]>.001)) {
4684 				found = true;
4685 			break;
4686 			    }
4687 			}
4688 			if ( found )
4689 		break;
4690 		    }
4691 		}
4692 		if ( found )
4693 	    break;
4694 	    }
4695 	    if ( found )
4696 	break;
4697 	}
4698 	if ( found )
4699     break;
4700     }
4701     if ( found ) {
4702 	*_spline = spline;
4703 	*_spline2 = spline2;
4704     }
4705 return( found );
4706 }
4707 
LineTangentToSplineThroughPt(Spline * s,BasePoint * pt,extended ts[4],extended tmin,extended tmax)4708 int LineTangentToSplineThroughPt(Spline *s, BasePoint *pt, extended ts[4],
4709 	extended tmin, extended tmax) {
4710     /* attempt to find a line though the point pt which is tangent to the spline */
4711     /*  we return t of the tangent point on the spline (if any)		  */
4712     /* So the slope of the line through pt&tangent point must match slope */
4713     /*  at the tangent point on the spline. Or...			  */
4714     /* (pt.x-xt)/(pt.y-yt) = (dx/dt)/(dy/dt)				  */
4715     /* (pt.x-xt)*(dy/dt) = (pt.y-yt)*(dx/dt)				  */
4716     /* (pt.x - ax*t^3 - bx*t^2 - cx*t - dx)(3ay*t^2 + 2by*t + cy) =	  */
4717     /*      (pt.y - ay*t^3 - by*t^2 - cy*t^2 - dy)(3ax*t^2 + 2bx*t + cx)  */
4718     /* (-ax*3ay + ay*3ax) * t^5 +					  */
4719     /*   (-ax*2by - bx*3ay + ay*2bx + by*3ax) * t^4 +			  */
4720     /*   (-ax*cy - bx*2by - cx*3ay + ay*cx + by*2bx + cy*3ax) * t^3 +	  */
4721     /*   (pt.x*3ay - bx*cy - cx*2by - dx*3ay - pt.y*3ax + by*cx + cy*2bx + dy*3ax) * t^2 +	*/
4722     /*   (pt.x*2by - cx*cy - dx*2by - pt.y*2bx + cy*cx + dy*2bx) * t + 	  */
4723     /*   (pt.x*cy - dx*cy - pt.y*cx + dy*cx) = 0 			  */
4724     /* Yeah! The order 5 terms cancel out 				  */
4725     /* (ax*by - bx*ay) * t^4 +						  */
4726     /*   (2*ax*cy - 2*cx*ay) * t^3 +					  */
4727     /*   (3*pt.x*ay + bx*cy - cx*by - 3*dx*ay - 3*pt.y*ax + 3*dy*ax) * t^2 +	*/
4728     /*   (2*pt.x*by - 2*dx*by - 2*pt.y*bx + 2*dy*bx) * t +		  */
4729     /*   (pt.x*cy - dx*cy - pt.y*cx + dy*cx) = 0 			  */
4730     Quartic quad;
4731     int i,j,k;
4732 
4733     if ( !isfinite(pt->x) || !isfinite(pt->y) ) {
4734 	IError( "Non-finite arguments passed to LineTangentToSplineThroughPt");
4735 return( -1 );
4736     }
4737 
4738     quad.a = s->splines[0].a*s->splines[1].b - s->splines[0].b*s->splines[1].a;
4739     quad.b = 2*s->splines[0].a*s->splines[1].c - 2*s->splines[0].c*s->splines[1].a;
4740     quad.c = 3*pt->x*s->splines[1].a + s->splines[0].b*s->splines[1].c - s->splines[0].c*s->splines[1].b - 3*s->splines[0].d*s->splines[1].a - 3*pt->y*s->splines[0].a + 3*s->splines[1].d*s->splines[0].a;
4741     quad.d = 2*pt->x*s->splines[1].b - 2*s->splines[0].d*s->splines[1].b - 2*pt->y*s->splines[0].b + 2*s->splines[1].d*s->splines[0].b;
4742     quad.e = pt->x*s->splines[1].c - s->splines[0].d*s->splines[1].c - pt->y*s->splines[0].c + s->splines[1].d*s->splines[0].c;
4743 
4744     if ( _QuarticSolve(&quad,ts)==-1 )
4745 return( -1 );
4746 
4747     for ( i=0; i<4 && ts[i]!=-999999; ++i ) {
4748 	if ( ts[i]>tmin-.0001 && ts[i]<tmin ) ts[i] = tmin;
4749 	if ( ts[i]>tmax && ts[i]<tmax+.001 ) ts[i] = tmax;
4750 	if ( ts[i]>tmax || ts[i]<tmin ) ts[i] = -999999;
4751     }
4752     for ( i=3; i>=0 && ts[i]==-999999; --i );
4753     if ( i==-1 )
4754 return( -1 );
4755     for ( j=i ; j>=0 ; --j ) {
4756 	if ( ts[j]<0 ) {
4757 	    for ( k=j+1; k<=i; ++k )
4758 		ts[k-1] = ts[k];
4759 	    ts[i--] = -999999;
4760 	}
4761     }
4762 return(i+1);
4763 }
4764 
XSolve(Spline * spline,real tmin,real tmax,FindSel * fs)4765 static int XSolve(Spline *spline,real tmin, real tmax,FindSel *fs) {
4766     Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4767     bigreal t,x,y;
4768 
4769     fs->p->t = t = SplineSolve(xspline,tmin,tmax,fs->p->cx);
4770     if ( t>=0 && t<=1 ) {
4771 	y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4772 	if ( fs->yl<y && fs->yh>y )
4773 return( true );
4774     }
4775     /* Although we know that globaly there's more x change, locally there */
4776     /*  maybe more y change */
4777     fs->p->t = t = SplineSolve(yspline,tmin,tmax,fs->p->cy);
4778     if ( t>=0 && t<=1 ) {
4779 	x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4780 	if ( fs->xl<x && fs->xh>x )
4781 return( true );
4782     }
4783 return( false );
4784 }
4785 
YSolve(Spline * spline,real tmin,real tmax,FindSel * fs)4786 static int YSolve(Spline *spline,real tmin, real tmax,FindSel *fs) {
4787     Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4788     bigreal t,x,y;
4789 
4790     fs->p->t = t = SplineSolve(yspline,tmin,tmax,fs->p->cy);
4791     if ( t>=0 && t<=1 ) {
4792 	x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4793 	if ( fs->xl<x && fs->xh>x )
4794 return( true );
4795     }
4796     /* Although we know that globaly there's more y change, locally there */
4797     /*  maybe more x change */
4798     fs->p->t = t = SplineSolve(xspline,tmin,tmax,fs->p->cx);
4799     if ( t>=0 && t<=1 ) {
4800 	y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4801 	if ( fs->yl<y && fs->yh>y )
4802 return( true );
4803     }
4804 return( false );
4805 }
4806 
NearXSpline(FindSel * fs,Spline * spline)4807 static int NearXSpline(FindSel *fs, Spline *spline) {
4808     /* If we get here we've checked the bounding box and we're in it */
4809     /*  the y spline is a horizontal line */
4810     /*  the x spline is not linear */
4811     bigreal t,y;
4812     Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4813 
4814     if ( xspline->a!=0 ) {
4815 	extended t1, t2, tbase;
4816 	SplineFindExtrema(xspline,&t1,&t2);
4817 	tbase = 0;
4818 	if ( t1!=-1 ) {
4819 	    if ( XSolve(spline,0,t1,fs))
4820 return( true );
4821 	    tbase = t1;
4822 	}
4823 	if ( t2!=-1 ) {
4824 	    if ( XSolve(spline,tbase,t2,fs))
4825 return( true );
4826 	    tbase = t2;
4827 	}
4828 	if ( XSolve(spline,tbase,1.0,fs))
4829 return( true );
4830     } else if ( xspline->b!=0 ) {
4831 	bigreal root = xspline->c*xspline->c - 4*xspline->b*(xspline->d-fs->p->cx);
4832 	if ( root < 0 )
4833 return( false );
4834 	root = sqrt(root);
4835 	fs->p->t = t = (-xspline->c + root)/(2*xspline->b);
4836 	if ( t>=0 && t<=1 ) {
4837 	    y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4838 	    if ( fs->yl<y && fs->yh>y )
4839 return( true );
4840 	}
4841 	fs->p->t = t = (-xspline->c - root)/(2*xspline->b);
4842 	if ( t>=0 && t<=1 ) {
4843 	    y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4844 	    if ( fs->yl<y && fs->yh>y )
4845 return( true );
4846 	}
4847     } else /* xspline->c can't be 0 because dx>dy => dx!=0 => xspline->c!=0 */ {
4848 	fs->p->t = t = (fs->p->cx-xspline->d)/xspline->c;
4849 	y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4850 	if ( fs->yl<y && fs->yh>y )
4851 return( true );
4852     }
4853 return( false );
4854 }
4855 
NearSpline(FindSel * fs,Spline * spline)4856 int NearSpline(FindSel *fs, Spline *spline) {
4857     bigreal t,x,y;
4858     Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4859     bigreal dx, dy;
4860 
4861     if (( dx = spline->to->me.x-spline->from->me.x)<0 ) dx = -dx;
4862     if (( dy = spline->to->me.y-spline->from->me.y)<0 ) dy = -dy;
4863 
4864     if ( spline->knownlinear ) {
4865 	if ( fs->xl > spline->from->me.x && fs->xl > spline->to->me.x )
4866 return( false );
4867 	if ( fs->xh < spline->from->me.x && fs->xh < spline->to->me.x )
4868 return( false );
4869 	if ( fs->yl > spline->from->me.y && fs->yl > spline->to->me.y )
4870 return( false );
4871 	if ( fs->yh < spline->from->me.y && fs->yh < spline->to->me.y )
4872 return( false );
4873 	if ( xspline->c==0 && yspline->c==0 ) 	/* It's a point. */
4874 return( true );
4875 	if ( dy>dx ) {
4876 	    t = (fs->p->cy-yspline->d)/yspline->c;
4877 	    fs->p->t = t;
4878 	    x = xspline->c*t + xspline->d;
4879 	    if ( fs->xl<x && fs->xh>x && t>=0 && t<=1 )
4880 return( true );
4881 	} else {
4882 	    t = (fs->p->cx-xspline->d)/xspline->c;
4883 	    fs->p->t = t;
4884 	    y = yspline->c*t + yspline->d;
4885 	    if ( fs->yl<y && fs->yh>y && t>=0 && t<=1 )
4886 return( true );
4887 	}
4888 return( false );
4889     } else {
4890 	if ( fs->xl > spline->from->me.x && fs->xl > spline->to->me.x &&
4891 		fs->xl > spline->from->nextcp.x && fs->xl > spline->to->prevcp.x )
4892 return( false );
4893 	if ( fs->xh < spline->from->me.x && fs->xh < spline->to->me.x &&
4894 		fs->xh < spline->from->nextcp.x && fs->xh < spline->to->prevcp.x )
4895 return( false );
4896 	if ( fs->yl > spline->from->me.y && fs->yl > spline->to->me.y &&
4897 		fs->yl > spline->from->nextcp.y && fs->yl > spline->to->prevcp.y )
4898 return( false );
4899 	if ( fs->yh < spline->from->me.y && fs->yh < spline->to->me.y &&
4900 		fs->yh < spline->from->nextcp.y && fs->yh < spline->to->prevcp.y )
4901 return( false );
4902 
4903 	if ( dx>dy )
4904 return( NearXSpline(fs,spline));
4905 	else if ( yspline->a == 0 && yspline->b == 0 ) {
4906 	    fs->p->t = t = (fs->p->cy-yspline->d)/yspline->c;
4907 	    x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4908 	    if ( fs->xl<x && fs->xh>x && t>=0 && t<=1 )
4909 return( true );
4910 	} else if ( yspline->a==0 ) {
4911 	    bigreal root = yspline->c*yspline->c - 4*yspline->b*(yspline->d-fs->p->cy);
4912 	    if ( root < 0 )
4913 return( false );
4914 	    root = sqrt(root);
4915 	    fs->p->t = t = (-yspline->c + root)/(2*yspline->b);
4916 	    x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4917 	    if ( fs->xl<x && fs->xh>x && t>0 && t<1 )
4918 return( true );
4919 	    fs->p->t = t = (-yspline->c - root)/(2*yspline->b);
4920 	    x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4921 	    if ( fs->xl<x && fs->xh>x && t>=0 && t<=1 )
4922 return( true );
4923 	} else {
4924 	    extended t1, t2, tbase;
4925 	    SplineFindExtrema(yspline,&t1,&t2);
4926 	    tbase = 0;
4927 	    if ( t1!=-1 ) {
4928 		if ( YSolve(spline,0,t1,fs))
4929 return( true );
4930 		tbase = t1;
4931 	    }
4932 	    if ( t2!=-1 ) {
4933 		if ( YSolve(spline,tbase,t2,fs))
4934 return( true );
4935 		tbase = t2;
4936 	    }
4937 	    if ( YSolve(spline,tbase,1.0,fs))
4938 return( true );
4939 	}
4940     }
4941 return( false );
4942 }
4943 
SplineNearPoint(Spline * spline,BasePoint * bp,real fudge)4944 real SplineNearPoint(Spline *spline, BasePoint *bp, real fudge) {
4945     PressedOn p;
4946     FindSel fs;
4947 
4948     memset(&fs,'\0',sizeof(fs));
4949     memset(&p,'\0',sizeof(p));
4950     fs.p = &p;
4951     p.cx = bp->x;
4952     p.cy = bp->y;
4953     fs.fudge = fudge;
4954     fs.xl = p.cx-fudge;
4955     fs.xh = p.cx+fudge;
4956     fs.yl = p.cy-fudge;
4957     fs.yh = p.cy+fudge;
4958     if ( !NearSpline(&fs,spline))
4959 return( -1 );
4960 
4961 return( p.t );
4962 }
4963 
SplineT2SpiroIndex(Spline * spline,bigreal t,SplineSet * spl)4964 int SplineT2SpiroIndex(Spline *spline,bigreal t,SplineSet *spl) {
4965     /* User clicked on a spline. Now, where in the spiro array was that? */
4966     /* I shall assume that the first time we hit a spiro point that corresponds */
4967     /*  to the point. In some really gnarly spiro tangles that might not be */
4968     /*  true, but in a well behaved contour I think (hope) it will be ok */
4969 
4970     /* It appears that each spiro cp has a corresponding splinepoint, but */
4971     /*  I don't want to rely on that because it won't be true after a simplify*/
4972     Spline *sp, *lastsp=spl->first->next;
4973     bigreal test;
4974     int i;
4975     BasePoint bp;
4976 
4977     for ( i=1; i<spl->spiro_cnt; ++i ) {	/* For once I do mean spiro count, that loops back to the start for close contours */
4978 	if ( i<spl->spiro_cnt-1 ) {
4979 	    bp.x = spl->spiros[i].x;
4980 	    bp.y = spl->spiros[i].y;
4981 	} else if ( SPIRO_SPL_OPEN(spl))
4982 return( -1 );
4983 	else {
4984 	    bp.x = spl->spiros[0].x;
4985 	    bp.y = spl->spiros[0].y;
4986 	}
4987 	for ( sp=lastsp; ; ) {
4988 	    test = SplineNearPoint(sp,&bp,.001);
4989 	    if ( test==-1 ) {
4990 		if ( sp==spline )
4991 return( i-1 );
4992 	    } else {
4993 		if ( sp==spline && t<test )
4994 return( i-1 );
4995 		lastsp = sp;
4996 	break;
4997 	    }
4998 	    if ( sp->to->next==NULL || sp->to==spl->first )
4999 return( -1 );
5000 	    sp = sp->to->next;
5001 	}
5002     }
5003 return( -1 );
5004 }
5005 
SplinePrevMinMax(Spline * s,int up)5006 static int SplinePrevMinMax(Spline *s,int up) {
5007     const bigreal t = .9999;
5008     bigreal y;
5009     int pup;
5010 
5011     s = s->from->prev;
5012     while ( s->from->me.y==s->to->me.y && s->islinear )
5013 	s = s->from->prev;
5014     y = ((s->splines[1].a*t + s->splines[1].b)*t + s->splines[1].c)*t + s->splines[1].d;
5015     pup = s->to->me.y > y;
5016 return( pup!=up );
5017 }
5018 
SplineNextMinMax(Spline * s,int up)5019 static int SplineNextMinMax(Spline *s,int up) {
5020     const bigreal t = .0001;
5021     bigreal y;
5022     int nup;
5023 
5024     s = s->to->next;
5025     while ( s->from->me.y==s->to->me.y && s->islinear )
5026 	s = s->to->next;
5027     y = ((s->splines[1].a*t + s->splines[1].b)*t + s->splines[1].c)*t + s->splines[1].d;
5028     nup = y > s->from->me.y;
5029 return( nup!=up );
5030 }
5031 
Crossings(Spline * s,BasePoint * pt)5032 static int Crossings(Spline *s,BasePoint *pt) {
5033     extended ext[4];
5034     int i, cnt=0;
5035     bigreal yi, yi1, t, x;
5036 
5037     ext[0] = 0; ext[3] = 1.0;
5038     SplineFindExtrema(&s->splines[1],&ext[1],&ext[2]);
5039     if ( ext[2]!=-1 && SplineAtInflection(&s->splines[1],ext[2])) ext[2]=-1;
5040     if ( ext[1]!=-1 && SplineAtInflection(&s->splines[1],ext[1])) {ext[1] = ext[2]; ext[2]=-1;}
5041     if ( ext[1]==-1 ) ext[1] = 1.0;
5042     else if ( ext[2]==-1 ) ext[2] = 1.0;
5043     yi = s->splines[1].d;
5044     for ( i=0; ext[i]!=1.0; ++i, yi=yi1 ) {
5045 	yi1 = ((s->splines[1].a*ext[i+1]+s->splines[1].b)*ext[i+1]+s->splines[1].c)*ext[i+1]+s->splines[1].d;
5046 	if ( yi==yi1 )
5047     continue;		/* Ignore horizontal lines */
5048 	if ( (yi>yi1 && (pt->y<yi1 || pt->y>yi)) ||
5049 		(yi<yi1 && (pt->y<yi || pt->y>yi1)) )
5050     continue;
5051 	t = IterateSplineSolve(&s->splines[1],ext[i],ext[i+1],pt->y);
5052 	if ( t==-1 )
5053     continue;
5054 	x = ((s->splines[0].a*t+s->splines[0].b)*t+s->splines[0].c)*t+s->splines[0].d;
5055 	if ( x>=pt->x )		/* Things on the edge are not inside */
5056     continue;
5057 	if (( ext[i]!=0 && RealApprox(t,ext[i]) && SplineAtMinMax(&s->splines[1],ext[i]) ) ||
5058 		( ext[i+1]!=1 && RealApprox(t,ext[i+1]) && SplineAtMinMax(&s->splines[1],ext[i+1]) ))
5059     continue;			/* Min/Max points don't add to count */
5060 	if (( RealApprox(t,0) && SplinePrevMinMax(s,yi1>yi) ) ||
5061 		( RealApprox(t,1) && SplineNextMinMax(s,yi1>yi) ))
5062     continue;			/* ditto */
5063 	if ( pt->y==yi1 )	/* Not a min/max. prev/next spline continues same direction */
5064     continue;			/* If it's at an endpoint we don't want to count it twice */
5065 				/* So only add to count at start endpoint, never at final */
5066 	if ( yi1>yi )
5067 	    ++cnt;
5068 	else
5069 	    --cnt;
5070     }
5071 return( cnt );
5072 }
5073 
5074 /* Return whether this point is within the set of contours in spl */
5075 /* Draw a line from [-infinity,pt.y] to [pt.x,pt.y] and count contour crossings */
SSPointWithin(SplineSet * spl,BasePoint * pt)5076 int SSPointWithin(SplineSet *spl,BasePoint *pt) {
5077     int cnt=0;
5078     Spline *s, *first;
5079 
5080     while ( spl!=NULL ) {
5081 	if ( spl->first->prev!=NULL ) {
5082 	    first = NULL;
5083 	    for ( s = spl->first->next; s!=first; s=s->to->next ) {
5084 		if ( first==NULL ) first = s;
5085 		if (( s->from->me.x>pt->x && s->from->nextcp.x>pt->x &&
5086 			s->to->me.x>pt->x && s->to->prevcp.x>pt->x) ||
5087 		    ( s->from->me.y>pt->y && s->from->nextcp.y>pt->y &&
5088 			s->to->me.y>pt->y && s->to->prevcp.y>pt->y) ||
5089 		    ( s->from->me.y<pt->y && s->from->nextcp.y<pt->y &&
5090 			s->to->me.y<pt->y && s->to->prevcp.y<pt->y))
5091 	    continue;
5092 		cnt += Crossings(s,pt);
5093 	    }
5094 	}
5095 	spl = spl->next;
5096     }
5097 return( cnt!=0 );
5098 }
5099 
StemInfoFree(StemInfo * h)5100 void StemInfoFree(StemInfo *h) {
5101     HintInstance *hi, *n;
5102 
5103     for ( hi=h->where; hi!=NULL; hi=n ) {
5104 	n = hi->next;
5105 	chunkfree(hi,sizeof(HintInstance));
5106     }
5107     chunkfree(h,sizeof(StemInfo));
5108 }
5109 
StemInfosFree(StemInfo * h)5110 void StemInfosFree(StemInfo *h) {
5111     StemInfo *hnext;
5112     HintInstance *hi, *n;
5113 
5114     for ( ; h!=NULL; h = hnext ) {
5115 	for ( hi=h->where; hi!=NULL; hi=n ) {
5116 	    n = hi->next;
5117 	    chunkfree(hi,sizeof(HintInstance));
5118 	}
5119 	hnext = h->next;
5120 	chunkfree(h,sizeof(StemInfo));
5121     }
5122 }
5123 
DStemInfoFree(DStemInfo * h)5124 void DStemInfoFree(DStemInfo *h) {
5125     HintInstance *hi, *n;
5126 
5127     for ( hi=h->where; hi!=NULL; hi=n ) {
5128 	n = hi->next;
5129 	chunkfree(hi,sizeof(HintInstance));
5130     }
5131     chunkfree(h,sizeof(DStemInfo));
5132 }
5133 
DStemInfosFree(DStemInfo * h)5134 void DStemInfosFree(DStemInfo *h) {
5135     DStemInfo *hnext;
5136     HintInstance *hi, *n;
5137 
5138     for ( ; h!=NULL; h = hnext ) {
5139 	for ( hi=h->where; hi!=NULL; hi=n ) {
5140 	    n = hi->next;
5141 	    chunkfree(hi,sizeof(HintInstance));
5142 	}
5143 	hnext = h->next;
5144 	chunkfree(h,sizeof(DStemInfo));
5145     }
5146 }
5147 
StemInfoCopy(StemInfo * h)5148 StemInfo *StemInfoCopy(StemInfo *h) {
5149     StemInfo *head=NULL, *last=NULL, *cur;
5150     HintInstance *hilast, *hicur, *hi;
5151 
5152     for ( ; h!=NULL; h = h->next ) {
5153 	cur = chunkalloc(sizeof(StemInfo));
5154 	*cur = *h;
5155 	cur->next = NULL;
5156 	if ( head==NULL )
5157 	    head = last = cur;
5158 	else {
5159 	    last->next = cur;
5160 	    last = cur;
5161 	}
5162 	cur->where = hilast = NULL;
5163 	for ( hi=h->where; hi!=NULL; hi=hi->next ) {
5164 	    hicur = chunkalloc(sizeof(StemInfo));
5165 	    *hicur = *hi;
5166 	    hicur->next = NULL;
5167 	    if ( hilast==NULL )
5168 		cur->where = hilast = hicur;
5169 	    else {
5170 		hilast->next = hicur;
5171 		hilast = hicur;
5172 	    }
5173 	}
5174     }
5175 return( head );
5176 }
5177 
DStemInfoCopy(DStemInfo * h)5178 DStemInfo *DStemInfoCopy(DStemInfo *h) {
5179     DStemInfo *head=NULL, *last=NULL, *cur;
5180     HintInstance *hilast, *hicur, *hi;
5181 
5182     for ( ; h!=NULL; h = h->next ) {
5183 	cur = chunkalloc(sizeof(DStemInfo));
5184 	*cur = *h;
5185 	cur->next = NULL;
5186 	if ( head==NULL )
5187 	    head = last = cur;
5188 	else {
5189 	    last->next = cur;
5190 	    last = cur;
5191 	}
5192 	cur->where = hilast = NULL;
5193 	for ( hi=h->where; hi!=NULL; hi=hi->next ) {
5194 	    hicur = chunkalloc(sizeof(StemInfo));
5195 	    *hicur = *hi;
5196 	    hicur->next = NULL;
5197 	    if ( hilast==NULL )
5198 		cur->where = hilast = hicur;
5199 	    else {
5200 		hilast->next = hicur;
5201 		hilast = hicur;
5202 	    }
5203 	}
5204     }
5205 return( head );
5206 }
5207 
MinimumDistanceCopy(MinimumDistance * md)5208 MinimumDistance *MinimumDistanceCopy(MinimumDistance *md) {
5209     MinimumDistance *head=NULL, *last=NULL, *cur;
5210 
5211     for ( ; md!=NULL; md = md->next ) {
5212 	cur = chunkalloc(sizeof(MinimumDistance));
5213 	*cur = *md;
5214 	cur->next = NULL;
5215 	if ( head==NULL )
5216 	    head = last = cur;
5217 	else {
5218 	    last->next = cur;
5219 	    last = cur;
5220 	}
5221     }
5222 return( head );
5223 }
5224 
KernPairsFree(KernPair * kp)5225 void KernPairsFree(KernPair *kp) {
5226     KernPair *knext;
5227     for ( ; kp!=NULL; kp = knext ) {
5228 	knext = kp->next;
5229 	if ( kp->adjust!=NULL ) {
5230 	    free(kp->adjust->corrections);
5231 	    chunkfree(kp->adjust,sizeof(DeviceTable));
5232 	}
5233 	chunkfree(kp,sizeof(KernPair));
5234     }
5235 }
5236 
AnchorPointsRemoveName(AnchorPoint * alist,AnchorClass * an)5237 static AnchorPoint *AnchorPointsRemoveName(AnchorPoint *alist,AnchorClass *an) {
5238     AnchorPoint *prev=NULL, *ap, *next;
5239 
5240     for ( ap=alist; ap!=NULL; ap=next ) {
5241 	next = ap->next;
5242 	if ( ap->anchor == an ) {
5243 	    if ( prev==NULL )
5244 		    alist = next;
5245 	    else
5246 		    prev->next = next;
5247 	    ap->next = NULL;
5248 	    if ( an->type == act_mark || (an->type==act_mklg && ap->type==at_mark))
5249 		next = NULL;	/* Only one instance of an anchor class in a glyph for mark to base anchors */
5250 				/*  Or for the mark glyphs of ligature classes */
5251 			        /*  Mark to mark & cursive will (probably) have 2 occurances */
5252 			        /*  and ligatures may have lots */
5253 	    AnchorPointsFree(ap);
5254 	} else
5255 	    prev = ap;
5256     }
5257 return( alist );
5258 }
5259 
5260 /* Finds or adds an AnchorClass of the given name. Resets it to have the given subtable if not NULL */
SFFindOrAddAnchorClass(SplineFont * sf,char * name,struct lookup_subtable * sub)5261 AnchorClass *SFFindOrAddAnchorClass(SplineFont *sf,char *name,struct lookup_subtable *sub) {
5262     AnchorClass *ac;
5263     int actype = act_unknown;
5264 
5265     for ( ac=sf->anchor; ac!=NULL; ac=ac->next )
5266         if (strcmp(name,ac->name)==0)
5267     break;
5268     if ( ac!=NULL && ( sub==NULL || ac->subtable==sub ) )
5269 return( ac );
5270 
5271     if ( sub!=NULL )
5272         actype = sub->lookup->lookup_type==gpos_cursive             ? act_curs :
5273                     sub->lookup->lookup_type==gpos_mark2base        ? act_mark :
5274                     sub->lookup->lookup_type==gpos_mark2ligature    ? act_mklg :
5275                     sub->lookup->lookup_type==gpos_mark2mark        ? act_mkmk :
5276                                                                       act_unknown;
5277     if ( ac==NULL ) {
5278         ac = chunkalloc(sizeof(AnchorClass));
5279         ac->subtable = sub;
5280         ac->type = actype;
5281         ac->name = copy( name );
5282         ac->next = sf->anchor;
5283         sf->anchor = ac;
5284     }
5285     else if ( sub!=NULL && ac->subtable!=sub ) {
5286         ac->subtable = sub;
5287         ac->type = actype;
5288     }
5289 return( ac );
5290 }
5291 
SCRemoveAnchorClass(SplineChar * sc,AnchorClass * an)5292 static void SCRemoveAnchorClass(SplineChar *sc,AnchorClass *an) {
5293     Undoes *test;
5294 
5295     if ( sc==NULL )
5296 return;
5297     sc->anchor = AnchorPointsRemoveName(sc->anchor,an);
5298     for ( test = sc->layers[ly_fore].undoes; test!=NULL; test=test->next )
5299 	if ( test->undotype==ut_state || test->undotype==ut_tstate ||
5300 		test->undotype==ut_statehint || test->undotype==ut_statename )
5301 	    test->u.state.anchor = AnchorPointsRemoveName(test->u.state.anchor,an);
5302     for ( test = sc->layers[ly_fore].redoes; test!=NULL; test=test->next )
5303 	if ( test->undotype==ut_state || test->undotype==ut_tstate ||
5304 		test->undotype==ut_statehint || test->undotype==ut_statename )
5305 	    test->u.state.anchor = AnchorPointsRemoveName(test->u.state.anchor,an);
5306 }
5307 
SFRemoveAnchorClass(SplineFont * sf,AnchorClass * an)5308 void SFRemoveAnchorClass(SplineFont *sf,AnchorClass *an) {
5309     int i;
5310     AnchorClass *prev, *test;
5311 
5312     PasteRemoveAnchorClass(sf,an);
5313 
5314     for ( i=0; i<sf->glyphcnt; ++i )
5315 	SCRemoveAnchorClass(sf->glyphs[i],an);
5316     prev = NULL;
5317     for ( test=sf->anchor; test!=NULL; test=test->next ) {
5318 	if ( test==an ) {
5319 	    if ( prev==NULL )
5320 		sf->anchor = test->next;
5321 	    else
5322 		prev->next = test->next;
5323 	    chunkfree(test,sizeof(AnchorClass));
5324     break;
5325 	} else
5326 	    prev = test;
5327     }
5328 }
5329 
APAnchorClassMerge(AnchorPoint * anchors,AnchorClass * into,AnchorClass * from)5330 AnchorPoint *APAnchorClassMerge(AnchorPoint *anchors,AnchorClass *into,AnchorClass *from) {
5331     AnchorPoint *api=NULL, *prev, *ap, *next;
5332 
5333     prev = NULL;
5334     for ( ap=anchors; ap!=NULL; ap=next ) {
5335 	next = ap->next;
5336 	if ( ap->anchor==from ) {
5337 	    for ( api=anchors; api!=NULL; api=api->next ) {
5338 		if ( api->anchor==into &&
5339 			(api->type!=at_baselig || ap->type!=at_baselig || api->lig_index==ap->lig_index))
5340 	    break;
5341 	    }
5342 	    if ( api==NULL && into!=NULL ) {
5343 		ap->anchor = into;
5344 		prev = ap;
5345 	    } else {
5346 		if ( prev==NULL )
5347 		    anchors = next;
5348 		else
5349 		    prev->next = next;
5350 		ap->next = NULL;
5351 		AnchorPointsFree(ap);
5352 	    }
5353 	} else
5354 	    prev = ap;
5355     }
5356 return( anchors );
5357 }
5358 
AnchorClassMerge(SplineFont * sf,AnchorClass * into,AnchorClass * from)5359 void AnchorClassMerge(SplineFont *sf,AnchorClass *into,AnchorClass *from) {
5360     int i;
5361 
5362     if ( into==from )
5363 return;
5364     PasteAnchorClassMerge(sf,into,from);
5365     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
5366 	SplineChar *sc = sf->glyphs[i];
5367 
5368 	sc->anchor = APAnchorClassMerge(sc->anchor,into,from);
5369     }
5370 }
5371 
AnchorPointsCopy(AnchorPoint * alist)5372 AnchorPoint *AnchorPointsCopy(AnchorPoint *alist) {
5373     AnchorPoint *head=NULL, *last, *ap;
5374 
5375     while ( alist!=NULL ) {
5376 	ap = chunkalloc(sizeof(AnchorPoint));
5377 	*ap = *alist;
5378 	if ( ap->xadjust.corrections!=NULL ) {
5379 	    int len = ap->xadjust.last_pixel_size-ap->xadjust.first_pixel_size+1;
5380 	    ap->xadjust.corrections = malloc(len);
5381 	    memcpy(ap->xadjust.corrections,alist->xadjust.corrections,len);
5382 	}
5383 	if ( ap->yadjust.corrections!=NULL ) {
5384 	    int len = ap->yadjust.last_pixel_size-ap->yadjust.first_pixel_size+1;
5385 	    ap->yadjust.corrections = malloc(len);
5386 	    memcpy(ap->yadjust.corrections,alist->yadjust.corrections,len);
5387 	}
5388 	if ( head==NULL )
5389 	    head = ap;
5390 	else
5391 	    last->next = ap;
5392 	last = ap;
5393 	alist = alist->next;
5394     }
5395 return( head );
5396 }
5397 
AnchorPointsFree(AnchorPoint * ap)5398 void AnchorPointsFree(AnchorPoint *ap) {
5399     AnchorPoint *anext;
5400     for ( ; ap!=NULL; ap = anext ) {
5401 	anext = ap->next;
5402 	free(ap->xadjust.corrections);
5403 	free(ap->yadjust.corrections);
5404 	chunkfree(ap,sizeof(AnchorPoint));
5405     }
5406 }
5407 
GuidelineSetFree(GuidelineSet * gl)5408 void GuidelineSetFree(GuidelineSet *gl) {
5409     GuidelineSet *glnext;
5410     for ( ; gl!=NULL; gl = glnext ) {
5411 	glnext = gl->next;
5412 	if (gl->name != NULL) {
5413 		free(gl->name);
5414 		gl->name = NULL;
5415 	}
5416 	if (gl->identifier != NULL) {
5417 		free(gl->identifier);
5418 		gl->identifier = NULL;
5419 	}
5420 	chunkfree(gl,sizeof(GuidelineSet));
5421     }
5422 }
5423 
ValDevFree(ValDevTab * adjust)5424 void ValDevFree(ValDevTab *adjust) {
5425     if ( adjust==NULL )
5426 return;
5427     free( adjust->xadjust.corrections );
5428     free( adjust->yadjust.corrections );
5429     free( adjust->xadv.corrections );
5430     free( adjust->yadv.corrections );
5431     chunkfree(adjust,sizeof(ValDevTab));
5432 }
5433 
ValDevTabCopy(ValDevTab * orig)5434 ValDevTab *ValDevTabCopy(ValDevTab *orig) {
5435     ValDevTab *new;
5436     int i;
5437 
5438     if ( orig==NULL )
5439 return( NULL );
5440     new = chunkalloc(sizeof(ValDevTab));
5441     for ( i=0; i<4; ++i ) {
5442 	if ( (&orig->xadjust)[i].corrections!=NULL ) {
5443 	    int len = (&orig->xadjust)[i].last_pixel_size - (&orig->xadjust)[i].first_pixel_size + 1;
5444 	    (&new->xadjust)[i] = (&orig->xadjust)[i];
5445 	    (&new->xadjust)[i].corrections = malloc(len);
5446 	    memcpy((&new->xadjust)[i].corrections,(&orig->xadjust)[i].corrections,len);
5447 	}
5448     }
5449 return( new );
5450 }
5451 
DeviceTableFree(DeviceTable * dt)5452 void DeviceTableFree(DeviceTable *dt) {
5453 
5454     if ( dt==NULL )
5455 return;
5456 
5457     free(dt->corrections);
5458     chunkfree(dt,sizeof(DeviceTable));
5459 }
5460 
DeviceTableCopy(DeviceTable * orig)5461 DeviceTable *DeviceTableCopy(DeviceTable *orig) {
5462     DeviceTable *new;
5463     int len;
5464 
5465     if ( orig==NULL )
5466 return( NULL );
5467     new = chunkalloc(sizeof(DeviceTable));
5468     *new = *orig;
5469     len = orig->last_pixel_size - orig->first_pixel_size + 1;
5470     new->corrections = malloc(len);
5471     memcpy(new->corrections,orig->corrections,len);
5472 return( new );
5473 }
5474 
DeviceTableSet(DeviceTable * adjust,int size,int correction)5475 void DeviceTableSet(DeviceTable *adjust, int size, int correction) {
5476     int len, i, j;
5477 
5478     len = adjust->last_pixel_size-adjust->first_pixel_size + 1;
5479     if ( correction==0 ) {
5480 	if ( adjust->corrections==NULL ||
5481 		size<adjust->first_pixel_size ||
5482 		size>adjust->last_pixel_size )
5483 return;
5484 	adjust->corrections[size-adjust->first_pixel_size] = 0;
5485 	for ( i=0; i<len; ++i )
5486 	    if ( adjust->corrections[i]!=0 )
5487 	break;
5488 	if ( i==len ) {
5489 	    free(adjust->corrections);
5490 	    memset(adjust,0,sizeof(DeviceTable));
5491 	} else {
5492 	    if ( i!=0 ) {
5493 		for ( j=0; j<len-i; ++j )
5494 		    adjust->corrections[j] = adjust->corrections[j+i];
5495 		adjust->first_pixel_size += i;
5496 		len -= i;
5497 	    }
5498 	    for ( i=len-1; i>=0; --i )
5499 		if ( adjust->corrections[i]!=0 )
5500 	    break;
5501 	    adjust->last_pixel_size = adjust->first_pixel_size+i;
5502 	}
5503     } else {
5504 	if ( adjust->corrections==NULL ) {
5505 	    adjust->first_pixel_size = adjust->last_pixel_size = size;
5506 	    adjust->corrections = malloc(1);
5507 	} else if ( size>=adjust->first_pixel_size &&
5508 		size<=adjust->last_pixel_size ) {
5509 	} else if ( size>adjust->last_pixel_size ) {
5510 	    adjust->corrections = realloc(adjust->corrections,
5511 		    size-adjust->first_pixel_size);
5512 	    for ( i=len; i<size-adjust->first_pixel_size; ++i )
5513 		adjust->corrections[i] = 0;
5514 	    adjust->last_pixel_size = size;
5515 	} else {
5516 	    int8 *new = malloc(adjust->last_pixel_size-size+1);
5517 	    memset(new,0,adjust->first_pixel_size-size);
5518 	    memcpy(new+adjust->first_pixel_size-size,
5519 		    adjust->corrections, len);
5520 	    adjust->first_pixel_size = size;
5521 	    free(adjust->corrections);
5522 	    adjust->corrections = new;
5523 	}
5524 	adjust->corrections[size-adjust->first_pixel_size] = correction;
5525     }
5526 }
5527 
PSTFree(PST * pst)5528 void PSTFree(PST *pst) {
5529     PST *pnext;
5530     for ( ; pst!=NULL; pst = pnext ) {
5531 	pnext = pst->next;
5532 	if ( pst->type==pst_lcaret )
5533 	    free(pst->u.lcaret.carets);
5534 	else if ( pst->type==pst_pair ) {
5535 	    free(pst->u.pair.paired);
5536 	    ValDevFree(pst->u.pair.vr[0].adjust);
5537 	    ValDevFree(pst->u.pair.vr[1].adjust);
5538 	    chunkfree(pst->u.pair.vr,sizeof(struct vr [2]));
5539 	} else if ( pst->type!=pst_position ) {
5540 	    free(pst->u.subs.variant);
5541 	} else if ( pst->type==pst_position ) {
5542 	    ValDevFree(pst->u.pos.adjust);
5543 	}
5544 	chunkfree(pst,sizeof(PST));
5545     }
5546 }
5547 
FPSTRuleContentsFree(struct fpst_rule * r,enum fpossub_format format)5548 void FPSTRuleContentsFree(struct fpst_rule *r, enum fpossub_format format) {
5549     int j;
5550 
5551     switch ( format ) {
5552       case pst_glyphs:
5553 	free(r->u.glyph.names);
5554 	free(r->u.glyph.back);
5555 	free(r->u.glyph.fore);
5556       break;
5557       case pst_class:
5558 	free(r->u.class.nclasses);
5559 	free(r->u.class.bclasses);
5560 	free(r->u.class.fclasses);
5561       break;
5562       case pst_reversecoverage:
5563 	free(r->u.rcoverage.replacements);
5564       case pst_coverage:
5565 	for ( j=0 ; j<r->u.coverage.ncnt ; ++j )
5566 	    free(r->u.coverage.ncovers[j]);
5567 	free(r->u.coverage.ncovers);
5568 	for ( j=0 ; j<r->u.coverage.bcnt ; ++j )
5569 	    free(r->u.coverage.bcovers[j]);
5570 	free(r->u.coverage.bcovers);
5571 	for ( j=0 ; j<r->u.coverage.fcnt ; ++j )
5572 	    free(r->u.coverage.fcovers[j]);
5573 	free(r->u.coverage.fcovers);
5574       break;
5575     }
5576     free(r->lookups);
5577 }
5578 
FPSTRulesFree(struct fpst_rule * r,enum fpossub_format format,int rcnt)5579 void FPSTRulesFree(struct fpst_rule *r, enum fpossub_format format, int rcnt) {
5580     int i;
5581     for ( i=0; i<rcnt; ++i )
5582 	FPSTRuleContentsFree(&r[i],format);
5583     free(r);
5584 }
5585 
RulesCopy(struct fpst_rule * from,int cnt,enum fpossub_format format)5586 static struct fpst_rule *RulesCopy(struct fpst_rule *from, int cnt,
5587 	enum fpossub_format format ) {
5588     int i, j;
5589     struct fpst_rule *to, *f, *t;
5590 
5591     if ( cnt==0 )
5592 return( NULL );
5593 
5594     to = calloc(cnt,sizeof(struct fpst_rule));
5595     for ( i=0; i<cnt; ++i ) {
5596 	f = from+i; t = to+i;
5597 	switch ( format ) {
5598 	  case pst_glyphs:
5599 	    t->u.glyph.names = copy(f->u.glyph.names);
5600 	    t->u.glyph.back = copy(f->u.glyph.back);
5601 	    t->u.glyph.fore = copy(f->u.glyph.fore);
5602 	  break;
5603 	  case pst_class:
5604 	    t->u.class.ncnt = f->u.class.ncnt;
5605 	    t->u.class.bcnt = f->u.class.bcnt;
5606 	    t->u.class.fcnt = f->u.class.fcnt;
5607 	    t->u.class.nclasses = malloc( f->u.class.ncnt*sizeof(uint16));
5608 	    memcpy(t->u.class.nclasses,f->u.class.nclasses,
5609 		    f->u.class.ncnt*sizeof(uint16));
5610 	    if ( t->u.class.bcnt!=0 ) {
5611 		t->u.class.bclasses = malloc( f->u.class.bcnt*sizeof(uint16));
5612 		memcpy(t->u.class.bclasses,f->u.class.bclasses,
5613 			f->u.class.bcnt*sizeof(uint16));
5614 	    }
5615 	    if ( t->u.class.fcnt!=0 ) {
5616 		t->u.class.fclasses = malloc( f->u.class.fcnt*sizeof(uint16));
5617 		memcpy(t->u.class.fclasses,f->u.class.fclasses,
5618 			f->u.class.fcnt*sizeof(uint16));
5619 	    }
5620 	  break;
5621 	  case pst_reversecoverage:
5622 	    t->u.rcoverage.replacements = copy(f->u.rcoverage.replacements);
5623 	  case pst_coverage:
5624 	    t->u.coverage.ncnt = f->u.coverage.ncnt;
5625 	    t->u.coverage.bcnt = f->u.coverage.bcnt;
5626 	    t->u.coverage.fcnt = f->u.coverage.fcnt;
5627 	    t->u.coverage.ncovers = malloc( f->u.coverage.ncnt*sizeof(char *));
5628 	    for ( j=0; j<t->u.coverage.ncnt; ++j )
5629 		t->u.coverage.ncovers[j] = copy(f->u.coverage.ncovers[j]);
5630 	    if ( t->u.coverage.bcnt!=0 ) {
5631 		t->u.coverage.bcovers = malloc( f->u.coverage.bcnt*sizeof(char *));
5632 		for ( j=0; j<t->u.coverage.bcnt; ++j )
5633 		    t->u.coverage.bcovers[j] = copy(f->u.coverage.bcovers[j]);
5634 	    }
5635 	    if ( t->u.coverage.fcnt!=0 ) {
5636 		t->u.coverage.fcovers = malloc( f->u.coverage.fcnt*sizeof(char *));
5637 		for ( j=0; j<t->u.coverage.fcnt; ++j )
5638 		    t->u.coverage.fcovers[j] = copy(f->u.coverage.fcovers[j]);
5639 	    }
5640 	  break;
5641 	}
5642 	if ( f->lookup_cnt!=0 ) {
5643 	    t->lookup_cnt = f->lookup_cnt;
5644 	    t->lookups = malloc(t->lookup_cnt*sizeof(struct seqlookup));
5645 	    memcpy(t->lookups,f->lookups,t->lookup_cnt*sizeof(struct seqlookup));
5646 	}
5647     }
5648 return( to );
5649 }
5650 
FPSTCopy(FPST * fpst)5651 FPST *FPSTCopy(FPST *fpst) {
5652     FPST *nfpst;
5653     int i;
5654 
5655     nfpst = chunkalloc(sizeof(FPST));
5656     *nfpst = *fpst;
5657     nfpst->next = NULL;
5658     if ( nfpst->nccnt!=0 ) {
5659 	nfpst->nclass = malloc(nfpst->nccnt*sizeof(char *));
5660 	nfpst->nclassnames = malloc(nfpst->nccnt*sizeof(char *));
5661 	for ( i=0; i<nfpst->nccnt; ++i ) {
5662 	    nfpst->nclass[i] = copy(fpst->nclass[i]);
5663 	    nfpst->nclassnames[i] = copy(fpst->nclassnames[i]);
5664 	}
5665     }
5666     if ( nfpst->bccnt!=0 ) {
5667 	nfpst->bclass = malloc(nfpst->bccnt*sizeof(char *));
5668 	nfpst->bclassnames = malloc(nfpst->bccnt*sizeof(char *));
5669 	for ( i=0; i<nfpst->bccnt; ++i ) {
5670 	    nfpst->bclass[i] = copy(fpst->bclass[i]);
5671 	    nfpst->bclassnames[i] = copy(fpst->bclassnames[i]);
5672 	}
5673     }
5674     if ( nfpst->fccnt!=0 ) {
5675 	nfpst->fclass = malloc(nfpst->fccnt*sizeof(char *));
5676 	nfpst->fclassnames = malloc(nfpst->fccnt*sizeof(char *));
5677 	for ( i=0; i<nfpst->fccnt; ++i ) {
5678 	    nfpst->fclass[i] = copy(fpst->fclass[i]);
5679 	    nfpst->fclassnames[i] = copy(fpst->fclassnames[i]);
5680 	}
5681     }
5682     nfpst->rules = RulesCopy(fpst->rules,fpst->rule_cnt,fpst->format);
5683 return( nfpst );
5684 }
5685 
FPSTClassesFree(FPST * fpst)5686 void FPSTClassesFree(FPST *fpst) {
5687     int i;
5688 
5689     for ( i=0; i<fpst->nccnt; ++i ) {
5690 	free(fpst->nclass[i]);
5691 	free(fpst->nclassnames[i]);
5692     }
5693     for ( i=0; i<fpst->bccnt; ++i ) {
5694 	free(fpst->bclass[i]);
5695 	free(fpst->bclassnames[i]);
5696     }
5697     for ( i=0; i<fpst->fccnt; ++i ) {
5698 	free(fpst->fclass[i]);
5699 	free(fpst->fclassnames[i]);
5700     }
5701     free(fpst->nclass); free(fpst->bclass); free(fpst->fclass);
5702     free(fpst->nclassnames); free(fpst->bclassnames); free(fpst->fclassnames);
5703 
5704     fpst->nccnt = fpst->bccnt = fpst->fccnt = 0;
5705     fpst->nclass = fpst->bclass = fpst->fclass = NULL;
5706     fpst->nclassnames = fpst->bclassnames = fpst->fclassnames = NULL;
5707 }
5708 
FPSTFree(FPST * fpst)5709 void FPSTFree(FPST *fpst) {
5710     FPST *next;
5711     int i;
5712 
5713     while ( fpst!=NULL ) {
5714 	next = fpst->next;
5715 	FPSTClassesFree(fpst);
5716 	for ( i=0; i<fpst->rule_cnt; ++i ) {
5717 	    FPSTRuleContentsFree( &fpst->rules[i],fpst->format );
5718 	}
5719 	free(fpst->rules);
5720 	chunkfree(fpst,sizeof(FPST));
5721 	fpst = next;
5722     }
5723 }
5724 
MinimumDistancesFree(MinimumDistance * md)5725 void MinimumDistancesFree(MinimumDistance *md) {
5726     MinimumDistance *next;
5727 
5728     while ( md!=NULL ) {
5729 	next = md->next;
5730 	chunkfree(md,sizeof(MinimumDistance));
5731 	md = next;
5732     }
5733 }
5734 
TTFLangNamesFree(struct ttflangname * l)5735 void TTFLangNamesFree(struct ttflangname *l) {
5736     struct ttflangname *next;
5737     int i;
5738 
5739     while ( l!=NULL ) {
5740 	next = l->next;
5741 	for ( i=0; i<ttf_namemax; ++i )
5742 	    free(l->names[i]);
5743 	chunkfree(l,sizeof(*l));
5744 	l = next;
5745     }
5746 }
5747 
AltUniFree(struct altuni * altuni)5748 void AltUniFree(struct altuni *altuni) {
5749     struct altuni *next;
5750 
5751     while ( altuni ) {
5752 	next = altuni->next;
5753 	chunkfree(altuni,sizeof(struct altuni));
5754 	altuni = next;
5755     }
5756 }
5757 
LayerDefault(Layer * layer)5758 void LayerDefault(Layer *layer) {
5759     memset(layer,0,sizeof(Layer));
5760     layer->fill_brush.opacity = layer->stroke_pen.brush.opacity = 1.0;
5761     layer->fill_brush.col = layer->stroke_pen.brush.col = COLOR_INHERITED;
5762     layer->stroke_pen.width = 10;
5763     layer->stroke_pen.linecap = lc_round;
5764     layer->stroke_pen.linejoin = lj_round;
5765     layer->dofill = true;
5766     layer->fillfirst = true;
5767     layer->stroke_pen.trans[0] = layer->stroke_pen.trans[3] = 1.0;
5768     layer->stroke_pen.trans[1] = layer->stroke_pen.trans[2] = 0.0;
5769     /* Dashes default to an unbroken line */
5770 }
5771 
SplineCharCreate(int layer_cnt)5772 SplineChar *SplineCharCreate(int layer_cnt) {
5773     SplineChar *sc = chunkalloc(sizeof(SplineChar));
5774     int i;
5775 
5776     sc->color = COLOR_DEFAULT;
5777     sc->orig_pos = 0xffff;
5778     sc->unicodeenc = -1;
5779     sc->layer_cnt = layer_cnt;
5780     sc->layers = calloc(layer_cnt,sizeof(Layer));
5781     for ( i=0; i<layer_cnt; ++i )
5782 	LayerDefault(&sc->layers[i]);
5783     sc->tex_height = sc->tex_depth = sc->italic_correction = sc->top_accent_horiz =
5784 	    TEX_UNDEF;
5785 return( sc );
5786 }
5787 
SFSplineCharCreate(SplineFont * sf)5788 SplineChar *SFSplineCharCreate(SplineFont *sf) {
5789     SplineChar *sc = SplineCharCreate(sf==NULL?2:sf->layer_cnt);
5790     int i;
5791 
5792     if ( sf==NULL ) {
5793 	sc->layers[ly_back].background = true;
5794 	sc->layers[ly_fore].background = false;
5795     } else {
5796 	for ( i=0; i<sf->layer_cnt; ++i ) {
5797 	    sc->layers[i].background = sf->layers[i].background;
5798 	    sc->layers[i].order2     = sf->layers[i].order2;
5799 	}
5800 	sc->parent = sf;
5801     }
5802 return( sc );
5803 }
5804 
GlyphVariantsFree(struct glyphvariants * gv)5805 void GlyphVariantsFree(struct glyphvariants *gv) {
5806     int i;
5807 
5808     if ( gv==NULL )
5809 return;
5810     free(gv->variants);
5811     DeviceTableFree(gv->italic_adjusts);
5812     for ( i=0; i<gv->part_cnt; ++i )
5813 	free( gv->parts[i].component );
5814     free(gv->parts);
5815     chunkfree(gv,sizeof(*gv));
5816 }
5817 
GlyphVariantsCopy(struct glyphvariants * gv)5818 struct glyphvariants *GlyphVariantsCopy(struct glyphvariants *gv) {
5819     struct glyphvariants *newgv;
5820     int i;
5821 
5822     if ( gv==NULL )
5823 return( NULL );
5824     newgv = chunkalloc(sizeof(struct glyphvariants));
5825     newgv->variants = copy(gv->variants);
5826     newgv->italic_adjusts = DeviceTableCopy(gv->italic_adjusts);
5827     newgv->part_cnt = gv->part_cnt;
5828     if ( gv->part_cnt!=0 ) {
5829 	newgv->parts = calloc(gv->part_cnt,sizeof(struct gv_part));
5830 	memcpy(newgv->parts,gv->parts,gv->part_cnt*sizeof(struct gv_part));
5831 	for ( i=0; i<gv->part_cnt; ++i )
5832 	    newgv->parts[i].component = copy(gv->parts[i].component);
5833     }
5834 return( newgv );
5835 }
5836 
MathKernCopy(struct mathkern * mk)5837 struct mathkern *MathKernCopy(struct mathkern *mk) {
5838     int i,j;
5839     struct mathkern *mknew;
5840 
5841     if ( mk==NULL )
5842 return( NULL );
5843     mknew = chunkalloc(sizeof(*mknew));
5844     for ( i=0; i<4; ++i ) {
5845 	struct mathkernvertex *mkv = &(&mk->top_right)[i];
5846 	struct mathkernvertex *mknewv = &(&mknew->top_right)[i];
5847 	mknewv->cnt = mkv->cnt;
5848 	if ( mknewv->cnt!=0 ) {
5849 	    mknewv->mkd = calloc(mkv->cnt,sizeof(struct mathkerndata));
5850 	    for ( j=0; j<mkv->cnt; ++j ) {
5851 		mknewv->mkd[j].height = mkv->mkd[j].height;
5852 		mknewv->mkd[j].kern   = mkv->mkd[j].kern;
5853 		mknewv->mkd[j].height_adjusts = DeviceTableCopy( mkv->mkd[j].height_adjusts );
5854 		mknewv->mkd[j].kern_adjusts   = DeviceTableCopy( mkv->mkd[j].kern_adjusts );
5855 	    }
5856 	}
5857     }
5858 return( mknew );
5859 }
5860 
MathKernVContentsFree(struct mathkernvertex * mk)5861 void MathKernVContentsFree(struct mathkernvertex *mk) {
5862     int i;
5863     for ( i=0; i<mk->cnt; ++i ) {
5864 	DeviceTableFree(mk->mkd[i].height_adjusts);
5865 	DeviceTableFree(mk->mkd[i].kern_adjusts);
5866     }
5867     free(mk->mkd);
5868 }
5869 
MathKernFree(struct mathkern * mk)5870 void MathKernFree(struct mathkern *mk) {
5871     int i;
5872 
5873     if ( mk==NULL )
5874 return;
5875     for ( i=0; i<4; ++i )
5876 	MathKernVContentsFree( &(&mk->top_right)[i] );
5877     chunkfree(mk,sizeof(*mk));
5878 }
5879 
SplineCharListsFree(struct splinecharlist * dlist)5880 void SplineCharListsFree(struct splinecharlist *dlist) {
5881     struct splinecharlist *dnext;
5882     for ( ; dlist!=NULL; dlist = dnext ) {
5883 	dnext = dlist->next;
5884 	chunkfree(dlist,sizeof(struct splinecharlist));
5885     }
5886 }
5887 
PatternCopy(struct pattern * old,real transform[6])5888 struct pattern *PatternCopy(struct pattern *old, real transform[6]) {
5889     struct pattern *pat;
5890 
5891     if ( old==NULL )
5892 return( NULL );
5893 
5894     pat = chunkalloc(sizeof(struct pattern));
5895 
5896     *pat = *old;
5897     pat->pattern = copy( old->pattern );
5898     if ( transform!=NULL )
5899 	MatMultiply(pat->transform,transform,pat->transform);
5900 return( pat );
5901 }
5902 
PatternFree(struct pattern * pat)5903 void PatternFree(struct pattern *pat) {
5904     if ( pat==NULL )
5905 return;
5906     free(pat->pattern);
5907     chunkfree(pat,sizeof(struct pattern));
5908 }
5909 
GradientCopy(struct gradient * old,real transform[6])5910 struct gradient *GradientCopy(struct gradient *old,real transform[6]) {
5911     struct gradient *grad;
5912 
5913     if ( old==NULL )
5914 return( NULL );
5915 
5916     grad = chunkalloc(sizeof(struct gradient));
5917 
5918     *grad = *old;
5919     grad->grad_stops = malloc(old->stop_cnt*sizeof(struct grad_stops));
5920     memcpy(grad->grad_stops,old->grad_stops,old->stop_cnt*sizeof(struct grad_stops));
5921     if ( transform!=NULL ) {
5922 	BpTransform(&grad->start,&grad->start,transform);
5923 	BpTransform(&grad->stop,&grad->stop,transform);
5924     }
5925 return( grad );
5926 }
5927 
GradientFree(struct gradient * grad)5928 void GradientFree(struct gradient *grad) {
5929     if ( grad==NULL )
5930 return;
5931     free(grad->grad_stops);
5932     chunkfree(grad,sizeof(struct gradient));
5933 }
5934 
BrushCopy(struct brush * into,struct brush * from,real transform[6])5935 void BrushCopy(struct brush *into, struct brush *from, real transform[6]) {
5936     *into = *from;
5937     into->gradient = GradientCopy(from->gradient,transform);
5938     into->pattern = PatternCopy(from->pattern,transform);
5939 }
5940 
PenCopy(struct pen * into,struct pen * from,real transform[6])5941 void PenCopy(struct pen *into, struct pen *from,real transform[6]) {
5942     *into = *from;
5943     into->brush.gradient = GradientCopy(from->brush.gradient,transform);
5944     into->brush.pattern = PatternCopy(from->brush.pattern,transform);
5945 }
5946 
LayerFreeContents(SplineChar * sc,int layer)5947 void LayerFreeContents(SplineChar *sc,int layer) {
5948     SplinePointListsFree(sc->layers[layer].splines);
5949     GradientFree(sc->layers[layer].fill_brush.gradient);
5950     PatternFree(sc->layers[layer].fill_brush.pattern);
5951     GradientFree(sc->layers[layer].stroke_pen.brush.gradient);
5952     PatternFree(sc->layers[layer].stroke_pen.brush.pattern);
5953     RefCharsFree(sc->layers[layer].refs);
5954     GuidelineSetFree(sc->layers[layer].guidelines);
5955     ImageListsFree(sc->layers[layer].images);
5956     /* image garbage collection????!!!! */
5957     UndoesFree(sc->layers[layer].undoes);
5958     UndoesFree(sc->layers[layer].redoes);
5959 }
5960 
SplineCharFreeContents(SplineChar * sc)5961 void SplineCharFreeContents(SplineChar *sc) {
5962     int i;
5963 
5964     if ( sc==NULL )
5965 return;
5966     if (sc->name != NULL) free(sc->name);
5967     if (sc->comment != NULL) free(sc->comment);
5968     if (sc->user_decomp != NULL) free(sc->user_decomp);
5969     for ( i=0; i<sc->layer_cnt; ++i ) {
5970 #if defined(_NO_PYTHON)
5971         if (sc->layers[i].python_persistent != NULL) free( sc->layers[i].python_persistent );	/* It's a string of pickled data which we leave as a string */
5972 #else
5973         PyFF_FreeSCLayer(sc, i);
5974 #endif
5975 	LayerFreeContents(sc,i);
5976     }
5977     StemInfosFree(sc->hstem);
5978     StemInfosFree(sc->vstem);
5979     DStemInfosFree(sc->dstem);
5980     MinimumDistancesFree(sc->md);
5981     KernPairsFree(sc->kerns);
5982     KernPairsFree(sc->vkerns);
5983     AnchorPointsFree(sc->anchor);
5984     SplineCharListsFree(sc->dependents);
5985     PSTFree(sc->possub);
5986     if (sc->ttf_instrs != NULL) free(sc->ttf_instrs);
5987     if (sc->countermasks != NULL) free(sc->countermasks);
5988     if (sc->layers != NULL) free(sc->layers);
5989     AltUniFree(sc->altuni);
5990     GlyphVariantsFree(sc->horiz_variants);
5991     GlyphVariantsFree(sc->vert_variants);
5992     DeviceTableFree(sc->italic_adjusts);
5993     DeviceTableFree(sc->top_accent_adjusts);
5994     MathKernFree(sc->mathkern);
5995     if (sc->glif_name != NULL) { free(sc->glif_name); sc->glif_name = NULL; }
5996 }
5997 
SplineCharFree(SplineChar * sc)5998 void SplineCharFree(SplineChar *sc) {
5999 
6000     if ( sc==NULL )
6001 return;
6002     SplineCharFreeContents(sc);
6003     chunkfree(sc,sizeof(SplineChar));
6004 }
6005 
AnchorClassesFree(AnchorClass * an)6006 void AnchorClassesFree(AnchorClass *an) {
6007     AnchorClass *anext;
6008     for ( ; an!=NULL; an = anext ) {
6009 	anext = an->next;
6010 	free(an->name);
6011 	chunkfree(an,sizeof(AnchorClass));
6012     }
6013 }
6014 
TtfTablesFree(struct ttf_table * tab)6015 void TtfTablesFree(struct ttf_table *tab) {
6016     struct ttf_table *next;
6017 
6018     for ( ; tab!=NULL; tab = next ) {
6019 	next = tab->next;
6020 	free(tab->data);
6021 	chunkfree(tab,sizeof(struct ttf_table));
6022     }
6023 }
6024 
SFRemoveSavedTable(SplineFont * sf,uint32 tag)6025 void SFRemoveSavedTable(SplineFont *sf, uint32 tag) {
6026     struct ttf_table *tab, *prev;
6027 
6028     for ( prev=NULL, tab=sf->ttf_tables; tab!=NULL && tab->tag!=tag; prev=tab, tab=tab->next );
6029     if ( tab!=NULL ) {
6030 	if ( prev==NULL )
6031 	    sf->ttf_tables = tab->next;
6032 	else
6033 	    prev->next = tab->next;
6034     } else {
6035 	for ( prev=NULL, tab=sf->ttf_tab_saved; tab!=NULL && tab->tag!=tag; prev=tab, tab=tab->next );
6036 	if ( tab==NULL )
6037 return;
6038 	if ( prev==NULL )
6039 	    sf->ttf_tab_saved = tab->next;
6040 	else
6041 	    prev->next = tab->next;
6042     }
6043     tab->next = NULL;
6044     TtfTablesFree(tab);
6045     if ( !sf->changed ) {
6046 	sf->changed = true;
6047 	FVSetTitles(sf);
6048     }
6049 }
6050 
ScriptLangListFree(struct scriptlanglist * sl)6051 void ScriptLangListFree(struct scriptlanglist *sl) {
6052     struct scriptlanglist *next;
6053 
6054     while ( sl!=NULL ) {
6055 	next = sl->next;
6056 	free(sl->morelangs);
6057 	chunkfree(sl,sizeof(*sl));
6058 	sl = next;
6059     }
6060 }
6061 
FeatureScriptLangListFree(FeatureScriptLangList * fl)6062 void FeatureScriptLangListFree(FeatureScriptLangList *fl) {
6063     FeatureScriptLangList *next;
6064 
6065     while ( fl!=NULL ) {
6066 	next = fl->next;
6067 	ScriptLangListFree(fl->scripts);
6068 	chunkfree(fl,sizeof(*fl));
6069 	fl = next;
6070     }
6071 }
6072 
OTLookupFree(OTLookup * lookup)6073 void OTLookupFree(OTLookup *lookup) {
6074     struct lookup_subtable *st, *stnext;
6075 
6076     free(lookup->lookup_name);
6077     FeatureScriptLangListFree(lookup->features);
6078     for ( st=lookup->subtables; st!=NULL; st=stnext ) {
6079 	stnext = st->next;
6080 	free(st->subtable_name);
6081 	free(st->suffix);
6082 	chunkfree(st,sizeof(struct lookup_subtable));
6083     }
6084     chunkfree( lookup,sizeof(OTLookup) );
6085 }
6086 
OTLookupListFree(OTLookup * lookup)6087 void OTLookupListFree(OTLookup *lookup ) {
6088     OTLookup *next;
6089 
6090     for ( ; lookup!=NULL; lookup = next ) {
6091 	next = lookup->next;
6092 	OTLookupFree(lookup);
6093     }
6094 }
6095 
KernClassCopy(KernClass * kc)6096 KernClass *KernClassCopy(KernClass *kc) {
6097     KernClass *new;
6098     int i;
6099     if ( kc==NULL )
6100 return( NULL );
6101     new = chunkalloc(sizeof(KernClass));
6102     *new = *kc;
6103     new->firsts = malloc(new->first_cnt*sizeof(char *));
6104     new->seconds = malloc(new->second_cnt*sizeof(char *));
6105     new->offsets = malloc(new->first_cnt*new->second_cnt*sizeof(int16));
6106     memcpy(new->offsets,kc->offsets, new->first_cnt*new->second_cnt*sizeof(int16));
6107     // Group kerning.
6108     if (kc->firsts_names) new->firsts_names = calloc(new->first_cnt,sizeof(char *));
6109     if (kc->seconds_names) new->seconds_names = calloc(new->second_cnt,sizeof(char *));
6110     if (kc->firsts_flags) {
6111 	new->firsts_flags = calloc(new->first_cnt,sizeof(int));
6112 	memcpy(new->firsts_flags, kc->firsts_flags, new->first_cnt*sizeof(int));
6113     }
6114     if (kc->seconds_flags) {
6115 	new->seconds_flags = calloc(new->second_cnt,sizeof(int));
6116 	memcpy(new->seconds_flags, kc->seconds_flags, new->second_cnt*sizeof(int));
6117     }
6118     if (kc->offsets_flags) {
6119 	new->offsets_flags = calloc(new->first_cnt*new->second_cnt,sizeof(int));
6120 	memcpy(new->offsets_flags, kc->offsets_flags, new->first_cnt*new->second_cnt*sizeof(int));
6121     }
6122     for ( i=0; i<new->first_cnt; ++i ) {
6123 	new->firsts[i] = copy(kc->firsts[i]);
6124 	if (kc->firsts_names && kc->firsts_names[i]) new->firsts_names[i] = copy(kc->firsts_names[i]);
6125     }
6126     for ( i=0; i<new->second_cnt; ++i ) {
6127 	new->seconds[i] = copy(kc->seconds[i]);
6128 	if (kc->seconds_names && kc->seconds_names[i]) new->seconds_names[i] = copy(kc->seconds_names[i]);
6129     }
6130     new->adjusts = calloc(new->first_cnt*new->second_cnt,sizeof(DeviceTable));
6131     memcpy(new->adjusts,kc->adjusts, new->first_cnt*new->second_cnt*sizeof(DeviceTable));
6132     for ( i=new->first_cnt*new->second_cnt-1; i>=0 ; --i ) {
6133 	if ( new->adjusts[i].corrections!=NULL ) {
6134 	    int8 *old = new->adjusts[i].corrections;
6135 	    int len = new->adjusts[i].last_pixel_size - new->adjusts[i].first_pixel_size + 1;
6136 	    new->adjusts[i].corrections = malloc(len);
6137 	    memcpy(new->adjusts[i].corrections,old,len);
6138 	}
6139     }
6140 
6141 
6142 
6143     new->next = NULL;
6144 return( new );
6145 }
6146 
KernClassFreeContents(KernClass * kc)6147 void KernClassFreeContents(KernClass *kc) {
6148     int i;
6149     for ( i=1; i<kc->first_cnt; ++i )
6150 	free(kc->firsts[i]);
6151     for ( i=1; i<kc->second_cnt; ++i )
6152 	free(kc->seconds[i]);
6153     free(kc->firsts);
6154     free(kc->seconds);
6155     free(kc->offsets);
6156     for ( i=kc->first_cnt*kc->second_cnt-1; i>=0 ; --i )
6157 	free(kc->adjusts[i].corrections);
6158     free(kc->adjusts);
6159     if (kc->firsts_flags) free(kc->firsts_flags);
6160     if (kc->seconds_flags) free(kc->seconds_flags);
6161     if (kc->offsets_flags) free(kc->offsets_flags);
6162     if (kc->firsts_names) {
6163       for ( i=kc->first_cnt-1; i>=0 ; --i )
6164 	free(kc->firsts_names[i]);
6165       free(kc->firsts_names);
6166     }
6167     if (kc->seconds_names) {
6168       for ( i=kc->second_cnt-1; i>=0 ; --i )
6169 	free(kc->seconds_names[i]);
6170       free(kc->seconds_names);
6171     }
6172 }
6173 
KernClassClearSpecialContents(KernClass * kc)6174 void KernClassClearSpecialContents(KernClass *kc) {
6175     // This frees and zeros special data not handled by the FontForge GUI,
6176     // most of which comes from U. F. O..
6177     int i;
6178     if (kc->firsts_flags) { free(kc->firsts_flags); kc->firsts_flags = NULL; }
6179     if (kc->seconds_flags) { free(kc->seconds_flags); kc->seconds_flags = NULL; }
6180     if (kc->offsets_flags) { free(kc->offsets_flags); kc->offsets_flags = NULL; }
6181     if (kc->firsts_names) {
6182       for ( i=kc->first_cnt-1; i>=0 ; --i )
6183 	free(kc->firsts_names[i]);
6184       free(kc->firsts_names);
6185       kc->firsts_names = NULL;
6186     }
6187     if (kc->seconds_names) {
6188       for ( i=kc->second_cnt-1; i>=0 ; --i )
6189 	free(kc->seconds_names[i]);
6190       free(kc->seconds_names);
6191       kc->seconds_names = NULL;
6192     }
6193 }
6194 
KernClassListFree(KernClass * kc)6195 void KernClassListFree(KernClass *kc) {
6196     KernClass *n;
6197 
6198     while ( kc ) {
6199 	KernClassFreeContents(kc);
6200 	n = kc->next;
6201 	chunkfree(kc,sizeof(KernClass));
6202 	kc = n;
6203     }
6204 }
6205 
KernClassListClearSpecialContents(KernClass * kc)6206 void KernClassListClearSpecialContents(KernClass *kc) {
6207     KernClass *n;
6208 
6209     while ( kc ) {
6210 	KernClassClearSpecialContents(kc);
6211 	n = kc->next;
6212 	kc = n;
6213     }
6214 }
6215 
MacNameListFree(struct macname * mn)6216 void MacNameListFree(struct macname *mn) {
6217     struct macname *next;
6218 
6219     while ( mn!=NULL ) {
6220 	next = mn->next;
6221 	free(mn->name);
6222 	chunkfree(mn,sizeof(struct macname));
6223 	mn = next;
6224     }
6225 }
6226 
MacSettingListFree(struct macsetting * ms)6227 void MacSettingListFree(struct macsetting *ms) {
6228     struct macsetting *next;
6229 
6230     while ( ms!=NULL ) {
6231 	next = ms->next;
6232 	MacNameListFree(ms->setname);
6233 	chunkfree(ms,sizeof(struct macsetting));
6234 	ms = next;
6235     }
6236 }
6237 
MacFeatListFree(MacFeat * mf)6238 void MacFeatListFree(MacFeat *mf) {
6239     MacFeat *next;
6240 
6241     while ( mf!=NULL ) {
6242 	next = mf->next;
6243 	MacNameListFree(mf->featname);
6244 	MacSettingListFree(mf->settings);
6245 	chunkfree(mf,sizeof(MacFeat));
6246 	mf = next;
6247     }
6248 }
6249 
ASMFree(ASM * sm)6250 void ASMFree(ASM *sm) {
6251     ASM *next;
6252     int i;
6253 
6254     while ( sm!=NULL ) {
6255 	next = sm->next;
6256 	if ( sm->type==asm_insert ) {
6257 	    for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
6258 		free( sm->state[i].u.insert.mark_ins );
6259 		free( sm->state[i].u.insert.cur_ins );
6260 	    }
6261 	} else if ( sm->type==asm_kern ) {
6262 	    for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
6263 		free( sm->state[i].u.kern.kerns );
6264 	    }
6265 	}
6266 	for ( i=4; i<sm->class_cnt; ++i )
6267 	    free(sm->classes[i]);
6268 	free(sm->state);
6269 	free(sm->classes);
6270 	chunkfree(sm,sizeof(ASM));
6271 	sm = next;
6272     }
6273 }
6274 
OtfNameListFree(struct otfname * on)6275 void OtfNameListFree(struct otfname *on) {
6276     struct otfname *on_next;
6277 
6278     for ( ; on!=NULL; on = on_next ) {
6279 	on_next = on->next;
6280 	free(on->name);
6281 	chunkfree(on,sizeof(*on));
6282     }
6283 }
6284 
OtfFeatNameListFree(struct otffeatname * fn)6285 void OtfFeatNameListFree(struct otffeatname *fn) {
6286     struct otffeatname *fn_next;
6287 
6288     for ( ; fn!=NULL; fn = fn_next ) {
6289 	fn_next = fn->next;
6290 	OtfNameListFree(fn->names);
6291 	chunkfree(fn,sizeof(*fn));
6292     }
6293 }
6294 
EncMapNew(int enccount,int backmax,Encoding * enc)6295 EncMap *EncMapNew(int enccount,int backmax,Encoding *enc) {
6296 /* NOTE: 'enccount' and 'backmax' can sometimes be different map sizes */
6297     EncMap *map;
6298 
6299     /* Ensure all memory available, otherwise cleanup and exit as NULL */
6300     if ( (map=chunkalloc(sizeof(EncMap)))!=NULL ) {
6301 	if ( (map->map=malloc(enccount*sizeof(int32)))!=NULL ) {
6302 	    if ( (map->backmap=malloc(backmax*sizeof(int32)))!=NULL ) {
6303 		map->enccount = map->encmax = enccount;
6304 		map->backmax = backmax;
6305 		memset(map->map,-1,enccount*sizeof(int32));
6306 		memset(map->backmap,-1,backmax*sizeof(int32));
6307 		map->enc = enc;
6308 		return( map );
6309 	    }
6310 	    free(map->map);
6311 	}
6312 	free(map);
6313     }
6314     return( NULL );
6315 }
6316 
EncMap1to1(int enccount)6317 EncMap *EncMap1to1(int enccount) {
6318 /* Used for CID fonts where CID is same as orig_pos */
6319 /* NOTE: map-enc point to a global variable custom. */
6320 /* TODO: avoid global custom and use passed pointer */
6321     EncMap *map;
6322     int i;
6323 
6324     if ( (map=EncMapNew(enccount,enccount,&custom))!=NULL ) {
6325 	for ( i=0; i<enccount; ++i )
6326 	    map->map[i] = map->backmap[i] = i;
6327     }
6328     return( map );
6329 }
6330 
EncMapFree(EncMap * map)6331 void EncMapFree(EncMap *map) {
6332     if ( map==NULL )
6333 return;
6334 
6335     if ( map->enc->is_temporary )
6336 	EncodingFree(map->enc);
6337     free(map->map);
6338     free(map->backmap);
6339     free(map->remap);
6340     chunkfree(map,sizeof(EncMap));
6341 }
6342 
EncMapCopy(EncMap * map)6343 EncMap *EncMapCopy(EncMap *map) {
6344 /* Make a duplicate 'new' copy of EncMap 'map', Return a NULL if error */
6345 /* NOTE: new-enc also shares map->enc, so be careful if freeing either */
6346     EncMap *new;
6347     int n;
6348 
6349     /* Ensure all memory available, otherwise cleanup and exit as NULL */
6350     if ( (new=chunkalloc(sizeof(EncMap)))!=NULL ) {
6351 	*new = *map;
6352 	if ( (new->map=malloc(map->encmax*sizeof(int32)))!=NULL ) {
6353 	    if ( (new->backmap=malloc(map->backmax*sizeof(int32)))!=NULL ) {
6354 		memcpy(new->map,map->map,map->enccount*sizeof(int32));
6355 		memcpy(new->backmap,map->backmap,map->backmax*sizeof(int32));
6356 		/* NOTE: This new->enc 'also' points to same map->enc. */
6357 		if ( map->remap==NULL )
6358 		    return( new );
6359 		for ( n=0; map->remap[n].infont!=-1; ++n );
6360 		if ( (new->remap=malloc(n*sizeof(struct remap)))!=NULL ) {
6361 		    memcpy(new->remap,map->remap,n*sizeof(struct remap));
6362 		    return( new );
6363 		}
6364 		free(new->backmap);
6365 	    }
6366 	    free(new->map);
6367 	}
6368 	free(new);
6369      }
6370     return( NULL );
6371 }
6372 
MarkClassFree(int cnt,char ** classes,char ** names)6373 void MarkClassFree(int cnt,char **classes,char **names) {
6374     int i;
6375 
6376     for ( i=1; i<cnt; ++i ) {
6377 	free( classes[i] );
6378 	free( names[i] );
6379     }
6380     free( classes );
6381     free( names );
6382 }
6383 
MarkSetFree(int cnt,char ** classes,char ** names)6384 void MarkSetFree(int cnt,char **classes,char **names) {
6385     int i;
6386 
6387     for ( i=0; i<cnt; ++i ) {
6388 	free( classes[i] );
6389 	free( names[i] );
6390     }
6391     free( classes );
6392     free( names );
6393 }
6394 
BaseLangCopy(struct baselangextent * extent)6395 struct baselangextent *BaseLangCopy(struct baselangextent *extent) {
6396     struct baselangextent *head, *last, *cur;
6397 
6398     last = head = NULL;
6399     for ( ; extent!=NULL; extent = extent->next ) {
6400 	cur = chunkalloc(sizeof(struct baselangextent));
6401 	*cur = *extent;
6402 	cur->features = BaseLangCopy(cur->features);
6403 	if ( head==NULL )
6404 	    head = cur;
6405 	else
6406 	    last->next = cur;
6407 	last = cur;
6408     }
6409 return( head );
6410 }
6411 
BaseLangFree(struct baselangextent * extent)6412 void BaseLangFree(struct baselangextent *extent) {
6413     struct baselangextent *next;
6414 
6415     while ( extent!=NULL ) {
6416 	next = extent->next;
6417 	BaseLangFree(extent->features);
6418 	chunkfree(extent,sizeof(struct baselangextent));
6419 	extent = next;
6420     }
6421 }
6422 
BaseScriptFree(struct basescript * bs)6423 void BaseScriptFree(struct basescript *bs) {
6424     struct basescript *next;
6425 
6426     while ( bs!=NULL ) {
6427 	next = bs->next;
6428 	if ( bs->baseline_pos )
6429 	    free(bs->baseline_pos);
6430 	BaseLangFree(bs->langs);
6431 	chunkfree(bs,sizeof(struct basescript));
6432 	bs = next;
6433     }
6434 }
6435 
BaseFree(struct Base * base)6436 void BaseFree(struct Base *base) {
6437     if ( base==NULL )
6438 return;
6439 
6440     free(base->baseline_tags);
6441     BaseScriptFree(base->scripts);
6442     chunkfree(base,sizeof(struct Base));
6443 }
6444 
OTLListCopy(OTLookup ** str)6445 static OTLookup **OTLListCopy(OTLookup **str) {
6446     OTLookup **ret;
6447     int i;
6448 
6449     if ( str == NULL )
6450 return( NULL );
6451     for ( i=0 ; str[i]!=NULL; ++i );
6452     ret = malloc((i+1)*sizeof( OTLookup *));
6453     for ( i=0 ; str[i]!=NULL; ++i )
6454 	ret[i] = str[i];
6455     ret[i] = NULL;
6456 return( ret );
6457 }
6458 
JstfLangsCopy(struct jstf_lang * jl)6459 struct jstf_lang *JstfLangsCopy(struct jstf_lang *jl) {
6460     struct jstf_lang *head=NULL, *last=NULL, *cur;
6461     int i;
6462 
6463     while ( jl!=NULL ) {
6464 	cur = chunkalloc(sizeof(*cur));
6465 	cur->lang = jl->lang;
6466 	cur->cnt = jl->cnt;
6467 	cur->prios = calloc(cur->cnt,sizeof(struct jstf_prio));
6468 	for ( i=0; i<cur->cnt; ++i ) {
6469 	    cur->prios[i].enableShrink = OTLListCopy( jl->prios[i].enableShrink );
6470 	    cur->prios[i].disableShrink = OTLListCopy( jl->prios[i].disableShrink );
6471 	    cur->prios[i].maxShrink = OTLListCopy( jl->prios[i].maxShrink );
6472 	    cur->prios[i].enableExtend = OTLListCopy( jl->prios[i].enableExtend );
6473 	    cur->prios[i].disableExtend = OTLListCopy( jl->prios[i].disableExtend );
6474 	    cur->prios[i].maxExtend = OTLListCopy( jl->prios[i].maxExtend );
6475 	}
6476 	if ( head==NULL )
6477 	    head = cur;
6478 	else
6479 	    last->next = cur;
6480 	last = cur;
6481 	jl = jl->next;
6482     }
6483 return( head );
6484 }
6485 
JstfLangFree(struct jstf_lang * jl)6486 void JstfLangFree(struct jstf_lang *jl) {
6487     struct jstf_lang *next;
6488     int i;
6489 
6490     while ( jl!=NULL ) {
6491 	next = jl->next;
6492 	for ( i=0; i<jl->cnt; ++i ) {
6493 	    struct jstf_prio *jp = &jl->prios[i];
6494 	    free(jp->enableShrink);
6495 	    free(jp->disableShrink);
6496 	    free(jp->maxShrink);
6497 	    free(jp->enableExtend);
6498 	    free(jp->disableExtend);
6499 	    free(jp->maxExtend);
6500 	}
6501 	free(jl->prios);
6502 	chunkfree(jl,sizeof(*jl));
6503 	jl = next;
6504     }
6505 }
6506 
JustifyFree(Justify * just)6507 void JustifyFree(Justify *just) {
6508     Justify *next;
6509 
6510     while ( just!=NULL ) {
6511 	next = just->next;
6512 	free(just->extenders);
6513 	JstfLangFree(just->langs);
6514 	chunkfree(just,sizeof(*just));
6515 	just = next;
6516     }
6517 }
6518 
SplineFontFree(SplineFont * sf)6519 void SplineFontFree(SplineFont *sf) {
6520     int i;
6521     BDFFont *bdf, *bnext;
6522 
6523     if ( sf==NULL )
6524 return;
6525     if ( sf->mm!=NULL ) {
6526 	MMSetFree(sf->mm);
6527 return;
6528     }
6529     CopyBufferClearCopiedFrom(sf);
6530     PasteRemoveSFAnchors(sf);
6531     if ( sf->sfd_version>0 && sf->sfd_version<2 ) {
6532       // Free special data.
6533       SplineFont1* oldsf = (SplineFont1*)sf;
6534       // First the script language lists.
6535       if (oldsf->script_lang != NULL) {
6536         int scripti;
6537         for (scripti = 0; oldsf->script_lang[scripti] != NULL; scripti ++) {
6538           int scriptj;
6539           for (scriptj = 0; oldsf->script_lang[scripti][scriptj].script != 0; scriptj ++) {
6540             if (oldsf->script_lang[scripti][scriptj].langs != NULL) free(oldsf->script_lang[scripti][scriptj].langs);
6541           }
6542           free(oldsf->script_lang[scripti]); oldsf->script_lang[scripti] = NULL;
6543         }
6544         free(oldsf->script_lang); oldsf->script_lang = NULL;
6545       }
6546       // Then the table orderings.
6547       {
6548         struct table_ordering *ord = oldsf->orders;
6549         while (ord != NULL) {
6550           struct table_ordering *ordtofree = ord;
6551           if (ord->ordered_features != NULL) free(ord->ordered_features);
6552           ord = ord->next;
6553           chunkfree(ordtofree, sizeof(struct table_ordering));
6554         }
6555         oldsf->orders = NULL;
6556       }
6557     }
6558     for ( bdf = sf->bitmaps; bdf!=NULL; bdf = bnext ) {
6559 	bnext = bdf->next;
6560 	BDFFontFree(bdf);
6561     }
6562     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
6563 	SplineCharFree(sf->glyphs[i]);
6564     free(sf->glyphs);
6565     free(sf->fontname);
6566     free(sf->fullname);
6567     free(sf->familyname);
6568     free(sf->weight);
6569     free(sf->copyright);
6570     free(sf->comments);
6571     free(sf->filename);
6572     free(sf->origname);
6573     free(sf->autosavename);
6574     free(sf->version);
6575     free(sf->xuid);
6576     free(sf->cidregistry);
6577     free(sf->ordering);
6578     if ( sf->styleMapFamilyName && sf->styleMapFamilyName[0]!='\0' ) { free(sf->styleMapFamilyName); sf->styleMapFamilyName = NULL; }
6579     MacFeatListFree(sf->features);
6580     /* We don't free the EncMap. That field is only a temporary pointer. Let the FontViewBase free it, that's where it really lives */
6581     // TODO: But that doesn't always get freed. The statement below causes double-frees, so we need to come up with better conditions.
6582     #if 0
6583     if (sf->cidmaster == NULL || sf->cidmaster == sf)
6584       if (sf->map != NULL) { free(sf->map); sf->map = NULL; }
6585     #endif // 0
6586     SplinePointListsFree(sf->grid.splines);
6587     AnchorClassesFree(sf->anchor);
6588     TtfTablesFree(sf->ttf_tables);
6589     TtfTablesFree(sf->ttf_tab_saved);
6590     UndoesFree(sf->grid.undoes);
6591     UndoesFree(sf->grid.redoes);
6592     PSDictFree(sf->private);
6593     TTFLangNamesFree(sf->names);
6594     for ( i=0; i<sf->subfontcnt; ++i )
6595 	SplineFontFree(sf->subfonts[i]);
6596     free(sf->subfonts);
6597     GlyphHashFree(sf);
6598     OTLookupListFree(sf->gpos_lookups);
6599     OTLookupListFree(sf->gsub_lookups);
6600     KernClassListFree(sf->kerns);
6601     KernClassListFree(sf->vkerns);
6602     FPSTFree(sf->possub);
6603     ASMFree(sf->sm);
6604     OtfNameListFree(sf->fontstyle_name);
6605     OtfFeatNameListFree(sf->feat_names);
6606     MarkClassFree(sf->mark_class_cnt,sf->mark_classes,sf->mark_class_names);
6607     MarkSetFree(sf->mark_set_cnt,sf->mark_sets,sf->mark_set_names);
6608     GlyphGroupsFree(sf->groups);
6609     GlyphGroupKernsFree(sf->groupkerns);
6610     GlyphGroupKernsFree(sf->groupvkerns);
6611     free( sf->gasp );
6612 #if defined(_NO_PYTHON)
6613     free( sf->python_persistent );	/* It's a string of pickled data which we leave as a string */
6614 #else
6615     PyFF_FreeSF(sf);
6616 #endif
6617     BaseFree(sf->horiz_base);
6618     BaseFree(sf->vert_base);
6619     JustifyFree(sf->justify);
6620     if (sf->layers != NULL) {
6621       int layer;
6622       for (layer = 0; layer < sf->layer_cnt; layer ++) {
6623         if (sf->layers[layer].name != NULL) {
6624           free(sf->layers[layer].name);
6625           sf->layers[layer].name = NULL;
6626         }
6627         if (sf->layers[layer].ufo_path != NULL) {
6628           free(sf->layers[layer].ufo_path);
6629           sf->layers[layer].ufo_path = NULL;
6630         }
6631       }
6632       free(sf->layers); sf->layers = NULL;
6633     }
6634     free(sf);
6635 }
6636 
SplineFontClearSpecial(SplineFont * sf)6637 void SplineFontClearSpecial(SplineFont *sf) {
6638     int i;
6639 
6640     if ( sf==NULL )
6641 return;
6642     if ( sf->mm!=NULL ) {
6643 	MMSetClearSpecial(sf->mm);
6644 return;
6645     }
6646     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
6647 	struct splinechar *sc = sf->glyphs[i];
6648 	if (sc->glif_name != NULL) { free(sc->glif_name); sc->glif_name = NULL; }
6649 	// Go through layers.
6650 	int lyi;
6651 	for ( lyi=0; lyi<sc->layer_cnt; ++lyi ) {
6652 		// Free guidelines.
6653 		GuidelineSetFree(sc->layers[lyi].guidelines);
6654 		sc->layers[lyi].guidelines = NULL;
6655 	}
6656     }
6657     for ( i=0; i<sf->subfontcnt; ++i )
6658 	SplineFontClearSpecial(sf->subfonts[i]);
6659     KernClassListClearSpecialContents(sf->kerns);
6660     KernClassListClearSpecialContents(sf->vkerns);
6661     if (sf->groups) { GlyphGroupsFree(sf->groups); sf->groups = NULL; }
6662     if (sf->groupkerns) { GlyphGroupKernsFree(sf->groupkerns); sf->groupkerns = NULL; }
6663     if (sf->groupvkerns) { GlyphGroupKernsFree(sf->groupvkerns); sf->groupvkerns = NULL; }
6664     if (sf->python_persistent) {
6665 #if defined(_NO_PYTHON)
6666       free( sf->python_persistent );	/* It's a string of pickled data which we leave as a string */
6667 #else
6668       PyFF_FreeSF(sf);
6669 #endif
6670       sf->python_persistent = NULL;
6671     }
6672     if (sf->layers != NULL) {
6673       int layer;
6674       for (layer = 0; layer < sf->layer_cnt; layer ++) {
6675         if (sf->layers[layer].ufo_path != NULL) {
6676           free(sf->layers[layer].ufo_path);
6677           sf->layers[layer].ufo_path = NULL;
6678         }
6679       }
6680     }
6681 }
6682 
6683 #if 0
6684 // These are in splinefont.h.
6685 #define GROUP_NAME_KERNING_UFO 1
6686 #define GROUP_NAME_KERNING_FEATURE 2
6687 #define GROUP_NAME_VERTICAL 4 // Otherwise horizontal.
6688 #define GROUP_NAME_RIGHT 8 // Otherwise left (or above).
6689 #endif // 0
6690 
6691 
GlyphGroupFree(struct ff_glyphclasses * group)6692 void GlyphGroupFree(struct ff_glyphclasses* group) {
6693   if (group->classname != NULL) free(group->classname);
6694   if (group->glyphs != NULL) free(group->glyphs);
6695   free(group);
6696 }
6697 
GlyphGroupsFree(struct ff_glyphclasses * root)6698 void GlyphGroupsFree(struct ff_glyphclasses* root) {
6699   struct ff_glyphclasses* current = root;
6700   struct ff_glyphclasses* next;
6701   while (current != NULL) {
6702     next = current->next;
6703     GlyphGroupFree(current);
6704     current = next;
6705   }
6706 }
6707 
GroupNameType(const char * input)6708 int GroupNameType(const char *input) {
6709   int kerning_type = 0; // 1 for U. F. O., 2 for feature file.
6710   int kerning_vert = 0;
6711   int kerning_side = 0; // 1 for left, 2 for right.
6712   if (strchr(input, ' ') || strchr(input, '\n')) return -1;
6713   if (strncmp(input, "public.kern", strlen("public.kern")) == 0) {
6714     int off1 = strlen("public.kern");
6715     char nextc = *(input+off1);
6716     if (nextc == '1') kerning_side = 1;
6717     if (nextc == '2') kerning_side = 2;
6718     if (kerning_side != 0 && *(input+off1+1) == '.' && *(input+off1+2) != '\0')
6719       kerning_type = 1;
6720     else return -1;
6721   } else if (strncmp(input, "public.vkern", strlen("public.vkern")) == 0) {
6722     kerning_vert = 1;
6723     int off1 = strlen("public.vkern");
6724     char nextc = *(input+off1);
6725     if (nextc == '1') kerning_side = 1;
6726     if (nextc == '2') kerning_side = 2;
6727     if (kerning_side != 0 && *(input+off1+1) == '.' && *(input+off1+2) != '\0')
6728       kerning_type = 1;
6729     else return -1;
6730   } else if (strncmp(input, "@MMK_", strlen("@MMK_")) == 0) {
6731     int off1 = strlen("@MMK_");
6732     char nextc = *(input+off1);
6733     if (nextc == 'L') kerning_side = 1;
6734     else if (nextc == 'R') kerning_side = 2;
6735     else if (nextc == 'A') { kerning_side = 1; kerning_vert = 1; }
6736     else if (nextc == 'B') { kerning_side = 2; kerning_vert = 1; }
6737     if (kerning_side != 0 && *(input+off1+1) == '_' && *(input+off1+2) != '\0')
6738       kerning_type = 2;
6739     else return -1;
6740   }
6741   return kerning_type | ((kerning_side == 2) ? GROUP_NAME_RIGHT : 0) | (kerning_vert * GROUP_NAME_VERTICAL);
6742 }
6743 
GlyphGroupKernFree(struct ff_rawoffsets * groupkern)6744 void GlyphGroupKernFree(struct ff_rawoffsets* groupkern) {
6745   if (groupkern->left != NULL) free(groupkern->left);
6746   if (groupkern->right != NULL) free(groupkern->right);
6747   free(groupkern);
6748 }
6749 
GlyphGroupKernsFree(struct ff_rawoffsets * root)6750 void GlyphGroupKernsFree(struct ff_rawoffsets* root) {
6751   struct ff_rawoffsets* current = root;
6752   struct ff_rawoffsets* next;
6753   while (current != NULL) {
6754     next = current->next;
6755     GlyphGroupKernFree(current);
6756     current = next;
6757   }
6758 }
6759 
CountKerningClasses(SplineFont * sf)6760 int CountKerningClasses(SplineFont *sf) {
6761     struct kernclass *current_kernclass;
6762     int isv;
6763     int isr;
6764     int i;
6765     int absolute_index = 0; // This gives us a unique index for each kerning class.
6766     // First we catch the existing names.
6767     absolute_index = 0;
6768     for (isv = 0; isv < 2; isv++)
6769     for (current_kernclass = (isv ? sf->vkerns : sf->kerns); current_kernclass != NULL; current_kernclass = current_kernclass->next)
6770     for (isr = 0; isr < 2; isr++) {
6771       // for ( i=0; i< (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt); ++i );
6772       // absolute_index +=i;
6773       absolute_index += (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt);
6774     }
6775     return absolute_index;
6776 }
6777 
count_caps(const char * input)6778 size_t count_caps(const char * input) {
6779   size_t count = 0;
6780   for (int i = 0; input[i] != '\0'; i++) {
6781     if ((input[i] >= 'A') && (input[i] <= 'Z')) count ++;
6782   }
6783   return count;
6784 }
6785 
upper_case(const char * input)6786 char * upper_case(const char * input) {
6787   size_t output_length = strlen(input);
6788   char * output = malloc(output_length + 1);
6789   off_t pos = 0;
6790   if (output == NULL) return NULL;
6791   while (pos < output_length) {
6792     if ((input[pos] >= 'a') && (input[pos] <= 'z')) {
6793       output[pos] = (char)(((unsigned char) input[pos]) - 0x20U);
6794     } else {
6795       output[pos] = input[pos];
6796     }
6797     pos++;
6798   }
6799   output[pos] = '\0';
6800   return output;
6801 }
6802 
same_case(const char * input)6803 char * same_case(const char * input) {
6804   size_t output_length = strlen(input);
6805   char * output = malloc(output_length + 1);
6806   off_t pos = 0;
6807   if (output == NULL) return NULL;
6808   while (pos < output_length) {
6809     output[pos] = input[pos];
6810     pos++;
6811   }
6812   output[pos] = '\0';
6813   return output;
6814 }
6815 
delimit_null(const char * input,char delimiter)6816 char * delimit_null(const char * input, char delimiter) {
6817   size_t output_length = strlen(input);
6818   char * output = malloc(output_length + 1);
6819   if (output == NULL) return NULL;
6820   off_t pos = 0;
6821   while (pos < output_length) {
6822     if (input[pos] == delimiter) {
6823       output[pos] = '\0';
6824     } else {
6825       output[pos] = input[pos];
6826     }
6827     pos++;
6828   }
6829   return output;
6830 }
6831 
HashKerningClassNamesFlex(SplineFont * sf,struct glif_name_index * class_name_hash,int capitalize)6832 int HashKerningClassNamesFlex(SplineFont *sf, struct glif_name_index * class_name_hash, int capitalize) {
6833     struct kernclass *current_kernclass;
6834     int isv;
6835     int isr;
6836     int i;
6837     int absolute_index = 0; // This gives us a unique index for each kerning class.
6838     // First we catch the existing names.
6839     absolute_index = 0;
6840     for (isv = 0; isv < 2; isv++)
6841     for (current_kernclass = (isv ? sf->vkerns : sf->kerns); current_kernclass != NULL; current_kernclass = current_kernclass->next)
6842     for (isr = 0; isr < 2; isr++) if ( (isr ? current_kernclass->seconds_names : current_kernclass->firsts_names) != NULL ) {
6843     for ( i=0; i < (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt); ++i )
6844     if ( (isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]) != NULL ) {
6845         // Add it to the hash table with its index.
6846 	if (capitalize) {
6847           char * cap_name = upper_case(isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]);
6848           glif_name_track_new(class_name_hash, absolute_index + i, cap_name);
6849           free(cap_name); cap_name = NULL;
6850 	} else {
6851           glif_name_track_new(class_name_hash, absolute_index + i, (isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]));
6852         }
6853     }
6854     absolute_index +=i;
6855     }
6856     return absolute_index;
6857 }
HashKerningClassNames(SplineFont * sf,struct glif_name_index * class_name_hash)6858 int HashKerningClassNames(SplineFont *sf, struct glif_name_index * class_name_hash) {
6859   return HashKerningClassNamesFlex(sf, class_name_hash, 0);
6860 }
HashKerningClassNamesCaps(SplineFont * sf,struct glif_name_index * class_name_hash)6861 int HashKerningClassNamesCaps(SplineFont *sf, struct glif_name_index * class_name_hash) {
6862   return HashKerningClassNamesFlex(sf, class_name_hash, 1);
6863 }
6864 
KerningClassSeekByAbsoluteIndex(const struct splinefont * sf,int seek_index,struct kernclass ** okc,int * oisv,int * oisr,int * ooffset)6865 int KerningClassSeekByAbsoluteIndex(const struct splinefont *sf, int seek_index, struct kernclass **okc, int *oisv, int *oisr, int *ooffset) {
6866     int current = 0;
6867     struct kernclass *current_kernclass;
6868     int isv;
6869     int isr;
6870     int absolute_index = 0; // This gives us a unique index for each kerning class.
6871     // First we catch the existing names.
6872     absolute_index = 0;
6873     for (isv = 0; isv < 2; isv++)
6874     for (current_kernclass = (isv ? sf->vkerns : sf->kerns); current_kernclass != NULL; current_kernclass = current_kernclass->next)
6875     for (isr = 0; isr < 2; isr++) {
6876       if (seek_index < absolute_index + (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt)) {
6877         *okc = current_kernclass;
6878         *oisv = isv;
6879         *oisr = isr;
6880         *ooffset = seek_index - absolute_index;
6881         return 1;
6882       }
6883       absolute_index += (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt);
6884     }
6885     return 0;
6886 }
6887 
SFGetGroup(const struct splinefont * sf,int index,const char * name)6888 struct ff_glyphclasses *SFGetGroup(const struct splinefont *sf, int index, const char *name) {
6889   if (sf == NULL) return NULL;
6890   struct ff_glyphclasses *ret = sf->groups;
6891   while (ret != NULL && (ret->classname == NULL || strcmp(ret->classname, name) != 0)) ret = ret->next;
6892   return ret;
6893 }
6894 
StringInStrings(char const * const * space,int length,const char * target)6895 int StringInStrings(char const* const* space, int length, const char *target) {
6896   int pos;
6897   for (pos = 0; pos < length; pos++) if (strcmp(space[pos], target) == 0) break;
6898   return pos;
6899 }
6900 
StringExplode(const char * input,char delimiter)6901 char **StringExplode(const char *input, char delimiter) {
6902   if (input == NULL) return NULL;
6903   const char *pstart = input;
6904   const char *pend = input;
6905   int entry_count = 0;
6906   while (*pend != '\0') {
6907     while (*pstart == delimiter) pstart++;
6908     pend = pstart;
6909     while (*pend != delimiter && *pend != '\0') pend++;
6910     if (pend > pstart) entry_count++;
6911     pstart = pend;
6912   }
6913   char **output = calloc(entry_count + 1, sizeof(char*));
6914   pstart = input;
6915   pend = input;
6916   entry_count = 0;
6917   while (*pend != '\0') {
6918     while (*pstart == delimiter) pstart++;
6919     pend = pstart;
6920     while (*pend != delimiter && *pend != '\0') pend++;
6921     if (pend > pstart) output[entry_count++] = copyn(pstart, pend-pstart);
6922     pstart = pend;
6923   }
6924   return output;
6925 }
6926 
ExplodedStringFree(char ** input)6927 void ExplodedStringFree(char **input) {
6928   int index = 0;
6929   while (input[index] != NULL) free(input[index++]);
6930   free(input);
6931 }
6932 
SFKerningGroupExistsSpecific(const struct splinefont * sf,const char * groupname,int isv,int isr)6933 int SFKerningGroupExistsSpecific(const struct splinefont *sf, const char *groupname, int isv, int isr) {
6934   if (sf == NULL) return 0;
6935   if (isv) {
6936     if (sf->vkerns == NULL) return 0;
6937     if (isr) return (StringInStrings((const char * const *)sf->vkerns->seconds_names, sf->vkerns->second_cnt, groupname) < sf->vkerns->second_cnt);
6938     else return (StringInStrings((const char * const *)sf->vkerns->firsts_names, sf->vkerns->first_cnt, groupname) < sf->vkerns->first_cnt);
6939   } else {
6940     if (sf->kerns == NULL) return 0;
6941     if (isr) return (StringInStrings((const char * const *)sf->kerns->seconds_names, sf->kerns->second_cnt, groupname) < sf->kerns->second_cnt);
6942     else return (StringInStrings((const char * const *)sf->kerns->firsts_names, sf->kerns->first_cnt, groupname) < sf->kerns->first_cnt);
6943   }
6944   return 0;
6945 }
6946 
MMSetFreeContents(MMSet * mm)6947 void MMSetFreeContents(MMSet *mm) {
6948     int i;
6949 
6950     free(mm->instances);
6951 
6952     free(mm->positions);
6953     free(mm->defweights);
6954 
6955     for ( i=0; i<mm->axis_count; ++i ) {
6956 	free(mm->axes[i]);
6957 	free(mm->axismaps[i].blends);
6958 	free(mm->axismaps[i].designs);
6959 	MacNameListFree(mm->axismaps[i].axisnames);
6960     }
6961     free(mm->axismaps);
6962     free(mm->cdv);
6963     free(mm->ndv);
6964     for ( i=0; i<mm->named_instance_count; ++i ) {
6965 	free(mm->named_instances[i].coords);
6966 	MacNameListFree(mm->named_instances[i].names);
6967     }
6968     free(mm->named_instances);
6969 }
6970 
MMSetFree(MMSet * mm)6971 void MMSetFree(MMSet *mm) {
6972     int i;
6973 
6974     for ( i=0; i<mm->instance_count; ++i ) {
6975 	mm->instances[i]->mm = NULL;
6976 	mm->instances[i]->map = NULL;
6977 	SplineFontFree(mm->instances[i]);
6978     }
6979     mm->normal->mm = NULL;
6980     SplineFontFree(mm->normal);		/* EncMap gets freed here */
6981     MMSetFreeContents(mm);
6982 
6983     chunkfree(mm,sizeof(*mm));
6984 }
6985 
MMSetClearSpecial(MMSet * mm)6986 void MMSetClearSpecial(MMSet *mm) {
6987     int i;
6988 
6989     for ( i=0; i<mm->instance_count; ++i ) {
6990 	SplineFontClearSpecial(mm->instances[i]);
6991     }
6992     SplineFontClearSpecial(mm->normal);
6993 }
6994 
xcmp(const void * _p1,const void * _p2)6995 static int xcmp(const void *_p1, const void *_p2) {
6996     const SplinePoint * const *_spt1 = _p1, * const *_spt2 = _p2;
6997     const SplinePoint *sp1 = *_spt1, *sp2 = *_spt2;
6998 
6999     if ( sp1->me.x>sp2->me.x )
7000 return( 1 );
7001     else if ( sp1->me.x<sp2->me.x )
7002 return( -1 );
7003 
7004 return( 0 );
7005 }
7006 
ycmp(const void * _p1,const void * _p2)7007 static int ycmp(const void *_p1, const void *_p2) {
7008     const SplinePoint * const *_spt1 = _p1, * const *_spt2 = _p2;
7009     const SplinePoint *sp1 = *_spt1, *sp2 = *_spt2;
7010 
7011     if ( sp1->me.y>sp2->me.y )
7012 return( 1 );
7013     else if ( sp1->me.y<sp2->me.y )
7014 return( -1 );
7015 
7016 return( 0 );
7017 }
7018 
7019 struct cluster {
7020     int cnt;
7021     int first, last;
7022 };
7023 
countcluster(SplinePoint ** ptspace,struct cluster * cspace,int ptcnt,int is_y,int i,bigreal within,bigreal max)7024 static void countcluster(SplinePoint **ptspace, struct cluster *cspace,
7025 	int ptcnt, int is_y, int i, bigreal within, bigreal max) {
7026     int j;
7027 
7028     cspace[i].cnt = 1;	/* current point is always within its own cluster */
7029     cspace[i].first = cspace[i].last = i;
7030     for ( j=i-1; j>=0; --j ) {
7031 	if ( cspace[j].cnt==0 )		/* Already allocated to a different cluster */
7032     break;
7033 	if ( (&ptspace[j+1]->me.x)[is_y]-(&ptspace[j]->me.x)[is_y]<within &&
7034 		(&ptspace[i]->me.x)[is_y]-(&ptspace[j]->me.x)[is_y]<max ) {
7035 	    ++cspace[i].cnt;
7036 	    cspace[i].first = j;
7037 	} else
7038     break;
7039     }
7040     for ( j=i+1; j<ptcnt; ++j ) {
7041 	if ( cspace[j].cnt==0 )		/* Already allocated to a different cluster */
7042     break;
7043 	if ( (&ptspace[j]->me.x)[is_y]-(&ptspace[j-1]->me.x)[is_y]<within &&
7044 		(&ptspace[j]->me.x)[is_y]-(&ptspace[i]->me.x)[is_y]<max ) {
7045 	    ++cspace[i].cnt;
7046 	    cspace[i].last = j;
7047 	} else
7048     break;
7049     }
7050 }
7051 
_SplineCharRoundToCluster(SplineChar * sc,SplinePoint ** ptspace,struct cluster * cspace,int ptcnt,int is_y,int dohints,int layer,int changed,bigreal within,bigreal max)7052 static int _SplineCharRoundToCluster(SplineChar *sc,SplinePoint **ptspace,
7053 	struct cluster *cspace,int ptcnt,int is_y,int dohints,
7054 	int layer, int changed,
7055 	bigreal within, bigreal max ) {
7056     int i,j,best;
7057     bigreal low,high,cur;
7058 
7059     for ( i=0; i<ptcnt; ++i )
7060 	cspace[i].cnt = 1;		/* Initialize to non-zero */
7061     for ( i=0; i<ptcnt; ++i )
7062 	countcluster(ptspace,cspace,ptcnt,is_y,i,within,max);
7063 
7064     for (;;) {
7065 	j=0; best = cspace[0].cnt;
7066 	for ( i=1; i<ptcnt; ++i ) {
7067 	    if ( cspace[i].cnt>best ) {
7068 		j=i;
7069 		best = cspace[i].cnt;
7070 	    }
7071 	}
7072 	if ( best<=1 )		/* No more clusters */
7073 return( changed );
7074 	for ( i=j+1; i<=cspace[j].last && cspace[i].cnt==cspace[j].cnt; ++i );
7075 	j = (j+i-1)/2;		/* There are probably several points with the */
7076 				/* same values for cspace. Pick one in the */
7077 			        /* middle, so that when round we round to the */
7078 			        /* middle rather than to an edge */
7079 	low = (&ptspace[cspace[j].first]->me.x)[is_y];
7080 	high = (&ptspace[cspace[j].last]->me.x)[is_y];
7081 	cur = (&ptspace[j]->me.x)[is_y];
7082 	if ( low==high ) {
7083 	    for ( i=cspace[j].first; i<=cspace[j].last; ++i )
7084 		cspace[i].cnt = 0;
7085     continue;
7086 	}
7087 	if ( !changed ) {
7088 	    if ( layer==ly_all )
7089 		SCPreserveState(sc,dohints);
7090 	    else if ( layer!=ly_grid )
7091 		SCPreserveLayer(sc,layer,dohints);
7092 	    changed = true;
7093 	}
7094 	for ( i=cspace[j].first; i<=cspace[j].last; ++i ) {
7095 	    bigreal off = (&ptspace[i]->me.x)[is_y] - cur;
7096 	    (&ptspace[i]->nextcp.x)[is_y] -= off;
7097 	    (&ptspace[i]->prevcp.x)[is_y] -= off;
7098 	    (&ptspace[i]->me.x)[is_y] -= off;
7099 	    if ( (&ptspace[i]->prevcp.x)[is_y]-cur>-within &&
7100 		    (&ptspace[i]->prevcp.x)[is_y]-cur<within ) {
7101 		(&ptspace[i]->prevcp.x)[is_y] = cur;
7102 		if ( (&ptspace[i]->prevcp.x)[!is_y]==(&ptspace[i]->me.x)[!is_y] )
7103 		    ptspace[i]->noprevcp = true;
7104 	    }
7105 	    if ( (&ptspace[i]->nextcp.x)[is_y]-cur>-within &&
7106 		    (&ptspace[i]->nextcp.x)[is_y]-cur<within ) {
7107 		(&ptspace[i]->nextcp.x)[is_y] = cur;
7108 		if ( (&ptspace[i]->nextcp.x)[!is_y]==(&ptspace[i]->me.x)[!is_y] )
7109 		    ptspace[i]->nonextcp = true;
7110 	    }
7111 	    cspace[i].cnt = 0;
7112 	}
7113 	if ( dohints ) {
7114 	    StemInfo *h = is_y ? sc->hstem : sc->vstem;
7115 	    while ( h!=NULL && h->start<=high ) {
7116 		if ( h->start>=low ) {
7117 		    h->width -= (h->start-cur);
7118 		    h->start = cur;
7119 		}
7120 		if ( h->start+h->width>=low && h->start+h->width<=high )
7121 		    h->width = cur-h->start;
7122 		h = h->next;
7123 	    }
7124 	}
7125 	/* Ok, surrounding points can no longer use the ones allocated to */
7126 	/*  this cluster. So refigure them */
7127 	for ( i=cspace[j].first-1; i>=0 &&
7128 		( (&ptspace[i]->me.x)[is_y]-cur>-max && (&ptspace[i]->me.x)[is_y]-cur<max ); --i )
7129 	    countcluster(ptspace,cspace,ptcnt,is_y,i,within,max);
7130 	for ( i=cspace[j].last+1; i<ptcnt &&
7131 		( (&ptspace[i]->me.x)[is_y]-cur>-max && (&ptspace[i]->me.x)[is_y]-cur<max ); ++i )
7132 	    countcluster(ptspace,cspace,ptcnt,is_y,i,within,max);
7133     }
7134 }
7135 
SCRoundToCluster(SplineChar * sc,int layer,int sel,bigreal within,bigreal max)7136 int SCRoundToCluster(SplineChar *sc,int layer,int sel,bigreal within,bigreal max) {
7137     /* Do a cluster analysis on the points in this character. Look at each */
7138     /* axis in turn. Order all points in char along this axis. For each pt: */
7139     /*  look at the two points before & after it. If those to pts are within */
7140     /*  the error bound (within) then continue until we reach a point that */
7141     /*  is further from its nearest point than "within" or is further from */
7142     /*  the center point than "max". Count all the points we have found. */
7143     /*  These points make up the cluster centered on this point. */
7144     /* Then find the largest cluster & round everything to the center point */
7145     /*  (shift each point & its cps to center point. Then if cps are "within" */
7146     /*  set the cps to the center point too) */
7147     /* Refigure all clusters within "max" of this one, Find the next largest */
7148     /* cluster, and continue. We stop when the largest cluster has only one */
7149     /* point in it */
7150     /* if "sel" is true then we are only interested in selected points */
7151     /* (if there are no selected points then all points in the current layer) */
7152     /* if "layer"==ly_grid then use sf->grid. if layer==ly_all then all foreground layers*/
7153     /* if "layer"==ly_fore or ly_all then round hints that fall in our clusters too*/
7154     int ptcnt, selcnt;
7155     int l,k,changed;
7156     SplineSet *spl;
7157     SplinePoint *sp;
7158     SplinePoint **ptspace = NULL;
7159     struct cluster *cspace;
7160     Spline *s, *first;
7161 
7162     /* First figure out what points we will need */
7163     for ( k=0; k<2; ++k ) {
7164 	ptcnt = selcnt = 0;
7165 	if ( layer==ly_all ) {
7166 	    for ( l=ly_fore; l<sc->layer_cnt; ++l ) {
7167 		for ( spl = sc->layers[l].splines; spl!=NULL; spl=spl->next ) {
7168 		    for ( sp = spl->first; ; ) {
7169 			if ( k && (!sel || (sel && sp->selected)) )
7170 			    ptspace[ptcnt++] = sp;
7171 			else if ( !k )
7172 			    ++ptcnt;
7173 			if ( sp->selected ) ++selcnt;
7174 			if ( sp->next==NULL )
7175 		    break;
7176 			sp = sp->next->to;
7177 			if ( sp==spl->first )
7178 		    break;
7179 		    }
7180 		    SplineSetSpirosClear(spl);
7181 		}
7182 	    }
7183 	} else {
7184 	    if ( layer==ly_grid )
7185 		spl = sc->parent->grid.splines;
7186 	    else
7187 		spl = sc->layers[layer].splines;
7188 	    for ( ; spl!=NULL; spl=spl->next ) {
7189 		for ( sp = spl->first; ; ) {
7190 		    if ( k && (!sel || (sel && sp->selected)) )
7191 			ptspace[ptcnt++] = sp;
7192 		    else if ( !k )
7193 			++ptcnt;
7194 		    if ( sp->selected ) ++selcnt;
7195 		    if ( sp->next==NULL )
7196 		break;
7197 		    sp = sp->next->to;
7198 		    if ( sp==spl->first )
7199 		break;
7200 		}
7201 	    }
7202 	}
7203 	if ( sel && selcnt==0 )
7204 	    sel = false;
7205 	if ( sel ) ptcnt = selcnt;
7206 	if ( ptcnt<=1 ) {
7207 	    free(ptspace);
7208 return(false);				/* Can't be any clusters */
7209 	}
7210 	if ( k==0 )
7211 	    ptspace = malloc((ptcnt+1)*sizeof(SplinePoint *));
7212 	else
7213 	    ptspace[ptcnt] = NULL;
7214     }
7215 
7216     cspace = malloc(ptcnt*sizeof(struct cluster));
7217 
7218     qsort(ptspace,ptcnt,sizeof(SplinePoint *),xcmp);
7219     changed = _SplineCharRoundToCluster(sc,ptspace,cspace,ptcnt,false,
7220 	    (layer==ly_all || layer==ly_fore) && !sel,layer,false,within,max);
7221 
7222     qsort(ptspace,ptcnt,sizeof(SplinePoint *),ycmp);
7223     changed = _SplineCharRoundToCluster(sc,ptspace,cspace,ptcnt,true,
7224 	    (layer==ly_all || layer==ly_fore) && !sel,layer,changed,within,max);
7225 
7226     free(ptspace);
7227     free(cspace);
7228 
7229     if ( changed ) {
7230 	if ( layer==ly_all ) {
7231 	    for ( l=ly_fore; l<sc->layer_cnt; ++l ) {
7232 		for ( spl = sc->layers[l].splines; spl!=NULL; spl=spl->next ) {
7233 		    first = NULL;
7234 		    SplineSetSpirosClear(spl);
7235 		    for ( s=spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
7236 			SplineRefigure(s);
7237 			if ( first==NULL ) first = s;
7238 		    }
7239 		}
7240 	    }
7241 	} else {
7242 	    if ( layer==ly_grid )
7243 		spl = sc->parent->grid.splines;
7244 	    else
7245 		spl = sc->layers[layer].splines;
7246 	    for ( ; spl!=NULL; spl=spl->next ) {
7247 		first = NULL;
7248 		for ( s=spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
7249 		    SplineRefigure(s);
7250 		    if ( first==NULL ) first = s;
7251 		}
7252 	    }
7253 	}
7254 	SCCharChangedUpdate(sc,layer);
7255     }
7256 return( changed );
7257 }
7258 
SplineRemoveAnnoyingExtrema1(Spline * s,int which,bigreal err_sq)7259 static int SplineRemoveAnnoyingExtrema1(Spline *s,int which,bigreal err_sq) {
7260     /* Remove extrema which are very close to one of the spline end-points */
7261     /*  and which are in the oposite direction (along the normal of the */
7262     /*  close end-point's cp) from the other end-point */
7263     extended ts[2], t1, t2;
7264     bigreal df, dt;
7265     bigreal dp, d_o;
7266     int i;
7267     BasePoint pos, norm;
7268     SplinePoint *close, *other;
7269     BasePoint *ccp;
7270     bigreal c_, b_, nextcp, prevcp, prop;
7271     int changed = false;
7272 
7273     SplineFindExtrema(&s->splines[which],&ts[0],&ts[1]);
7274 
7275     for ( i=0; i<2; ++i ) if ( ts[i]!=-1 && ts[i]!=0 && ts[i]!=1 ) {
7276 	pos.x = ((s->splines[0].a*ts[i]+s->splines[0].b)*ts[i]+s->splines[0].c)*ts[i]+s->splines[0].d;
7277 	pos.y = ((s->splines[1].a*ts[i]+s->splines[1].b)*ts[i]+s->splines[1].c)*ts[i]+s->splines[1].d;
7278 	df = (pos.x-s->from->me.x)*(pos.x-s->from->me.x) + (pos.y-s->from->me.y)*(pos.y-s->from->me.y);
7279 	dt = (pos.x-s->to->me.x)*(pos.x-s->to->me.x) + (pos.y-s->to->me.y)*(pos.y-s->to->me.y);
7280 	if ( df<dt && df<err_sq ) {
7281 	    close = s->from;
7282 	    ccp = &s->from->nextcp;
7283 	    other = s->to;
7284 	} else if ( dt<df && dt<err_sq ) {
7285 	    close = s->to;
7286 	    ccp = &s->to->prevcp;
7287 	    other = s->from;
7288 	} else
7289     continue;
7290 	if ( ccp->x==close->me.x && ccp->y==close->me.y )
7291     continue;
7292 
7293 	norm.x = (ccp->y-close->me.y);
7294 	norm.y = -(ccp->x-close->me.x);
7295 	dp = (pos.x-close->me.x)*norm.x + (pos.y-close->me.y)*norm.y;
7296 	d_o = (other->me.x-close->me.x)*norm.x + (other->me.y-close->me.y)*norm.y;
7297 	if ( dp!=0 && dp*d_o>=0 )
7298     continue;
7299 
7300 	_SplineFindExtrema(&s->splines[which],&t1,&t2);
7301 	if ( t1==ts[i] ) {
7302 	    if ( close==s->from ) t1=0;
7303 	    else t1 = 1;
7304 	} else if ( t2==ts[i] ) {
7305 	    if ( close==s->from ) t2=0;
7306 	    else t2 = 1;
7307 	} else
7308     continue;
7309 
7310 	if ( t2==-1 )		/* quadratic */
7311     continue;			/* Can't happen in a quadratic */
7312 
7313 	/* The roots of the "slope" quadratic were t1, t2. We have shifted one*/
7314 	/*  root so that that extremum is exactly on an end point */
7315 	/*  Figure out the new slope quadratic, from that what the cubic must */
7316 	/*  be, and from that what the control points must be */
7317 	/* Quad = 3at^2 + 2bt + c */
7318 	/* New quad = 3a * (t^2 -(t1+t2)t + t1*t2) */
7319 	/* a' = a, b' = -(t1+t2)/6a, c' = t1*t2/3a, d' = d */
7320 	/* nextcp = from + c'/3, prevcp = nextcp + (b' + c')/3 */
7321 	/* Then for each cp figure what percentage of the original cp vector */
7322 	/*  (or at least this one dimension of that vector) this represents */
7323 	/*  and scale both dimens by this amount */
7324 	b_ = -(t1+t2)*3*s->splines[which].a/2;
7325 	c_ = (t1*t2)*3*s->splines[which].a;
7326 	nextcp = (&s->from->me.x)[which] + c_/3;
7327 	prevcp = nextcp + (b_ + c_)/3;
7328 
7329 	if ( (&s->from->nextcp.x)[which] != (&s->from->me.x)[which] ) {
7330 	    prop = (c_/3) / ( (&s->from->nextcp.x)[which] - (&s->from->me.x)[which] );
7331 	    if ( prop<0 && (c_/3 < .1 && c_/3 > -.1))
7332 		(&s->to->prevcp.x)[which] = nextcp;
7333 	    else if ( prop>=0 && prop<=10 ) {
7334 		s->from->nextcp.x = s->from->me.x + prop*(s->from->nextcp.x-s->from->me.x);
7335 		s->from->nextcp.y = s->from->me.y + prop*(s->from->nextcp.y-s->from->me.y);
7336 		s->from->nonextcp = (prop == 0);
7337 	    }
7338 	}
7339 
7340 	if ( (&s->to->prevcp.x)[which] != (&s->to->me.x)[which] ) {
7341 	    prop = ( prevcp - (&s->to->me.x)[which]) /
7342 			( (&s->to->prevcp.x)[which] - (&s->to->me.x)[which] );
7343 	    if ( prop<0 && (prevcp - (&s->to->me.x)[which] < .1 && prevcp - (&s->to->me.x)[which] > -.1))
7344 		(&s->to->prevcp.x)[which] = prevcp;
7345 	    else if ( prop>=0 && prop<=10 ) {
7346 		s->to->prevcp.x = s->to->me.x + prop*(s->to->prevcp.x-s->to->me.x);
7347 		s->to->prevcp.y = s->to->me.y + prop*(s->to->prevcp.y-s->to->me.y);
7348 		s->to->noprevcp = (prop == 0);
7349 	    }
7350 	}
7351 	SplineRefigure(s);
7352 	changed = true;
7353     }
7354 return( changed );
7355 }
7356 
SplineRemoveAnnoyingExtrema(Spline * s,bigreal err_sq)7357 static int SplineRemoveAnnoyingExtrema(Spline *s,bigreal err_sq) {
7358     int changed;
7359 
7360     changed = SplineRemoveAnnoyingExtrema1(s,0,err_sq);
7361     if ( SplineRemoveAnnoyingExtrema1(s,1,err_sq) )
7362 	changed = true;
7363 return( changed );
7364 }
7365 
SplineSetsRemoveAnnoyingExtrema(SplineSet * ss,bigreal err)7366 int SplineSetsRemoveAnnoyingExtrema(SplineSet *ss,bigreal err) {
7367     int changed = false;
7368     bigreal err_sq = err*err;
7369     Spline *s, *first;
7370 
7371 
7372     while ( ss!=NULL ) {
7373 	first = NULL;
7374 	for ( s = ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
7375 	    if ( first == NULL ) first = s;
7376 	    if ( SplineRemoveAnnoyingExtrema(s,err_sq))
7377 		changed = true;
7378 	}
7379 	ss = ss->next;
7380     }
7381 return( changed );
7382 }
7383 
SplineRemoveWildControlPoints(Spline * s,bigreal distratio)7384 int SplineRemoveWildControlPoints(Spline *s, bigreal distratio) {
7385 	// If the distance between the control point and its base
7386 	// exceeds the the distance between the base points
7387 	// by a great factor,
7388 	// it is likely erroneous and is likely to cause problems.
7389 	// So we remove it.
7390 	if (s->from == NULL || s->to == NULL)
7391 		return 0;
7392 	int changed;
7393 	bigreal pdisplacement = DistanceBetweenPoints(&s->from->me, &s->to->me);
7394 	bigreal bcdisplacement0 = 0.0;
7395 	bigreal bcdisplacement1 = 0.0;
7396 	if (!s->from->nonextcp)
7397 		bcdisplacement0 = DistanceBetweenPoints(&s->from->me, &s->from->nextcp);
7398 	if (!s->to->noprevcp)
7399 		bcdisplacement1 = DistanceBetweenPoints(&s->to->me, &s->to->prevcp);
7400 	if (pdisplacement == 0 || MAX(bcdisplacement0, bcdisplacement1) / pdisplacement > distratio) {
7401 		changed = s->islinear = s->from->nonextcp = s->to->noprevcp = true;
7402 		s->from->nextcp = s->from->me;
7403 		s->to->prevcp = s->to->me;
7404 		SplineRefigure(s);
7405 	}
7406 	return changed;
7407 }
7408 
SplineSetsRemoveWildControlPoints(SplineSet * ss,bigreal distratio)7409 int SplineSetsRemoveWildControlPoints(SplineSet *ss, bigreal distratio) {
7410     int changed = false;
7411     Spline *s, *first;
7412 
7413 
7414     while ( ss!=NULL ) {
7415 	first = NULL;
7416 	for ( s = ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
7417 	    if ( first == NULL ) first = s;
7418 	    if ( SplineRemoveWildControlPoints(s,distratio))
7419 		changed = true;
7420 	}
7421 	ss = ss->next;
7422     }
7423 return( changed );
7424 }
7425 
SplineBisect(Spline * spline,extended t)7426 SplinePoint *SplineBisect(Spline *spline, extended t) {
7427     Spline1 xstart, xend;
7428     Spline1 ystart, yend;
7429     Spline *spline1, *spline2;
7430     SplinePoint *mid;
7431     SplinePoint *old0, *old1;
7432     Spline1D *xsp = &spline->splines[0], *ysp = &spline->splines[1];
7433     int order2 = spline->order2;
7434 
7435 #ifdef DEBUG
7436     if ( t<=1e-3 || t>=1-1e-3 )
7437 	IError("Bisection to create a zero length spline");
7438 #endif
7439     xstart.s0 = xsp->d; ystart.s0 = ysp->d;
7440     xend.s1 = (extended) xsp->a+xsp->b+xsp->c+xsp->d;
7441     yend.s1 = (extended) ysp->a+ysp->b+ysp->c+ysp->d;
7442     xstart.s1 = xend.s0 = ((xsp->a*t+xsp->b)*t+xsp->c)*t + xsp->d;
7443     ystart.s1 = yend.s0 = ((ysp->a*t+ysp->b)*t+ysp->c)*t + ysp->d;
7444     FigureSpline1(&xstart,0,t,xsp);
7445     FigureSpline1(&xend,t,1,xsp);
7446     FigureSpline1(&ystart,0,t,ysp);
7447     FigureSpline1(&yend,t,1,ysp);
7448 
7449     mid = chunkalloc(sizeof(SplinePoint));
7450     mid->me.x = xstart.s1;	mid->me.y = ystart.s1;
7451     if ( order2 ) {
7452 	mid->nextcp.x = xend.sp.d + xend.sp.c/2;
7453 	mid->nextcp.y = yend.sp.d + yend.sp.c/2;
7454 	mid->prevcp.x = xstart.sp.d + xstart.sp.c/2;
7455 	mid->prevcp.y = ystart.sp.d + ystart.sp.c/2;
7456     } else {
7457 	mid->nextcp.x = xend.c0;	mid->nextcp.y = yend.c0;
7458 	mid->prevcp.x = xstart.c1;	mid->prevcp.y = ystart.c1;
7459     }
7460     if ( mid->me.x==mid->nextcp.x && mid->me.y==mid->nextcp.y )
7461 	mid->nonextcp = true;
7462     if ( mid->me.x==mid->prevcp.x && mid->me.y==mid->prevcp.y )
7463 	mid->noprevcp = true;
7464 
7465     old0 = spline->from; old1 = spline->to;
7466     if ( order2 ) {
7467 	old0->nextcp = mid->prevcp;
7468 	old1->prevcp = mid->nextcp;
7469     } else {
7470 	old0->nextcp.x = xstart.c0;	old0->nextcp.y = ystart.c0;
7471 	old1->prevcp.x = xend.c1;	old1->prevcp.y = yend.c1;
7472     }
7473     old0->nonextcp = (old0->nextcp.x==old0->me.x && old0->nextcp.y==old0->me.y);
7474     old1->noprevcp = (old1->prevcp.x==old1->me.x && old1->prevcp.y==old1->me.y);
7475     old0->nextcpdef = false;
7476     old1->prevcpdef = false;
7477     SplineFree(spline);
7478 
7479     spline1 = chunkalloc(sizeof(Spline));
7480     spline1->splines[0] = xstart.sp;	spline1->splines[1] = ystart.sp;
7481     spline1->from = old0;
7482     spline1->to = mid;
7483     spline1->order2 = order2;
7484     old0->next = spline1;
7485     mid->prev = spline1;
7486     if ( SplineIsLinear(spline1)) {
7487 	spline1->islinear = spline1->from->nonextcp = spline1->to->noprevcp = true;
7488 	spline1->from->nextcp = spline1->from->me;
7489 	spline1->to->prevcp = spline1->to->me;
7490     }
7491     SplineRefigure(spline1);
7492 
7493     spline2 = chunkalloc(sizeof(Spline));
7494     spline2->splines[0] = xend.sp;	spline2->splines[1] = xend.sp;
7495     spline2->from = mid;
7496     spline2->to = old1;
7497     spline2->order2 = order2;
7498     mid->next = spline2;
7499     old1->prev = spline2;
7500     if ( SplineIsLinear(spline2)) {
7501 	spline2->islinear = spline2->from->nonextcp = spline2->to->noprevcp = true;
7502 	spline2->from->nextcp = spline2->from->me;
7503 	spline2->to->prevcp = spline2->to->me;
7504     }
7505     SplineRefigure(spline2);
7506 return( mid );
7507 }
7508 
SplineSplit(Spline * spline,extended ts[3])7509 Spline *SplineSplit(Spline *spline, extended ts[3]) {
7510     /* Split the current spline in up to 3 places */
7511     Spline1 splines[2][4];
7512     int i,cnt;
7513     bigreal base;
7514     SplinePoint *last, *sp;
7515     Spline *new;
7516     int order2 = spline->order2;
7517 
7518     memset(splines,0,sizeof(splines));
7519     base=0;
7520     for ( i=cnt=0; i<3 && ts[i]!=-1; ++i ) {
7521 	if ( base>1-1e-3 )			/* Avoid tiny splines */
7522     break;
7523 	else if ( base<ts[i]-1e-3 ) {
7524 	    FigureSpline1(&splines[0][cnt],base,ts[i],&spline->splines[0]);
7525 	    FigureSpline1(&splines[1][cnt++],base,ts[i],&spline->splines[1]);
7526 	    base = ts[i];
7527 	}
7528     }
7529     if ( base==0 )
7530 return( spline );
7531 
7532     FigureSpline1(&splines[0][cnt],base,1.0,&spline->splines[0]);
7533     FigureSpline1(&splines[1][cnt],base,1.0,&spline->splines[1]);
7534 
7535     last = spline->from;
7536     for ( i=0; i<=cnt; ++i ) {
7537 	if ( order2 ) {
7538 	    last->nextcp.x = splines[0][i].sp.d+splines[0][i].sp.c/2;
7539 	    last->nextcp.y = splines[1][i].sp.d+splines[1][i].sp.c/2;
7540 	} else {
7541 	    last->nextcp.x = splines[0][i].c0;
7542 	    last->nextcp.y = splines[1][i].c0;
7543 	}
7544 	if ( i==cnt )
7545 	    sp = spline->to;
7546 	else {
7547 	    sp = chunkalloc(sizeof(SplinePoint));
7548 	    sp->me.x = splines[0][i+1].sp.d;
7549 	    sp->me.y = splines[1][i+1].sp.d;
7550 	}
7551 	if ( order2 ) {
7552 	    sp->prevcp = last->nextcp;
7553 	    SplineMake2(last,sp);
7554 	} else {
7555 	    sp->prevcp.x = splines[0][i].c1;
7556 	    sp->prevcp.y = splines[1][i].c1;
7557 	    SplineMake3(last,sp);
7558 	}
7559 	last = sp;
7560     }
7561 
7562     new = spline->from->next;
7563     SplineFree(spline);
7564 return( new );
7565 }
7566 
SSExistsInLayer(SplineSet * ss,SplineSet * lots)7567 int SSExistsInLayer(SplineSet *ss,SplineSet *lots ) {
7568     /* In Find Problems we hold some state while we allow the user to go off */
7569     /*  and do stuff. It is perfectly possible for the user to delete the */
7570     /*  state we hold pointers to. Do a rough check that the thing hasn't */
7571     /*  been deleted */
7572     while ( lots!=NULL ) {
7573 	if ( lots==ss )
7574 return( true );
7575 	lots = lots->next;
7576     }
7577 return( false );
7578 }
7579 
SplineExistsInSS(Spline * s,SplineSet * ss)7580 int SplineExistsInSS(Spline *s,SplineSet *ss) {
7581     /* In Find Problems we hold some state while we allow the user to go off */
7582     /*  and do stuff. It is perfectly possible for the user to delete the */
7583     /*  state we hold pointers to. Do a rough check that the thing hasn't */
7584     /*  been deleted */
7585     Spline *spline, *first;
7586 
7587     first = NULL;
7588     for ( spline = ss->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
7589 	if ( first==NULL ) first = spline;
7590 	if ( spline==s )
7591 return( true );
7592     }
7593 return( false );
7594 }
7595 
SpExistsInSS(SplinePoint * sp,SplineSet * ss)7596 int SpExistsInSS(SplinePoint *sp,SplineSet *ss) {
7597     /* In Find Problems we hold some state while we allow the user to go off */
7598     /*  and do stuff. It is perfectly possible for the user to delete the */
7599     /*  state we hold pointers to. Do a rough check that the thing hasn't */
7600     /*  been deleted */
7601     SplinePoint *sp2;
7602 
7603     for ( sp2 = ss->first; ; ) {
7604 	if ( sp==sp2 )
7605 return( true );
7606 	if ( sp2->next==NULL )
7607 return( false );
7608 	sp2 = sp2->next->to;
7609 	if ( sp2==ss->first )
7610 return( false );
7611     }
7612 }
7613 
SSHasClip(SplineSet * ss)7614 int SSHasClip(SplineSet *ss) {
7615     while ( ss!=NULL ) {
7616 	if ( ss->is_clip_path )
7617 return( true );
7618 	ss = ss->next;
7619     }
7620 return( false );
7621 }
7622 
SSHasDrawn(SplineSet * ss)7623 int SSHasDrawn(SplineSet *ss) {
7624     while ( ss!=NULL ) {
7625 	if ( !ss->is_clip_path )
7626 return( true );
7627 	ss = ss->next;
7628     }
7629 return( false );
7630 }
7631 
SSBoundsWithin(SplineSet * ss,bigreal z1,bigreal z2,bigreal * wmin,bigreal * wmax,int major)7632 int SSBoundsWithin(SplineSet *ss,bigreal z1, bigreal z2, bigreal *wmin, bigreal *wmax, int major ) {
7633     /* if major==0 then find y values when x between z1, z2 */
7634     /* if major==1 then find x values when y between z1, z2 */
7635     bigreal w0= 1e23, w1= -1e23;
7636     int any=0;
7637     Spline *s, *first;
7638     Spline1D *ws, *zs;
7639     extended ts[3];
7640     bigreal w, z;
7641     int i;
7642     int other = !major;
7643 
7644     if ( z1>z2 ) {
7645 	bigreal temp = z1;
7646 	z1 = z2;
7647 	z2 = temp;
7648     }
7649 
7650     while ( ss!=NULL ) {
7651 	first = NULL;
7652 	for ( s=ss->first->next; s!=first; s=s->to->next ) {
7653 	    if ( first==NULL ) first = s;
7654 	    ws = &s->splines[other];
7655 	    zs = &s->splines[major];
7656 	    if ( major ) {
7657 		if ( s->from->me.y<z1 && s->from->nextcp.y<z1 && s->to->prevcp.y<z1 && s->to->me.y<z1 )
7658 	continue;
7659 		else if ( s->from->me.y>z2 && s->from->nextcp.y>z2 && s->to->prevcp.y>z2 && s->to->me.y>z2 )
7660 	continue;
7661 	    } else {
7662 		if ( s->from->me.x<z1 && s->from->nextcp.x<z1 && s->to->prevcp.x<z1 && s->to->me.x<z1 )
7663 	continue;
7664 		else if ( s->from->me.x>z2 && s->from->nextcp.x>z2 && s->to->prevcp.x>z2 && s->to->me.x>z2 )
7665 	continue;
7666 	    }
7667 	    if ( CubicSolve(zs,z1,ts)) {
7668 		for ( i=0; i<2 && ts[i]!=-1; ++i ) {
7669 		    w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7670 		    if ( w<w0 ) w0=w;
7671 		    if ( w>w1 ) w1=w;
7672 		    any = true;
7673 		}
7674 	    }
7675 	    if ( CubicSolve(zs,z2,ts)) {
7676 		for ( i=0; i<2 && ts[i]!=-1; ++i ) {
7677 		    w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7678 		    if ( w<w0 ) w0=w;
7679 		    if ( w>w1 ) w1=w;
7680 		    any = true;
7681 		}
7682 	    }
7683 	    ts[0]=0; ts[1]=1.0;
7684 	    for ( i=0; i<2; ++i ) {
7685 		w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7686 		z = ((zs->a*ts[i]+zs->b)*ts[i]+zs->c)*ts[i]+zs->d;
7687 		if ( z>=z1 && z<=z2 ) {
7688 		    if ( w<w0 ) w0=w;
7689 		    if ( w>w1 ) w1=w;
7690 		    any = true;
7691 		}
7692 	    }
7693 	    SplineFindExtrema(ws,&ts[0],&ts[1]);
7694 	    for ( i=0; i<2 && ts[i]!=-1; ++i ) {
7695 		w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7696 		z = ((zs->a*ts[i]+zs->b)*ts[i]+zs->c)*ts[i]+zs->d;
7697 		if ( z>=z1 && z<=z2 ) {
7698 		    if ( w<w0 ) w0=w;
7699 		    if ( w>w1 ) w1=w;
7700 		    any = true;
7701 		}
7702 	    }
7703 	}
7704 	ss = ss->next;
7705     }
7706 
7707     *wmin = w0; *wmax = w1;
7708 return( any );
7709 }
7710 
FindZero5(bigreal w[7],bigreal tlow,bigreal thigh)7711 static bigreal FindZero5(bigreal w[7],bigreal tlow, bigreal thigh) {
7712     /* Somewhere between tlow and thigh there is a value of t where w(t)==0 */
7713     /*  It is conceiveable that there might be 3 such ts if there are some high frequency effects */
7714     /*  but I ignore that for now */
7715     bigreal t, test;
7716     int bot_negative;
7717 
7718     t = tlow;
7719     test = ((((w[5]*t+w[4])*t+w[3])*t+w[2])*t+w[1])*t + w[0];
7720     bot_negative = test<0;
7721 
7722     for (;;) {
7723 	t = (thigh+tlow)/2;
7724 	if ( thigh==t || tlow==t )
7725 return( t );		/* close as we can get */
7726 	test = ((((w[5]*t+w[4])*t+w[3])*t+w[2])*t+w[1])*t + w[0];
7727 	if ( test==0 )
7728 return( t );
7729 	if ( bot_negative ) {
7730 	    if ( test<0 )
7731 		tlow = t;
7732 	    else
7733 		thigh = t;
7734 	} else {
7735 	    if ( test<0 )
7736 		thigh = t;
7737 	    else
7738 		tlow = t;
7739 	}
7740     }
7741 }
7742 
FindZero3(bigreal w[7],bigreal tlow,bigreal thigh)7743 static bigreal FindZero3(bigreal w[7],bigreal tlow, bigreal thigh) {
7744     /* Somewhere between tlow and thigh there is a value of t where w(t)==0 */
7745     /*  It is conceiveable that there might be 3 such ts if there are some high frequency effects */
7746     /*  but I ignore that for now */
7747     bigreal t, test;
7748     int bot_negative;
7749 
7750     t = tlow;
7751     test = ((w[3]*t+w[2])*t+w[1])*t + w[0];
7752     bot_negative = test<0;
7753 
7754     for (;;) {
7755 	t = (thigh+tlow)/2;
7756 	if ( thigh==t || tlow==t )
7757 return( t );		/* close as we can get */
7758 	test = ((w[3]*t+w[2])*t+w[1])*t + w[0];
7759 	if ( test==0 )
7760 return( t );
7761 	if ( bot_negative ) {
7762 	    if ( test<0 )
7763 		tlow = t;
7764 	    else
7765 		thigh = t;
7766 	} else {
7767 	    if ( test<0 )
7768 		thigh = t;
7769 	    else
7770 		tlow = t;
7771 	}
7772     }
7773 }
7774 
SplineMinDistanceToPoint(Spline * s,BasePoint * p)7775 bigreal SplineMinDistanceToPoint(Spline *s, BasePoint *p) {
7776     /* So to find the minimum distance we want the sqrt( (sx(t)-px)^2 + (sy(t)-py)^2 ) */
7777     /*  Same minima as (sx(t)-px)^2 + (sy(t)-py)^2, which is easier to deal with */
7778     bigreal w[7];
7779     Spline1D *x = &s->splines[0], *y = &s->splines[1];
7780     bigreal off[2], best;
7781 
7782     off[0] = (x->d-p->x); off[1] = (y->d-p->y);
7783 
7784     w[6] = (x->a*x->a) + (y->a*y->a);
7785     w[5] = 2*(x->a*x->b + y->a*y->b);
7786     w[4] = (x->b*x->b) + 2*(x->a*x->c) + (y->b*y->b) + 2*(y->a*y->c);
7787     w[3] = 2* (x->b*x->c + x->a*off[0] + y->b*y->c + y->a*off[1]);
7788     w[2] = (x->c*x->c) + 2*(x->b*off[0]) + (y->c*y->c) + 2*y->b*off[1];
7789     w[1] = 2*(x->c*off[0] + y->c*off[1]);
7790     w[0] = off[0]*off[0] + off[1]*off[1];
7791 
7792     /* Take derivative */
7793     w[0] = w[1];
7794     w[1] = 2*w[2];
7795     w[2] = 3*w[3];
7796     w[3] = 4*w[4];
7797     w[4] = 5*w[5];
7798     w[5] = 6*w[6];
7799     w[6] = 0;
7800 
7801     if ( w[5]!=0 ) {
7802 	bigreal tzeros[8], t, incr, test, lasttest, zerot;
7803 	int i, zcnt=0;
7804 	/* Well, we've got a 5th degree poly and no way to play cute tricks. */
7805 	/* brute force it */
7806 	incr = 1.0/1024;
7807 	lasttest = w[0];
7808 	for ( t = incr; t<=1.0; t += incr ) {
7809 	    test = ((((w[5]*t+w[4])*t+w[3])*t+w[2])*t+w[1])*t + w[0];
7810 	    if ( test==0 )
7811 		tzeros[zcnt++] = t;
7812 	    else {
7813 		if ( lasttest!=0 && (test>0) != (lasttest>0) ) {
7814 		    zerot = FindZero5(w,t-incr,t);
7815 		    if ( zerot>0 )
7816 			tzeros[zcnt++] = zerot;
7817 		}
7818 	    }
7819 	    lasttest = test;
7820 	}
7821 	best = off[0]*off[0] + off[1]*off[1];		/* t==0 */
7822 	test = (x->a+x->b+x->c+off[0])*(x->a+x->b+x->c+off[0]) +
7823 		(y->a+y->b+y->c+off[1])*(y->a+y->b+y->c+off[1]); 	/* t==1 */
7824 	if ( best>test ) best = test;
7825 	for ( i=0; i<zcnt; ++i ) {
7826 	    bigreal tx, ty;
7827 	    tx = ((x->a*tzeros[i]+x->b)*tzeros[i]+x->c)*tzeros[i] + off[0];
7828 	    ty = ((y->a*tzeros[i]+y->b)*tzeros[i]+y->c)*tzeros[i] + off[1];
7829 	    test = tx*tx + ty*ty;
7830 	    if ( best>test ) best = test;
7831 	}
7832 return( sqrt(best));
7833     } else if ( w[4]==0 && w[3]!=0 ) {
7834 	/* Started with a quadratic -- now, find 0s of a cubic */
7835 	/* We could find the extrema, so we have a bunch of monotonics */
7836 	/* Or we could brute force it as above */
7837 	bigreal tzeros[8], test, zerot;
7838 	bigreal quad[3], disc, e[5], t1, t2;
7839 	int i, zcnt=0, ecnt;
7840 
7841 	quad[2] = 3*w[3]; quad[1] = 2*w[2]; quad[0] = w[1];
7842 	disc = (-quad[1]*quad[1] - 4*quad[2]*quad[0]);
7843 	e[0] = 0;
7844 	if ( disc<0 ) {
7845 	    e[1] = 1.0;
7846 	    ecnt = 2;
7847 	} else
7848 	    disc = sqrt(disc);
7849 	t1 = (-w[1] - disc) / (2*w[2]);
7850 	t2 = (-w[1] + disc) / (2*w[2]);
7851 	if ( t1>t2 ) {
7852 	    bigreal temp = t1;
7853 	    t1 = t2;
7854 	    t2 = temp;
7855 	}
7856 	ecnt=1;
7857 	if ( t1>0 && t1<1 )
7858 	    e[ecnt++] = t1;
7859 	if ( t2>0 && t2<1 && t1!=t2 )
7860 	    e[ecnt++] = t2;
7861 	e[ecnt++] = 1.0;
7862 	for ( i=1; i<ecnt; ++i ) {
7863 	    zerot = FindZero3(w,e[i-1],e[i]);
7864 	    if ( zerot>0 )
7865 		tzeros[zcnt++] = zerot;
7866 	}
7867 	best = off[0]*off[0] + off[1]*off[1];		/* t==0 */
7868 	test = (x->b+x->c+off[0])*(x->b+x->c+off[0]) +
7869 		(y->b+y->c+off[1])*(y->b+y->c+off[1]); 	/* t==1 */
7870 	if ( best>test ) best = test;
7871 	for ( i=0; i<zcnt; ++i ) {
7872 	    bigreal tx, ty;
7873 	    tx = (x->b*tzeros[i]+x->c)*tzeros[i] + off[0];
7874 	    ty = (y->b*tzeros[i]+y->c)*tzeros[i] + off[1];
7875 	    test = tx*tx + ty*ty;
7876 	    if ( best>test ) best = test;
7877 	}
7878 return( sqrt(best));
7879     } else if ( w[2]==0 && w[1]!=0 ) {
7880 	/* Started with a line */
7881 	bigreal t = -w[0]/w[1], test, best;
7882 	best = off[0]*off[0] + off[1]*off[1];		/* t==0 */
7883 	test = (x->c+off[0])*(x->c+off[0]) + (y->c+off[1])*(y->c+off[1]); 	/* t==1 */
7884 	if ( best>test ) best = test;
7885 	if ( t>0 && t<1 ) {
7886 	    test = (x->c*t+off[0])*(x->c*t+off[0]) + (y->c*t+off[1])*(y->c*t+off[1]);
7887 	    if ( best>test ) best = test;
7888 	}
7889 return(sqrt(best));
7890     } else if ( w[4]!=0 && w[3]!=0 && w[2]!=0 && w[1]!=0 ) {
7891 	IError( "Impossible condition in SplineMinDistanceToPoint");
7892     } else {
7893 	/* It's a point, minimum distance is the only distance */
7894 return( sqrt(off[0]*off[0] + off[1]*off[1]) );
7895     }
7896 return( -1 );
7897 }
7898 
GrowBuffer(GrowBuf * gb)7899 void GrowBuffer(GrowBuf *gb) {
7900     if ( gb->base==NULL ) {
7901 	gb->base = gb->pt = malloc(200);
7902 	gb->end = gb->base + 200;
7903     } else {
7904 	int len = (gb->end-gb->base) + 400;
7905 	int off = gb->pt-gb->base;
7906 	gb->base = realloc(gb->base,len);
7907 	gb->end = gb->base + len;
7908 	gb->pt = gb->base+off;
7909     }
7910 }
7911 
GrowBufferAdd(GrowBuf * gb,int ch)7912 void GrowBufferAdd(GrowBuf *gb,int ch) {
7913     if ( gb->base==NULL ) {
7914 	gb->base = gb->pt = malloc(200);
7915 	gb->end = gb->base + 200;
7916     } else if ( gb->pt>=gb->end ) {
7917 	int len = (gb->end-gb->base) + 400;
7918 	int off = gb->pt-gb->base;
7919 	gb->base = realloc(gb->base,len);
7920 	gb->end = gb->base + len;
7921 	gb->pt = gb->base+off;
7922     }
7923     *gb->pt++ = ch;
7924 }
7925 
GrowBufferAddStr(GrowBuf * gb,char * str)7926 void GrowBufferAddStr(GrowBuf *gb,char *str) {
7927     int n;
7928 
7929     if ( str==NULL )
7930 return;
7931     n = strlen(str);
7932 
7933     if ( gb->base==NULL ) {
7934 	gb->base = gb->pt = malloc(200+n);
7935 	gb->end = gb->base + 200+n;
7936     } else if ( gb->pt+n+1>=gb->end ) {
7937 	int len = (gb->end-gb->base) + n+200;
7938 	int off = gb->pt-gb->base;
7939 	gb->base = realloc(gb->base,len);
7940 	gb->end = gb->base + len;
7941 	gb->pt = gb->base+off;
7942     }
7943     strcpy((char *)gb->pt, str);
7944     gb->pt += n;
7945 }
7946 
DistanceBetweenPoints(BasePoint * p1,BasePoint * p2)7947 bigreal DistanceBetweenPoints( BasePoint *p1, BasePoint *p2 )
7948 {
7949     bigreal t = pow(p1->x - p2->x,2) + pow(p1->y - p2->y,2);
7950     if( !t )
7951 	return t;
7952 
7953     t = sqrt( t );
7954     return t;
7955 }
7956