1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2000-2012 by George Williams */
3 /*
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6 
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9 
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13 
14  * The name of the author may not be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <fontforge-config.h>
30 
31 #include "cvundoes.h"
32 #include "dumppfa.h"
33 #include "ffglib.h"
34 #include "fontforgevw.h"
35 #include "fvfonts.h"
36 #include "gresource.h"
37 #include "lookups.h"
38 #include "mem.h"
39 #include "parsettf.h"
40 #include "spiro.h"
41 #include "splineorder2.h"
42 #include "splinesaveafm.h"
43 #include "splineutil.h"
44 #include "splineutil2.h"
45 #include "tottf.h"
46 #include "ttf.h"
47 #include "ustring.h"
48 #include "utype.h"
49 
50 #include <locale.h>
51 #include <math.h>
52 
53 #ifdef HAVE_IEEEFP_H
54 # include <ieeefp.h>		/* Solaris defines isnan in ieeefp rather than math.h */
55 #endif
56 
57 int adjustwidth = true;
58 int adjustlbearing = true;
59 int allow_utf8_glyphnames = false;
60 int clear_tt_instructions_when_needed = true;
61 
SCClearRounds(SplineChar * sc,int layer)62 void SCClearRounds(SplineChar *sc,int layer) {
63     SplineSet *ss;
64     SplinePoint *sp;
65 
66     for ( ss=sc->layers[layer].splines; ss!=NULL; ss=ss->next ) {
67 	for ( sp=ss->first; ; ) {
68 	    sp->roundx = sp->roundy = false;
69 	    if ( sp->next==NULL )
70 	break;
71 	    sp = sp->next->to;
72 	    if ( sp==ss->first )
73 	break;
74 	}
75     }
76 }
77 
MDReplace(MinimumDistance * md,SplineSet * old,SplineSet * rpl)78 void MDReplace(MinimumDistance *md,SplineSet *old,SplineSet *rpl) {
79     /* Replace all the old points with the ones in rpl in the minimum distance hints */
80     SplinePoint *osp, *rsp;
81     MinimumDistance *test;
82 
83     if ( md==NULL )
84 return;
85 
86     while ( old!=NULL && rpl!=NULL ) {
87 	osp = old->first; rsp = rpl->first;
88 	while ( 1 ) {
89 	    for ( test=md; test!=NULL ; test=test->next ) {
90 		if ( test->sp1==osp )
91 		    test->sp1 = rsp;
92 		if ( test->sp2==osp )
93 		    test->sp2 = rsp;
94 	    }
95 	    if ( osp->next==NULL || rsp->next==NULL )
96 	break;
97 	    osp = osp->next->to;
98 	    rsp = rsp->next->to;
99 	    if ( osp==old->first )
100 	break;
101 	}
102 	old = old->next;
103 	rpl = rpl->next;
104     }
105 }
106 
HasUseMyMetrics(SplineChar * sc,int layer)107 RefChar *HasUseMyMetrics(SplineChar *sc,int layer) {
108     RefChar *r;
109 
110     if ( layer==ly_grid ) layer = ly_fore;
111 
112     for ( r=sc->layers[layer].refs; r!=NULL; r=r->next )
113 	if ( r->use_my_metrics )
114 return( r );
115 
116 return( NULL );
117 }
118 
119 /* if they changed the width, then change the width on all bitmap chars of */
120 /*  ours, and if we are a letter, then change the width on all chars linked */
121 /*  to us which had the same width that we used to have (so if we change the */
122 /*  width of A, we'll also change that of À and Ä and ... */
SCSynchronizeWidth(SplineChar * sc,real newwidth,real oldwidth,FontViewBase * flagfv)123 void SCSynchronizeWidth(SplineChar *sc,real newwidth, real oldwidth, FontViewBase *flagfv) {
124     BDFFont *bdf;
125     struct splinecharlist *dlist;
126     RefChar *r = HasUseMyMetrics(sc,ly_fore);
127     int isprobablybase;
128 
129     sc->widthset = true;
130     if( r!=NULL ) {
131 	if ( oldwidth==r->sc->width ) {
132 	    sc->width = r->sc->width;
133 return;
134 	}
135 	newwidth = r->sc->width;
136     }
137     if ( newwidth==oldwidth )
138 return;
139     sc->width = newwidth;
140     for ( bdf=sc->parent->bitmaps; bdf!=NULL; bdf=bdf->next ) {
141 	BDFChar *bc = bdf->glyphs[sc->orig_pos];
142 	if ( bc!=NULL ) {
143 	    int width = rint(sc->width*bdf->pixelsize / (real) (sc->parent->ascent+sc->parent->descent));
144 	    if ( bc->width!=width ) {
145 		/*BCPreserveWidth(bc);*/ /* Bitmaps can't set width, so no undo for it */
146 		bc->width = width;
147 		BCCharChangedUpdate(bc);
148 	    }
149 	}
150     }
151 
152     if ( !adjustwidth )
153 return;
154 
155     isprobablybase = true;
156     if ( sc->unicodeenc==-1 || sc->unicodeenc>=0x10000 ||
157 	    !isalpha(sc->unicodeenc) || iscombining(sc->unicodeenc))
158 	isprobablybase = false;
159 
160     for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next ) {
161 	RefChar *metrics = HasUseMyMetrics(dlist->sc,ly_fore);
162 	if ( metrics!=NULL && metrics->sc!=sc )
163     continue;
164 	else if ( metrics==NULL && !isprobablybase )
165     continue;
166 	if ( dlist->sc->width==oldwidth &&
167 		(metrics!=NULL || flagfv==NULL ||
168 		    !flagfv->selected[flagfv->map->backmap[dlist->sc->orig_pos]])) {
169 	    SCSynchronizeWidth(dlist->sc,newwidth,oldwidth,flagfv);
170 	    if ( !dlist->sc->changed ) {
171 		dlist->sc->changed = true;
172 		FVToggleCharChanged(dlist->sc);
173 	    }
174 	    SCUpdateAll(dlist->sc);
175 	}
176     }
177 }
178 
179 /* If they change the left bearing of a character, then in all chars */
180 /*  that depend on it should be adjusted too. */
181 /* Also all vstem hints */
182 /* I deliberately don't set undoes in the dependants. The change is not */
183 /*  in them, after all */
SCSynchronizeLBearing(SplineChar * sc,real off,int layer)184 void SCSynchronizeLBearing(SplineChar *sc,real off,int layer) {
185     struct splinecharlist *dlist;
186     RefChar *ref;
187     DStemInfo *d;
188     StemInfo *h;
189     HintInstance *hi;
190     int isprobablybase;
191 
192     for ( h=sc->vstem; h !=NULL; h=h->next )
193 	h->start += off;
194     for ( h=sc->hstem; h !=NULL; h=h->next )
195 	for ( hi = h->where; hi!=NULL; hi=hi->next ) {
196 	    hi->begin += off;
197 	    hi->end += off;
198 	}
199     for ( d=sc->dstem; d !=NULL; d=d->next ) {
200 	d->left.x += off;
201 	d->right.x += off;
202     }
203 
204     if ( !adjustlbearing )
205 return;
206 
207     isprobablybase = true;
208     if ( sc->unicodeenc==-1 || sc->unicodeenc>=0x10000 ||
209 	    !isalpha(sc->unicodeenc) || iscombining(sc->unicodeenc))
210 	isprobablybase = false;
211 
212     for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next ) {
213 	RefChar *metrics = HasUseMyMetrics(dlist->sc,layer);
214 	if ( metrics!=NULL && metrics->sc!=sc )
215     continue;
216 	else if ( metrics==NULL && !isprobablybase )
217     continue;
218 	else if ( metrics==NULL && sc->width!=dlist->sc->width )
219     continue;
220 	SCPreserveLayer(dlist->sc,layer,false);
221 	SplinePointListShift(dlist->sc->layers[layer].splines,off,tpt_AllPoints);
222 	for ( ref = dlist->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
223 		if ( ref->sc!=sc ) {
224 	    SplinePointListShift(ref->layers[0].splines,off,tpt_AllPoints);
225 	    ref->transform[4] += off;
226 	    ref->bb.minx += off; ref->bb.maxx += off;
227 	}
228 	SCUpdateAll(dlist->sc);
229 	SCSynchronizeLBearing(dlist->sc,off,layer);
230     }
231 }
232 
_SCRefNumberPoints2(SplineSet ** _rss,SplineChar * sc,int pnum,int layer)233 static int _SCRefNumberPoints2(SplineSet **_rss,SplineChar *sc,int pnum,int layer) {
234     SplineSet *ss, *rss = *_rss;
235     SplinePoint *sp, *rsp;
236     RefChar *r;
237     int starts_with_cp, startcnt;
238 
239     for ( ss=sc->layers[layer].splines; ss!=NULL; ss=ss->next, rss=rss->next ) {
240 	if ( rss==NULL )		/* Can't happen */
241     break;
242 	starts_with_cp = !ss->first->noprevcp &&
243 		((ss->first->ttfindex == pnum+1 && ss->first->prev!=NULL &&
244 		    ss->first->prev->from->nextcpindex==pnum ) ||
245 		 ((ss->first->ttfindex==0xffff || SPInterpolate( ss->first ))));
246 	startcnt = pnum;
247 	if ( starts_with_cp ) ++pnum;
248 	for ( sp = ss->first, rsp=rss->first; ; ) {
249 	    if ( sp->ttfindex==0xffff || SPInterpolate( sp ))
250 		rsp->ttfindex = 0xffff;
251 	    else
252 		rsp->ttfindex = pnum++;
253 	    if ( sp->next==NULL )
254 	break;
255 	    if ( sp->next!=NULL && sp->next->to == ss->first ) {
256 		if ( sp->nonextcp )
257 		    rsp->nextcpindex = 0xffff;
258 		else if ( starts_with_cp )
259 		    rsp->nextcpindex = startcnt;
260 		else
261 		    rsp->nextcpindex = pnum++;
262 	break;
263 	    }
264 	    if ( sp->nonextcp )
265 		rsp->nextcpindex = 0xffff;
266 	    else
267 		rsp->nextcpindex = pnum++;
268 	    if ( sp->next==NULL || rsp->next==NULL )
269 	break;
270 	    sp = sp->next->to;
271 	    rsp = rsp->next->to;
272 	}
273     }
274 
275     *_rss = rss;
276     for ( r = sc->layers[layer].refs; r!=NULL; r=r->next )
277 	pnum = _SCRefNumberPoints2(_rss,r->sc,pnum,layer);
278 return( pnum );
279 }
280 
SCRefNumberPoints2(RefChar * ref,int pnum,int layer)281 static int SCRefNumberPoints2(RefChar *ref,int pnum,int layer) {
282     SplineSet *rss;
283 
284     rss = ref->layers[0].splines;
285 return( _SCRefNumberPoints2(&rss,ref->sc,pnum,layer));
286 }
287 
SSTtfNumberPoints(SplineSet * ss)288 int SSTtfNumberPoints(SplineSet *ss) {
289     int pnum=0;
290     SplinePoint *sp;
291     int starts_with_cp;
292 
293     for ( ; ss!=NULL; ss=ss->next ) {
294 	starts_with_cp = !ss->first->noprevcp &&
295 		((ss->first->ttfindex == pnum+1 && ss->first->prev!=NULL &&
296 		  ss->first->prev->from->nextcpindex==pnum ) ||
297 		 SPInterpolate( ss->first ));
298 	if ( starts_with_cp && ss->first->prev!=NULL )
299 	    ss->first->prev->from->nextcpindex = pnum++;
300 	for ( sp=ss->first; ; ) {
301 	    if ( SPInterpolate(sp) )
302 		sp->ttfindex = 0xffff;
303 	    else
304 		sp->ttfindex = pnum++;
305 	    if ( sp->nonextcp && sp->nextcpindex!=pnum )
306 		sp->nextcpindex = 0xffff;
307 	    else if ( !starts_with_cp || (sp->next!=NULL && sp->next->to!=ss->first) )
308 		sp->nextcpindex = pnum++;
309 	    if ( sp->next==NULL )
310 	break;
311 	    sp = sp->next->to;
312 	    if ( sp==ss->first )
313 	break;
314 	}
315     }
316 return( pnum );
317 }
318 
SSPsNumberPoints(SplineChar * sc,SplineSet * splines,int pnum)319 static int SSPsNumberPoints(SplineChar *sc, SplineSet *splines,int pnum) {
320     SplineSet *ss;
321     SplinePoint *sp;
322 
323     for ( ss = splines; ss!=NULL; ss=ss->next ) {
324 	for ( sp=ss->first; ; ) {
325 	    sp->ttfindex = pnum++;
326 	    sp->nextcpindex = 0xffff;
327 	    if ( sc->numberpointsbackards ) {
328 		if ( sp->prev==NULL )
329 	break;
330 		if ( !sp->noprevcp || !sp->prev->from->nonextcp )
331 		    pnum += 2;
332 		sp = sp->prev->from;
333 	    } else {
334 		if ( sp->next==NULL )
335 	break;
336 		if ( !sp->nonextcp || !sp->next->to->noprevcp )
337 		    pnum += 2;
338 		sp = sp->next->to;
339 	    }
340 	    if ( sp==ss->first )
341 	break;
342 	}
343     }
344 return( pnum );
345 }
346 
SCNumberPoints(SplineChar * sc,int layer)347 int SCNumberPoints(SplineChar *sc,int layer) {
348     int pnum=0;
349     SplineSet *ss;
350     SplinePoint *sp;
351     RefChar *ref;
352 
353     if ( layer<0 || layer>=sc->layer_cnt )
354         return( pnum );
355 
356     if ( sc->layers[layer].order2 ) {		/* TrueType and its complexities. I ignore svg here */
357 	if ( sc->layers[layer].refs!=NULL ) {
358 	    /* if there are references there can't be splines. So if we've got*/
359 	    /*  splines mark all point numbers on them as meaningless */
360 	    for ( ss = sc->layers[layer].splines; ss!=NULL; ss=ss->next ) {
361 		for ( sp=ss->first; ; ) {
362 		    sp->ttfindex = 0xfffe;
363 		    if ( !sp->nonextcp )
364 			sp->nextcpindex = 0xfffe;
365 		    if ( sp->next==NULL )
366 		break;
367 		    sp = sp->next->to;
368 		    if ( sp==ss->first )
369 		break;
370 		}
371 	    }
372 	    for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next )
373 		pnum = SCRefNumberPoints2(ref,pnum,layer);
374 	} else {
375 	    pnum = SSTtfNumberPoints(sc->layers[layer].splines);
376 	}
377     } else {		/* cubic (PostScript/SVG) splines */
378 	int first, last;
379 	if ( sc->parent->multilayer ) {
380 	    first = ly_fore;
381 	    last = sc->layer_cnt-1;
382 	} else
383 	    first = last = layer;
384 	for ( layer=first; layer<=last; ++layer ) {
385 	    for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next )
386 		pnum = SSPsNumberPoints(sc,ref->layers[0].splines,pnum);
387 	    pnum = SSPsNumberPoints(sc,sc->layers[layer].splines,pnum);
388 	}
389     }
390 return( pnum );
391 }
392 
SCPointsNumberedProperly(SplineChar * sc,int layer)393 int SCPointsNumberedProperly(SplineChar *sc,int layer) {
394     int pnum=0, skipit;
395     SplineSet *ss;
396     SplinePoint *sp;
397     int starts_with_cp;
398     int start_pnum;
399 
400     if ( sc->layers[layer].splines!=NULL &&
401 	    sc->layers[layer].refs!=NULL )
402 return( false );	/* TrueType can't represent this, so always remove instructions. They can't be meaningful */
403 
404     for ( ss = sc->layers[layer].splines; ss!=NULL; ss=ss->next ) {
405 	starts_with_cp = (ss->first->ttfindex == pnum+1 || ss->first->ttfindex==0xffff) &&
406 		!ss->first->noprevcp;
407 	start_pnum = pnum;
408 	if ( starts_with_cp ) ++pnum;
409 	for ( sp=ss->first; ; ) {
410 	    skipit = SPInterpolate(sp);
411 	    if ( sp->nonextcp || sp->noprevcp ) skipit = false;
412 	    if ( sp->ttfindex==0xffff && skipit )
413 		/* Doesn't count */;
414 	    else if ( sp->ttfindex!=pnum )
415 return( false );
416 	    else
417 		++pnum;
418 	    if ( sp->nonextcp && sp->nextcpindex==0xffff )
419 		/* Doesn't count */;
420 	    else if ( sp->nextcpindex==pnum )
421 		++pnum;
422 	    else if ( sp->nextcpindex==start_pnum && starts_with_cp &&
423 		    (sp->next!=NULL && sp->next->to==ss->first) )
424 		/* Ok */;
425 	    else
426 return( false );
427 	    if ( sp->next==NULL )
428 	break;
429 	    sp = sp->next->to;
430 	    if ( sp==ss->first )
431 	break;
432 	}
433 	/* if ( starts_with_cp ) --pnum; */
434     }
435 return( true );
436 }
437 
SCClearLayer(SplineChar * sc,int layer)438 void SCClearLayer(SplineChar *sc,int layer) {
439     RefChar *refs, *next;
440 
441     SplinePointListsFree(sc->layers[layer].splines);
442     sc->layers[layer].splines = NULL;
443     for ( refs=sc->layers[layer].refs; refs!=NULL; refs = next ) {
444 	next = refs->next;
445 	SCRemoveDependent(sc,refs,layer);
446     }
447     sc->layers[layer].refs = NULL;
448     ImageListsFree(sc->layers[layer].images);
449     sc->layers[layer].images = NULL;
450 }
451 
SCClearContents(SplineChar * sc,int layer)452 void SCClearContents(SplineChar *sc,int layer) {
453     int ly_first, ly_last;
454 
455     if ( sc==NULL )
456 return;
457     if ( sc->parent!=NULL && sc->parent->multilayer ) {
458 	ly_first = ly_fore;
459 	ly_last = sc->layer_cnt-1;
460     } else
461 	ly_first = ly_last = layer;
462     for ( layer = ly_first; layer<=ly_last; ++layer )
463 	SCClearLayer(sc,layer);
464     --layer;
465 
466     if ( sc->parent!=NULL &&
467 	    (sc->parent->multilayer ||
468 		(!sc->parent->layers[layer].background && SCWasEmpty(sc,layer)))) {
469 	sc->widthset = false;
470 	if ( sc->parent!=NULL && sc->width!=0 )
471 	    sc->vwidth = sc->width = sc->parent->ascent+sc->parent->descent;
472 	AnchorPointsFree(sc->anchor);
473 	sc->anchor = NULL;
474 	StemInfosFree(sc->hstem); sc->hstem = NULL;
475 	StemInfosFree(sc->vstem); sc->vstem = NULL;
476 	DStemInfosFree(sc->dstem); sc->dstem = NULL;
477 	MinimumDistancesFree(sc->md); sc->md = NULL;
478 	free(sc->ttf_instrs);
479 	sc->ttf_instrs = NULL;
480 	sc->ttf_instrs_len = 0;
481 	SCOutOfDateBackground(sc);
482     }
483 }
484 
SCClearAll(SplineChar * sc,int layer)485 void SCClearAll(SplineChar *sc,int layer) {
486     extern int copymetadata;
487 
488     if ( sc==NULL )
489 return;
490     if ( sc->layers[layer].splines==NULL && sc->layers[layer].refs==NULL && !sc->widthset &&
491 	    sc->hstem==NULL && sc->vstem==NULL && sc->anchor==NULL &&
492 	    !sc->parent->multilayer &&
493 	    (!copymetadata ||
494 		(sc->unicodeenc==-1 && strcmp(sc->name,".notdef")==0)))
495 return;
496     SCPreserveLayer(sc,layer,2);
497     if ( copymetadata ) {
498 	sc->unicodeenc = -1;
499 	free(sc->name);
500 	sc->name = copy(".notdef");
501 	PSTFree(sc->possub);
502 	sc->possub = NULL;
503     }
504     SCClearContents(sc,layer);
505     SCCharChangedUpdate(sc,layer);
506 }
507 
SCClearBackground(SplineChar * sc)508 void SCClearBackground(SplineChar *sc) {
509 
510     if ( sc==NULL )
511 return;
512     if ( sc->layers[0].splines==NULL && sc->layers[ly_back].images==NULL &&
513 	    sc->layers[0].refs==NULL )
514 return;
515     SCPreserveBackground(sc);
516     SCClearLayer(sc,ly_back);
517     SCOutOfDateBackground(sc);
518     SCCharChangedUpdate(sc,ly_back);
519 }
520 
SCCopyLayerToLayer(SplineChar * sc,int from,int to,int doclear)521 void SCCopyLayerToLayer(SplineChar *sc, int from, int to,int doclear) {
522     SplinePointList *fore, *temp;
523     RefChar *ref, *oldref;
524 
525     SCPreserveLayer(sc,to,false);
526     if ( doclear )
527 	SCClearLayer(sc,to);
528 
529     fore = SplinePointListCopy(sc->layers[from].splines);
530     if ( !sc->layers[from].order2 && sc->layers[to].order2 ) {
531 	temp = SplineSetsTTFApprox(fore);
532 	SplinePointListsFree(fore);
533 	fore = temp;
534     } else if ( sc->layers[from].order2 && !sc->layers[to].order2 ) {
535 	temp = SplineSetsPSApprox(fore);
536 	SplinePointListsFree(fore);
537 	fore = temp;
538     }
539     if ( fore!=NULL ) {
540 	for ( temp=fore; temp->next!=NULL; temp = temp->next );
541 	temp->next = sc->layers[to].splines;
542 	sc->layers[to].splines = fore;
543     }
544 
545     if ( sc->layers[to].refs==NULL )
546 	sc->layers[to].refs = ref = RefCharsCopyState(sc,from);
547     else {
548 	for ( oldref = sc->layers[to].refs; oldref->next!=NULL; oldref=oldref->next );
549 	oldref->next = ref = RefCharsCopyState(sc,from);
550     }
551     for ( ; ref!=NULL; ref=ref->next ) {
552 	SCReinstanciateRefChar(sc,ref,to);
553 	SCMakeDependent(sc,ref->sc);
554     }
555     SCCharChangedUpdate(sc,to);
556 }
557 
BpColinear(BasePoint * first,BasePoint * mid,BasePoint * last)558 int BpColinear(BasePoint *first, BasePoint *mid, BasePoint *last) {
559     BasePoint dist_f, unit_f, dist_l, unit_l;
560     bigreal len, off_l, off_f;
561 
562     dist_f.x = first->x - mid->x; dist_f.y = first->y - mid->y;
563     len = sqrt( dist_f.x*dist_f.x + dist_f.y*dist_f.y );
564     if ( len==0 )
565 return( false );
566     unit_f.x = dist_f.x/len; unit_f.y = dist_f.y/len;
567 
568     dist_l.x = last->x - mid->x; dist_l.y = last->y - mid->y;
569     len = sqrt( dist_l.x*dist_l.x + dist_l.y*dist_l.y );
570     if ( len==0 )
571 return( false );
572     unit_l.x = dist_l.x/len; unit_l.y = dist_l.y/len;
573 
574     off_f = dist_l.x*unit_f.y - dist_l.y*unit_f.x;
575     off_l = dist_f.x*unit_l.y - dist_f.y*unit_l.x;
576     if ( ( off_f<-1.5 || off_f>1.5 ) && ( off_l<-1.5 || off_l>1.5 ))
577 return( false );
578 
579 return( true );
580 }
581 
BpWithin(BasePoint * first,BasePoint * mid,BasePoint * last)582 int BpWithin(BasePoint *first, BasePoint *mid, BasePoint *last) {
583     BasePoint dist_mf, unit_mf, dist_lf, unit_lf;
584     bigreal len, off_lf, off_mf, len2;
585 
586     dist_mf.x = mid->x - first->x; dist_mf.y = mid->y - first->y;
587     len = sqrt( dist_mf.x*dist_mf.x + dist_mf.y*dist_mf.y );
588     if ( len==0 )
589 return( true );
590     unit_mf.x = dist_mf.x/len; unit_mf.y = dist_mf.y/len;
591 
592     dist_lf.x = last->x - first->x; dist_lf.y = last->y - first->y;
593     len = sqrt( dist_lf.x*dist_lf.x + dist_lf.y*dist_lf.y );
594     if ( len==0 )
595 return( false );
596     unit_lf.x = dist_lf.x/len; unit_lf.y = dist_lf.y/len;
597 
598     off_mf = dist_lf.x*unit_mf.y - dist_lf.y*unit_mf.x;
599     off_lf = dist_mf.x*unit_lf.y - dist_mf.y*unit_lf.x;
600     if ( ( off_mf<-.1 || off_mf>.1 ) && ( off_lf<-.1 || off_lf>.1 ))
601 return( false );
602 
603     len2 = dist_mf.x*unit_lf.x + dist_mf.y*unit_lf.y;
604 return( len2>=0 && len2<=len );
605 }
606 
SPChangePointType(SplinePoint * sp,int pointtype)607 void SPChangePointType(SplinePoint *sp, int pointtype) {
608     BasePoint unitnext, unitprev;
609     bigreal nextlen, prevlen;
610     int makedflt;
611     /*int oldpointtype = sp->pointtype;*/
612 
613     if ( sp->pointtype==pointtype ) {
614 	if ( pointtype==pt_curve || pointtype == pt_hvcurve ) {
615 	    if ( !sp->nextcpdef && sp->next!=NULL && !sp->next->order2 )
616 		SplineCharDefaultNextCP(sp);
617 	    if ( !sp->prevcpdef && sp->prev!=NULL && !sp->prev->order2 )
618 		SplineCharDefaultPrevCP(sp);
619 	}
620 return;
621     }
622     sp->pointtype = pointtype;
623 
624     if ( pointtype==pt_corner ) {
625 	/* Leave control points as they are */;
626 	sp->nextcpdef = sp->nonextcp;
627 	sp->prevcpdef = sp->noprevcp;
628     } else if ( pointtype==pt_tangent ) {
629 	if ( sp->next!=NULL && !sp->nonextcp && sp->next->knownlinear ) {
630 	    sp->nonextcp = true;
631 	    sp->nextcp = sp->me;
632 	} else if ( sp->prev!=NULL && !sp->nonextcp &&
633 		BpColinear(&sp->prev->from->me,&sp->me,&sp->nextcp) ) {
634 	    /* The current control point is reasonable */
635 	} else {
636 	    SplineCharTangentNextCP(sp);
637 	    if ( sp->next ) SplineRefigure(sp->next);
638 	}
639 	if ( sp->prev!=NULL && !sp->noprevcp && sp->prev->knownlinear ) {
640 	    sp->noprevcp = true;
641 	    sp->prevcp = sp->me;
642 	} else if ( sp->next!=NULL && !sp->noprevcp &&
643 		BpColinear(&sp->next->to->me,&sp->me,&sp->prevcp) ) {
644 	    /* The current control point is reasonable */
645 	} else {
646 	    SplineCharTangentPrevCP(sp);
647 	    if ( sp->prev ) SplineRefigure(sp->prev);
648 	}
649     } else if ( pointtype!=pt_curve
650 		&& ((BpColinear(&sp->prevcp,&sp->me,&sp->nextcp) ||
651 	    ( sp->nonextcp ^ sp->noprevcp )) &&
652 	    ( pointtype!=pt_hvcurve ||
653 		(sp->nextcp.x == sp->me.x && sp->nextcp.y != sp->me.y ) ||
654 	      (sp->nextcp.y == sp->me.y && sp->nextcp.x != sp->me.x ) )))
655     {
656 	/* Retain the old control points */
657     }
658     else
659     {
660 	unitnext.x = sp->nextcp.x-sp->me.x; unitnext.y = sp->nextcp.y-sp->me.y;
661 	nextlen = sqrt(unitnext.x*unitnext.x + unitnext.y*unitnext.y);
662 	unitprev.x = sp->prevcp.x-sp->me.x; unitprev.y = sp->prevcp.y-sp->me.y;
663 	prevlen = sqrt(unitprev.x*unitprev.x + unitprev.y*unitprev.y);
664 	makedflt=true;
665 	if ( nextlen!=0 && prevlen!=0 ) {
666 	    unitnext.x /= nextlen; unitnext.y /= nextlen;
667 	    unitprev.x /= prevlen; unitprev.y /= prevlen;
668 	    if ( unitnext.x*unitprev.x + unitnext.y*unitprev.y<=-.95 ) {
669 		/* If the control points are essentially in the same direction*/
670 		/*  (so valid for a curve) then leave them as is */
671 		makedflt = false;
672 	    }
673 	}
674 	if ( pointtype==pt_hvcurve &&
675 		((unitnext.x!=0 && unitnext.y!=0) ||
676 		 (unitprev.x!=0 && unitprev.y!=0)) ) {
677 	    BasePoint ncp, pcp;
678 	    if ( fabs(unitnext.x)+fabs(unitprev.x)>fabs(unitnext.y)+fabs(unitprev.y) ) {
679 		unitnext.y = unitprev.y = 0;
680 		unitnext.x = unitnext.x>0 ? 1 : -1;
681 		unitprev.x = unitprev.x>0 ? 1 : -1;
682 	    } else {
683 		unitnext.x = unitprev.x = 0;
684 		unitnext.y = unitnext.y>0 ? 1 : -1;
685 		unitprev.y = unitprev.y>0 ? 1 : -1;
686 	    }
687 	    ncp.x = sp->me.x + unitnext.x*nextlen;
688 	    ncp.y = sp->me.y + unitnext.y*nextlen;
689 	    sp->nextcp = ncp;
690 	    if ( sp->next!=NULL && sp->next->order2 )
691 		sp->next->to->prevcp = ncp;
692 	    pcp.x = sp->me.x + unitprev.x*prevlen;
693 	    pcp.y = sp->me.y + unitprev.y*prevlen;
694 	    sp->prevcp = pcp;
695 	    if ( sp->prev!=NULL && sp->prev->order2 )
696 		sp->prev->from->nextcp = pcp;
697 	    makedflt = false;
698 	}
699 	if( pointtype==pt_curve )
700 	    makedflt = true;
701 
702 	if ( makedflt ) {
703 	    sp->nextcpdef = sp->prevcpdef = true;
704 	    if (( sp->prev!=NULL && sp->prev->order2 ) ||
705 		    (sp->next!=NULL && sp->next->order2)) {
706 		if ( sp->prev!=NULL )
707 		    SplineRefigureFixup(sp->prev);
708 		if ( sp->next!=NULL )
709 		    SplineRefigureFixup(sp->next);
710 	    } else {
711 		SplineCharDefaultPrevCP(sp);
712 		SplineCharDefaultNextCP(sp);
713 	    }
714 	}
715     }
716     /* Now in order2 splines it is possible to request combinations that are */
717     /*  mathematically impossible -- two adjacent hv points often don't work */
718     if ( pointtype==pt_hvcurve &&
719 		!(sp->nextcp.x == sp->me.x && sp->nextcp.y != sp->me.y ) &&
720 		!(sp->nextcp.y == sp->me.y && sp->nextcp.x != sp->me.x ) )
721 	sp->pointtype = pt_curve;
722 }
723 
SplinePointRound(SplinePoint * sp,real factor)724 void SplinePointRound(SplinePoint *sp,real factor) {
725     BasePoint noff, poff;
726 
727     if ( sp->prev!=NULL && sp->next!=NULL && sp->next->order2 &&
728 	    sp->ttfindex == 0xffff ) {
729 	/* For interpolated points we want to round the controls */
730 	/* and then interpolated based on that */
731 	sp->nextcp.x = rint(sp->nextcp.x*factor)/factor;
732 	sp->nextcp.y = rint(sp->nextcp.y*factor)/factor;
733 	sp->prevcp.x = rint(sp->prevcp.x*factor)/factor;
734 	sp->prevcp.y = rint(sp->prevcp.y*factor)/factor;
735 	sp->me.x = (sp->nextcp.x + sp->prevcp.x)/2;
736 	sp->me.y = (sp->nextcp.y + sp->prevcp.y)/2;
737     } else {
738 	/* For normal points we want to round the distance of the controls */
739 	/*  from the base */
740 	noff.x = rint((sp->nextcp.x - sp->me.x)*factor)/factor;
741 	noff.y = rint((sp->nextcp.y - sp->me.y)*factor)/factor;
742 	poff.x = rint((sp->prevcp.x - sp->me.x)*factor)/factor;
743 	poff.y = rint((sp->prevcp.y - sp->me.y)*factor)/factor;
744 
745 	sp->me.x = rint(sp->me.x*factor)/factor;
746 	sp->me.y = rint(sp->me.y*factor)/factor;
747 
748 	sp->nextcp.x = sp->me.x + noff.x;
749 	sp->nextcp.y = sp->me.y + noff.y;
750 	sp->prevcp.x = sp->me.x + poff.x;
751 	sp->prevcp.y = sp->me.y + poff.y;
752     }
753     if ( sp->next!=NULL && sp->next->order2 )
754 	sp->next->to->prevcp = sp->nextcp;
755     if ( sp->prev!=NULL && sp->prev->order2 )
756 	sp->prev->from->nextcp = sp->prevcp;
757     if ( sp->nextcp.x==sp->me.x && sp->nextcp.y==sp->me.y )
758 	sp->nonextcp = true;
759     if ( sp->prevcp.x==sp->me.x && sp->prevcp.y==sp->me.y )
760 	sp->noprevcp = true;
761 }
762 
SpiroRound2Int(spiro_cp * cp,real factor)763 static void SpiroRound2Int(spiro_cp *cp,real factor) {
764     cp->x = rint(cp->x*factor)/factor;
765     cp->y = rint(cp->y*factor)/factor;
766 }
767 
SplineSetsRound2Int(SplineSet * spl,real factor,int inspiro,int onlysel)768 void SplineSetsRound2Int(SplineSet *spl,real factor, int inspiro, int onlysel) {
769     SplinePoint *sp;
770     int i;
771 
772     for ( ; spl!=NULL; spl=spl->next ) {
773 	if ( inspiro && spl->spiro_cnt!=0 ) {
774 	    for ( i=0; i<spl->spiro_cnt-1; ++i )
775 		if ( !onlysel || SPIRO_SELECTED(&spl->spiros[i]) )
776 		    SpiroRound2Int(&spl->spiros[i],factor);
777 	    SSRegenerateFromSpiros(spl);
778 	} else {
779 	    SplineSetSpirosClear(spl);
780 	    for ( sp=spl->first; ; ) {
781 		if ( sp->selected || !onlysel )
782 		    SplinePointRound(sp,factor);
783 		if ( sp->prev!=NULL )
784 		    SplineRefigure(sp->prev);
785 		if ( sp->next==NULL )
786 	    break;
787 		sp = sp->next->to;
788 		if ( sp==spl->first )
789 	    break;
790 	    }
791 	    if ( spl->first->prev!=NULL )
792 		SplineRefigure(spl->first->prev);
793 	}
794     }
795 }
796 
SplineSetsChangeCoord(SplineSet * spl,real old,real new,int isy,int inspiro)797 static void SplineSetsChangeCoord(SplineSet *spl,real old, real new,int isy,
798 	int inspiro) {
799     SplinePoint *sp;
800     int changed;
801     int i;
802 
803     for ( ; spl!=NULL; spl=spl->next ) {
804 	changed = false;
805 	if ( inspiro ) {
806 	    for ( i=0; i<spl->spiro_cnt-1; ++i ) {
807 		if ( isy && RealNear(spl->spiros[i].y,old)) {
808 		    spl->spiros[i].y = new;
809 		    changed = true;
810 		} else if ( !isy && RealNear(spl->spiros[i].x,old)) {
811 		    spl->spiros[i].x = new;
812 		    changed = true;
813 		}
814 	    }
815 	/* SSRegenerateFromSpiros will be done in Round2Int */
816 	} else {
817 	    for ( sp=spl->first; ; ) {
818 		if ( isy ) {
819 		    if ( RealNear(sp->me.y,old) ) {
820 			if ( RealNear(sp->nextcp.y,old))
821 			    sp->nextcp.y = new;
822 			else
823 			    sp->nextcp.y += new-sp->me.y;
824 			if ( RealNear(sp->prevcp.y,old))
825 			    sp->prevcp.y = new;
826 			else
827 			    sp->prevcp.y += new-sp->me.y;
828 			sp->me.y = new;
829 			changed = true;
830 			/* we expect to be called before SplineSetRound2Int and will */
831 			/*  allow it to do any SplineRefigures */
832 		    }
833 		} else {
834 		    if ( RealNear(sp->me.x,old) ) {
835 			if ( RealNear(sp->nextcp.x,old))
836 			    sp->nextcp.x = new;
837 			else
838 			    sp->nextcp.x += new-sp->me.x;
839 			if ( RealNear(sp->prevcp.x,old))
840 			    sp->prevcp.x = new;
841 			else
842 			    sp->prevcp.x += new-sp->me.x;
843 			sp->me.x = new;
844 			changed = true;
845 		    }
846 		}
847 		if ( sp->next==NULL )
848 	    break;
849 		sp = sp->next->to;
850 		if ( sp==spl->first )
851 	    break;
852 	    }
853 	    if ( changed )
854 		SplineSetSpirosClear(spl);
855 	}
856     }
857 }
858 
SCRound2Int(SplineChar * sc,int layer,real factor)859 void SCRound2Int(SplineChar *sc,int layer, real factor) {
860     RefChar *r;
861     AnchorPoint *ap;
862     StemInfo *stems;
863     real old, new;
864     int first, last;
865 
866     for ( stems = sc->hstem; stems!=NULL; stems=stems->next ) {
867 	old = stems->start+stems->width;
868 	stems->start = rint(stems->start*factor)/factor;
869 	stems->width = rint(stems->width*factor)/factor;
870 	new = stems->start+stems->width;
871 	if ( old!=new )
872 	    SplineSetsChangeCoord(sc->layers[ly_fore].splines,old,new,true,sc->inspiro && hasspiro());
873     }
874     for ( stems = sc->vstem; stems!=NULL; stems=stems->next ) {
875 	old = stems->start+stems->width;
876 	stems->start = rint(stems->start*factor)/factor;
877 	stems->width = rint(stems->width*factor)/factor;
878 	new = stems->start+stems->width;
879 	if ( old!=new )
880 	    SplineSetsChangeCoord(sc->layers[ly_fore].splines,old,new,false,sc->inspiro && hasspiro());
881     }
882 
883     if ( sc->parent->multilayer ) {
884 	first = ly_fore;
885 	last = sc->layer_cnt-1;
886     } else
887 	first = last = layer;
888     for ( layer = first; layer<=last; ++layer ) {
889 	SplineSetsRound2Int(sc->layers[layer].splines,factor,sc->inspiro && hasspiro(),false);
890 	for ( r=sc->layers[layer].refs; r!=NULL; r=r->next ) {
891 	    r->transform[4] = rint(r->transform[4]*factor)/factor;
892 	    r->transform[5] = rint(r->transform[5]*factor)/factor;
893 	    RefCharFindBounds(r);
894 	}
895     }
896     if ( sc->parent->multilayer )
897 	layer = ly_fore;
898     else
899 	--layer;
900 
901     for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
902 	ap->me.x = rint(ap->me.x*factor)/factor;
903 	ap->me.y = rint(ap->me.y*factor)/factor;
904     }
905     SCCharChangedUpdate(sc,layer);
906 }
907 
AltUniRemove(SplineChar * sc,int uni)908 void AltUniRemove(SplineChar *sc,int uni) {
909     struct altuni *altuni, *prev;
910 
911     if ( sc==NULL || uni==-1 )
912 return;
913 
914     if ( sc->unicodeenc==uni ) {
915 	for ( altuni = sc->altuni; altuni!=NULL; altuni=altuni->next )
916 	    if ( altuni->fid==0 && altuni->vs==-1 )
917 	break;
918 	if ( altuni!=NULL ) {
919 	    sc->unicodeenc = altuni->unienc;
920 	    altuni->unienc = uni;
921 	}
922     }
923 
924     if ( sc->unicodeenc==uni )
925 return;
926     for ( prev=NULL, altuni=sc->altuni; altuni!=NULL && (altuni->unienc!=uni || altuni->vs==-1 || altuni->fid!=0);
927 	    prev = altuni, altuni = altuni->next );
928     if ( altuni ) {
929 	if ( prev==NULL )
930 	    sc->altuni = altuni->next;
931 	else
932 	    prev->next = altuni->next;
933 	altuni->next = NULL;
934 	AltUniFree(altuni);
935     }
936 }
937 
AltUniAdd(SplineChar * sc,int uni)938 void AltUniAdd(SplineChar *sc,int uni) {
939     struct altuni *altuni;
940 
941     if ( sc!=NULL && uni!=-1 && uni!=sc->unicodeenc ) {
942 	for ( altuni = sc->altuni; altuni!=NULL && (altuni->unienc!=uni ||
943 						    altuni->vs!=-1 ||
944 			                            altuni->fid); altuni=altuni->next );
945 	if ( altuni==NULL ) {
946 	    altuni = chunkalloc(sizeof(struct altuni));
947 	    altuni->next = sc->altuni;
948 	    sc->altuni = altuni;
949 	    altuni->unienc = uni;
950 	    altuni->vs = -1;
951 	    altuni->fid = 0;
952 	}
953     }
954 }
955 
AltUniAdd_DontCheckDups(SplineChar * sc,int uni)956 void AltUniAdd_DontCheckDups(SplineChar *sc,int uni) {
957     struct altuni *altuni;
958 
959     if ( sc!=NULL && uni!=-1 && uni!=sc->unicodeenc ) {
960 	altuni = chunkalloc(sizeof(struct altuni));
961 	altuni->next = sc->altuni;
962 	sc->altuni = altuni;
963 	altuni->unienc = uni;
964 	altuni->vs = -1;
965 	altuni->fid = 0;
966     }
967 }
968 
SCOrderAP(SplineChar * sc)969 void SCOrderAP(SplineChar *sc) {
970     int lc=0, cnt=0, out=false, i,j;
971     AnchorPoint *ap, **array;
972     /* Order so that first ligature index comes first */
973 
974     for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
975 	if ( ap->lig_index<lc ) out = true;
976 	if ( ap->lig_index>lc ) lc = ap->lig_index;
977 	++cnt;
978     }
979     if ( !out )
980 return;
981 
982     array = malloc(cnt*sizeof(AnchorPoint *));
983     for ( i=0, ap=sc->anchor; ap!=NULL; ++i, ap=ap->next )
984 	array[i] = ap;
985     for ( i=0; i<cnt-1; ++i ) {
986 	for ( j=i+1; j<cnt; ++j ) {
987 	    if ( array[i]->lig_index>array[j]->lig_index ) {
988 		ap = array[i];
989 		array[i] = array[j];
990 		array[j] = ap;
991 	    }
992 	}
993     }
994     sc->anchor = array[0];
995     for ( i=0; i<cnt-1; ++i )
996 	array[i]->next = array[i+1];
997     array[cnt-1]->next = NULL;
998     free( array );
999 }
1000 
UnlinkThisReference(FontViewBase * fv,SplineChar * sc,int layer)1001 void UnlinkThisReference(FontViewBase *fv,SplineChar *sc,int layer) {
1002     /* We are about to clear out sc. But somebody refers to it and that we */
1003     /*  aren't going to delete. So (if the user asked us to) instanciate sc */
1004     /*  into all characters which refer to it and which aren't about to be */
1005     /*  cleared out */
1006     struct splinecharlist *dep, *dnext;
1007 
1008     for ( dep=sc->dependents; dep!=NULL; dep=dnext ) {
1009 	dnext = dep->next;
1010 	if ( fv==NULL || !fv->selected[fv->map->backmap[dep->sc->orig_pos]]) {
1011 	    SplineChar *dsc = dep->sc;
1012 	    RefChar *rf, *rnext;
1013 	    /* May be more than one reference to us, colon has two refs to period */
1014 	    /*  but only one dlist entry */
1015 	    for ( rf = dsc->layers[layer].refs; rf!=NULL; rf=rnext ) {
1016 		rnext = rf->next;
1017 		if ( rf->sc == sc ) {
1018 		    /* Even if we were to preserve the state there would be no */
1019 		    /*  way to undo the operation until we undid the delete... */
1020 		    SCRefToSplines(dsc,rf,layer);
1021 		    SCUpdateAll(dsc);
1022 		}
1023 	    }
1024 	}
1025     }
1026 }
1027 
MultipleValues(char * name,int local)1028 static int MultipleValues(char *name, int local) {
1029     char *buts[3];
1030     buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
1031     if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this Unicode encoding\n(named %1$.40s, at local encoding %2$d).\nIs that what you want?"),name,local)==0 )
1032 return( true );
1033 
1034 return( false );
1035 }
1036 
MultipleNames(void)1037 static int MultipleNames(void) {
1038     char *buts[3];
1039     buts[0] = _("_Yes"); buts[1]=_("_Cancel"); buts[2] = NULL;
1040     if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this name,\ndo you want to swap names?"))==0 )
1041 return( true );
1042 
1043 return( false );
1044 }
1045 
SCSetMetaData(SplineChar * sc,const char * name,int unienc,const char * comment)1046 int SCSetMetaData(SplineChar *sc,const char *name,int unienc,const char *comment) {
1047     SplineFont *sf = sc->parent;
1048     int i, mv=0;
1049     int isnotdef, samename=false, sameuni=false;
1050     struct altuni *alt;
1051 
1052     if ( sf->glyphs[sc->orig_pos]!=sc )
1053 	IError("Bad call to SCSetMetaData");
1054 
1055     for ( alt=sc->altuni; alt!=NULL && (alt->unienc!=unienc || alt->vs!=-1 || alt->fid!=0); alt=alt->next );
1056     if ( unienc==sc->unicodeenc || alt!=NULL )
1057 	sameuni=true;
1058     if ( sameuni && strcmp(name,sc->name)==0 ) {
1059 	samename = true;	/* No change, it must be good */
1060     }
1061     if ( alt!=NULL || !samename ) {
1062 	isnotdef = strcmp(name,".notdef")==0;
1063 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->orig_pos!=sc->orig_pos ) {
1064 	    if ( unienc!=-1 && sf->glyphs[i]->unicodeenc==unienc ) {
1065 		if ( !mv && !MultipleValues(sf->glyphs[i]->name,i)) {
1066 return( false );
1067 		}
1068 		mv = 1;
1069 	    } else if ( !isnotdef && strcmp(name,sf->glyphs[i]->name)==0 ) {
1070 		if ( !MultipleNames()) {
1071 return( false );
1072 		}
1073 		free(sf->glyphs[i]->name);
1074 		sf->glyphs[i]->namechanged = true;
1075 		if ( strncmp(sc->name,"uni",3)==0 && sf->glyphs[i]->unicodeenc!=-1) {
1076 		    char buffer[12];
1077 		    if ( sf->glyphs[i]->unicodeenc<0x10000 )
1078 			sprintf( buffer,"uni%04X", sf->glyphs[i]->unicodeenc);
1079 		    else
1080 			sprintf( buffer,"u%04X", sf->glyphs[i]->unicodeenc);
1081 		    sf->glyphs[i]->name = copy(buffer);
1082 		} else {
1083 		    sf->glyphs[i]->name = sc->name;
1084 		    sc->name = NULL;
1085 		}
1086 	    break;
1087 	    }
1088 	}
1089 	if ( sc->unicodeenc!=unienc ) {
1090 	    struct splinecharlist *scl;
1091 	    int layer;
1092 	    RefChar *ref;
1093 
1094 	    for ( scl=sc->dependents; scl!=NULL; scl=scl->next ) {
1095 		for ( layer=ly_back; layer<scl->sc->layer_cnt; ++layer )
1096 		    for ( ref = scl->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1097 			if ( ref->sc==sc )
1098 			    ref->unicode_enc = unienc;
1099 	    }
1100 	}
1101     }
1102     if ( alt!=NULL )
1103 	alt->unienc = sc->unicodeenc;
1104     sc->unicodeenc = unienc;
1105     if ( sc->name==NULL || strcmp(name,sc->name)!=0 ) {
1106 	if ( sc->name!=NULL )
1107 	    SFGlyphRenameFixup(sf,sc->name,name,false);
1108 	free(sc->name);
1109 	sc->name = copy(name);
1110 	sc->namechanged = true;
1111 	GlyphHashFree(sf);
1112     }
1113     sf->changed = true;
1114     if ( samename )
1115 	/* Ok to name it itself */;
1116     else if ( sameuni && ( unienc>=0xe000 && unienc<=0xf8ff ))
1117 	/* Ok to name things in the private use area */;
1118     else {
1119 	FontViewBase *fvs;
1120 	for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1121 	    int enc = fvs->map->backmap[sc->orig_pos];
1122 	    if ( enc!=-1 && ((fvs->map->enc->only_1byte && enc<256) ||
1123 			(fvs->map->enc->has_2byte && enc<65535 ))) {
1124 		fvs->map->enc = &custom;
1125 		FVSetTitle(fvs);
1126 	    }
1127 	}
1128     }
1129     free(sc->comment); sc->comment = NULL;
1130     if ( comment!=NULL && *comment!='\0' )
1131 	sc->comment = copy(comment);
1132 
1133     SCRefreshTitles(sc);
1134 return( true );
1135 }
1136 
RevertedGlyphReferenceFixup(SplineChar * sc,SplineFont * sf)1137 void RevertedGlyphReferenceFixup(SplineChar *sc, SplineFont *sf) {
1138     RefChar *refs, *prev, *next;
1139     KernPair *kp, *kprev, *knext;
1140     SplineFont *cidmaster = sf, *ksf;
1141     int layer, isv, l;
1142 
1143     for ( layer = 0; layer<sc->layer_cnt; ++layer ) {
1144 	for ( prev=NULL, refs = sc->layers[layer].refs ; refs!=NULL; refs = next ) {
1145 	    next = refs->next;
1146 	    if ( refs->orig_pos<sf->glyphcnt && sf->glyphs[refs->orig_pos]!=NULL ) {
1147 		prev = refs;
1148 		refs->sc = sf->glyphs[refs->orig_pos];
1149 		refs->unicode_enc = refs->sc->unicodeenc;
1150 		SCReinstanciateRefChar(sc,refs,layer);
1151 		SCMakeDependent(sc,refs->sc);
1152 	    } else {
1153 		if ( prev==NULL )
1154 		    sc->layers[layer].refs = next;
1155 		else
1156 		    prev->next = next;
1157 		RefCharFree(refs);
1158 	    }
1159 	}
1160     }
1161     /* Fixup kerning pairs as well */
1162     for ( isv=0; isv<2; ++isv ) {
1163 	for ( kprev = NULL, kp=isv?sc->vkerns : sc->kerns; kp!=NULL; kp=knext ) {
1164 	    int index = (intpt) (kp->sc);
1165 	    knext = kp->next;
1166 	    kp->kcid = false;
1167 	    ksf = sf;
1168 	    if ( cidmaster!=sf ) {
1169 		for ( l=0; l<cidmaster->subfontcnt; ++l ) {
1170 		    ksf = cidmaster->subfonts[l];
1171 		    if ( index<ksf->glyphcnt && ksf->glyphs[index]!=NULL )
1172 	    break;
1173 		}
1174 	    }
1175 	    if ( index>=ksf->glyphcnt || ksf->glyphs[index]==NULL ) {
1176 		IError( "Bad kerning information in glyph %s\n", sc->name );
1177 		kp->sc = NULL;
1178 	    } else
1179 		kp->sc = ksf->glyphs[index];
1180 	    if ( kp->sc!=NULL )
1181 		kprev = kp;
1182 	    else{
1183 		if ( kprev!=NULL )
1184 		    kprev->next = knext;
1185 		else if ( isv )
1186 		    sc->vkerns = knext;
1187 		else
1188 		    sc->kerns = knext;
1189 		chunkfree(kp,sizeof(KernPair));
1190 	    }
1191 	}
1192     }
1193 }
1194 
CheckBluePair(char * blues,char * others,int bluefuzz,int magicpointsize)1195 static int CheckBluePair(char *blues, char *others, int bluefuzz,
1196 	int magicpointsize) {
1197     int bound = 2*bluefuzz+1;
1198     int bluevals[10+14], cnt, pos=0, maxzoneheight;
1199     int err = 0;
1200     char *end;
1201 
1202     if ( others!=NULL ) {
1203 	while ( *others==' ' ) ++others;
1204 	if ( *others=='[' || *others=='{' ) ++others;
1205 	for ( cnt=0; ; ++cnt ) {
1206 	    bigreal temp;
1207 	    while ( *others==' ' ) ++others;
1208 	    if ( *others==']' || *others=='}' )
1209 	break;
1210 	    temp = g_ascii_strtod(others,&end);
1211 	    if ( temp!=rint(temp))
1212 		err |= pds_notintegral;
1213 	    else if ( end==others ) {
1214 		err |= pds_notintegral;
1215 	break;
1216 	    }
1217 	    others = end;
1218 	    if ( cnt>=10 )
1219 		err |= pds_toomany;
1220 	    else
1221 		bluevals[pos++] = temp;
1222 	}
1223 	if ( cnt&1 )
1224 	    err |= pds_odd;
1225     }
1226 
1227     while ( *blues==' ' ) ++blues;
1228     if ( *blues=='{' || *blues=='[' ) ++blues;
1229     for ( cnt=0; ; ++cnt ) {
1230 	bigreal temp;
1231 	while ( *blues==' ' ) ++blues;
1232 	if ( *blues==']' || *blues=='}' )
1233     break;
1234 	temp = g_ascii_strtod(blues,&end);
1235 	if ( temp!=rint(temp))
1236 	    err |= pds_notintegral;
1237 	else if ( end==blues ) {
1238 	    err |= pds_notintegral;
1239     break;
1240 	}
1241 	blues = end;
1242 	if ( cnt>=14 )
1243 	    err |= pds_toomany;
1244 	else
1245 	    bluevals[pos++] = temp;
1246     }
1247     if ( cnt&1 )
1248 	err |= pds_odd;
1249 
1250     /* Now there is nothing which says that otherblues must all be less than */
1251     /*  blues. But the examples suggest it. And I shall assume it */
1252 
1253     maxzoneheight = -1;
1254     for ( cnt=0; cnt<pos; cnt+=2 ) {
1255 	if ( cnt+1<pos && bluevals[cnt]>bluevals[cnt+1] )
1256 	    err |= pds_outoforder;
1257 	else if ( cnt+1<pos && maxzoneheight<bluevals[cnt+1]-bluevals[cnt] )
1258 	    maxzoneheight = bluevals[cnt+1]-bluevals[cnt];
1259 	if ( cnt!=0 && bluevals[cnt-1]>=bluevals[cnt] )
1260 	    err |= pds_outoforder;
1261 	if ( cnt!=0 && bluevals[cnt-1]+bound>bluevals[cnt] )
1262 	    err |= pds_tooclose;
1263     }
1264 
1265     if ( maxzoneheight>0 && (magicpointsize-.49)*maxzoneheight>=240 )
1266 	err |= pds_toobig;
1267 
1268 return( err );
1269 }
1270 
CheckStdW(struct psdict * dict,char * key)1271 static int CheckStdW(struct psdict *dict,char *key ) {
1272     char *str_val, *end;
1273     bigreal val;
1274 
1275     if ( (str_val = PSDictHasEntry(dict,key))==NULL )
1276 return( true );
1277     while ( *str_val==' ' ) ++str_val;
1278     if ( *str_val!='[' && *str_val!='{' )
1279 return( false );
1280     ++str_val;
1281 
1282     val = g_ascii_strtod(str_val,&end);
1283     while ( *end==' ' ) ++end;
1284     if ( *end!=']' && *end!='}' )
1285 return( false );
1286     ++end;
1287     while ( *end==' ' ) ++end;
1288     if ( *end!='\0' || end==str_val || val<=0 )
1289 return( false );
1290 
1291 return( true );
1292 }
1293 
CheckStemSnap(struct psdict * dict,char * snapkey,char * stdkey)1294 static int CheckStemSnap(struct psdict *dict,char *snapkey, char *stdkey ) {
1295     char *str_val, *end;
1296     bigreal std_val = -1;
1297     bigreal stems[12], temp;
1298     int cnt, found;
1299     /* At most 12 double values, in order, must include Std?W value, array */
1300 
1301     if ( (str_val = PSDictHasEntry(dict,stdkey))!=NULL ) {
1302 	while ( *str_val==' ' ) ++str_val;
1303 	if ( *str_val=='[' && *str_val!='{' ) ++str_val;
1304 	std_val = g_ascii_strtod(str_val,&end);
1305     }
1306 
1307     if ( (str_val = PSDictHasEntry(dict,snapkey))==NULL )
1308 return( true );		/* This entry is not required */
1309     while ( *str_val==' ' ) ++str_val;
1310     if ( *str_val!='[' && *str_val!='{' )
1311 return( false );
1312     ++str_val;
1313 
1314     found = false;
1315     for ( cnt=0; ; ++cnt ) {
1316 	while ( *str_val==' ' ) ++str_val;
1317 	if ( *str_val==']' && *str_val!='}' )
1318     break;
1319 	temp = g_ascii_strtod(str_val,&end);
1320 	if ( end==str_val )
1321 return( false );
1322 	str_val = end;
1323 	if ( cnt>=12 )
1324 return( false );
1325 	stems[cnt] = temp;
1326 	if ( cnt>0 && stems[cnt-1]>=stems[cnt] )
1327 return( false );
1328 	if ( stems[cnt] == std_val )
1329 	    found = true;
1330     }
1331     if ( !found && std_val>0 )
1332 return( -1 );
1333 
1334 return( true );
1335 }
1336 
ValidatePrivate(SplineFont * sf)1337 int ValidatePrivate(SplineFont *sf) {
1338     int errs = 0;
1339     char *blues, *bf, *test, *end;
1340     int fuzz = 1;
1341     bigreal bluescale = .039625;
1342     int magicpointsize;
1343 
1344     if ( sf->private==NULL )
1345 return( pds_missingblue );
1346 
1347     if ( (bf = PSDictHasEntry(sf->private,"BlueFuzz"))!=NULL ) {
1348 	fuzz = strtol(bf,&end,10);
1349 	if ( *end!='\0' || fuzz<0 )
1350 	    errs |= pds_badbluefuzz;
1351     }
1352 
1353     if ( (test=PSDictHasEntry(sf->private,"BlueScale"))!=NULL ) {
1354 	bluescale = g_ascii_strtod(test,&end);
1355 	if ( *end!='\0' || end==test || bluescale<0 )
1356 	    errs |= pds_badbluescale;
1357     }
1358     magicpointsize = rint( bluescale*240 + 0.49 );
1359 
1360     if ( (blues = PSDictHasEntry(sf->private,"BlueValues"))==NULL )
1361 	errs |= pds_missingblue;
1362     else
1363 	errs |= CheckBluePair(blues,PSDictHasEntry(sf->private,"OtherBlues"),fuzz,magicpointsize);
1364 
1365     if ( (blues = PSDictHasEntry(sf->private,"FamilyBlues"))!=NULL )
1366 	errs |= CheckBluePair(blues,PSDictHasEntry(sf->private,"FamilyOtherBlues"),
1367 		fuzz,magicpointsize)<<pds_shift;
1368 
1369 
1370     if ( (test=PSDictHasEntry(sf->private,"BlueShift"))!=NULL ) {
1371 	int val = strtol(test,&end,10);
1372 	if ( *end!='\0' || end==test || val<0 )
1373 	    errs |= pds_badblueshift;
1374     }
1375 
1376     if ( !CheckStdW(sf->private,"StdHW"))
1377 	errs |= pds_badstdhw;
1378     if ( !CheckStdW(sf->private,"StdVW"))
1379 	errs |= pds_badstdvw;
1380 
1381     switch ( CheckStemSnap(sf->private,"StemSnapH", "StdHW")) {
1382       case false:
1383 	errs |= pds_badstemsnaph;
1384       break;
1385       case -1:
1386 	errs |= pds_stemsnapnostdh;
1387       break;
1388     }
1389     switch ( CheckStemSnap(sf->private,"StemSnapV", "StdVW")) {
1390       case false:
1391 	errs |= pds_badstemsnapv;
1392       break;
1393       case -1:
1394 	errs |= pds_stemsnapnostdv;
1395       break;
1396     }
1397 
1398 return( errs );
1399 }
1400 
SFValidNameList(SplineFont * sf,char * list)1401 static int SFValidNameList(SplineFont *sf, char *list) {
1402     char *start, *pt;
1403     int ch;
1404     SplineChar *sc;
1405 
1406     for ( start = list ; ; ) {
1407 	while ( *start==' ' ) ++start;
1408 	if ( *start=='\0' )
1409 return( true );
1410 	for ( pt=start; *pt!=':' && *pt!=' ' && *pt!='\0' ; ++pt );
1411 	ch = *pt;
1412 	if ( ch==' ' || ch=='\0' )
1413 return( -1 );
1414 	if ( sf!=NULL ) {
1415 	    *pt = '\0';
1416 	    sc = SFGetChar(sf,-1,start);
1417 	    *pt = ch;
1418 	    if ( sc==NULL )
1419 return( -1 );
1420 	}
1421 	start = pt;
1422     }
1423 }
1424 
BPTooFar(BasePoint * bp1,BasePoint * bp2)1425 int BPTooFar(BasePoint *bp1, BasePoint *bp2) {
1426 return( bp1->x - bp2->x > 32767 || bp2->x - bp1->x > 32767 ||
1427 	bp1->y - bp2->y > 32767 || bp2->y - bp1->y > 32767 );
1428 }
1429 
SCValidateAnchors(SplineChar * sc)1430 AnchorClass *SCValidateAnchors(SplineChar *sc) {
1431     SplineFont *sf = sc->parent;
1432     AnchorClass *ac;
1433     AnchorPoint *ap;
1434 
1435     if ( sf==NULL )
1436 return( NULL );
1437     if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
1438 
1439     for ( ac=sf->anchor; ac!=NULL; ac=ac->next ) {
1440 	ac->ticked = 0;
1441 	if ( ac->subtable ) ac->subtable->ticked = 0;
1442     }
1443 
1444     for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
1445 	if ( ap->type==at_basechar || ap->type==at_basemark ) {
1446 	    ac = ap->anchor;
1447 	    ac->ticked = true;
1448 	    if ( ac->subtable ) ac->subtable->ticked = true;
1449 	}
1450     }
1451 
1452     for ( ac=sf->anchor; ac!=NULL; ac=ac->next ) {
1453 	if ( !ac->ticked && ac->subtable && ac->subtable->ticked )
1454 return( ac );
1455     }
1456 return( NULL );
1457 }
1458 
UniMatch(int vs,int uni,SplineChar * sc)1459 static int UniMatch(int vs, int uni, SplineChar *sc) {
1460     struct altuni *alt;
1461 
1462     if ( sc->unicodeenc!=-1 && vs==-1 && uni == sc->unicodeenc )
1463 return( true );
1464     for ( alt = sc->altuni; alt!=NULL; alt=alt->next )
1465 	if ( alt->vs==vs && alt->unienc==uni )
1466 return( true );
1467 
1468 return( false );
1469 }
1470 
SCHintOverlapInMask(SplineChar * sc,HintMask * hm)1471 StemInfo *SCHintOverlapInMask(SplineChar *sc,HintMask *hm) {
1472     int hi1, hi2, hcnt=0;
1473     StemInfo *h1, *h2;
1474     int v;
1475 
1476     for ( v=0; v<2; ++v ) {
1477 	if ( v==0 ) {
1478 	    h1 = sc->hstem;
1479 	    hi1 = 0;
1480 	} else {
1481 	    h1 = sc->vstem;
1482 	    hi1 = hcnt;
1483 	}
1484 	for ( ; h1!=NULL && hi1<HntMax; ++hi1, h1=h1->next ) {
1485 	    if ( hm==NULL || ((*hm)[(hi1>>3)] & (0x80>>(hi1&7))) ) {
1486 		for ( hi2=hi1+1, h2=h1->next; h2!=NULL && hi2<HntMax; ++hi2, h2=h2->next ) {
1487 		    if ( hm==NULL || ((*hm)[(hi2>>3)] & (0x80>>(hi2&7))) ) {
1488 			real start1, end1, start2, end2;
1489 			if ( h1->width>0 ) {
1490 			    start1 = h1->start;
1491 			    end1 = start1+h1->width;
1492 			} else {
1493 			    end1 = h1->start;
1494 			    start1 = end1+h1->width;
1495 			}
1496 			if ( h2->width>0 ) {
1497 			    start2 = h2->start;
1498 			    end2 = start2+h2->width;
1499 			} else {
1500 			    end2 = h2->start;
1501 			    start2 = end2+h2->width;
1502 			}
1503 			if ( end1<start2 || start1>end2 )
1504 			    /* No overlap */;
1505 			else
1506 return( h1 );
1507 		    }
1508 		}
1509 	    }
1510 	}
1511 	hcnt = hi1;
1512     }
1513 return( NULL );
1514 }
1515 
SCValidate(SplineChar * sc,int layer,int force)1516 int SCValidate(SplineChar *sc, int layer, int force) {
1517     SplineSet *ss;
1518     Spline *s1, *s2, *s, *first;
1519     SplinePoint *sp;
1520     RefChar *ref;
1521     int lastscan= -1;
1522     int cnt, path_cnt, pt_cnt;
1523     StemInfo *h;
1524     SplineSet *base;
1525     bigreal len2, bound2, x, y;
1526     extended extrema[4];
1527     PST *pst;
1528     struct ttf_table *tab;
1529     extern int allow_utf8_glyphnames;
1530     RefChar *r;
1531     BasePoint lastpt;
1532     int gid, k;
1533     SplineFont *cid, *sf;
1534     SplineChar *othersc;
1535     struct altuni *alt;
1536 
1537     if ( (sc->layers[layer].validation_state&vs_known) && !force )
1538   goto end;
1539 
1540     sc->layers[layer].validation_state = 0;
1541 
1542     base = LayerAllSplines(&sc->layers[layer]);
1543 
1544     if ( !allow_utf8_glyphnames ) {
1545 	if ( strlen(sc->name)>31 )
1546 	    sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1547 	else {
1548 	    char *pt;
1549 	    for ( pt = sc->name; *pt; ++pt ) {
1550 		if (( *pt>='A' && *pt<='Z' ) ||
1551 			(*pt>='a' && *pt<='z' ) ||
1552 			(*pt>='0' && *pt<='9' ) ||
1553 			*pt == '.' || *pt == '_' )
1554 		    /* That's ok */;
1555 		else {
1556 		    sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1557 	    break;
1558 		}
1559 	    }
1560 	}
1561     }
1562 
1563     for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
1564 	if ( pst->type==pst_substitution &&
1565 		!SCWorthOutputting(SFGetChar(sc->parent,-1,pst->u.subs.variant))) {
1566 	    sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1567     break;
1568 	} else if ( pst->type==pst_pair &&
1569 		!SCWorthOutputting(SFGetChar(sc->parent,-1,pst->u.pair.paired))) {
1570 	    sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1571     break;
1572 	} else if ( (pst->type==pst_alternate || pst->type==pst_multiple || pst->type==pst_ligature) &&
1573 		!SFValidNameList(sc->parent,pst->u.mult.components)) {
1574 	    sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1575     break;
1576 	}
1577     }
1578     if ( sc->vert_variants!=NULL && sc->vert_variants->variants != NULL &&
1579 	    !SFValidNameList(sc->parent,sc->vert_variants->variants) )
1580 	sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1581     else if ( sc->horiz_variants!=NULL && sc->horiz_variants->variants != NULL &&
1582 	    !SFValidNameList(sc->parent,sc->horiz_variants->variants) )
1583 	sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1584     else {
1585 	int i;
1586 	if ( sc->vert_variants!=NULL ) {
1587 	    for ( i=0; i<sc->vert_variants->part_cnt; ++i ) {
1588 		if ( !SCWorthOutputting(SFGetChar(sc->parent,-1,sc->vert_variants->parts[i].component)))
1589 		    sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1590 	    break;
1591 	    }
1592 	}
1593 	if ( sc->horiz_variants!=NULL ) {
1594 	    for ( i=0; i<sc->horiz_variants->part_cnt; ++i ) {
1595 		if ( !SCWorthOutputting(SFGetChar(sc->parent,-1,sc->horiz_variants->parts[i].component)))
1596 		    sc->layers[layer].validation_state |= vs_badglyphname|vs_known;
1597 	    break;
1598 	    }
1599 	}
1600     }
1601 
1602     for ( ss=sc->layers[layer].splines; ss!=NULL; ss=ss->next ) {
1603 	/* TrueType uses single points to move things around so ignore them */
1604 	if ( ss->first->next==NULL )
1605 	    /* Do Nothing */;
1606 	else if ( ss->first->prev==NULL ) {
1607 	    sc->layers[layer].validation_state |= vs_opencontour|vs_known;
1608     break;
1609 	}
1610     }
1611 
1612     /* If there's an open contour we can't really tell whether it self-intersects */
1613     if ( sc->layers[layer].validation_state & vs_opencontour )
1614 	/* sc->layers[layer].validation_state |= vs_selfintersects*/;
1615     else {
1616 	if ( SplineSetIntersect(base,&s1,&s2) )
1617 	    sc->layers[layer].validation_state |= vs_selfintersects|vs_known;
1618     }
1619 
1620     /* If there's a self-intersection we are guaranteed that both the self- */
1621     /*  intersecting contours will be in the wrong direction at some point */
1622     if ( sc->layers[layer].validation_state & vs_selfintersects )
1623 	/*sc->layers[layer].validation_state |= vs_wrongdirection*/;
1624     else {
1625 	if ( SplineSetsDetectDir(&base,&lastscan)!=NULL )
1626 	    sc->layers[layer].validation_state |= vs_wrongdirection|vs_known;
1627     }
1628 
1629     /* Different kind of "wrong direction" */
1630     for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
1631 	if ( ref->transform[0]*ref->transform[3]<0 ||
1632 		(ref->transform[0]==0 && ref->transform[1]*ref->transform[2]>0)) {
1633 	    sc->layers[layer].validation_state |= vs_flippedreferences|vs_known;
1634     break;
1635 	}
1636     }
1637 
1638     for ( h=sc->hstem, cnt=0; h!=NULL; h=h->next, ++cnt );
1639     for ( h=sc->vstem       ; h!=NULL; h=h->next, ++cnt );
1640     if ( cnt>=96 )
1641 	sc->layers[layer].validation_state |= vs_toomanyhints|vs_known;
1642 
1643     if ( sc->layers[layer].splines!=NULL ) {
1644 	int anyhm=0;
1645 	h=NULL;
1646 	for ( ss=sc->layers[layer].splines; ss!=NULL && h==NULL; ss=ss->next ) {
1647 	    sp = ss->first;
1648 	    do {
1649 		if ( sp->hintmask!=NULL ) {
1650 		    anyhm = true;
1651 		    h = SCHintOverlapInMask(sc,sp->hintmask);
1652 		    if ( h!=NULL )
1653 	    break;
1654 		}
1655 		if ( sp->next==NULL )
1656 	    break;
1657 		sp = sp->next->to;
1658 	    } while ( sp!=ss->first );
1659 	}
1660 	if ( !anyhm )
1661 	    h = SCHintOverlapInMask(sc,NULL);
1662 	if ( h!=NULL )
1663 	    sc->layers[layer].validation_state |= vs_overlappedhints|vs_known;
1664     }
1665 
1666     memset(&lastpt,0,sizeof(lastpt));
1667     for ( ss=sc->layers[layer].splines, pt_cnt=path_cnt=0; ss!=NULL; ss=ss->next, ++path_cnt ) {
1668 	for ( sp=ss->first; ; ) {
1669 	    /* If we're interpolating the point, it won't show up in the truetype */
1670 	    /*  points list and it need not be integral (often it will end in .5) */
1671 	    if ( (!SPInterpolate(sp) && (sp->me.x != rint(sp->me.x) || sp->me.y != rint(sp->me.y))) ||
1672 		    sp->nextcp.x != rint(sp->nextcp.x) || sp->nextcp.y != rint(sp->nextcp.y) ||
1673 		    sp->prevcp.x != rint(sp->prevcp.x) || sp->prevcp.y != rint(sp->prevcp.y))
1674 		sc->layers[layer].validation_state |= vs_nonintegral|vs_known;
1675 	    if ( BPTooFar(&lastpt,&sp->prevcp) ||
1676 		    BPTooFar(&sp->prevcp,&sp->me) ||
1677 		    BPTooFar(&sp->me,&sp->nextcp))
1678 		sc->layers[layer].validation_state |= vs_pointstoofarapart|vs_known;
1679 	    memcpy(&lastpt,&sp->nextcp,sizeof(lastpt));
1680 	    ++pt_cnt;
1681 	    if ( sp->next==NULL )
1682 	break;
1683 	    if ( !sp->next->knownlinear ) {
1684 		if ( sp->next->order2 )
1685 		    ++pt_cnt;
1686 		else
1687 		    pt_cnt += 2;
1688 	    }
1689 	    sp = sp->next->to;
1690 	    if ( sp==ss->first ) {
1691 		memcpy(&lastpt,&sp->me,sizeof(lastpt));
1692 	break;
1693 	    }
1694 	}
1695     }
1696     if ( pt_cnt>1500 )
1697 	sc->layers[layer].validation_state |= vs_toomanypoints|vs_known;
1698 
1699     LayerUnAllSplines(&sc->layers[layer]);
1700 
1701     /* Only check the splines in the glyph, not those in refs */
1702     bound2 = sc->parent->extrema_bound;
1703     if ( bound2<=0 )
1704 	bound2 = (sc->parent->ascent + sc->parent->descent)/32.0;
1705     bound2 *= bound2;
1706     for ( ss=sc->layers[layer].splines, cnt=0; ss!=NULL; ss=ss->next ) {
1707 	first = NULL;
1708 	for ( s=ss->first->next ; s!=NULL && s!=first; s=s->to->next ) {
1709 	    if ( first==NULL )
1710 		first = s;
1711 	    if ( s->acceptableextrema )
1712 	continue;		/* If marked as good, don't check it */
1713 	    /* rough appoximation to spline's length */
1714 	    x = (s->to->me.x-s->from->me.x);
1715 	    y = (s->to->me.y-s->from->me.y);
1716 	    len2 = x*x + y*y;
1717 	    /* short splines (serifs) are not required to have points at their extrema */
1718 	    if ( len2>bound2 && Spline2DFindExtrema(s,extrema)>0 ) {
1719 		sc->layers[layer].validation_state |= vs_missingextrema|vs_known;
1720     goto break_2_loops;
1721 	    }
1722 	}
1723     }
1724     break_2_loops:;
1725 
1726     if ( (tab = SFFindTable(sc->parent,CHR('m','a','x','p')))!=NULL && tab->len>=32 ) {
1727 	/* If we have a maxp table then do some truetype checks */
1728 	/* these are only errors for fontlint, we'll fix them up when we */
1729 	/*  generate the font -- but fontlint needs to know this stuff */
1730 	int pt_max = memushort(tab->data,tab->len,3*sizeof(uint16));
1731 	int path_max = memushort(tab->data,tab->len,4*sizeof(uint16));
1732 	int composit_pt_max = memushort(tab->data,tab->len,5*sizeof(uint16));
1733 	int composit_path_max = memushort(tab->data,tab->len,6*sizeof(uint16));
1734 	int instr_len_max = memushort(tab->data,tab->len,13*sizeof(uint16));
1735 	int num_comp_max = memushort(tab->data,tab->len,14*sizeof(uint16));
1736 	int comp_depth_max  = memushort(tab->data,tab->len,15*sizeof(uint16));
1737 	int rd, rdtest;
1738 
1739 	/* Already figured out two of these */
1740 	if ( sc->layers[layer].splines==NULL ) {
1741 	    if ( pt_cnt>composit_pt_max )
1742 		sc->layers[layer].validation_state |= vs_maxp_toomanycomppoints|vs_known;
1743 	    if ( path_cnt>composit_path_max )
1744 		sc->layers[layer].validation_state |= vs_maxp_toomanycomppaths|vs_known;
1745 	}
1746 
1747 	for ( ss=sc->layers[layer].splines, pt_cnt=path_cnt=0; ss!=NULL; ss=ss->next, ++path_cnt ) {
1748 	    for ( sp=ss->first; ; ) {
1749 		++pt_cnt;
1750 		if ( sp->next==NULL )
1751 	    break;
1752 		sp = sp->next->to;
1753 		if ( sp==ss->first )
1754 	    break;
1755 	    }
1756 	}
1757 	if ( pt_cnt>pt_max )
1758 	    sc->layers[layer].validation_state |= vs_maxp_toomanypoints|vs_known;
1759 	if ( path_cnt>path_max )
1760 	    sc->layers[layer].validation_state |= vs_maxp_toomanypaths|vs_known;
1761 
1762 	if ( sc->ttf_instrs_len>instr_len_max )
1763 	    sc->layers[layer].validation_state |= vs_maxp_instrtoolong|vs_known;
1764 
1765 	rd = 0;
1766 	for ( r=sc->layers[layer].refs, cnt=0; r!=NULL; r=r->next, ++cnt ) {
1767 	    rdtest = RefDepth(r,layer);
1768 	    if ( rdtest>rd )
1769 		rd = rdtest;
1770 	}
1771 	if ( cnt>num_comp_max )
1772 	    sc->layers[layer].validation_state |= vs_maxp_toomanyrefs|vs_known;
1773 	if ( rd>comp_depth_max )
1774 	    sc->layers[layer].validation_state |= vs_maxp_refstoodeep|vs_known;
1775     }
1776 
1777     k=0;
1778     cid = sc->parent;
1779     if ( cid->cidmaster != NULL )
1780 	cid = cid->cidmaster;
1781     do {
1782 	sf = cid->subfontcnt==0 ? cid : cid->subfonts[k];
1783 	for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (othersc=sf->glyphs[gid])!=NULL ) {
1784 	    if ( othersc==sc )
1785 	continue;
1786 	    if ( strcmp(sc->name,othersc->name)==0 )
1787 		sc->layers[layer].validation_state |= vs_dupname|vs_known;
1788 	    if ( sc->unicodeenc!=-1 && UniMatch(-1,sc->unicodeenc,othersc) )
1789 		sc->layers[layer].validation_state |= vs_dupunicode|vs_known;
1790 	    for ( alt=sc->altuni; alt!=NULL; alt=alt->next )
1791 		if ( UniMatch(alt->vs,alt->unienc,othersc) )
1792 		    sc->layers[layer].validation_state |= vs_dupunicode|vs_known;
1793 	}
1794 	++k;
1795     } while ( k<cid->subfontcnt );
1796 
1797   end:;
1798     /* This test is intentionally here and should be done even if the glyph */
1799     /*  hasn't changed. If the lookup changed it could make the glyph invalid */
1800     if ( SCValidateAnchors(sc)!=NULL )
1801 	sc->layers[layer].validation_state |= vs_missinganchor;
1802 
1803     sc->layers[layer].validation_state |= vs_known;
1804     if ( sc->unlink_rm_ovrlp_save_undo )
1805 return( sc->layers[layer].validation_state&~(vs_known|vs_selfintersects) );
1806 
1807 return( sc->layers[layer].validation_state&~vs_known );
1808 }
1809 
SFValidate(SplineFont * sf,int layer,int force)1810 int SFValidate(SplineFont *sf, int layer, int force) {
1811     int k, gid;
1812     SplineFont *sub;
1813     int any = 0;
1814     SplineChar *sc;
1815     int cnt=0;
1816 
1817     if ( sf->cidmaster )
1818 	sf = sf->cidmaster;
1819 
1820     if ( !no_windowing_ui ) {
1821 	cnt = 0;
1822 	k = 0;
1823 	do {
1824 	    sub = sf->subfontcnt==0 ? sf : sf->subfonts[k];
1825 	    for ( gid=0; gid<sub->glyphcnt; ++gid ) if ( (sc=sub->glyphs[gid])!=NULL ) {
1826 		if ( force || !(sc->layers[layer].validation_state&vs_known) )
1827 		    ++cnt;
1828 	    }
1829 	    ++k;
1830 	} while ( k<sf->subfontcnt );
1831 	if ( cnt!=0 )
1832 	    ff_progress_start_indicator(10,_("Validating..."),_("Validating..."),0,cnt,1);
1833     }
1834 
1835     k = 0;
1836     do {
1837 	sub = sf->subfontcnt==0 ? sf : sf->subfonts[k];
1838 	for ( gid=0; gid<sub->glyphcnt; ++gid ) if ( (sc=sub->glyphs[gid])!=NULL ) {
1839 	    if ( force || !(sc->layers[layer].validation_state&vs_known) ) {
1840 		SCValidate(sc,layer,true);
1841 		if ( !ff_progress_next())
1842 return( -1 );
1843 	    } else if ( SCValidateAnchors(sc)!=NULL )
1844 		sc->layers[layer].validation_state |= vs_missinganchor;
1845 
1846 	    if ( sc->unlink_rm_ovrlp_save_undo )
1847 		any |= sc->layers[layer].validation_state&~vs_selfintersects;
1848 	    else
1849 		any |= sc->layers[layer].validation_state;
1850 	}
1851 	++k;
1852     } while ( k<sf->subfontcnt );
1853     ff_progress_end_indicator();
1854 
1855     /* a lot of asian ttf files have a bad postscript fontname stored in the */
1856     /*  name table */
1857 return( any&~vs_known );
1858 }
1859 
SCTickValidationState(SplineChar * sc,int layer)1860 void SCTickValidationState(SplineChar *sc,int layer) {
1861     struct splinecharlist *dlist;
1862 
1863     sc->layers[layer].validation_state = vs_unknown;
1864     for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next ) {
1865 	if ( dlist->sc==sc )
1866 	    IError("A glyph may not depend on itself in SCTickValidationState");
1867 	else
1868 	    SCTickValidationState(dlist->sc,layer);
1869     }
1870 }
1871 
VSMaskFromFormat(SplineFont * sf,int layer,enum fontformat format)1872 int VSMaskFromFormat(SplineFont *sf, int layer, enum fontformat format) {
1873     if ( format==ff_cid || format==ff_cffcid || format==ff_otfcid || format==ff_otfciddfont )
1874 return( vs_maskcid );
1875     else if ( format<=ff_cff )
1876 return( vs_maskps );
1877     else if ( format<=ff_ttfdfont )
1878 return( vs_maskttf );
1879     else if ( format<=ff_otfdfont )
1880 return( vs_maskps );
1881     else if ( format==ff_svg )
1882 return( vs_maskttf );
1883     else if ( format==ff_woff2 )
1884 return( vs_maskttf );
1885     else
1886 return( sf->subfontcnt!=0 || sf->cidmaster!=NULL ? vs_maskcid :
1887 	sf->layers[layer].order2 ? vs_maskttf : vs_maskps );
1888 }
1889 
CirclePoint(int which)1890 static SplinePoint *CirclePoint(int which) {
1891     SplinePoint *sp;
1892     static struct shapedescrip {
1893         BasePoint me, prevcp, nextcp; int nocp;
1894     } ellipse3[] = {
1895         { { 1, 0 }, { 1, 0.552 }, { 1, -.552 }, false },
1896         { { 0, -1 }, { 0.552, -1 }, { -0.552, -1 }, false },
1897         { { -1, 0 }, { -1, -0.552 }, { -1, .552 }, false },
1898         { { 0, 1 }, { -0.552, 1 }, { 0.552, 1 }, false },
1899         { { 0, 0 }, { 0, 0 }, { 0, 0 }, 0 }
1900     };
1901 
1902     sp = SplinePointCreate(ellipse3[which].me.x,ellipse3[which].me.y);
1903     sp->nonextcp = sp->noprevcp = false;
1904     sp->nextcp = ellipse3[which].nextcp;
1905     sp->prevcp = ellipse3[which].prevcp;
1906 return( sp );
1907 }
1908 
UnitCircle(int clockwise)1909 static SplineSet *UnitCircle(int clockwise) {
1910     SplineSet *spl;
1911     SplinePoint *sps[5];
1912     int i;
1913 
1914     spl = chunkalloc(sizeof(SplineSet));
1915     for ( i=0; i<4; ++i )
1916 	sps[i] = CirclePoint(i&3);
1917     sps[4] = sps[0];
1918     for ( i=0; i<4; ++i )
1919 	SplineMake3(sps[i], sps[i+1]);
1920     spl->first = sps[0]; spl->last = sps[4];
1921     spl->start_offset = 0;
1922     if ( !clockwise )
1923 	SplineSetReverse(spl);
1924 return( spl );
1925 }
1926 
CutCircle(SplineSet * spl,BasePoint * me,int first)1927 static int CutCircle(SplineSet *spl,BasePoint *me,int first) {
1928     Spline *s, *firsts;
1929     SplinePoint *end;
1930     extended ts[3];
1931     int i;
1932     bigreal best_t = -1;
1933     Spline *best_s = NULL;
1934     bigreal best_off = 2;
1935 
1936     firsts = NULL;
1937     for ( s = spl->first->next ; s!=NULL && s!=firsts; s = s->to->next ) {
1938 	if ( firsts==NULL ) firsts = s;
1939 	CubicSolve(&s->splines[0],me->x,ts);
1940 	for ( i=0; i<3 && ts[i]!=-1; ++i ) {
1941 	    bigreal y = ((s->splines[1].a*ts[i]+s->splines[1].b)*ts[i]+s->splines[1].c)*ts[i]+s->splines[1].d;
1942 	    bigreal off = me->y-y;
1943 	    if ( off<0 ) off = -off;
1944 	    if ( off < best_off ) {
1945 		best_s = s;
1946 		best_t = ts[i];
1947 		best_off = off;
1948 	    }
1949 	}
1950     }
1951     if ( best_s==NULL ) {
1952 return(false);
1953     }
1954 
1955     if ( best_t<.0001 )
1956 	end = best_s->from;
1957     else if ( best_t>.999 )
1958 	end = best_s->to;
1959     else
1960 	end = SplineBisect(best_s,best_t);
1961     if ( first ) {
1962 	spl->first = end;
1963 	spl->last = end;
1964 	spl->start_offset = 0;
1965     } else {
1966 	spl->last = end;
1967 	s = end->next;
1968 	end->next = NULL;
1969 	while ( s!=NULL ) {
1970 	    end = s->to;
1971 	    SplineFree(s);
1972 	    if ( end==spl->first )
1973 	break;
1974 	    s = end->next;
1975 	    SplinePointFree(end);
1976 	}
1977     }
1978 return( true );
1979 }
1980 
PrevSlope(SplinePoint * sp,BasePoint * slope)1981 static void PrevSlope(SplinePoint *sp,BasePoint *slope) {
1982     bigreal len;
1983 
1984     if ( sp->prev==NULL )
1985 	slope->x = slope->y = 0;
1986     else if ( sp->prev->knownlinear ) {
1987 	slope->x = sp->me.x - sp->prev->from->me.x;
1988 	slope->y = sp->me.y - sp->prev->from->me.y;
1989     } else if ( !sp->noprevcp ) {
1990 	slope->x = sp->me.x - sp->prevcp.x;
1991 	slope->y = sp->me.x - sp->prevcp.y;
1992     } else {
1993 	bigreal t = 1.0-1/256.0;
1994 	slope->x = (3*sp->prev->splines[0].a*t+2*sp->prev->splines[0].b)*t+sp->prev->splines[0].c;
1995 	slope->y = (3*sp->prev->splines[1].a*t+2*sp->prev->splines[1].b)*t+sp->prev->splines[1].c;
1996     }
1997     len = sqrt(slope->x*slope->x + slope->y*slope->y);
1998     if ( len==0 )
1999 return;
2000     slope->x /= len;
2001     slope->y /= len;
2002 return;
2003 }
2004 
NextSlope(SplinePoint * sp,BasePoint * slope)2005 static void NextSlope(SplinePoint *sp,BasePoint *slope) {
2006     bigreal len;
2007 
2008     if ( sp->next==NULL )
2009 	slope->x = slope->y = 0;
2010     else if ( sp->next->knownlinear ) {
2011 	slope->x = sp->next->to->me.x - sp->me.x;
2012 	slope->y = sp->next->to->me.y - sp->me.y;
2013     } else if ( !sp->nonextcp ) {
2014 	slope->x = sp->nextcp.x - sp->me.x;
2015 	slope->y = sp->nextcp.y - sp->me.y;
2016     } else {
2017 	bigreal t = 1/256.0;
2018 	slope->x = (3*sp->next->splines[0].a*t+2*sp->next->splines[0].b)*t+sp->next->splines[0].c;
2019 	slope->y = (3*sp->next->splines[1].a*t+2*sp->next->splines[1].b)*t+sp->next->splines[1].c;
2020     }
2021     len = sqrt(slope->x*slope->x + slope->y*slope->y);
2022     if ( len==0 )
2023 return;
2024     slope->x /= len;
2025     slope->y /= len;
2026 return;
2027 }
2028 
EllipseClockwise(SplinePoint * sp1,SplinePoint * sp2,BasePoint * slope1,BasePoint * slope2)2029 static int EllipseClockwise(SplinePoint *sp1,SplinePoint *sp2,BasePoint *slope1,
2030 	BasePoint *slope2) {
2031     /* Build up a temporary shape to see whether the ellipse will be clockwise*/
2032     /*  or counter */
2033     SplinePoint *e1, *e2;
2034     SplineSet *ss;
2035     int ret;
2036     bigreal len;
2037 
2038     e1 = SplinePointCreate(sp1->me.x,sp1->me.y);
2039     e2 = SplinePointCreate(sp2->me.x,sp2->me.y);
2040     SplineMake3(e2,e1);
2041     e1->nonextcp = false; e2->noprevcp = false;
2042     len = sqrt((sp1->me.x-sp2->me.x) * (sp1->me.x-sp2->me.x)  +
2043 	  (sp1->me.y-sp2->me.y) * (sp1->me.y-sp2->me.y));
2044     e1->nextcp.x = e1->me.x + len*slope1->x;
2045     e1->nextcp.y = e1->me.y + len*slope1->y;
2046     e2->prevcp.x = e2->me.x - len*slope2->x;
2047     e2->prevcp.y = e2->me.y - len*slope2->y;
2048     SplineMake3(e1,e2);
2049     ss = chunkalloc(sizeof(SplineSet));
2050     ss->first = ss->last = e1;
2051     ss->start_offset = 0;
2052     ret = SplinePointListIsClockwise(ss);
2053     SplinePointListFree(ss);
2054 return( ret );
2055 }
2056 
BuildEllipse(int clockwise,bigreal r1,bigreal r2,bigreal theta,BasePoint * center,SplinePoint * sp1,SplinePoint * sp2,CharViewBase * cv,int changed,int order2,int ellipse_to_back)2057 static int BuildEllipse(int clockwise,bigreal r1,bigreal r2, bigreal theta,
2058 	BasePoint *center,SplinePoint *sp1,SplinePoint *sp2,CharViewBase *cv,
2059 	int changed, int order2, int ellipse_to_back) {
2060     SplineSet *spl, *ss=NULL;
2061     real trans[6];
2062     bigreal c,s;
2063 
2064     spl = UnitCircle(clockwise);
2065     memset(trans,0,sizeof(trans));
2066     trans[0] = r1; trans[3] = r2;
2067     SplinePointListTransform(spl,trans,tpt_AllPoints);
2068     c = cos(theta); s = sin(theta);
2069     trans[0] = trans[3] = c;
2070     trans[1] = s; trans[2] = -s;
2071     trans[4] = center->x; trans[5] = center->y;
2072     SplinePointListTransform(spl,trans,tpt_AllPoints);
2073     if ( ellipse_to_back && CVLayer(cv)!=ly_back )
2074 	/* Originally this was debugging code... but hey, it's kind of neat */
2075 	/*  and may prove useful if we need to do more debugging. Invoked by */
2076 	/*  holding down the <Alt> modifier when selecting the menu item */
2077 	ss = SplinePointListCopy(spl);
2078     if ( !CutCircle(spl,&sp1->me,true) || !CutCircle(spl,&sp2->me,false) ) {
2079 	SplinePointListFree(spl);
2080 	SplinePointListFree(ss);
2081 return( false );
2082     }
2083     if ( ellipse_to_back && ss!=NULL ) {
2084 	SCPreserveBackground(cv->sc);
2085 	if ( cv->sc->layers[ly_back].order2 )
2086 	    ss = SplineSetsConvertOrder(ss,true);
2087 	ss->next = cv->sc->layers[ly_back].splines;
2088 	cv->sc->layers[ly_back].splines = ss;
2089     }
2090     if ( order2 )
2091 	spl = SplineSetsConvertOrder(spl,true);
2092     if ( !changed )
2093 	CVPreserveState(cv);
2094     if ( sp1->next!=NULL ) {
2095 	chunkfree(sp1->next,sizeof(Spline));
2096 	sp1->next = sp2->prev = NULL;
2097     }
2098     sp1->nextcp = spl->first->nextcp;
2099     sp1->nonextcp = spl->first->nonextcp;
2100     sp1->next = spl->first->next;
2101     sp1->next->from = sp1;
2102     sp2->prevcp.x = sp2->me.x + (spl->last->prevcp.x-spl->last->me.x);
2103     sp2->prevcp.y = sp2->me.y + (spl->last->prevcp.y-spl->last->me.y);
2104     sp2->noprevcp = spl->last->noprevcp;
2105     sp2->prev = spl->last->prev;
2106     sp2->prev->to = sp2;
2107     SplineRefigure(sp1->next); SplineRefigure(sp2->prev);
2108     SplinePointFree(spl->first);
2109     SplinePointFree(spl->last);
2110     spl->first = spl->last = NULL;
2111     spl->start_offset = 0;
2112     SplinePointListFree(spl);
2113 return( true );
2114 }
2115 
MakeEllipseWithAxis(CharViewBase * cv,SplinePoint * sp1,SplinePoint * sp2,int order2,int changed,int ellipse_to_back)2116 static int MakeEllipseWithAxis(CharViewBase *cv,SplinePoint *sp1,SplinePoint *sp2,int order2,
2117 	int changed, int ellipse_to_back ) {
2118     BasePoint center;
2119     bigreal r1,r2, len, dot, theta, c, s, factor, denom;
2120     BasePoint slope1, slope2, offset, roffset, rslope, temp;
2121     int clockwise;
2122 
2123     PrevSlope(sp1,&slope1);
2124     NextSlope(sp2,&slope2);
2125     if ( slope1.x==0 && slope1.y==0 ) {
2126 	if ( slope2.x==0 && slope2.y==0 ) {
2127 	    /* No direction info. Draw a semicircle with center halfway between*/
2128 	    slope1.y =   sp2->me.x - sp1->me.x ;
2129 	    slope1.x = -(sp2->me.y - sp1->me.y);
2130 	    len = sqrt(slope1.x*slope1.x + slope1.y*slope1.y);
2131 	    slope1.x /= len; slope1.y /= len;
2132 	    slope2.x = -slope1.x;
2133 	    slope2.y = -slope1.y;
2134 	} else {
2135 	    slope1.x = -slope2.y;
2136 	    slope1.y =  slope2.x;
2137 	}
2138     } else if ( slope2.x==0 && slope2.y==0 ) {
2139 	slope2.x =  slope1.y;
2140 	slope2.y = -slope1.x;
2141     }
2142     clockwise = EllipseClockwise(sp1,sp2,&slope1,&slope2);
2143     dot = slope1.y*slope2.x - slope1.x*slope2.y;
2144     theta = atan2(-slope1.x,slope1.y);
2145     if ( !isfinite(theta))
2146 return( false );
2147     c = cos(theta); s = sin(theta);
2148     if ( RealNear(dot,0) ) {
2149 	/* The slopes are parallel. Most cases have no solution, but */
2150 	/*  one case gives us a semicircle centered between the two points*/
2151 	if ( slope1.x*slope2.x + slope1.y*slope2.y > 0 )
2152 return( false );		/* Point in different directions */
2153 	temp.x = sp2->me.x - sp1->me.x;
2154 	temp.y = sp2->me.y - sp1->me.y;
2155 	if ( !RealNear(slope1.x*temp.x - slope1.y*temp.y,0) )
2156 return( false );
2157 	center.x = sp1->me.x + temp.x/2;
2158 	center.y = sp1->me.y + temp.y/2;
2159 	len = sqrt(temp.x*temp.x + temp.y*temp.y);
2160 	r1 = r2 = len/2;
2161 	factor = 1;
2162     } else {
2163 	/* The data we have been given do not specify an unique ellipse*/
2164 	/*  in fact there are an infinite number of them, (I think)    */
2165 	/*  but once we fix the orientation of the axes then there is  */
2166 	/*  only one. So let's say that one axis is normal to sp1,     */
2167 	/* Now in a circle... if we draw a line through the center to  */
2168 	/*  the edge, and we represent the slope of the circle at that */
2169 	/*  point as slope2.y/slope2.x, and the height of the point as */
2170 	/*  offset.y and the difference between the x coord of the pt  */
2171 	/*  and the radius of the circle, then we have two identities  */
2172 	/*    (radius-offset.x)^2 + offset.y^2 = radius^2              */
2173 	/*    => radius = (offset.x^2+offset.y^2)/(2*offset.x)         */
2174 	/*    slope.y/slope.x = (radius-offset.x)/offset.y             */
2175 	/*  Now in an ellipse we must multiply each y value by a factor*/
2176 	/*  Solving for both equations for radius, this gives us an    */
2177 	/*  equation for factor:                                       */
2178 	/*  f = sqrt( dx^2*sx / (sx*dy^2 - 2*sy*dy*dx ))               */
2179 	offset.x = sp2->me.x - sp1->me.x;
2180 	offset.y = sp2->me.y - sp1->me.y;
2181 	roffset.x =  offset.x*c + offset.y*s;
2182 	roffset.y = -offset.x*s + offset.y*c;
2183 	if ( RealNear(roffset.x,0) || RealNear(roffset.y,0))
2184 return( false );
2185 	rslope.x =  slope2.x*c + slope2.y*s;
2186 	rslope.y = -slope2.x*s + slope2.y*c;
2187 	if ( roffset.x<0 ) roffset.x = -roffset.x;
2188 	if ( roffset.y<0 ) roffset.y = -roffset.y;
2189 	if ( rslope.x<0 ) rslope.x = -rslope.x;
2190 	if ( rslope.y<0 ) rslope.y = -rslope.y;
2191 	denom = roffset.y*(rslope.x*roffset.y - 2*roffset.x*rslope.y);
2192 	if ( RealNear(denom,0))
2193 return( false );
2194 	factor = rslope.x*roffset.x*roffset.x/denom;
2195 	if ( factor<0 )
2196 return( false );
2197 	factor = sqrt( factor );
2198 	r1 = (roffset.x*roffset.x+roffset.y*roffset.y*factor*factor)/(2*roffset.x);
2199 	r2 = r1/factor;
2200 	/* And the center is normal to sp1 and r1 away from it */
2201 	if ( clockwise ) {
2202 	    center.x = sp1->me.x + slope1.y*r1;
2203 	    center.y = sp1->me.y - slope1.x*r1;
2204 	} else {
2205 	    center.x = sp1->me.x - slope1.y*r1;
2206 	    center.y = sp1->me.y + slope1.x*r1;
2207 	}
2208     }
2209 return( BuildEllipse(clockwise,r1,r1/factor,theta,&center,sp1,sp2,cv,changed,
2210 	order2, ellipse_to_back));
2211 }
2212 
2213 #define ITER	3
EllipseSomewhere(CharViewBase * cv,SplinePoint * sp1,SplinePoint * sp2,int order2,int changed,int ellipse_to_back)2214 static int EllipseSomewhere(CharViewBase *cv,SplinePoint *sp1,SplinePoint *sp2,
2215 	int order2, int changed, int ellipse_to_back ) {
2216     BasePoint center;
2217     bigreal len, dot, rc, rs;
2218     BasePoint slope1, slope2, temp;
2219     struct transstate {
2220 	BasePoint me1, me2;
2221 	BasePoint slope1, slope2;
2222     } centered, rot;
2223     bigreal bestrot=9999, bestrtest = 1e50, e1sq, e2sq, r1, r2, rtest;
2224     bigreal low, high, offset=FF_PI/128., rotation;
2225     int i;
2226     int clockwise;
2227     /* First figure out a center. There will be one: */
2228     /*  Take a line through sp1 but parallel to slope2 */
2229     /*  Take a line through sp2 but parallel to slope1 */
2230     /* The intersection of these two lines gives us a center */
2231     /* First rotate everything by the rotation angle (around the origin -- it */
2232     /*  will do to cancel out the rotation */
2233 
2234     PrevSlope(sp1,&slope1);
2235     NextSlope(sp2,&slope2);
2236     if ( slope1.x==0 && slope1.y==0 ) {
2237 	if ( slope2.x==0 && slope2.y==0 ) {
2238 	    /* No direction info. Draw a semicircle with center halfway between*/
2239 	    slope1.y =   sp2->me.x - sp1->me.x ;
2240 	    slope1.x = -(sp2->me.y - sp1->me.y);
2241 	    len = sqrt(slope1.x*slope1.x + slope1.y*slope1.y);
2242 	    slope1.x /= len; slope1.y /= len;
2243 	    slope2.x = -slope1.x;
2244 	    slope2.y = -slope1.y;
2245 	} else {
2246 	    slope1.x = -slope2.y;
2247 	    slope1.y =  slope2.x;
2248 	}
2249     } else if ( slope2.x==0 && slope2.y==0 ) {
2250 	slope2.x =  slope1.y;
2251 	slope2.y = -slope1.x;
2252     }
2253     clockwise = EllipseClockwise(sp1,sp2,&slope1,&slope2);
2254     dot = slope1.y*slope2.x - slope1.x*slope2.y;
2255     if ( RealNear(dot,0)) {
2256 	/* Essentially parallel lines, already handled the only case we can */
2257 return( false );
2258     }
2259     center.x = (slope1.x*slope2.x*(sp1->me.y-sp2->me.y) + slope2.x*slope1.y*sp2->me.x - slope1.x*slope2.y*sp1->me.x)/dot;
2260     if ( slope2.x!=0 )
2261 	center.y = sp1->me.y + slope2.y*(center.x-sp1->me.x)/slope2.x;
2262     else	/* Can't both be 0, else lines would be parallel */
2263 	center.y = sp2->me.y + slope1.y*(center.x-sp2->me.x)/slope1.x;
2264     centered.me1.x = sp1->me.x - center.x; centered.me1.y = sp1->me.y - center.y;
2265     centered.me2.x = sp2->me.x - center.x; centered.me2.y = sp2->me.y - center.y;
2266 
2267     /* now guess the angle of rotation and find one which works */
2268     /* doubtless there is a better way to do this, but I get lost in */
2269     /*  algebraic grunge */
2270     r1 = r2 = 1;
2271     for ( i=0; i<ITER; ++i ) {
2272 	if ( i==0 ) {
2273 	    low = 0; high = FF_PI; offset = FF_PI/1024;
2274 	} else {
2275 	    low = bestrot-offset; high = bestrot+offset; offset /= 64.;
2276 	}
2277 	bestrot = 9999; bestrtest = 1e50;
2278 	for ( rotation = low; rotation<=high; rotation += offset ) {
2279 	    rc = cos(rotation); rs = sin(rotation);
2280 	    temp.x =  slope1.x*rc + slope1.y*rs;
2281 	    temp.y = -slope1.x*rs + slope1.y*rc;
2282 	    rot.slope1 = temp;
2283 	    temp.x =  slope2.x*rc + slope2.y*rs;
2284 	    temp.y = -slope2.x*rs + slope2.y*rc;
2285 	    rot.slope2 = temp;
2286 	    rot.me1.x =  centered.me1.x*rc + centered.me1.y*rs;
2287 	    rot.me1.y = -centered.me1.x*rs + centered.me1.y*rc;
2288 	    rot.me2.x =  centered.me2.x*rc + centered.me2.y*rs;
2289 	    rot.me2.y = -centered.me2.x*rs + centered.me2.y*rc;
2290 
2291 	    /* Now we know that in a circle: */
2292 	    /* (x-cx)/(y-cy) = -sy/sx,  or  sx*(x-cx) = -sy*(y-cy)     */
2293 	    /* on an ellipse that becomes  sx*(x-cx) = -e^2*sy*(y-cy)  */
2294 	    /*  e^2 = -sx*(x-cx)/(sy*(y-cy))                           */
2295 	    if ( rot.slope1.y==0 || rot.slope2.y==0 || rot.me1.y==0 || rot.me2.y==0 ||
2296 		    rot.slope1.x==0 || rot.slope2.x==0 || rot.me1.x==0 || rot.me2.x==0 )
2297 	continue;
2298 	    e1sq = -rot.slope1.x*rot.me1.x/(rot.slope1.y*rot.me1.y);
2299 	    e2sq = -rot.slope2.x*rot.me2.x/(rot.slope2.y*rot.me2.y);
2300 	    if ( e1sq<=0 || e2sq<=0 )
2301 	continue;
2302 	    e1sq = (e1sq+e2sq)/2;
2303 	    r1 = sqrt(rot.me1.x*rot.me1.x + e1sq*rot.me1.y*rot.me1.y);
2304 	    rtest = sqrt(rot.me2.x*rot.me2.x + e1sq*rot.me2.y*rot.me2.y);
2305 	    if ( (rtest -= r1)<0 ) rtest = -rtest;
2306 	    if ( rtest<bestrtest ) {
2307 		bestrtest = rtest;
2308 		bestrot = rotation;
2309 		r2 = r1/sqrt(e1sq);
2310 		/* Since we've got two points with tangents we know:       */
2311 		/* -s1x*(x1-cx)/(s1y*(y1-cy)) = -s2x*(x2-cx)/(s2y*(y2-cy)) */
2312 		/* s1x*(x1-cx)*s2y*(y2-cy) = s2x*(x2-cx)*s1y*(y1-cy)       */
2313 		/* s1x*s2y*(x1-cx)*y2 - s2x*s1y*(x2-cx)*y1 = (s1x*s2y*(x1-cx)-s2x*s1y*(x2-cx))*cy */
2314 		/*      s1x*s2y*(x1-cx)*y2 - s2x*s1y*(x2-cx)*y1            */
2315 		/* cy = ---------------------------------------            */
2316 		/*          s1x*s2y*(x1-cx)-s2x*s1y*(x2-cx)                */
2317 		/* Since the points lie on the curve we know               */
2318 		/*  (x-cx)^2 + e^2*(y-cy)^2 = r^2                          */
2319 		/* Removing r^2....                                        */
2320 		/*  (x1-cx)^2 + e^2*(y1-cy)^2 = (x2-cx)^2 + e^2*(y2-cy)^2  */
2321 		/*  e^2 * [(y1-cy)^2-(y2-cy)^2] = (x2-cx)^2 - (x1-cx)^2    */
2322 		/*        (x2-cx)^2 - (x1-cx)^2                            */
2323 		/*  e^2 = ---------------------                            */
2324 		/*        (y1-cy)^2 - (y2-cy)^2                            */
2325 	    }
2326 	}
2327 	if ( bestrot>9990 )
2328 return( false );
2329     }
2330 return( BuildEllipse(clockwise,r1,r2,bestrot,&center,sp1,sp2,cv,changed,
2331 	order2, ellipse_to_back));
2332 }
2333 
MakeShape(CharViewBase * cv,SplinePointList * spl1,SplinePointList * spl2,SplinePoint * sp1,SplinePoint * sp2,int order2,int changed,int do_arc,int ellipse_to_back)2334 static int MakeShape(CharViewBase *cv,SplinePointList *spl1,SplinePointList *spl2,
2335 	SplinePoint *sp1,SplinePoint *sp2,int order2, int changed, int do_arc,
2336 	int ellipse_to_back ) {
2337     if ( !do_arc || ( sp1->me.x==sp2->me.x && sp1->me.y==sp2->me.y )) {
2338 	if ( !changed )
2339 	    CVPreserveState(cv);
2340 	sp1->nonextcp = true;
2341 	sp1->nextcp = sp1->me;
2342 	sp2->noprevcp = true;
2343 	sp2->prevcp = sp2->me;
2344 	if ( sp1->next==NULL )
2345 	    SplineMake(sp1,sp2,order2);
2346 	else
2347 	    SplineRefigure(sp1->next);
2348 return( true );
2349     } else {
2350 	/* There are either an infinite number of elliptical solutions or none*/
2351 	/* First search for a solution where one of the points lies on one of */
2352 	/*  the axes of the ellipse. (If there is a circular solution this    */
2353 	/*  will find it as the above statement is true of all points on a    */
2354 	/*  circle). If that fails then try a more general search which will  */
2355 	/*  find something, but may not find an intuitively expected soln.    */
2356 	if ( MakeEllipseWithAxis(cv,sp1,sp2,order2,changed,ellipse_to_back))
2357 return( true );
2358 	/* OK, sp1 wasn't on an axis. How about sp2? */
2359 	SplineSetReverse(spl1);
2360 	if ( spl1!=spl2 )
2361 	    SplineSetReverse(spl2);
2362 	if ( MakeEllipseWithAxis(cv,sp2,sp1,order2,changed,ellipse_to_back))
2363 return( -1 );
2364 	SplineSetReverse(spl1);
2365 	if ( spl1!=spl2 )
2366 	    SplineSetReverse(spl2);
2367 	/* OK, neither was on an axis. Ellipse is rotated by some odd amount */
2368 	if ( EllipseSomewhere(cv,sp1,sp2,order2,changed,ellipse_to_back) )
2369 return( true );
2370 
2371 return( false );
2372     }
2373 }
2374 
_CVMenuMakeLine(CharViewBase * cv,int do_arc,int ellipse_to_back)2375 void _CVMenuMakeLine(CharViewBase *cv,int do_arc,int ellipse_to_back) {
2376     SplinePointList *spl, *spl1=NULL, *spl2=NULL;
2377     SplinePoint *sp, *sp1=NULL, *sp2=NULL;
2378     int changed = false;
2379     int layer;
2380 
2381     for ( spl = cv->layerheads[cv->drawmode]->splines; spl!=NULL; spl = spl->next ) {
2382 	for ( sp=spl->first; ; ) {
2383 	    if  ( sp->selected ) {
2384 		if ( sp1==NULL ) { sp1 = sp; spl1 = spl; }
2385 		else if ( sp2==NULL ) { sp2 = sp; spl2 = spl; }
2386 		else {
2387 		    sp1 = (SplinePoint *) -1;
2388 	break;
2389 		}
2390 	    }
2391 	    if ( sp->next==NULL )
2392 	break;
2393 	    sp = sp->next->to;
2394 	    if ( sp==spl->first )
2395 	break;
2396 	}
2397 	if ( sp1 == (SplinePoint *) -1 )
2398     break;
2399     }
2400     if ( sp1!=(SplinePoint *) -1 && sp2!=NULL &&
2401 	    (( sp1->prev==NULL || sp1->next==NULL ) && ( sp2->prev==NULL || sp2->next==NULL ) &&
2402 		!(sp1->next!=NULL && sp1->next->to==sp2) &&
2403 		!(sp1->prev!=NULL && sp1->prev->from==sp2) )) {
2404 	layer = CVLayer(cv);
2405 	CVPreserveState(cv);
2406 	if ( sp1->next!=NULL ) {
2407 	    sp = sp1; sp1 = sp2; sp2 = sp;
2408 	    spl = spl1; spl1 = spl2; spl2 = spl;
2409 	}
2410 	if ( spl1==spl2 ) {
2411 	    /* case of two connected points is handled below */
2412 	    /* This case joins the endpoints of an open-contour */
2413 	    if ( MakeShape(cv,spl1,spl2,sp1,sp2,cv->sc->layers[layer].order2,changed,do_arc,ellipse_to_back)) {
2414 		changed = true;
2415 		spl1->last = spl1->first;
2416 	    }
2417 	} else {
2418 	    if ( sp1->next!=NULL )
2419 		SplineSetReverse(spl1);
2420 	    if ( sp2->prev!=NULL )
2421 		SplineSetReverse(spl2);
2422 	    switch ( MakeShape(cv,spl1,spl2,sp1,sp2,cv->sc->layers[layer].order2,changed,do_arc,ellipse_to_back) ) {
2423 	      case 1:
2424 		spl1->last = spl2->last;
2425 		for ( spl=cv->layerheads[cv->drawmode]->splines;
2426 			spl!=NULL && spl->next!=spl2; spl = spl->next );
2427 		if ( spl!=NULL )
2428 		    spl->next = spl2->next;
2429 		else
2430 		    cv->layerheads[cv->drawmode]->splines = spl2->next;
2431 		chunkfree(spl2,sizeof(*spl2));
2432 		changed = true;
2433 	      break;
2434 	      case -1:
2435 		/* we reversed spl1 and spl2 to get a good match */
2436 		spl2->last = spl1->last;
2437 		SplineSetReverse(spl2);
2438 		for ( spl=cv->layerheads[cv->drawmode]->splines;
2439 			spl!=NULL && spl->next!=spl1; spl = spl->next );
2440 		if ( spl!=NULL )
2441 		    spl->next = spl1->next;
2442 		else
2443 		    cv->layerheads[cv->drawmode]->splines = spl1->next;
2444 		chunkfree(spl1,sizeof(*spl1));
2445 		changed = true;
2446 	      break;
2447 	    }
2448 	}
2449     } else for ( spl = cv->layerheads[cv->drawmode]->splines; spl!=NULL; spl = spl->next ) {
2450 	for ( sp=spl->first; ; ) {
2451 	    if ( sp->selected ) {
2452 		if ( sp->next!=NULL && sp->next->to->selected ) {
2453 		    if ( MakeShape(cv,spl,spl,sp,sp->next->to,sp->next->order2,changed,do_arc,ellipse_to_back))
2454 			changed = true;
2455 		    if ( !changed ) {
2456 			CVPreserveState(cv);
2457 			changed = true;
2458 		    }
2459 		    if (!do_arc) {
2460 			sp->nextcp = sp->me;
2461 			sp->nonextcp = true;
2462 			sp->next->to->prevcp = sp->next->to->me;
2463 			sp->next->to->noprevcp = true;
2464 		    }
2465 		    SplineRefigure(sp->next);
2466 		}
2467 	    }
2468 	    if ( sp->next==NULL )
2469 	break;
2470 	    sp = sp->next->to;
2471 	    if ( sp==spl->first )
2472 	break;
2473 	}
2474     }
2475 
2476     if ( changed )
2477 	CVCharChangedUpdate(cv);
2478 }
2479 
SCClearInstrsOrMark(SplineChar * sc,int layer,int complain)2480 void SCClearInstrsOrMark(SplineChar *sc, int layer, int complain) {
2481     uint8 *instrs = sc->ttf_instrs==NULL && sc->parent->mm!=NULL && sc->parent->mm->apple ?
2482 		sc->parent->mm->normal->glyphs[sc->orig_pos]->ttf_instrs : sc->ttf_instrs;
2483     struct splinecharlist *dep;
2484     SplineSet *ss;
2485     SplinePoint *sp;
2486     AnchorPoint *ap;
2487     int had_ap, had_dep, had_instrs;
2488 
2489     had_ap = had_dep = had_instrs = 0;
2490     if ( instrs!=NULL ) {
2491 	if ( clear_tt_instructions_when_needed ) {
2492 	    free(sc->ttf_instrs); sc->ttf_instrs = NULL;
2493 	    sc->ttf_instrs_len = 0;
2494 	    SCMarkInstrDlgAsChanged(sc);
2495 	    had_instrs = 1;
2496 	} else {
2497 	    sc->instructions_out_of_date = true;
2498 	    had_instrs = 2;
2499 	}
2500     }
2501     for ( dep=sc->dependents; dep!=NULL; dep=dep->next ) {
2502 	RefChar *ref;
2503 	if ( dep->sc->ttf_instrs_len!=0 ) {
2504 	    if ( clear_tt_instructions_when_needed ) {
2505 		free(dep->sc->ttf_instrs); dep->sc->ttf_instrs = NULL;
2506 		dep->sc->ttf_instrs_len = 0;
2507 		SCMarkInstrDlgAsChanged(dep->sc);
2508 		had_instrs = 1;
2509 	    } else {
2510 		dep->sc->instructions_out_of_date = true;
2511 		had_instrs = 2;
2512 	    }
2513 	}
2514 	for ( ref=dep->sc->layers[layer].refs; ref!=NULL && ref->sc!=sc; ref=ref->next );
2515 	for ( ; ref!=NULL ; ref=ref->next ) {
2516 	    if ( ref->point_match ) {
2517 		ref->point_match_out_of_date = true;
2518 		had_dep = true;
2519 	    }
2520 	}
2521     }
2522     SCNumberPoints(sc,layer);
2523     for ( ap=sc->anchor ; ap!=NULL; ap=ap->next ) {
2524 	if ( ap->has_ttf_pt ) {
2525 	    had_ap = true;
2526 	    ap->has_ttf_pt = false;
2527 	    for ( ss = sc->layers[layer].splines; ss!=NULL; ss=ss->next ) {
2528 		for ( sp=ss->first; ; ) {
2529 		    if ( sp->me.x==ap->me.x && sp->me.y==ap->me.y && sp->ttfindex!=0xffff ) {
2530 			ap->has_ttf_pt = true;
2531 			ap->ttf_pt_index = sp->ttfindex;
2532 	    goto found;
2533 		    } else if ( sp->nextcp.x==ap->me.x && sp->nextcp.y==ap->me.y && sp->nextcpindex!=0xffff ) {
2534 			ap->has_ttf_pt = true;
2535 			ap->ttf_pt_index = sp->nextcpindex;
2536 	    goto found;
2537 		    }
2538 		    if ( sp->next==NULL )
2539 		break;
2540 		    sp = sp->next->to;
2541 		    if ( sp==ss->first )
2542 		break;
2543 		}
2544 	    }
2545 	    found: ;
2546 	}
2547     }
2548     if ( !complain || no_windowing_ui )
2549 	/* If we're in a script it's annoying (and pointless) to get this message */;
2550     else if ( sc->complained_about_ptnums )
2551 	/* It's annoying to get the same message over and over again as you edit a glyph */;
2552     else if ( had_ap || had_dep || had_instrs ) {
2553 	ff_post_notice(_("You changed the point numbering"),
2554 		_("You have just changed the point numbering of glyph %s.%s%s%s"),
2555 			sc->name,
2556 			had_instrs==0 ? "" :
2557 			had_instrs==1 ? _(" Instructions in this glyph (or one that refers to it) have been lost.") :
2558 			                _(" Instructions in this glyph (or one that refers to it) are now out of date."),
2559 			had_dep ? _(" At least one reference to this glyph used point matching. That match is now out of date.")
2560 				: "",
2561 			had_ap ? _(" At least one anchor point used point matching. It may be out of date now.")
2562 				: "" );
2563 	sc->complained_about_ptnums = true;
2564 	if ( had_instrs==2 )
2565 	    FVRefreshAll( sc->parent );
2566     }
2567 }
2568 
PatternSCBounds(SplineChar * sc,DBounds * b)2569 void PatternSCBounds(SplineChar *sc, DBounds *b) {
2570     if ( sc==NULL )
2571 	memset(b,0,sizeof(DBounds));
2572     else if ( sc->tile_margin!=0 || (sc->tile_bounds.minx==0 && sc->tile_bounds.maxx==0) ) {
2573 	SplineCharFindBounds(sc,b);
2574 	b->minx -= sc->tile_margin; b->miny -= sc->tile_margin;
2575 	b->maxx += sc->tile_margin; b->maxy += sc->tile_margin;
2576     } else
2577 	*b = sc->tile_bounds;
2578     if ( b->minx>=b->maxx )
2579 	b->maxx = b->minx+1;
2580     if ( b->miny>=b->maxy )
2581 	b->maxy = b->miny+1;
2582 }
2583 
SCUpdateNothing(SplineChar * sc)2584 static void SCUpdateNothing(SplineChar *sc) {
2585 }
2586 
SCHintsChng(SplineChar * sc)2587 static void SCHintsChng(SplineChar *sc) {
2588     sc->changedsincelasthinted = false;
2589     if ( !sc->changed ) {
2590 	sc->changed = true;
2591 	sc->parent->changed = true;
2592     }
2593 }
2594 
instrcheck(SplineChar * sc,int layer)2595 void instrcheck(SplineChar *sc,int layer) {
2596     uint8 *instrs = sc->ttf_instrs==NULL && sc->parent->mm!=NULL && sc->parent->mm->apple ?
2597 		sc->parent->mm->normal->glyphs[sc->orig_pos]->ttf_instrs : sc->ttf_instrs;
2598 
2599     if ( !sc->layers[layer].order2 || sc->layers[layer].background )
2600 return;
2601 
2602     if ( sc->instructions_out_of_date && no_windowing_ui && sc->anchor==NULL )
2603 return;
2604     if ( instrs==NULL && sc->dependents==NULL && no_windowing_ui && sc->anchor==NULL )
2605 return;
2606     /* If the points are no longer in order then the instructions are not valid */
2607     /*  (because they'll refer to the wrong points) and should be removed */
2608     /* Except that annoys users who don't expect it */
2609     if ( !SCPointsNumberedProperly(sc,layer)) {
2610 	SCClearInstrsOrMark(sc,layer,true);
2611     }
2612 }
2613 
TTFPointMatches(SplineChar * sc,int layer,int top)2614 void TTFPointMatches(SplineChar *sc,int layer,int top) {
2615     AnchorPoint *ap;
2616     BasePoint here, there;
2617     struct splinecharlist *deps;
2618     RefChar *ref;
2619 
2620     if ( !sc->layers[layer].order2 || sc->layers[layer].background )
2621 return;
2622     for ( ap=sc->anchor ; ap!=NULL; ap=ap->next ) {
2623 	if ( ap->has_ttf_pt )
2624 	    if ( ttfFindPointInSC(sc,layer,ap->ttf_pt_index,&ap->me,NULL)!=-1 )
2625 		ap->has_ttf_pt = false;
2626     }
2627     for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
2628 	if ( ref->point_match ) {
2629 	    if ( ttfFindPointInSC(sc,layer,ref->match_pt_base,&there,ref)==-1 &&
2630 		    ttfFindPointInSC(ref->sc,layer,ref->match_pt_ref,&here,NULL)==-1 ) {
2631 		if ( ref->transform[4]!=there.x-here.x ||
2632 			ref->transform[5]!=there.y-here.y ) {
2633 		    ref->transform[4] = there.x-here.x;
2634 		    ref->transform[5] = there.y-here.y;
2635 		    SCReinstanciateRefChar(sc,ref,layer);
2636 		    if ( !top )
2637 			_SCCharChangedUpdate(sc,layer,true);
2638 		}
2639 	    } else
2640 		ref->point_match = false;		/* one of the points no longer exists */
2641 	}
2642     }
2643     for ( deps = sc->dependents; deps!=NULL; deps = deps->next )
2644 	TTFPointMatches(deps->sc,layer,false);
2645 }
2646 
_SCChngNoUpdate(SplineChar * sc,int layer,int changed)2647 static void _SCChngNoUpdate(SplineChar *sc,int layer,int changed) {
2648     SplineFont *sf = sc->parent;
2649 
2650     if ( layer>=sc->layer_cnt ) {
2651 	IError( "Bad layer in _SCChngNoUpdate");
2652 	layer = ly_fore;
2653     }
2654     if ( layer>=0 && !sc->layers[layer].background )
2655 	TTFPointMatches(sc,layer,true);
2656     if ( changed!=-1 ) {
2657 	sc->changed_since_autosave = true;
2658 	SFSetModTime(sf);
2659 	if ( (sc->changed==0) != (changed==0) ) {
2660 	    sc->changed = (changed!=0);
2661 	    if ( changed && (sc->layers[ly_fore].splines!=NULL || sc->layers[ly_fore].refs!=NULL))
2662 		sc->parent->onlybitmaps = false;
2663 	}
2664 	if ( changed && layer>=0 && !sc->layers[layer].background )
2665 	    instrcheck(sc,layer);
2666 	sc->changedsincelasthinted = true;
2667 	sc->changed_since_search = true;
2668 	sf->changed = true;
2669 	sf->changed_since_autosave = true;
2670 	sf->changed_since_xuidchanged = true;
2671 	if ( layer>=0 )
2672 	    SCTickValidationState(sc,layer);
2673     }
2674 }
2675 
SCChngNoUpdate(SplineChar * sc,int layer)2676 static void SCChngNoUpdate(SplineChar *sc,int layer) {
2677     _SCChngNoUpdate(sc,layer,true);
2678 }
2679 
SCB_MoreLayers(SplineChar * sc,Layer * old)2680 static void SCB_MoreLayers(SplineChar *sc,Layer *old) {
2681 }
2682 
2683 static struct sc_interface noui_sc = {
2684     SCUpdateNothing,
2685     SCUpdateNothing,
2686     SCUpdateNothing,
2687     SCHintsChng,
2688     SCChngNoUpdate,
2689     _SCChngNoUpdate,
2690     SCUpdateNothing,
2691     SCUpdateNothing,
2692     SCB_MoreLayers
2693 };
2694 
2695 struct sc_interface *sc_interface = &noui_sc;
2696 
FF_SetSCInterface(struct sc_interface * sci)2697 void FF_SetSCInterface(struct sc_interface *sci) {
2698     sc_interface = sci;
2699 }
2700 
CVChngNoUpdate(CharViewBase * cv)2701 static void CVChngNoUpdate(CharViewBase *cv) {
2702     _SCChngNoUpdate(cv->sc,CVLayer(cv),true);
2703 }
2704 
_CVChngNoUpdate(CharViewBase * cv,int changed)2705 static void _CVChngNoUpdate(CharViewBase *cv,int changed) {
2706     _SCChngNoUpdate(cv->sc,CVLayer(cv),changed);
2707 }
2708 
CVGlphRenameFixup(SplineFont * sf,const char * oldname,const char * newname)2709 static void CVGlphRenameFixup(SplineFont *sf, const char *oldname, const char *newname) {
2710 }
2711 
CV__LayerPaletteCheck(SplineFont * sf)2712 static void CV__LayerPaletteCheck(SplineFont *sf) {
2713 }
2714 
2715 static struct cv_interface noui_cv = {
2716     CVChngNoUpdate,
2717     _CVChngNoUpdate,
2718     CVGlphRenameFixup,
2719     CV__LayerPaletteCheck
2720 };
2721 
2722 struct cv_interface *cv_interface = &noui_cv;
2723 
FF_SetCVInterface(struct cv_interface * cvi)2724 void FF_SetCVInterface(struct cv_interface *cvi) {
2725     cv_interface = cvi;
2726 }
2727 
2728 
SCRemoveKern(SplineChar * sc)2729 void SCRemoveKern(SplineChar* sc) {
2730     if ( sc->kerns!=NULL ) {
2731 	KernPairsFree(sc->kerns);
2732 	sc->kerns = NULL;
2733 	sc->parent->changed = true;
2734 	if( sc->parent->fv->cidmaster!=NULL )
2735 	    sc->parent->fv->cidmaster->changed = true;
2736     }
2737 }
2738 
SCRemoveVKern(SplineChar * sc)2739 void SCRemoveVKern(SplineChar* sc) {
2740     if ( sc->vkerns!=NULL ) {
2741 	KernPairsFree(sc->vkerns);
2742 	sc->vkerns = NULL;
2743 	sc->parent->changed = true;
2744 	if( sc->parent->fv->cidmaster!=NULL )
2745 	    sc->parent->fv->cidmaster->changed = true;
2746     }
2747 }
2748