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,¢er,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,¢er,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