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 "autohint.h"
32 #include "autosave.h"
33 #include "baseviews.h"
34 #include "bitmapchar.h"
35 #include "bvedit.h"
36 #include "chardata.h"
37 #include "cvundoes.h"
38 #include "encoding.h"
39 #include "fontforge.h"
40 #include "fvcomposite.h"
41 #include "fvfonts.h"
42 #include "gfile.h"
43 #include "gio.h"
44 #include "gresource.h"
45 #include "groups.h"
46 #include "namelist.h"
47 #include "psfont.h"
48 #include "pua.h"
49 #include "scripting.h"
50 #include "sfd.h"
51 #include "spiro.h"
52 #include "splineoverlap.h"
53 #include "splinesaveafm.h"
54 #include "splineutil.h"
55 #include "splineutil2.h"
56 #include "ustring.h"
57 #include "utype.h"
58 
59 #include <math.h>
60 #include <unistd.h>
61 
62 static FontViewBase *fv_list=NULL;
63 
64 extern int onlycopydisplayed;
65 float joinsnap=0;
66 
SCUnselectedDependents(FontViewBase * fv,SplineChar * sc)67 static int SCUnselectedDependents(FontViewBase *fv, SplineChar *sc) {
68     struct splinecharlist *dep;
69 
70     if ( sc == NULL )
71 return( false );
72 
73     for ( dep=sc->dependents; dep!=NULL; dep=dep->next ) {
74 	if ( !fv->selected[fv->map->backmap[dep->sc->orig_pos]] )
75 return( true );
76 	if ( SCUnselectedDependents(fv,dep->sc))
77 return( true );
78     }
79 return( false );
80 }
81 
BCUnselectedDependents(FontViewBase * fv,BDFChar * bc)82 static int BCUnselectedDependents(FontViewBase *fv, BDFChar *bc) {
83     struct bdfcharlist *dep;
84 
85     if ( bc == NULL )
86 return( false );
87 
88     for ( dep=bc->dependents; dep!=NULL; dep=dep->next ) {
89 	if ( !fv->selected[fv->map->backmap[dep->bc->orig_pos]] )
90 return( true );
91 	if ( BCUnselectedDependents(fv,dep->bc))
92 return( true );
93     }
94 return( false );
95 }
96 
UnselectedDependents(FontViewBase * fv,int gid)97 static int UnselectedDependents(FontViewBase *fv,int gid) {
98     int ret = false;
99     BDFFont *bdf;
100 
101     if ( onlycopydisplayed && fv->active_bitmap == NULL ) {
102 	ret = SCUnselectedDependents( fv,fv->sf->glyphs[gid] );
103     } else if ( onlycopydisplayed ) {
104 	ret = BCUnselectedDependents( fv,fv->active_bitmap->glyphs[gid] );
105     } else {
106 	ret = SCUnselectedDependents( fv,fv->sf->glyphs[gid] );
107 	for ( bdf=fv->sf->cidmaster?fv->sf->cidmaster->bitmaps:fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
108 	    ret |= BCUnselectedDependents( fv,bdf->glyphs[gid] );
109     }
110 return( ret );
111 }
112 
FVClear(FontViewBase * fv)113 void FVClear(FontViewBase *fv) {
114     int i;
115     BDFFont *bdf;
116     int refstate = 0;
117     char *buts[6];
118     int yes, unsel, gid;
119     /* refstate==0 => ask, refstate==1 => clearall, refstate==-1 => skip all */
120 
121     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] && (gid=fv->map->map[i])!=-1 ) {
122 	/* If we are messing with the outline character, check for dependencies */
123 	if ( refstate<=0 && ( unsel = UnselectedDependents( fv,gid ))) {
124 	    if ( refstate==0 ) {
125 		buts[0] = _("_Yes");
126 		buts[1] = _("Yes to _All");
127 		buts[2] = _("_Unlink All");
128 		buts[3] = _("No _to All");
129 		buts[4] = _("_No");
130 		buts[5] = NULL;
131 		yes = ff_ask(_("Bad Reference"),(const char **) buts,2,4,_("You are attempting to clear %.30s which is referred to by\nanother character. Are you sure you want to clear it?"),fv->sf->glyphs[gid]->name);
132 		if ( yes==1 )
133 		    refstate = 1;
134 		else if ( yes==2 )
135 		    refstate = -2;
136 		else if ( yes==3 )
137 		    refstate = -1;
138 		else if ( yes==4 )
139     continue;
140 	    }
141 	    if ( refstate==-2 ) {
142 		if ( onlycopydisplayed && fv->active_bitmap == NULL )
143 		    UnlinkThisReference( fv,fv->sf->glyphs[gid],fv->active_layer );
144 		else if ( onlycopydisplayed && fv->active_bitmap != NULL )
145 		    BCUnlinkThisReference( fv,fv->active_bitmap->glyphs[gid] );
146 		else {
147 		    UnlinkThisReference(fv,fv->sf->glyphs[gid],fv->active_layer);
148 		    for ( bdf=fv->sf->cidmaster?fv->sf->cidmaster->bitmaps:fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next )
149 			BCUnlinkThisReference( fv,bdf->glyphs[gid] );
150 		}
151 	    } else if ( refstate == -1 )
152     continue;
153 	}
154 
155 	if ( onlycopydisplayed && fv->active_bitmap==NULL ) {
156 	    SCClearAll(fv->sf->glyphs[gid],fv->active_layer);
157 	} else if ( onlycopydisplayed ) {
158 	    BCClearAll(fv->active_bitmap->glyphs[gid]);
159 	} else {
160 	    SCClearAll(fv->sf->glyphs[gid],fv->active_layer);
161 	    for ( bdf=fv->sf->cidmaster?fv->sf->cidmaster->bitmaps:fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next )
162 		BCClearAll(bdf->glyphs[gid]);
163 	}
164     }
165 }
166 
FVClearBackground(FontViewBase * fv)167 void FVClearBackground(FontViewBase *fv) {
168     SplineFont *sf = fv->sf;
169     int i, gid;
170 
171     if ( onlycopydisplayed && fv->active_bitmap!=NULL )
172 return;
173 
174     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
175 	    (gid = fv->map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
176 	SCClearBackground(sf->glyphs[gid]);
177     }
178 }
179 
FVCopyFgtoBg(FontViewBase * fv)180 void FVCopyFgtoBg(FontViewBase *fv) {
181     int i, gid;
182 
183     for ( i=0; i<fv->map->enccount; ++i )
184 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
185 		fv->sf->glyphs[gid]!=NULL )
186 	    SCCopyLayerToLayer(fv->sf->glyphs[gid],fv->active_layer,ly_back,true);
187 }
188 
FVUnlinkRef(FontViewBase * fv)189 void FVUnlinkRef(FontViewBase *fv) {
190     int i,layer, first, last, gid;
191     SplineChar *sc;
192     RefChar *rf, *next;
193     BDFFont *bdf;
194     BDFChar *bdfc;
195     BDFRefChar *head, *cur;
196 
197     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
198 	    (gid = fv->map->map[i])!=-1 && (sc = fv->sf->glyphs[gid])!=NULL) {
199 	if (( fv->active_bitmap==NULL || !onlycopydisplayed ) &&
200 		sc->layers[fv->active_layer].refs!=NULL) {
201 	    SCPreserveLayer(sc,fv->active_layer,false);
202 	    if ( sc->parent->multilayer ) {
203 		first = ly_fore;
204 		last = sc->layer_cnt-1;
205 	    } else
206 		first = last = fv->active_layer;
207 	    for ( layer=first; layer<=last; ++layer ) {
208 		for ( rf=sc->layers[layer].refs; rf!=NULL ; rf=next ) {
209 		    next = rf->next;
210 		    SCRefToSplines(sc,rf,layer);
211 		}
212 	    }
213 	    SCCharChangedUpdate( sc,fv->active_layer );
214 	}
215 
216 	for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
217 	    if ( bdf != fv->active_bitmap && onlycopydisplayed )
218 	continue;
219 
220 	    bdfc = gid==-1 || gid>=bdf->glyphcnt? NULL : bdf->glyphs[gid];
221 	    if ( bdfc != NULL && bdfc->refs != NULL ) {
222 		BCMergeReferences( bdfc,bdfc,0,0 );
223 		for ( head = bdfc->refs; head != NULL; ) {
224 		    cur = head; head = cur->next; free( cur );
225 		}
226 		bdfc->refs = NULL;
227 		BCCharChangedUpdate(bdfc);
228 	    }
229 	}
230     }
231 }
232 
FVUndo(FontViewBase * fv)233 void FVUndo(FontViewBase *fv) {
234     int i,j,layer,first,last, gid;
235     MMSet *mm = fv->sf->mm;
236     int was_blended = mm!=NULL && mm->normal==fv->sf;
237     BDFFont *bdf;
238     BDFChar *bdfc;
239 
240     SFUntickAll(fv->sf);
241     for ( i=0; i<fv->map->enccount; ++i )
242 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
243 		fv->sf->glyphs[gid]!=NULL && !fv->sf->glyphs[gid]->ticked) {
244 	    if ( fv->active_bitmap==NULL || !onlycopydisplayed ) {
245 		SplineChar *sc = fv->sf->glyphs[gid];
246 		if ( sc->parent->multilayer ) {
247 		    first = ly_fore;
248 		    last = sc->layer_cnt-1;
249 		} else
250 		    first = last = fv->active_layer;
251 		for ( layer=first; layer<=last; ++layer ) {
252 		    if ( sc->layers[layer].undoes!=NULL ) {
253 			SCDoUndo(sc,layer);
254 			if ( was_blended ) {
255 			    for ( j=0; j<mm->instance_count; ++j )
256 				SCDoUndo(mm->instances[j]->glyphs[gid],layer);
257 			}
258 		    }
259 		}
260 		sc->ticked = true;
261 	    }
262 	    for ( bdf=fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
263 		if ( bdf != fv->active_bitmap && onlycopydisplayed )
264 	    continue;
265 
266 	    	bdfc = bdf->glyphs[gid];
267 	    	if ( bdfc != NULL && bdfc->undoes != NULL )
268 	    	    BCDoUndo( bdfc );
269 	    }
270 	}
271 }
272 
FVRedo(FontViewBase * fv)273 void FVRedo(FontViewBase *fv) {
274     int i,j,layer,first,last, gid;
275     MMSet *mm = fv->sf->mm;
276     int was_blended = mm!=NULL && mm->normal==fv->sf;
277     BDFFont *bdf;
278     BDFChar *bdfc;
279 
280     SFUntickAll(fv->sf);
281     for ( i=0; i<fv->map->enccount; ++i )
282 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
283 		fv->sf->glyphs[gid]!=NULL && !fv->sf->glyphs[gid]->ticked) {
284 	    if ( fv->active_bitmap==NULL || !onlycopydisplayed ) {
285 		SplineChar *sc = fv->sf->glyphs[gid];
286 		if ( sc->parent->multilayer ) {
287 		    first = ly_fore;
288 		    last = sc->layer_cnt-1;
289 		} else
290 		    first = last = fv->active_layer;
291 		for ( layer=first; layer<=last; ++layer ) {
292 		    if ( sc->layers[layer].redoes!=NULL ) {
293 			SCDoRedo(sc,layer);
294 			if ( was_blended ) {
295 			    for ( j=0; j<mm->instance_count; ++j )
296 				SCDoRedo(mm->instances[j]->glyphs[gid],layer);
297 			}
298 		    }
299 		}
300 		sc->ticked = true;
301 	    }
302 	    for ( bdf=fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
303 		if ( bdf != fv->active_bitmap && onlycopydisplayed )
304 	    continue;
305 
306 	    	bdfc = bdf->glyphs[gid];
307 	    	if ( bdfc != NULL && bdfc->redoes != NULL )
308 	    	    BCDoRedo( bdfc );
309 	    }
310 	}
311 }
312 
FVJoin(FontViewBase * fv)313 void FVJoin(FontViewBase *fv) {
314     SplineFont *sf = fv->sf;
315     int i,changed,gid;
316 
317     if ( onlycopydisplayed && fv->active_bitmap!=NULL )
318 return;
319 
320     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
321 	    (gid = fv->map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
322 	SCPreserveLayer(sf->glyphs[gid],fv->active_layer,false);
323 	sf->glyphs[gid]->layers[fv->active_layer].splines = SplineSetJoin(sf->glyphs[gid]->layers[fv->active_layer].splines,true,joinsnap,&changed);
324 	if ( changed )
325 	    SCCharChangedUpdate(sf->glyphs[gid],fv->active_layer);
326     }
327 }
328 
LinkEncToGid(FontViewBase * fv,int enc,int gid)329 static void LinkEncToGid(FontViewBase *fv,int enc, int gid) {
330     EncMap *map = fv->map;
331     int old_gid;
332     int flags = -1;
333     int j;
334 
335     if ( map->map[enc]!=-1 && map->map[enc]!=gid ) {
336 	SplineFont *sf = fv->sf;
337 	old_gid = map->map[enc];
338 	for ( j=0; j<map->enccount; ++j )
339 	    if ( j!=enc && map->map[j]==old_gid )
340 	break;
341 	/* If the glyph is used elsewhere in the encoding then reusing this */
342 	/* slot causes no problems */
343 	if ( j==map->enccount ) {
344 	    /* However if this is the only use and the glyph is interesting */
345 	    /*  then add it to the unencoded area. If it is uninteresting we*/
346 	    /*  can just get rid of it */
347 	    if ( SCWorthOutputting(sf->glyphs[old_gid]) )
348 		SFAddEncodingSlot(sf,old_gid);
349 	    else
350 		SFRemoveGlyph(sf,sf->glyphs[old_gid]);
351 	}
352     }
353     map->map[enc] = gid;
354     if ( map->backmap[gid]==-1 )
355 	map->backmap[gid] = enc;
356     if ( map->enc!=&custom ) {
357 	int uni = UniFromEnc(enc,map->enc);
358 	AltUniAdd(fv->sf->glyphs[gid],uni);
359     }
360 }
361 
FVSameGlyphAs(FontViewBase * fv)362 void FVSameGlyphAs(FontViewBase *fv) {
363     SplineFont *sf = fv->sf;
364     RefChar *base = CopyContainsRef(sf);
365     int i;
366     EncMap *map = fv->map;
367 
368     if ( base==NULL || fv->cidmaster!=NULL )
369 return;
370     for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] ) {
371 	LinkEncToGid(fv,i,base->orig_pos);
372     }
373 }
374 
FVBuildDuplicate(FontViewBase * fv)375 void FVBuildDuplicate(FontViewBase *fv) {
376     const int *pua = fv->sf->uni_interp==ui_trad_chinese ? cns14pua : fv->sf->uni_interp==ui_ams ? amspua : NULL;
377     int i, cnt=0, gid;
378     SplineChar dummy;
379     const unichar_t *pt;
380 
381     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] )
382 	++cnt;
383     ff_progress_start_indicator(10,_("Building duplicate encodings"),
384 	_("Building duplicate encodings"),NULL,cnt,1);
385 
386     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
387 	SplineChar *sc;
388 	int baseuni = 0;
389 	if ( (gid = fv->map->map[i])==-1 || (sc = fv->sf->glyphs[gid])==NULL )
390 	    sc = SCBuildDummy(&dummy,fv->sf,fv->map,i);
391 	if ( pua!=NULL && sc->unicodeenc>=0xe000 && sc->unicodeenc<=0xf8ff )
392 	    baseuni = pua[sc->unicodeenc-0xe000];
393 	if ( baseuni==0 && ( pt = SFGetAlternate(fv->sf,sc->unicodeenc,sc,false))!=NULL &&
394 		pt[0]!='\0' && pt[1]=='\0' )
395 	    baseuni = pt[0];
396 
397 	if ( baseuni!=0 && (gid = SFFindExistingSlot(fv->sf,baseuni,NULL))!=-1 )
398 	    LinkEncToGid(fv,i,gid);
399 	if ( !ff_progress_next())
400     break;
401     }
402     ff_progress_end_indicator();
403 }
404 
TransHints(StemInfo * stem,real mul1,real off1,real mul2,real off2,int round_to_int)405 void TransHints(StemInfo *stem,real mul1, real off1, real mul2, real off2, int round_to_int ) {
406     HintInstance *hi;
407 
408     for ( ; stem!=NULL; stem=stem->next ) {
409 	stem->start = stem->start*mul1 + off1;
410 	stem->width *= mul1;
411 	if ( round_to_int ) {
412 	    stem->start = rint(stem->start);
413 	    stem->width = rint(stem->width);
414 	}
415 	if ( mul1<0 ) {
416 	    stem->start += stem->width;
417 	    stem->width = -stem->width;
418 	}
419 	for ( hi=stem->where; hi!=NULL; hi=hi->next ) {
420 	    hi->begin = hi->begin*mul2 + off2;
421 	    hi->end = hi->end*mul2 + off2;
422 	    if ( round_to_int ) {
423 		hi->begin = rint(hi->begin);
424 		hi->end = rint(hi->end);
425 	    }
426 	    if ( mul2<0 ) {
427 		double temp = hi->begin;
428 		hi->begin = hi->end;
429 		hi->end = temp;
430 	    }
431 	}
432     }
433 }
434 
435 /* added by akryukov 01/01/2008 to enable resizing and flipping DStem hints */
TransDStemHints(DStemInfo * ds,real xmul,real xoff,real ymul,real yoff,int round_to_int)436 void TransDStemHints( DStemInfo *ds,real xmul,real xoff,real ymul,real yoff,int round_to_int ) {
437     HintInstance *hi;
438     double dmul, temp;
439 
440     for ( ; ds!=NULL; ds=ds->next ) {
441 	ds->left.x = xmul*ds->left.x + xoff;
442 	ds->left.y = ymul*ds->left.y + yoff;
443 	ds->right.x = xmul*ds->right.x + xoff;
444 	ds->right.y = ymul*ds->right.y + yoff;
445 	if ( round_to_int ) {
446 	    ds->left.x = rint( ds->left.x );
447             ds->left.y = rint( ds->left.y );
448 	    ds->right.x = rint( ds->right.x );
449             ds->right.y = rint( ds->right.y );
450 	}
451 
452 	if (( xmul < 0 && ymul > 0 ) || ( xmul > 0 && ymul < 0 ))
453 	    ds->unit.y = -ds->unit.y;
454         ds->unit.x *= fabs( xmul ); ds->unit.y *= fabs( ymul );
455         dmul = sqrt( pow( ds->unit.x,2 ) + pow( ds->unit.y,2 ));
456         ds->unit.x /= dmul; ds->unit.y /= dmul;
457         if ( xmul < 0 ) dmul = -dmul;
458 
459 	for ( hi=ds->where; hi!=NULL; hi=hi->next ) {
460 	    if ( dmul > 0 ) {
461 	        hi->begin = hi->begin * dmul;
462 	        hi->end = hi->end * dmul;
463             } else {
464                 temp = hi->begin;
465 	        hi->begin = hi->end * dmul;
466 	        hi->end = temp * dmul;
467             }
468 	}
469     }
470 }
471 
VrTrans(struct vr * vr,real transform[6])472 void VrTrans(struct vr *vr,real transform[6]) {
473     /* I'm interested in scaling and skewing. I think translation should */
474     /*  not affect these guys (they are offsets, so offsets should be */
475     /*  unchanged by translation */
476     double x,y;
477 
478     x = vr->xoff; y=vr->yoff;
479     vr->xoff = rint(transform[0]*x + transform[1]*y);
480     vr->yoff = rint(transform[2]*x + transform[3]*y);
481     x = vr->h_adv_off; y=vr->v_adv_off;
482     vr->h_adv_off = rint(transform[0]*x + transform[1]*y);
483     vr->v_adv_off = rint(transform[2]*x + transform[3]*y);
484 }
485 
BackgroundImageTransform(SplineChar * sc,ImageList * img,real transform[6])486 void BackgroundImageTransform(SplineChar *sc, ImageList *img,real transform[6]) {
487     if ( transform[1]==0 && transform[2]==0 && transform[0]>0 && transform[3]>0 ) {
488 	img->xoff = transform[0]*img->xoff + transform[4];
489 	img->yoff = transform[3]*img->yoff + transform[5];
490 	if (( img->xscale *= transform[0])<0 ) img->xscale = -img->xscale;
491 	if (( img->yscale *= transform[3])<0 ) img->yscale = -img->yscale;
492 	img->bb.minx = img->xoff; img->bb.maxy = img->yoff;
493 	img->bb.maxx = img->xoff + GImageGetWidth(img->image)*img->xscale;
494 	img->bb.miny = img->yoff - GImageGetHeight(img->image)*img->yscale;
495     } else {
496 	/* Don't support rotating, flipping or skewing images */
497 	;
498     }
499     SCOutOfDateBackground(sc);
500 }
501 
GV_Trans(struct glyphvariants * gv,real transform[6],int is_v)502 static void GV_Trans(struct glyphvariants *gv,real transform[6], int is_v) {
503     int i;
504 
505     if ( gv==NULL )
506 return;
507     gv->italic_correction = rint(gv->italic_correction*transform[0]);
508     is_v = 3*is_v;
509     for ( i=0; i<gv->part_cnt; ++i ) {
510 	gv->parts[i].startConnectorLength = rint( gv->parts[i].startConnectorLength*transform[is_v] );
511 	gv->parts[i].endConnectorLength = rint( gv->parts[i].endConnectorLength*transform[is_v] );
512 	gv->parts[i].fullAdvance = rint( gv->parts[i].fullAdvance*transform[is_v] );
513     }
514 }
515 
MKV_Trans(struct mathkernvertex * mkv,real transform[6])516 static void MKV_Trans(struct mathkernvertex *mkv,real transform[6]) {
517     int i;
518 
519     for ( i=0; i<mkv->cnt; ++i ) {
520 	mkv->mkd[i].kern  = rint( mkv->mkd[i].kern  *transform[0]);
521 	mkv->mkd[i].height= rint( mkv->mkd[i].height*transform[0]);
522     }
523 }
524 
MK_Trans(struct mathkern * mk,real transform[6])525 static void MK_Trans(struct mathkern *mk,real transform[6]) {
526     if ( mk==NULL )
527 return;
528     MKV_Trans(&mk->top_right,transform);
529     MKV_Trans(&mk->top_left ,transform);
530     MKV_Trans(&mk->bottom_right,transform);
531     MKV_Trans(&mk->bottom_left ,transform);
532 }
533 
MATH_Trans(struct MATH * math,real transform[6])534 static void MATH_Trans(struct MATH *math,real transform[6]) {
535     if ( math==NULL )
536 return;
537     math->DelimitedSubFormulaMinHeight = rint( math->DelimitedSubFormulaMinHeight*transform[3]);
538     math->DisplayOperatorMinHeight = rint( math->DisplayOperatorMinHeight*transform[3]);
539     math->MathLeading = rint( math->MathLeading*transform[3]);
540     math->AxisHeight = rint( math->AxisHeight*transform[3]);
541     math->AccentBaseHeight = rint( math->AccentBaseHeight*transform[3]);
542     math->FlattenedAccentBaseHeight = rint( math->FlattenedAccentBaseHeight*transform[3]);
543     math->SubscriptShiftDown = rint( math->SubscriptShiftDown*transform[3]);
544     math->SubscriptTopMax = rint( math->SubscriptTopMax*transform[3]);
545     math->SubscriptBaselineDropMin = rint( math->SubscriptBaselineDropMin*transform[3]);
546     math->SuperscriptShiftUp = rint( math->SuperscriptShiftUp*transform[3]);
547     math->SuperscriptShiftUpCramped = rint( math->SuperscriptShiftUpCramped*transform[3]);
548     math->SuperscriptBottomMin = rint( math->SuperscriptBottomMin*transform[3]);
549     math->SuperscriptBaselineDropMax = rint( math->SuperscriptBaselineDropMax*transform[3]);
550     math->SubSuperscriptGapMin = rint( math->SubSuperscriptGapMin*transform[3]);
551     math->SuperscriptBottomMaxWithSubscript = rint( math->SuperscriptBottomMaxWithSubscript*transform[3]);
552     /* SpaceAfterScript is horizontal and is below */
553     math->UpperLimitGapMin = rint( math->UpperLimitGapMin*transform[3]);
554     math->UpperLimitBaselineRiseMin = rint( math->UpperLimitBaselineRiseMin*transform[3]);
555     math->LowerLimitGapMin = rint( math->LowerLimitGapMin*transform[3]);
556     math->LowerLimitBaselineDropMin = rint( math->LowerLimitBaselineDropMin*transform[3]);
557     math->StackTopShiftUp = rint( math->StackTopShiftUp*transform[3]);
558     math->StackTopDisplayStyleShiftUp = rint( math->StackTopDisplayStyleShiftUp*transform[3]);
559     math->StackBottomShiftDown = rint( math->StackBottomShiftDown*transform[3]);
560     math->StackBottomDisplayStyleShiftDown = rint( math->StackBottomDisplayStyleShiftDown*transform[3]);
561     math->StackGapMin = rint( math->StackGapMin*transform[3]);
562     math->StackDisplayStyleGapMin = rint( math->StackDisplayStyleGapMin*transform[3]);
563     math->StretchStackTopShiftUp = rint( math->StretchStackTopShiftUp*transform[3]);
564     math->StretchStackBottomShiftDown = rint( math->StretchStackBottomShiftDown*transform[3]);
565     math->StretchStackGapAboveMin = rint( math->StretchStackGapAboveMin*transform[3]);
566     math->StretchStackGapBelowMin = rint( math->StretchStackGapBelowMin*transform[3]);
567     math->FractionNumeratorShiftUp = rint( math->FractionNumeratorShiftUp*transform[3]);
568     math->FractionNumeratorDisplayStyleShiftUp = rint( math->FractionNumeratorDisplayStyleShiftUp*transform[3]);
569     math->FractionDenominatorShiftDown = rint( math->FractionDenominatorShiftDown*transform[3]);
570     math->FractionDenominatorDisplayStyleShiftDown = rint( math->FractionDenominatorDisplayStyleShiftDown*transform[3]);
571     math->FractionNumeratorGapMin = rint( math->FractionNumeratorGapMin*transform[3]);
572     math->FractionNumeratorDisplayStyleGapMin = rint( math->FractionNumeratorDisplayStyleGapMin*transform[3]);
573     math->FractionRuleThickness = rint( math->FractionRuleThickness*transform[3]);
574     math->FractionDenominatorGapMin = rint( math->FractionDenominatorGapMin*transform[3]);
575     math->FractionDenominatorDisplayStyleGapMin = rint( math->FractionDenominatorDisplayStyleGapMin*transform[3]);
576     /* SkewedFractionHorizontalGap is horizontal and is below */
577     math->SkewedFractionVerticalGap = rint( math->SkewedFractionVerticalGap*transform[3]);
578     math->OverbarVerticalGap = rint( math->OverbarVerticalGap*transform[3]);
579     math->OverbarRuleThickness = rint( math->OverbarRuleThickness*transform[3]);
580     math->OverbarExtraAscender = rint( math->OverbarExtraAscender*transform[3]);
581     math->UnderbarVerticalGap = rint( math->UnderbarVerticalGap*transform[3]);
582     math->UnderbarRuleThickness = rint( math->UnderbarRuleThickness*transform[3]);
583     math->UnderbarExtraDescender = rint( math->UnderbarExtraDescender*transform[3]);
584     math->RadicalVerticalGap = rint( math->RadicalVerticalGap*transform[3]);
585     math->RadicalDisplayStyleVerticalGap = rint( math->RadicalDisplayStyleVerticalGap*transform[3]);
586     math->RadicalRuleThickness = rint( math->RadicalRuleThickness*transform[3]);
587     math->RadicalExtraAscender = rint( math->RadicalExtraAscender*transform[3]);
588     math->RadicalDegreeBottomRaisePercent = rint( math->RadicalDegreeBottomRaisePercent*transform[3]);
589 
590     /* Horizontals */
591     math->SpaceAfterScript = rint( math->SpaceAfterScript*transform[0]);
592     math->SkewedFractionHorizontalGap = rint( math->SkewedFractionHorizontalGap*transform[0]);
593     math->RadicalKernBeforeDegree = rint( math->RadicalKernBeforeDegree*transform[0]);
594     math->RadicalKernAfterDegree = rint( math->RadicalKernAfterDegree*transform[0]);
595 
596     /* This number is the same for both horizontal and vertical connections */
597     /*  Use the vertical amount as a) will probably be the same and */
598     /*   b) most are vertical anyway */
599     math->RadicalKernAfterDegree = rint( math->RadicalKernAfterDegree*transform[0]);
600 }
601 
KCTrans(KernClass * kc,double scale)602 static void KCTrans(KernClass *kc,double scale) {
603     /* Again these are offsets, so I don't apply translation */
604     int i;
605 
606     for ( i=kc->first_cnt*kc->second_cnt-1; i>=0; --i )
607 	kc->offsets[i] = rint(scale*kc->offsets[i]);
608 }
609 
SCTransLayer(FontViewBase * fv,SplineChar * sc,int flags,int i,real transform[6],uint8 * sel)610 static void SCTransLayer(FontViewBase *fv, SplineChar *sc, int flags, int i, real transform[6], uint8 *sel) {
611     int j;
612     RefChar *refs;
613     real t[6];
614     ImageList *img;
615 
616     SplinePointListTransform(sc->layers[i].splines,transform,tpt_AllPoints);
617     for ( refs = sc->layers[i].refs; refs!=NULL; refs=refs->next ) {
618 	if ( (sel!=NULL && sel[fv->map->backmap[refs->sc->orig_pos]]) ||
619 		(flags&fvt_partialreftrans)) {
620 	    /* if the character referred to is selected then it's going to */
621 	    /*  be scaled too (or will have been) so we don't want to scale */
622 	    /*  it twice */
623 	    t[4] = refs->transform[4]*transform[0] +
624 			refs->transform[5]*transform[2] +
625 			/*transform[4]*/0;
626 	    t[5] = refs->transform[4]*transform[1] +
627 			refs->transform[5]*transform[3] +
628 			/*transform[5]*/0;
629 	    t[0] = refs->transform[4]; t[1] = refs->transform[5];
630 	    refs->transform[4] = t[4];
631 	    refs->transform[5] = t[5];
632 	    /* Now update the splines to match */
633 	    t[4] -= t[0]; t[5] -= t[1];
634 	    if ( t[4]!=0 || t[5]!=0 ) {
635 		t[0] = t[3] = 1; t[1] = t[2] = 0;
636 		for ( j=0; j<refs->layer_cnt; ++j )
637 		    SplinePointListTransform(refs->layers[j].splines,t,tpt_AllPoints);
638 	    }
639 	} else {
640 	    for ( j=0; j<refs->layer_cnt; ++j )
641 		SplinePointListTransform(refs->layers[j].splines,transform,tpt_AllPoints);
642 	    t[0] = refs->transform[0]*transform[0] +
643 			refs->transform[1]*transform[2];
644 	    t[1] = refs->transform[0]*transform[1] +
645 			refs->transform[1]*transform[3];
646 	    t[2] = refs->transform[2]*transform[0] +
647 			refs->transform[3]*transform[2];
648 	    t[3] = refs->transform[2]*transform[1] +
649 			refs->transform[3]*transform[3];
650 	    t[4] = refs->transform[4]*transform[0] +
651 			refs->transform[5]*transform[2] +
652 			transform[4];
653 	    t[5] = refs->transform[4]*transform[1] +
654 			refs->transform[5]*transform[3] +
655 			transform[5];
656 	    memcpy(refs->transform,t,sizeof(t));
657 	}
658 	RefCharFindBounds(refs);
659     }
660     for ( img = sc->layers[i].images; img!=NULL; img=img->next )
661 	BackgroundImageTransform(sc, img, transform);
662 }
663 
664 /* If sel is specified then we decide how to transform references based on */
665 /*  whether the refered glyph is selected. (If we tranform a reference that */
666 /*  is selected we are, in effect, transforming it twice -- since the glyph */
667 /*  itself will be transformed -- so instead we just transform the offsets */
668 /*  of the reference */
669 /* If sel is NULL then we transform the reference */
670 /* if flags&fvt_partialreftrans then we always just transform the offsets */
FVTrans(FontViewBase * fv,SplineChar * sc,real transform[6],uint8 * sel,enum fvtrans_flags flags)671 void FVTrans(FontViewBase *fv,SplineChar *sc,real transform[6], uint8 *sel,
672 	enum fvtrans_flags flags) {
673     AnchorPoint *ap;
674     int i,first,last;
675     KernPair *kp;
676     PST *pst;
677 
678     if ( sc->blended ) {
679 	int j;
680 	MMSet *mm = sc->parent->mm;
681 	for ( j=0; j<mm->instance_count; ++j )
682 	    FVTrans(fv,mm->instances[j]->glyphs[sc->orig_pos],transform,sel,flags);
683     }
684 
685     if (!(flags & fvt_nopreserve)) {
686 	if ( flags&fvt_alllayers ) {
687 	    for ( i=0; i<sc->layer_cnt; ++i )
688 		SCPreserveLayer(sc,i,fv->active_layer==i);
689 	} else if ( fv->sf->multilayer )
690 	    SCPreserveState(sc,true);
691 	else
692 	    SCPreserveLayer(sc,fv->active_layer,true);
693     }
694     if ( !(flags&fvt_dontmovewidth) )
695 	if ( transform[0]>0 && transform[3]>0 && transform[1]==0 && transform[2]==0 ) {
696 	    int widthset = sc->widthset;
697 	    SCSynchronizeWidth(sc,sc->width*transform[0]+transform[4],sc->width,fv);
698 	    if ( !(flags&fvt_dontsetwidth) ) sc->widthset = widthset;
699 	    sc->vwidth = sc->vwidth*transform[3]+transform[5];
700 	}
701     if ( flags & fvt_scalepstpos ) {
702 	for ( kp=sc->kerns; kp!=NULL; kp=kp->next )
703 	    kp->off = rint(kp->off*transform[0]);
704 	for ( kp=sc->vkerns; kp!=NULL; kp=kp->next )
705 	    kp->off = rint(kp->off*transform[3]);
706 	for ( pst = sc->possub; pst!=NULL; pst=pst->next ) {
707 	    if ( pst->type == pst_position )
708 		VrTrans(&pst->u.pos,transform);
709 	    else if ( pst->type==pst_pair ) {
710 		VrTrans(&pst->u.pair.vr[0],transform);
711 		VrTrans(&pst->u.pair.vr[1],transform);
712 	    } else if ( pst->type == pst_lcaret ) {
713 		int j;
714 		for ( j=0; j<pst->u.lcaret.cnt; ++j )
715 		    pst->u.lcaret.carets[j] = rint(pst->u.lcaret.carets[j]*transform[0]+transform[4]);
716 	    }
717 	}
718     }
719 
720     if ( sc->tex_height!=TEX_UNDEF )
721 	sc->tex_height = rint(sc->tex_height*transform[3]);
722     if ( sc->tex_depth !=TEX_UNDEF )
723 	sc->tex_depth  = rint(sc->tex_depth *transform[3]);
724     if ( sc->italic_correction!=TEX_UNDEF )
725 	sc->italic_correction = rint(sc->italic_correction *transform[0]);
726     if ( sc->top_accent_horiz !=TEX_UNDEF )
727 	sc->top_accent_horiz  = rint(sc->top_accent_horiz *transform[0]);
728     GV_Trans(sc->vert_variants ,transform, true);
729     GV_Trans(sc->horiz_variants,transform, false);
730     MK_Trans(sc->mathkern,transform);
731 
732     for ( ap=sc->anchor; ap!=NULL; ap=ap->next )
733 	ApTransform(ap,transform);
734     if ( flags&fvt_alllayers ) {
735 	first = 0;
736 	last = sc->layer_cnt-1;
737     } else if ( sc->parent->multilayer ) {
738 	first = ly_fore;
739 	last = sc->layer_cnt-1;
740     } else
741 	first = last = fv->active_layer;
742     for ( i=first; i<=last; ++i )
743 	SCTransLayer(fv,sc,flags,i,transform,sel);
744     if ( transform[1]==0 && transform[2]==0 ) {
745 	if ( transform[0]==1 && transform[3]==1 &&
746 		transform[5]==0 && transform[4]!=0 &&
747 		sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 &&
748 		isalpha(sc->unicodeenc)) {
749 	    SCUndoSetLBearingChange(sc,(int) rint(transform[4]));
750 	    SCSynchronizeLBearing(sc,transform[4],fv->active_layer);	/* this moves the hints */
751 	} else {
752 	    TransHints(sc->hstem,transform[3],transform[5],transform[0],transform[4],flags&fvt_round_to_int);
753 	    TransHints(sc->vstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
754 	    TransDStemHints(sc->dstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
755 	}
756     }
757     /*if ( flags&fvt_round_to_int )*/
758     if ( (flags&fvt_round_to_int) && (!sc->inspiro || !hasspiro())) {
759     	/* Rounding the spiros might be a bad idea. */
760 	/* Not rounding the spiros is also a bad idea. */
761 	/* Not sure which is worse */
762 	/* Barry thinks rounding them is a bad idea. */
763 	SCRound2Int(sc,fv->active_layer,1.0);
764     }
765     if ( !(flags&fvt_noupdate) )
766 	SCCharChangedUpdate(sc,fv->active_layer);
767 }
768 
FVTransFunc(void * _fv,real transform[6],int otype,BVTFunc * bvts,enum fvtrans_flags flags)769 void FVTransFunc(void *_fv,real transform[6],int otype, BVTFunc *bvts,
770 	enum fvtrans_flags flags ) {
771     FontViewBase *fv = _fv;
772     real transx = transform[4], transy=transform[5];
773     DBounds bb;
774     BasePoint base;
775     int i, cnt=0, gid;
776     BDFFont *bdf;
777 
778     for ( i=0; i<fv->map->enccount; ++i )
779 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
780 		SCWorthOutputting(fv->sf->glyphs[gid]) )
781 	    ++cnt;
782 
783 
784     ff_progress_start_indicator(10,_("Transforming..."),_("Transforming..."),0,cnt,1);
785 
786     SFUntickAll(fv->sf);
787     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
788 	    (gid = fv->map->map[i])!=-1 &&
789 	    SCWorthOutputting(fv->sf->glyphs[gid]) &&
790 	    !fv->sf->glyphs[gid]->ticked ) {
791 	SplineChar *sc = fv->sf->glyphs[gid];
792 
793 	if ( onlycopydisplayed && fv->active_bitmap!=NULL ) {
794 	    if ( fv->active_bitmap->glyphs[gid]!=NULL )
795 		BCTrans(fv->active_bitmap,fv->active_bitmap->glyphs[gid],bvts,fv);
796 	} else {
797 	    if ( otype==1 ) {
798 		SplineCharFindBounds(sc,&bb);
799 		base.x = (bb.minx+bb.maxx)/2;
800 		base.y = (bb.miny+bb.maxy)/2;
801 		transform[4]=transx+base.x-
802 		    (transform[0]*base.x+transform[2]*base.y);
803 		transform[5]=transy+base.y-
804 		    (transform[1]*base.x+transform[3]*base.y);
805 	    }
806 	    FVTrans(fv,sc,transform,fv->selected,flags);
807 	    if ( !onlycopydisplayed ) {
808 		for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
809 		    if ( gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL )
810 			BCTrans(bdf,bdf->glyphs[gid],bvts,fv);
811 	    }
812 	}
813 	sc->ticked = true;
814 	if ( !ff_progress_next())
815     break;
816     }
817     if ( flags&fvt_dogrid ) {
818 	SFPreserveGuide(fv->sf);
819 	SplinePointListTransform(fv->sf->grid.splines,transform,tpt_AllPoints);
820     }
821     ff_progress_end_indicator();
822 
823     if ( flags&fvt_scalekernclasses ) {
824 	KernClass *kc;
825 	SplineFont *sf = fv->cidmaster!=NULL ? fv->cidmaster : fv->sf;
826 	for ( kc=sf->kerns; kc!=NULL; kc=kc->next )
827 	    KCTrans(kc,transform[0]);
828 	for ( kc=sf->vkerns; kc!=NULL; kc=kc->next )
829 	    KCTrans(kc,transform[3]);
830 	if ( sf->MATH!=NULL )
831 	    MATH_Trans(sf->MATH,transform);
832     }
833 }
834 
FVReencode(FontViewBase * fv,Encoding * enc)835 void FVReencode(FontViewBase *fv,Encoding *enc) {
836     EncMap *map;
837 
838     if ( enc==&custom )
839 	fv->map->enc = &custom;
840     else {
841 	map = EncMapFromEncoding(fv->sf,enc);
842 	fv->selected = realloc(fv->selected,map->enccount);
843 	memset(fv->selected,0,map->enccount);
844 	EncMapFree(fv->map);
845 	if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = map; }
846 	fv->map = map;
847     }
848     if ( fv->normal!=NULL ) {
849 	EncMapFree(fv->normal);
850 	if (fv->sf != NULL && fv->normal == fv->sf->map) { fv->sf->map = NULL; }
851 	fv->normal = NULL;
852     }
853     SFReplaceEncodingBDFProps(fv->sf,fv->map);
854     FVSetTitle(fv);
855     FontViewReformatOne(fv);
856 }
857 
FVOverlap(FontViewBase * fv,enum overlap_type ot)858 void FVOverlap(FontViewBase *fv,enum overlap_type ot) {
859     int i, cnt=0, layer, first, last, gid;
860     SplineChar *sc;
861 
862     /* We know it's more likely that we'll find a problem in the overlap code */
863     /*  than anywhere else, so let's save the current state against a crash */
864     DoAutoSaves();
865 
866     for ( i=0; i<fv->map->enccount; ++i )
867 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
868 		SCWorthOutputting(fv->sf->glyphs[gid]) )
869 	    ++cnt;
870 
871     ff_progress_start_indicator(10,_("Removing overlaps..."),_("Removing overlaps..."),0,cnt,1);
872 
873     SFUntickAll(fv->sf);
874     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
875 	    (gid = fv->map->map[i])!=-1 &&
876 	    SCWorthOutputting((sc=fv->sf->glyphs[gid])) &&
877 	    !sc->ticked ) {
878 	sc->ticked = true;
879 #if 0
880 	// We await testing on the necessity of this operation.
881 	if ( !SCRoundToCluster(sc,ly_all,false,.03,.12))
882 	    SCPreserveLayer(sc,fv->active_layer,false);
883 #else
884 	    SCPreserveLayer(sc,fv->active_layer,false);
885 #endif // 0
886 	MinimumDistancesFree(sc->md);
887 	if ( sc->parent->multilayer ) {
888 	    first = ly_fore;
889 	    last = sc->layer_cnt-1;
890 	} else
891 	    first = last = fv->active_layer;
892 	for ( layer = first; layer<=last; ++layer )
893 	    sc->layers[layer].splines = SplineSetRemoveOverlap(sc,sc->layers[layer].splines,ot);
894 	SCCharChangedUpdate(sc,fv->active_layer);
895 	if ( !ff_progress_next())
896     break;
897     }
898     ff_progress_end_indicator();
899 }
900 
FVAddExtrema(FontViewBase * fv,int force_adding)901 void FVAddExtrema(FontViewBase *fv, int force_adding ) {
902     int i, cnt=0, layer, first, last, gid;
903     SplineChar *sc;
904     SplineFont *sf = fv->sf;
905     int emsize = sf->ascent+sf->descent;
906 
907     for ( i=0; i<fv->map->enccount; ++i )
908 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
909 		SCWorthOutputting(fv->sf->glyphs[gid]) )
910 	    ++cnt;
911     ff_progress_start_indicator(10,_("Adding points at Extrema..."),_("Adding points at Extrema..."),0,cnt,1);
912 
913     SFUntickAll(fv->sf);
914     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
915 	    (gid = fv->map->map[i])!=-1 &&
916 	    SCWorthOutputting((sc = fv->sf->glyphs[gid])) &&
917 	    !sc->ticked) {
918 	sc->ticked = true;
919 	if ( sc->parent->multilayer ) {
920 	    first = ly_fore;
921 	    last = sc->layer_cnt-1;
922 	} else
923 	    first = last = fv->active_layer;
924 	for ( layer = first; layer<=last; ++layer ) {
925 	    SCPreserveLayer(sc,layer,false);
926 	    SplineCharAddExtrema(sc, sc->layers[layer].splines,
927 		force_adding? ae_all : ae_only_good, emsize);
928 	}
929 	SCCharChangedUpdate(sc,fv->active_layer);
930 	if ( !ff_progress_next())
931     break;
932     }
933     ff_progress_end_indicator();
934 }
935 
FVCanonicalStart(FontViewBase * fv)936 void FVCanonicalStart(FontViewBase *fv) {
937     int i, gid;
938 
939     for ( i=0; i<fv->map->enccount; ++i )
940 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 )
941 	    SPLsStartToLeftmost(fv->sf->glyphs[gid],fv->active_layer);
942 }
943 
FVCanonicalContours(FontViewBase * fv)944 void FVCanonicalContours(FontViewBase *fv) {
945     int i, gid;
946 
947     for ( i=0; i<fv->map->enccount; ++i )
948 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 )
949 	    CanonicalContours(fv->sf->glyphs[gid],fv->active_layer);
950 }
951 
FVRound2Int(FontViewBase * fv,real factor)952 void FVRound2Int(FontViewBase *fv,real factor) {
953     int i, cnt=0, gid;
954 
955     for ( i=0; i<fv->map->enccount; ++i )
956 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
957 		SCWorthOutputting(fv->sf->glyphs[gid]) )
958 	    ++cnt;
959     ff_progress_start_indicator(10,_("Rounding to integer..."),_("Rounding to integer..."),0,cnt,1);
960 
961     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
962 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
963 	SplineChar *sc = fv->sf->glyphs[gid];
964 
965 	SCPreserveLayer(sc,fv->active_layer,false);
966 	SCRound2Int( sc,fv->active_layer,factor);
967 	if ( !ff_progress_next())
968     break;
969     }
970     ff_progress_end_indicator();
971 }
972 
FVCluster(FontViewBase * fv)973 void FVCluster(FontViewBase *fv) {
974     int i, cnt=0, gid;
975 
976     for ( i=0; i<fv->map->enccount; ++i )
977 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
978 		SCWorthOutputting(fv->sf->glyphs[gid]) )
979 	    ++cnt;
980     ff_progress_start_indicator(10,_("Rounding to integer..."),_("Rounding to integer..."),0,cnt,1);
981 
982     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
983 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
984 	SCRoundToCluster(fv->sf->glyphs[gid],ly_all,false,.1,.5);
985 	if ( !ff_progress_next())
986     break;
987     }
988     ff_progress_end_indicator();
989 }
990 
FVCorrectDir(FontViewBase * fv)991 void FVCorrectDir(FontViewBase *fv) {
992     int i, cnt=0, changed, refchanged, preserved, layer, first, last, gid;
993     int askedall=-1, asked;
994     RefChar *ref, *next;
995     SplineChar *sc;
996 
997     for ( i=0; i<fv->map->enccount; ++i )
998 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
999 		SCWorthOutputting(fv->sf->glyphs[gid]) )
1000 	    ++cnt;
1001     ff_progress_start_indicator(10,_("Correcting Direction..."),_("Correcting Direction..."),0,cnt,1);
1002 
1003     SFUntickAll(fv->sf);
1004     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1005 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting((sc=fv->sf->glyphs[gid])) &&
1006 	    !sc->ticked ) {
1007 	sc->ticked = true;
1008 	changed = refchanged = preserved = false;
1009 	asked = askedall;
1010 	if ( sc->parent->multilayer ) {
1011 	    first = ly_fore;
1012 	    last = sc->layer_cnt-1;
1013 	} else
1014 	    first = last = fv->active_layer;
1015 	for ( layer = first; layer<=last; ++layer ) {
1016 	    for ( ref=sc->layers[layer].refs; ref!=NULL; ref=next ) {
1017 		next = ref->next;
1018 		if ( ref->transform[0]*ref->transform[3]<0 ||
1019 			(ref->transform[0]==0 && ref->transform[1]*ref->transform[2]>0)) {
1020 		    if ( asked==-1 ) {
1021 			char *buts[5];
1022 			buts[0] = _("Unlink All");
1023 			buts[1] = _("Unlink");
1024 			buts[2] = _("_Cancel");
1025 			buts[3] = NULL;
1026 			asked = ff_ask(_("Flipped Reference"),(const char **) buts,0,2,_("%.50s contains a flipped reference. This cannot be corrected as is. Would you like me to unlink it and then correct it?"), sc->name );
1027 			if ( asked==3 )
1028 return;
1029 			else if ( asked==2 )
1030 	    break;
1031 			else if ( asked==0 )
1032 			    askedall = 0;
1033 		    }
1034 		    if ( asked==0 || asked==1 ) {
1035 			if ( !preserved ) {
1036 			    preserved = refchanged = true;
1037 			    SCPreserveLayer(sc,layer,false);
1038 			}
1039 			SCRefToSplines(sc,ref,layer);
1040 		    }
1041 		}
1042 	    }
1043 
1044 	    if ( !preserved && sc->layers[layer].splines!=NULL ) {
1045 		SCPreserveLayer(sc,layer,false);
1046 		preserved = true;
1047 	    }
1048 	    sc->layers[layer].splines = SplineSetsCorrect(sc->layers[layer].splines,&changed);
1049 	}
1050 	if ( changed || refchanged )
1051 	    SCCharChangedUpdate(sc,fv->active_layer);
1052 	if ( !ff_progress_next())
1053     break;
1054     }
1055     ff_progress_end_indicator();
1056 }
1057 
_FVSimplify(FontViewBase * fv,struct simplifyinfo * smpl)1058 void _FVSimplify(FontViewBase *fv,struct simplifyinfo *smpl) {
1059     int i, cnt=0, layer, first, last, gid;
1060     SplineChar *sc;
1061 
1062     for ( i=0; i<fv->map->enccount; ++i )
1063 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1064 		SCWorthOutputting(fv->sf->glyphs[gid]) )
1065 	    ++cnt;
1066     ff_progress_start_indicator(10,_("Simplifying..."),_("Simplifying..."),0,cnt,1);
1067 
1068     SFUntickAll(fv->sf);
1069     for ( i=0; i<fv->map->enccount; ++i )
1070 	if ( (gid=fv->map->map[i])!=-1 && SCWorthOutputting((sc=fv->sf->glyphs[gid])) &&
1071 		fv->selected[i] && !sc->ticked ) {
1072 	    sc->ticked = true;
1073 	    SCPreserveLayer(sc,fv->active_layer,false);
1074 	    if ( sc->parent->multilayer ) {
1075 		first = ly_fore;
1076 		last = sc->layer_cnt-1;
1077 	    } else
1078 		first = last = fv->active_layer;
1079 	    for ( layer = first; layer<=last; ++layer )
1080 		sc->layers[layer].splines = SplineCharSimplify(sc,sc->layers[layer].splines,smpl);
1081 	    SCCharChangedUpdate(sc,fv->active_layer);
1082 	    if ( !ff_progress_next())
1083     break;
1084 	}
1085     ff_progress_end_indicator();
1086 }
1087 
FVAutoHint(FontViewBase * fv)1088 void FVAutoHint(FontViewBase *fv) {
1089     int i, cnt=0, gid;
1090     BlueData *bd = NULL, _bd;
1091     SplineChar *sc;
1092 
1093     if ( fv->sf->mm==NULL ) {
1094 	QuickBlues(fv->sf,fv->active_layer,&_bd);
1095 	bd = &_bd;
1096     }
1097 
1098     /* Tick the ones we don't want to AH, untick the ones that need AH */
1099     for ( gid = 0; gid<fv->sf->glyphcnt; ++gid ) if ( (sc = fv->sf->glyphs[gid])!=NULL )
1100 	sc->ticked = true;
1101 
1102     for ( i=0; i<fv->map->enccount; ++i )
1103 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1104 		SCWorthOutputting(sc = fv->sf->glyphs[gid]) ) {
1105 	    ++cnt;
1106 	    sc->ticked = false;
1107 	}
1108     ff_progress_start_indicator(10,_("Auto Hinting Font..."),_("Auto Hinting Font..."),0,cnt,1);
1109 
1110     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1111 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1112 	sc = fv->sf->glyphs[gid];
1113 	sc->manualhints = false;
1114 	/* Hint undoes are done in _SplineCharAutoHint */
1115 	SFSCAutoHint(sc,fv->active_layer,bd);
1116 	if ( !ff_progress_next())
1117     break;
1118     }
1119     ff_progress_end_indicator();
1120     FVRefreshAll(fv->sf);
1121 }
1122 
FVAutoHintSubs(FontViewBase * fv)1123 void FVAutoHintSubs(FontViewBase *fv) {
1124     int i, cnt=0, gid;
1125 
1126     if ( fv->sf->mm!=NULL && fv->sf->mm->apple )
1127 return;
1128     for ( i=0; i<fv->map->enccount; ++i )
1129 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1130 		SCWorthOutputting(fv->sf->glyphs[gid]) )
1131 	    ++cnt;
1132     ff_progress_start_indicator(10,_("Finding Substitution Points..."),_("Finding Substitution Points..."),0,cnt,1);
1133 
1134     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1135 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1136 	SplineChar *sc = fv->sf->glyphs[gid];
1137 	SCFigureHintMasks(sc,fv->active_layer);
1138 	SCUpdateAll(sc);
1139 	if ( !ff_progress_next())
1140     break;
1141     }
1142     ff_progress_end_indicator();
1143 }
1144 
FVAutoCounter(FontViewBase * fv)1145 void FVAutoCounter(FontViewBase *fv) {
1146     int i, cnt=0, gid;
1147 
1148     for ( i=0; i<fv->map->enccount; ++i )
1149 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1150 		SCWorthOutputting(fv->sf->glyphs[gid]) )
1151 	    ++cnt;
1152     ff_progress_start_indicator(10,_("Finding Counter Masks..."),_("Finding Counter Masks..."),0,cnt,1);
1153 
1154     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1155 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1156 	SplineChar *sc = fv->sf->glyphs[gid];
1157 	SCFigureCounterMasks(sc);
1158 	if ( !ff_progress_next())
1159     break;
1160     }
1161     ff_progress_end_indicator();
1162 }
1163 
FVDontAutoHint(FontViewBase * fv)1164 void FVDontAutoHint(FontViewBase *fv) {
1165     int i, gid;
1166 
1167     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1168 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1169 	SplineChar *sc = fv->sf->glyphs[gid];
1170 	sc->manualhints = true;
1171     }
1172 }
1173 
AllGlyphsSelected(FontViewBase * fv)1174 static int AllGlyphsSelected(FontViewBase *fv) {
1175     SplineFont *sf = fv->sf;
1176     int gid, enc;
1177     SplineChar *sc;
1178 
1179     for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL )
1180 	sc->ticked = false;
1181 
1182     for ( enc=0; enc<fv->map->enccount; ++enc ) {
1183 	if ( fv->selected[enc] && (gid=fv->map->map[enc])!=-1 &&
1184 		(sc = sf->glyphs[gid])!=NULL )
1185 	    sc->ticked = true;
1186     }
1187     for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL )
1188 	if ( !sc->ticked )
1189 return( false );
1190 
1191 return( true );
1192 }
1193 
AnySelectedHints(FontViewBase * fv)1194 static int AnySelectedHints(FontViewBase *fv) {
1195     SplineFont *sf = fv->sf;
1196     int gid, enc;
1197     SplineChar *sc;
1198 
1199     for ( enc=0; enc<fv->map->enccount; ++enc ) {
1200 	if ( fv->selected[enc] && (gid=fv->map->map[enc])!=-1 &&
1201 		(sc = sf->glyphs[gid])!=NULL &&
1202 		(sc->hstem!=NULL || sc->vstem!=NULL || sc->dstem!=NULL ))
1203 return( true );		/* A glyph with hints! */
1204     }
1205 
1206 return( false );
1207 }
1208 
CIDSetEncMap(FontViewBase * fv,SplineFont * new)1209 void CIDSetEncMap(FontViewBase *fv, SplineFont *new ) {
1210     int gcnt = new->glyphcnt;
1211 
1212     if ( fv->cidmaster!=NULL && gcnt!=fv->sf->glyphcnt ) {
1213 	int i;
1214 	if ( fv->map->encmax<gcnt ) {
1215 	    fv->map->map = realloc(fv->map->map,gcnt*sizeof(int32));
1216 	    fv->map->backmap = realloc(fv->map->backmap,gcnt*sizeof(int32));
1217 	    fv->map->backmax = fv->map->encmax = gcnt;
1218 	}
1219 	for ( i=0; i<gcnt; ++i )
1220 	    fv->map->map[i] = fv->map->backmap[i] = i;
1221 	if ( gcnt<fv->map->enccount )
1222 	    memset(fv->selected+gcnt,0,fv->map->enccount-gcnt);
1223 	else {
1224 	    free(fv->selected);
1225 	    fv->selected = calloc(gcnt,sizeof(uint8));
1226 	}
1227 	fv->map->enccount = gcnt;
1228     }
1229     fv->sf = new;
1230     new->fv = fv;
1231     FVSetTitle(fv);
1232     FontViewReformatOne(fv);
1233 }
1234 
FVInsertInCID(FontViewBase * fv,SplineFont * sf)1235 void FVInsertInCID(FontViewBase *fv,SplineFont *sf) {
1236     SplineFont *cidmaster = fv->cidmaster;
1237     SplineFont **subs;
1238     int i;
1239 
1240     subs = malloc((cidmaster->subfontcnt+1)*sizeof(SplineFont *));
1241     for ( i=0; i<cidmaster->subfontcnt && cidmaster->subfonts[i]!=fv->sf; ++i )
1242 	subs[i] = cidmaster->subfonts[i];
1243     subs[i] = sf;
1244     if ( sf->uni_interp == ui_none || sf->uni_interp == ui_unset )
1245 	sf->uni_interp = cidmaster->uni_interp;
1246     for ( ; i<cidmaster->subfontcnt ; ++i )
1247 	subs[i+1] = cidmaster->subfonts[i];
1248     ++cidmaster->subfontcnt;
1249     free(cidmaster->subfonts);
1250     cidmaster->subfonts = subs;
1251     cidmaster->changed = true;
1252     sf->cidmaster = cidmaster;
1253 
1254     CIDSetEncMap( fv,sf);
1255 }
1256 
ClearFpgmPrepCvt(SplineFont * sf)1257 static void ClearFpgmPrepCvt(SplineFont *sf) {
1258     struct ttf_table *tab, *prev = NULL, *next;
1259 
1260     for ( tab = sf->ttf_tables; tab!=NULL ; tab=next ) {
1261 	next = tab->next;
1262 	if ( tab->tag==CHR('c','v','t',' ') ||
1263 		tab->tag==CHR('f','p','g','m') ||
1264 		tab->tag==CHR('p','r','e','p') ) {
1265 	    if ( prev==NULL )
1266 		sf->ttf_tables = next;
1267 	    else
1268 		prev->next = next;
1269 	    tab->next = NULL;
1270 	    TtfTablesFree(tab);
1271 	} else
1272 	    prev = tab;
1273     }
1274 }
1275 
FVAutoInstr(FontViewBase * fv)1276 void FVAutoInstr(FontViewBase *fv) {
1277     BlueData bd;
1278     int i, cnt=0, gid;
1279     GlobalInstrCt gic;
1280 
1281     /* If all glyphs are selected, then no legacy hint will remain after */
1282     /*  instructing, so we might as well clear all the legacy tables too */
1283     /* (This way the auto hinter won't complain if they existed) */
1284     if ( fv->sf->ttf_tables!=NULL && AllGlyphsSelected(fv))
1285 	ClearFpgmPrepCvt(fv->sf);
1286     if ( fv->sf->private==NULL && !no_windowing_ui )
1287 	ff_post_notice( _("Things could be better..."), _("You will get better instructions if you fill in the Private dictionary, Element->Font Info->Private, for the font"));
1288     if ( !no_windowing_ui && !AnySelectedHints(fv))
1289 	ff_post_notice(_("Things could be better..."), _("The selected glyphs have no hints. FontForge will not produce many instructions."));
1290 
1291     QuickBlues(fv->sf,fv->active_layer,&bd);
1292 
1293     InitGlobalInstrCt(&gic,fv->sf,fv->active_layer,&bd);
1294 
1295     for ( i=0; i<fv->map->enccount; ++i )
1296 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1297 		SCWorthOutputting(fv->sf->glyphs[gid]) )
1298 	    ++cnt;
1299     ff_progress_start_indicator(10,_("Auto Instructing Font..."),_("Auto Instructing Font..."),0,cnt,1);
1300 
1301     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1302 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1303 	SplineChar *sc = fv->sf->glyphs[gid];
1304 	NowakowskiSCAutoInstr(&gic,sc);
1305 	if ( !ff_progress_next())
1306     break;
1307     }
1308 
1309     FreeGlobalInstrCt(&gic);
1310 
1311     ff_progress_end_indicator();
1312 }
1313 
FVClearInstrs(FontViewBase * fv)1314 void FVClearInstrs(FontViewBase *fv) {
1315     SplineChar *sc;
1316     int i, gid;
1317 
1318     if ( !SFCloseAllInstrs(fv->sf))
1319 return;
1320 
1321     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1322 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting((sc = fv->sf->glyphs[gid])) ) {
1323 	if ( sc->ttf_instrs_len!=0 ) {
1324 	    free(sc->ttf_instrs);
1325 	    sc->ttf_instrs = NULL;
1326 	    sc->ttf_instrs_len = 0;
1327 	    sc->instructions_out_of_date = false;
1328 	    SCCharChangedUpdate(sc,ly_none);
1329 	    sc->complained_about_ptnums = false;
1330 	}
1331     }
1332 }
1333 
FVClearHints(FontViewBase * fv)1334 void FVClearHints(FontViewBase *fv) {
1335     int i, gid;
1336 
1337     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1338 	    (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1339 	SplineChar *sc = fv->sf->glyphs[gid];
1340 	sc->manualhints = true;
1341 	SCPreserveHints(sc,fv->active_layer);
1342 	SCClearHints(sc);
1343 	SCUpdateAll(sc);
1344     }
1345 }
1346 
ViewPostScriptFont(const char * filename,int openflags)1347 FontViewBase *ViewPostScriptFont(const char *filename,int openflags) {
1348     SplineFont *sf = LoadSplineFont(filename,openflags);
1349     extern NameList *force_names_when_opening;
1350     if ( sf==NULL )
1351 return( NULL );
1352     if ( sf->fv==NULL && force_names_when_opening!=NULL )
1353 	SFRenameGlyphsToNamelist(sf,force_names_when_opening );
1354 return( FontViewCreate(sf,openflags&of_hidewindow));	/* Always make a new view now */
1355 }
1356 
tester(SplineChar * sc,struct lookup_subtable * sub)1357 static int tester(SplineChar *sc, struct lookup_subtable *sub) {
1358     PST *pst;
1359     KernPair *kp;
1360     int isv;
1361     AnchorPoint *ap;
1362 
1363     if ( sc==NULL )
1364 return( false );
1365 
1366     for ( ap=sc->anchor; ap!=NULL; ap=ap->next )
1367 	if ( ap->anchor->subtable == sub )
1368 return( true );
1369     for ( pst=sc->possub; pst!=NULL; pst=pst->next )
1370 	if ( pst->subtable==sub )
1371 return( true );
1372     for ( isv=0; isv<2; ++isv )
1373 	for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
1374 	    if ( kp->subtable == sub )
1375 return( true );
1376 
1377 return( false );
1378 }
1379 
FVBParseSelectByPST(FontViewBase * fv,struct lookup_subtable * sub,int search_type)1380 int FVBParseSelectByPST(FontViewBase *fv,struct lookup_subtable *sub,
1381 	int search_type) {
1382     int i;
1383     SplineFont *sf;
1384     int first;
1385     int gid;
1386 
1387     sf = fv->sf;
1388     first = -1;
1389     if ( search_type==1 ) {	/* Select results */
1390 	for ( i=0; i<fv->map->enccount; ++i ) {
1391 	    gid=fv->map->map[i];
1392 	    if ( (fv->selected[i] = tester(gid==-1?NULL:sf->glyphs[gid],sub)) && first==-1 )
1393 		first = i;
1394 	}
1395     } else if ( search_type==2) {/* merge results */
1396 	for ( i=0; i<fv->map->enccount; ++i ) if ( !fv->selected[i] ) {
1397 	    gid=fv->map->map[i];
1398 	    if ( (fv->selected[i] = tester(gid==-1?NULL:sf->glyphs[gid],sub)) && first==-1 )
1399 		first = i;
1400 	}
1401     } else {			/* restrict selection */
1402 	for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
1403 	    gid=fv->map->map[i];
1404 	    if ( (fv->selected[i] = tester(gid==-1?NULL:sf->glyphs[gid],sub)) && first==-1 )
1405 		first = i;
1406 	}
1407     }
1408 return( first );
1409 }
1410 
FVBuildAccent(FontViewBase * fv,int onlyaccents)1411 void FVBuildAccent(FontViewBase *fv,int onlyaccents) {
1412     int i, cnt=0, gid;
1413     SplineChar dummy;
1414     SplineChar *sc;
1415 
1416     for ( i=0; i<fv->map->enccount; ++i )
1417 	if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1418 		SCWorthOutputting(fv->sf->glyphs[gid]) )
1419 	    ++cnt;
1420     ff_progress_start_indicator(10,_("Building accented glyphs"),
1421 	    _("Building accented glyphs"),NULL,cnt,1);
1422 
1423     SFUntickAll(fv->sf);
1424     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
1425 	gid = fv->map->map[i];
1426 	sc = NULL;
1427 	if ( gid!=-1 ) {
1428 	    sc = fv->sf->glyphs[gid];
1429 	    if ( sc!=NULL && sc->ticked )
1430     continue;
1431 	}
1432 	if ( sc==NULL )
1433 	    sc = SCBuildDummy(&dummy,fv->sf,fv->map,i);
1434 	else if ( !no_windowing_ui && sc->unicodeenc == 0x00c5 /* Aring */ &&
1435 		sc->layers[fv->active_layer].splines!=NULL ) {
1436 	    char *buts[3];
1437 	    buts[0] = _("_Yes");
1438 	    buts[1] = _("_No");
1439 	    buts[2] = NULL;
1440 	    if ( ff_ask(U_("Replace Å"),(const char **) buts,0,1,U_("Are you sure you want to replace Å?\nThe ring will not join to the A."))==1 )
1441     continue;
1442 	}
1443 	if ( SFIsSomethingBuildable(fv->sf,sc,fv->active_layer,onlyaccents) ) {
1444 	    sc = SFMakeChar(fv->sf,fv->map,i);
1445 	    sc->ticked = true;
1446 	    SCBuildComposit(fv->sf,sc,fv->active_layer,fv->active_bitmap,onlycopydisplayed,onlyaccents);
1447 	}
1448 	if ( !ff_progress_next())
1449     break;
1450     }
1451     ff_progress_end_indicator();
1452 }
1453 
FVAddUnencoded(FontViewBase * fv,int cnt)1454 void FVAddUnencoded(FontViewBase *fv, int cnt) {
1455     int i;
1456     EncMap *map = fv->map;
1457 
1458     if ( fv->normal!=NULL ) {
1459 	/* If it's compacted, lose the base encoding and the fact that it's */
1460 	/*  compact and make it be custom. That's what Alexey Kryukov asked */
1461 	/*  for */
1462 	EncMapFree(fv->normal);
1463 	// If fv->normal happens to be fv->sf->map, freeing it leaves an invalid pointer in the splinefont.
1464 	// So we tell the splinefont to use the fontview map.
1465 	if (fv->sf != NULL && fv->normal == fv->sf->map) { fv->sf->map = NULL; }
1466 	fv->normal = NULL;
1467 	fv->map->enc = &custom;
1468 	FVSetTitle(fv);
1469     }
1470     if ( fv->cidmaster ) {
1471 	SplineFont *sf = fv->sf;
1472 	FontViewBase *fvs;
1473 	if ( sf->glyphcnt+cnt>=sf->glyphmax )
1474 	    sf->glyphs = realloc(sf->glyphs,(sf->glyphmax = sf->glyphcnt+cnt+10)*sizeof(SplineChar *));
1475 	memset(sf->glyphs+sf->glyphcnt,0,cnt*sizeof(SplineChar *));
1476 	for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1477 	    EncMap *map = fvs->map;
1478 	    if ( map->enccount+cnt>=map->encmax )
1479 		map->map = realloc(map->map,(map->encmax += cnt+10)*sizeof(int));
1480 	    if ( sf->glyphcnt+cnt>=map->backmax )
1481 		map->backmap = realloc(map->backmap,(map->backmax += cnt+10)*sizeof(int));
1482 	    for ( i=map->enccount; i<map->enccount+cnt; ++i )
1483 		map->map[i] = map->backmap[i] = i;
1484 	    fvs->selected = realloc(fvs->selected,(map->enccount+cnt));
1485 	    memset(fvs->selected+map->enccount,0,cnt);
1486 	    map->enccount += cnt;
1487 	}
1488 	sf->glyphcnt += cnt;
1489 	FontViewReformatAll(fv->sf);
1490     } else {
1491 	if ( map->enccount+cnt>=map->encmax )
1492 	    map->map = realloc(map->map,(map->encmax += cnt+10)*sizeof(int));
1493 	for ( i=map->enccount; i<map->enccount+cnt; ++i )
1494 	    map->map[i] = -1;
1495 	fv->selected = realloc(fv->selected,(map->enccount+cnt));
1496 	memset(fv->selected+map->enccount,0,cnt);
1497 	map->enccount += cnt;
1498 	FontViewReformatOne(fv);
1499 	FVDisplayEnc(fv,map->enccount-cnt);
1500     }
1501 }
1502 
FVRemoveUnused(FontViewBase * fv)1503 void FVRemoveUnused(FontViewBase *fv) {
1504     SplineFont *sf = fv->sf;
1505     EncMap *map = fv->map;
1506     int oldcount = map->enccount;
1507     int gid, i;
1508     int flags = -1;
1509 
1510     for ( i=map->enccount-1;
1511             i>=map->enc->char_cnt &&
1512                 ((gid=map->map[i])==-1 || !SCWorthOutputting(sf->glyphs[gid]));
1513 	    --i ) {
1514 	if ( gid!=-1 )
1515 	    SFRemoveGlyph(sf,sf->glyphs[gid]);
1516 	map->enccount = i;
1517     }
1518     /* We reduced the encoding, so don't really need to reallocate the selection */
1519     /*  array. It's just bigger than it needs to be. */
1520     if ( oldcount!=map->enccount )
1521 	FontViewReformatOne(fv);
1522 }
1523 
FVCompact(FontViewBase * fv)1524 void FVCompact(FontViewBase *fv) {
1525     int oldcount = fv->map->enccount;
1526 
1527     if ( fv->normal!=NULL ) {
1528 	EncMapFree(fv->map);
1529 	if (fv->sf != NULL && fv->sf->map == fv->map) { fv->sf->map = fv->normal ; }
1530 	fv->map = fv->normal;
1531 	fv->normal = NULL;
1532 	fv->selected = realloc(fv->selected,fv->map->enccount);
1533 	memset(fv->selected,0,fv->map->enccount);
1534     } else {
1535 	/* We reduced the encoding, so don't really need to reallocate the selection */
1536 	/*  array. It's just bigger than it needs to be. */
1537 	fv->normal = EncMapCopy(fv->map);
1538 	CompactEncMap(fv->map,fv->sf);
1539 	fv->sf->map = fv->map;
1540     }
1541     if ( oldcount!=fv->map->enccount )
1542 	FontViewReformatOne(fv);
1543     FVSetTitle(fv);
1544 }
1545 
FVDetachGlyphs(FontViewBase * fv)1546 void FVDetachGlyphs(FontViewBase *fv) {
1547     int i, j, gid;
1548     EncMap *map = fv->map;
1549     int altered = false;
1550     SplineFont *sf = fv->sf;
1551 
1552     for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] && (gid=map->map[i])!=-1 ) {
1553 	altered = true;
1554 	map->map[i] = -1;
1555 	if ( map->backmap[gid]==i ) {
1556 	    for ( j=map->enccount-1; j>=0 && map->map[j]!=gid; --j );
1557 	    map->backmap[gid] = j;
1558 	}
1559 	if ( sf->glyphs[gid]!=NULL && sf->glyphs[gid]->altuni != NULL && map->enc!=&custom )
1560 	    AltUniRemove(sf->glyphs[gid],UniFromEnc(i,map->enc));
1561     }
1562     if ( altered )
1563 	FVRefreshAll(sf);
1564 }
1565 
FVDetachAndRemoveGlyphs(FontViewBase * fv)1566 void FVDetachAndRemoveGlyphs(FontViewBase *fv) {
1567     int i, j, gid;
1568     EncMap *map = fv->map;
1569     SplineFont *sf = fv->sf;
1570     int flags = -1;
1571     int changed = false, altered = false;
1572     FontViewBase *fvs;
1573 
1574     for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] && (gid=map->map[i])!=-1 ) {
1575 	altered = true;
1576 	map->map[i] = -1;
1577 	if ( map->backmap[gid]==i ) {
1578 	    for ( j=map->enccount-1; j>=0 && map->map[j]!=gid; --j );
1579 	    map->backmap[gid] = j;
1580 	    if ( j==-1 ) {
1581 		SFRemoveGlyph(sf,sf->glyphs[gid]);
1582 		changed = true;
1583 	    } else if ( sf->glyphs[gid]!=NULL && sf->glyphs[gid]->altuni != NULL && map->enc!=&custom )
1584 		AltUniRemove(sf->glyphs[gid],UniFromEnc(i,map->enc));
1585 	}
1586     }
1587     if ( changed && !fv->sf->changed ) {
1588 	fv->sf->changed = true;
1589 	for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame )
1590 	    FVSetTitle(fvs);
1591     }
1592     if ( altered )
1593 	FVRefreshAll(sf);
1594 }
1595 
FVMetricsCenter(FontViewBase * fv,int docenter)1596 void FVMetricsCenter(FontViewBase *fv,int docenter) {
1597     int i, gid;
1598     SplineChar *sc;
1599     DBounds bb;
1600     IBounds ib;
1601     real transform[6], itransform[6];
1602     BVTFunc bvts[2];
1603     BDFFont *bdf;
1604 
1605     memset(transform,0,sizeof(transform));
1606     memset(itransform,0,sizeof(itransform));
1607     transform[0] = transform[3] = 1.0;
1608     itransform[0] = itransform[3] = 1.0;
1609     itransform[2] = tan( fv->sf->italicangle * FF_PI/180.0 );
1610     bvts[1].func = bvt_none;
1611     bvts[0].func = bvt_transmove; bvts[0].y = 0;
1612     if ( !fv->sf->onlybitmaps ) {
1613 	for ( i=0; i<fv->map->enccount; ++i ) {
1614 	    if ( fv->selected[i] && (gid=fv->map->map[i])!=-1 &&
1615 		    (sc = fv->sf->glyphs[gid])!=NULL ) {
1616 		if ( itransform[2] == 0 )
1617 		    SplineCharFindBounds(sc,&bb);
1618 		else {
1619 		    SplineSet *base, *temp;
1620 		    base = LayerAllSplines(&sc->layers[fv->active_layer]);
1621 		    temp = SplinePointListTransform(SplinePointListCopy(base),itransform,tpt_AllPoints);
1622 		    LayerUnAllSplines(&sc->layers[fv->active_layer]);
1623 		    SplineSetFindBounds(temp,&bb);
1624 		    SplinePointListsFree(temp);
1625 		}
1626 		if ( docenter )
1627 		    transform[4] = (sc->width-(bb.maxx-bb.minx))/2 - bb.minx;
1628 		else
1629 		    transform[4] = (sc->width-(bb.maxx-bb.minx))/3 - bb.minx;
1630 		if ( transform[4]!=0 ) {
1631 		    FVTrans(fv,sc,transform,NULL, fvt_dontmovewidth | fvt_alllayers );
1632 		    bvts[0].x = transform[4];
1633 		    for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
1634 			if ( gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL )
1635 			    BCTrans(bdf,bdf->glyphs[gid],bvts,fv);
1636 		}
1637 	    }
1638 	}
1639     } else {
1640 	double scale = (fv->sf->ascent+fv->sf->descent)/(double) (fv->active_bitmap->pixelsize);
1641 	for ( i=0; i<fv->map->enccount; ++i ) {
1642 	    if ( fv->selected[i] && (gid=fv->map->map[i])!=-1 &&
1643 		    fv->sf->glyphs[gid]!=NULL ) {
1644 		BDFChar *bc = fv->active_bitmap->glyphs[gid];
1645 		if ( bc==NULL ) bc = BDFMakeChar(fv->active_bitmap,fv->map,i);
1646 		BDFCharFindBounds(bc,&ib);
1647 		if ( docenter )
1648 		    transform[4] = scale * ((bc->width-(ib.maxx-ib.minx))/2 - ib.minx);
1649 		else
1650 		    transform[4] = scale * ((bc->width-(ib.maxx-ib.minx))/3 - ib.minx);
1651 		if ( transform[4]!=0 ) {
1652 		    FVTrans(fv,fv->sf->glyphs[gid],transform,NULL,fvt_dontmovewidth);
1653 		    bvts[0].x = transform[4];
1654 		    for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
1655 			if ( gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL )
1656 			    BCTrans(bdf,bdf->glyphs[gid],bvts,fv);
1657 		}
1658 	    }
1659 	}
1660     }
1661 }
1662 
RevertAskChanged(char * fontname,char * filename)1663 static int RevertAskChanged(char *fontname,char *filename) {
1664     int ret;
1665     char *buts[3];
1666 
1667     if ( filename==NULL ) filename = "untitled.sfd";
1668     filename = GFileNameTail(filename);
1669     buts[0] = _("_Revert");
1670     buts[1] = _("_Cancel");
1671     buts[2] = NULL;
1672     ret = ff_ask( _("Font changed"),(const char **) buts,0,1,_("Font %1$.40s in file %2$.40s has been changed.\nReverting the file will lose those changes.\nIs that what you want?"),fontname,filename);
1673 return( ret==0 );
1674 }
1675 
_FVRevert(FontViewBase * fv,int tobackup)1676 static void _FVRevert(FontViewBase *fv,int tobackup) {
1677     SplineFont *temp, *old = fv->cidmaster?fv->cidmaster:fv->sf;
1678     BDFFont *bdf;
1679     int i;
1680     FontViewBase *fvs;
1681     EncMap *map;
1682 
1683     if ( old->origname==NULL )
1684 return;
1685     if ( old->changed )
1686 	if ( !RevertAskChanged(old->fontname,old->origname))
1687 return;
1688     if ( tobackup ) {
1689 	/* we can only revert to backup if it's an sfd file. So we use filename*/
1690 	/*  here. In the normal case we revert to whatever file we read it from*/
1691 	/*  (sfd or not) so we use origname */
1692 	char *buf = malloc(strlen(old->filename)+20);
1693 	strcpy(buf,old->filename);
1694 	if ( old->compression!=0 ) {
1695 	    char *tmpf;
1696 	    strcat(buf,compressors[old->compression-1].ext);
1697 	    strcat(buf,"~");
1698 	    tmpf = Decompress(buf,old->compression-1);
1699 	    if ( tmpf==NULL )
1700 		temp = NULL;
1701 	    else {
1702 		temp = ReadSplineFont(tmpf,0);
1703 		unlink(tmpf);
1704 		free(tmpf);
1705 	    }
1706 	} else {
1707 	    strcat(buf,"~");
1708 	    temp = ReadSplineFont(buf,0);
1709 	}
1710 	free(buf);
1711     } else {
1712 	if ( old->compression!=0 ) {
1713 	    char *tmpf;
1714 	    char *buf = malloc(strlen(old->filename)+20);
1715 	    strcpy(buf,old->filename);
1716 	    strcat(buf,compressors[old->compression-1].ext);
1717 	    tmpf = Decompress(buf,old->compression-1);
1718 	    if ( tmpf==NULL )
1719 		temp = NULL;
1720 	    else {
1721 		temp = ReadSplineFont(tmpf,0);
1722 		unlink(tmpf);
1723 		free(tmpf);
1724 	    }
1725 	} else
1726 	    temp = ReadSplineFont(old->origname,0);
1727     }
1728     if ( temp==NULL ) {
1729 return;
1730     }
1731     if ( temp->filename!=NULL ) {
1732 	free(temp->filename);
1733 	temp->filename = copy(old->filename);
1734     }
1735     if ( temp->origname!=NULL ) {
1736 	free(temp->origname);
1737 	temp->origname = copy(old->origname);
1738     }
1739     temp->compression = old->compression;
1740     temp->fv = old->fv;
1741     FVReattachCVs(old,temp);
1742     for ( i=0; i<old->subfontcnt; ++i )
1743 	FVReattachCVs(old->subfonts[i],temp);
1744     if ( fv->sf->fontinfo )
1745 	FontInfo_Destroy(fv->sf);
1746     for ( bdf=old->bitmaps; bdf!=NULL; bdf=bdf->next )
1747 	for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL )
1748 	    BCDestroyAll(bdf->glyphs[i]);
1749     MVDestroyAll(old);
1750     for ( fvs=fv->sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1751 	if ( fvs==fv )
1752 	    map = temp->map;
1753 	else
1754 	    map = EncMapFromEncoding(fv->sf,fv->map->enc);
1755 	if ( map->enccount>fvs->map->enccount ) {
1756 	    fvs->selected = realloc(fvs->selected,map->enccount);
1757 	    memset(fvs->selected+fvs->map->enccount,0,map->enccount-fvs->map->enccount);
1758 	}
1759 	EncMapFree(fv->map);
1760 	if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = map; }
1761 	fv->map = map;
1762 	if ( fvs->normal!=NULL ) {
1763 	    EncMapFree(fvs->normal);
1764 	    fvs->normal = EncMapCopy(fvs->map);
1765 	    CompactEncMap(fvs->map,temp);
1766 	}
1767     }
1768     ff_progress_allow_events();
1769     SFClearAutoSave(old);
1770     temp->fv = fv->sf->fv;
1771     for ( fvs=fv->sf->fv; fvs!=NULL; fvs=fvs->nextsame )
1772 	fvs->sf = temp;
1773     FontViewReformatAll(fv->sf);
1774     SplineFontFree(old);
1775 }
1776 
FVRevert(FontViewBase * fv)1777 void FVRevert(FontViewBase *fv) {
1778     _FVRevert(fv,false);
1779 }
1780 
FVRevertBackup(FontViewBase * fv)1781 void FVRevertBackup(FontViewBase *fv) {
1782     _FVRevert(fv,true);
1783 }
1784 
FVRevertGlyph(FontViewBase * fv)1785 void FVRevertGlyph(FontViewBase *fv) {
1786     int i, gid;
1787     int nc_state = -1;
1788     SplineFont *sf = fv->sf;
1789     SplineChar *sc, *tsc;
1790     SplineChar temp;
1791     Undoes **undoes;
1792     int layer, lc;
1793     EncMap *map = fv->map;
1794     CharViewBase *cvs;
1795     int alayer = ly_fore;
1796 
1797     if ( fv->sf->sfd_version<2 )
1798 	ff_post_error(_("Old sfd file"),_("This font comes from an old format sfd file. Not all aspects of it can be reverted successfully."));
1799 
1800     for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] && (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
1801 	tsc = sf->glyphs[gid];
1802 	if ( tsc->namechanged ) {
1803 	    if ( nc_state==-1 ) {
1804 		ff_post_error(_("Glyph Name Changed"),_("The name of glyph %.40s has changed. This is what I use to find the glyph in the file, so I cannot revert this glyph.\n(You will not be warned for subsequent glyphs.)"),tsc->name);
1805 		nc_state = 0;
1806 	    }
1807 	} else {
1808 	    sc = SFDReadOneChar(sf,tsc->name);
1809 	    if ( sc==NULL ) {
1810 		ff_post_error(_("Can't Find Glyph"),_("The glyph, %.80s, can't be found in the sfd file"),tsc->name);
1811 		tsc->namechanged = true;
1812 	    } else {
1813 		SCPreserveState(tsc,true);
1814 		SCPreserveBackground(tsc);
1815 		if ( tsc->views!=NULL )
1816 		    alayer = CVLayer(tsc->views);
1817 		temp = *tsc;
1818 		tsc->dependents = NULL;
1819 		lc = tsc->layer_cnt;
1820 		undoes = malloc(lc*sizeof(Undoes *));
1821 		for ( layer=0; layer<lc; ++layer ) {
1822 		    undoes[layer] = tsc->layers[layer].undoes;
1823 		    tsc->layers[layer].undoes = NULL;
1824 		}
1825 		SplineCharFreeContents(tsc);
1826 		*tsc = *sc;
1827 		chunkfree(sc,sizeof(SplineChar));
1828 		tsc->parent = sf;
1829 		tsc->dependents = temp.dependents;
1830 		tsc->views = temp.views;
1831 		for ( layer = 0; layer<lc && layer<tsc->layer_cnt; ++layer )
1832 		    tsc->layers[layer].undoes = undoes[layer];
1833 		for ( ; layer<lc; ++layer )
1834 		    UndoesFree(undoes[layer]);
1835 		free(undoes);
1836 		/* tsc->changed = temp.changed; */
1837 		/* tsc->orig_pos = temp.orig_pos; */
1838 		for ( cvs=tsc->views; cvs!=NULL; cvs= cvs->next ) {
1839 		    cvs->layerheads[dm_back] = &tsc->layers[ly_back];
1840 		    cvs->layerheads[dm_fore] = &tsc->layers[ly_fore];
1841 		    if ( sf->multilayer ) {
1842 			if ( alayer!=ly_back )
1843 			    cvs->layerheads[dm_fore] = &tsc->layers[alayer];
1844 		    } else {
1845 			if ( alayer!=ly_fore )
1846 			    cvs->layerheads[dm_back] = &tsc->layers[alayer];
1847 		    }
1848 		}
1849 		RevertedGlyphReferenceFixup(tsc, sf);
1850 		_SCCharChangedUpdate(tsc,alayer,false);
1851 	    }
1852 	}
1853     }
1854 }
1855 
FVClearSpecialData(FontViewBase * fv)1856 void FVClearSpecialData(FontViewBase *fv) {
1857     SplineFont *sf = fv->sf;
1858     if (sf) SplineFontClearSpecial(sf);
1859 }
1860 
isuniname(char * name)1861 static int isuniname(char *name) {
1862     int i;
1863     if ( name[0]!='u' || name[1]!='n' || name[2]!='i' )
1864 return( false );
1865     for ( i=3; i<7; ++i )
1866 	if ( name[i]<'0' || (name[i]>'9' && name[i]<'A') || name[i]>'F' )
1867 return( false );
1868     if ( name[7]!='\0' )
1869 return( false );
1870 
1871 return( true );
1872 }
1873 
isuname(char * name)1874 static int isuname(char *name) {
1875     int i;
1876     if ( name[0]!='u' )
1877 return( false );
1878     for ( i=1; i<5; ++i )
1879 	if ( name[i]<'0' || (name[i]>'9' && name[i]<'A') || name[i]>'F' )
1880 return( false );
1881     if ( name[5]!='\0' )
1882 return( false );
1883 
1884 return( true );
1885 }
1886 
FVB_MakeNamelist(FontViewBase * fv,FILE * file)1887 void FVB_MakeNamelist(FontViewBase *fv, FILE *file) {
1888     SplineChar *sc;
1889     int i;
1890 
1891     for ( i=0; i<fv->sf->glyphcnt; ++i ) {
1892 	if ( (sc = fv->sf->glyphs[i])!=NULL && sc->unicodeenc!=-1 ) {
1893 	    if ( !isuniname(sc->name) && !isuname(sc->name ) )
1894 		fprintf( file, "0x%04X %s\n", sc->unicodeenc, sc->name );
1895 	}
1896     }
1897 }
1898 
1899 /*                             FV Interface                                   */
1900 
_FontViewBaseCreate(SplineFont * sf)1901 static FontViewBase *_FontViewBaseCreate(SplineFont *sf) {
1902     FontViewBase *fv = calloc(1,sizeof(FontViewBase));
1903     int i;
1904 
1905     fv->nextsame = sf->fv;
1906     fv->active_layer = ly_fore;
1907     sf->fv = fv;
1908     if ( sf->mm!=NULL ) {
1909 	sf->mm->normal->fv = fv;
1910 	for ( i = 0; i<sf->mm->instance_count; ++i )
1911 	    sf->mm->instances[i]->fv = fv;
1912     }
1913     if ( sf->subfontcnt==0 ) {
1914 	fv->sf = sf;
1915 	if ( fv->nextsame!=NULL ) {
1916 	    fv->map = EncMapCopy(fv->nextsame->map);
1917 	    fv->normal = fv->nextsame->normal==NULL ? NULL : EncMapCopy(fv->nextsame->normal);
1918 	    fprintf(stderr, "There are two FontViews using the same SplineFont. Please report on the issue tracker or the mailing list how you reached this point.\n");
1919 	} else if ( sf->compacted ) {
1920 	    fv->normal = sf->map;
1921 	    fv->map = CompactEncMap(EncMapCopy(sf->map),sf);
1922 	    sf->map = fv->map;
1923 	} else {
1924 	    fv->map = sf->map;
1925 	    fv->normal = NULL;
1926 	}
1927     } else {
1928 	fv->cidmaster = sf;
1929 	for ( i=0; i<sf->subfontcnt; ++i )
1930 	    sf->subfonts[i]->fv = fv;
1931 	for ( i=0; i<sf->subfontcnt; ++i )	/* Search for a subfont that contains more than ".notdef" (most significant in .gai fonts) */
1932 	    if ( sf->subfonts[i]->glyphcnt>1 ) {
1933 		fv->sf = sf->subfonts[i];
1934 	break;
1935 	    }
1936 	if ( fv->sf==NULL )
1937 	    fv->sf = sf->subfonts[0];
1938 	sf = fv->sf;
1939 	if ( fv->nextsame==NULL ) { EncMapFree(sf->map); sf->map = NULL; }
1940 	fv->map = EncMap1to1(sf->glyphcnt);
1941 	if ( fv->nextsame==NULL ) { sf->map = fv->map; }
1942     }
1943     fv->selected = calloc(fv->map->enccount,sizeof(uint8));
1944 
1945 #ifndef _NO_PYTHON
1946     PyFF_InitFontHook(fv);
1947 #endif
1948 return( fv );
1949 }
1950 
FontViewBase_Create(SplineFont * sf,int UNUSED (hide))1951 static FontViewBase *FontViewBase_Create(SplineFont *sf,int UNUSED(hide)) {
1952     FontViewBase *fv = _FontViewBaseCreate(sf);
1953 return( fv );
1954 }
1955 
FontViewBase_Append(FontViewBase * fv)1956 static FontViewBase *FontViewBase_Append(FontViewBase *fv)
1957 {
1958     /* Normally fontviews get added to the fv list when their windows are */
1959     /*  created. but we don't create any windows here, so... */
1960     FontViewBase *test;
1961 
1962     if ( fv_list==NULL ) fv_list = fv;
1963     else {
1964 	for ( test = fv_list; test->next!=NULL; test=test->next );
1965 	test->next = fv;
1966     }
1967 return( fv );
1968 }
1969 
FontViewBase_Free(FontViewBase * fv)1970 static void FontViewBase_Free(FontViewBase *fv) {
1971     int i;
1972     FontViewBase *prev;
1973 
1974    if ( fv->nextsame==NULL && fv->sf->fv==fv ) {
1975 	EncMapFree(fv->map);
1976 	if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = NULL; }
1977 	fv->map = NULL;
1978 	SplineFontFree(fv->cidmaster?fv->cidmaster:fv->sf);
1979     } else {
1980 	EncMapFree(fv->map);
1981 	if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = NULL; }
1982 	fv->map = NULL;
1983 	if ( fv->sf->fv==fv ) {
1984 	    if ( fv->cidmaster==NULL )
1985 		fv->sf->fv = fv->nextsame;
1986 	    else {
1987 		fv->cidmaster->fv = fv->nextsame;
1988 		for ( i=0; i<fv->cidmaster->subfontcnt; ++i )
1989 		    fv->cidmaster->subfonts[i]->fv = fv->nextsame;
1990 	    }
1991 	} else {
1992 	    for ( prev = fv->sf->fv; prev->nextsame!=fv; prev=prev->nextsame );
1993 	    prev->nextsame = fv->nextsame;
1994 	}
1995     }
1996 #ifndef _NO_FFSCRIPT
1997     DictionaryFree(fv->fontvars);
1998     free(fv->fontvars);
1999 #endif
2000     free(fv->selected);
2001 #ifndef _NO_PYTHON
2002     PyFF_FreeFV(fv);
2003 #endif
2004     free(fv);
2005 }
2006 
FontViewBaseWinInfo(FontViewBase * UNUSED (fv),int * cc,int * rc)2007 static int FontViewBaseWinInfo(FontViewBase *UNUSED(fv), int *cc, int *rc) {
2008     *cc = 16; *rc = 4;
2009 return( -1 );
2010 }
2011 
FontViewBaseSetTitle(FontViewBase * UNUSED (foo))2012 static void FontViewBaseSetTitle(FontViewBase *UNUSED(foo)) { }
FontViewBaseSetTitles(SplineFont * UNUSED (foo))2013 static void FontViewBaseSetTitles(SplineFont *UNUSED(foo)) { }
FontViewBaseRefreshAll(SplineFont * UNUSED (foo))2014 static void FontViewBaseRefreshAll(SplineFont *UNUSED(foo)) { }
FontViewBaseReformatOne(FontViewBase * UNUSED (foo))2015 static void FontViewBaseReformatOne(FontViewBase *UNUSED(foo)) { }
FontViewBaseReformatAll(SplineFont * UNUSED (foo))2016 static void FontViewBaseReformatAll(SplineFont *UNUSED(foo)) { }
FontViewBaseLayerChanged(FontViewBase * UNUSED (foo))2017 static void FontViewBaseLayerChanged(FontViewBase *UNUSED(foo)) { }
FV_ToggleCharChanged(SplineChar * UNUSED (foo))2018 static void FV_ToggleCharChanged(SplineChar *UNUSED(foo)) { }
FVAny(void)2019 static FontViewBase *FVAny(void) { return fv_list; }
FontIsActive(SplineFont * sf)2020 static int  FontIsActive(SplineFont *sf) {
2021     FontViewBase *fv;
2022 
2023     for ( fv=fv_list; fv!=NULL; fv=fv->next )
2024 	if ( fv->sf == sf )
2025 return( true );
2026 
2027 return( false );
2028 }
2029 
FontOfFilename(const char * filename)2030 static SplineFont *FontOfFilename(const char *filename) {
2031     char buffer[1025];
2032     FontViewBase *fv;
2033 
2034     GFileGetAbsoluteName((char *) filename,buffer,sizeof(buffer));
2035     for ( fv=fv_list; fv!=NULL ; fv=fv->next ) {
2036 	if ( fv->sf->filename!=NULL && strcmp(fv->sf->filename,buffer)==0 )
2037 return( fv->sf );
2038 	else if ( fv->sf->origname!=NULL && strcmp(fv->sf->origname,buffer)==0 )
2039 return( fv->sf );
2040     }
2041 return( NULL );
2042 }
2043 
FVExtraEncSlots(FontViewBase * UNUSED (fv),int UNUSED (encmax))2044 static void FVExtraEncSlots(FontViewBase *UNUSED(fv), int UNUSED(encmax)) {
2045 }
2046 
FontViewBase_Close(FontViewBase * fv)2047 static void FontViewBase_Close(FontViewBase *fv) {
2048     if ( fv_list==fv )
2049 	fv_list = fv->next;
2050     else {
2051 	FontViewBase *n;
2052 	for ( n=fv_list; n->next!=fv; n=n->next );
2053 	n->next = fv->next;
2054     }
2055     FontViewFree(fv);
2056 }
2057 
FVB_ChangeDisplayBitmap(FontViewBase * fv,BDFFont * bdf)2058 static void FVB_ChangeDisplayBitmap(FontViewBase *fv, BDFFont *bdf) {
2059     fv->active_bitmap = bdf;
2060 }
2061 
FVB_ShowFilled(FontViewBase * fv)2062 static void FVB_ShowFilled(FontViewBase *fv) {
2063     fv->active_bitmap = NULL;
2064 }
2065 
FVB_ReattachCVs(SplineFont * UNUSED (old),SplineFont * UNUSED (new))2066 static void FVB_ReattachCVs(SplineFont *UNUSED(old), SplineFont *UNUSED(new)) {
2067 }
2068 
FVB_DeselectAll(FontViewBase * fv)2069 static void FVB_DeselectAll(FontViewBase *fv) {
2070     memset(fv->selected,0,fv->map->encmax);
2071 }
2072 
FVB_DisplayChar(FontViewBase * UNUSED (fv),int UNUSED (gid))2073 static void FVB_DisplayChar(FontViewBase *UNUSED(fv),int UNUSED(gid)) {
2074 }
2075 
SFB_CloseAllInstrs(SplineFont * UNUSED (sf))2076 static int SFB_CloseAllInstrs(SplineFont *UNUSED(sf)) {
2077 return( true );
2078 }
2079 
2080 struct fv_interface noui_fv = {
2081     FontViewBase_Create,
2082     _FontViewBaseCreate,
2083     FontViewBase_Close,
2084     FontViewBase_Free,
2085     FontViewBaseSetTitle,
2086     FontViewBaseSetTitles,
2087     FontViewBaseRefreshAll,
2088     FontViewBaseReformatOne,
2089     FontViewBaseReformatAll,
2090     FontViewBaseLayerChanged,
2091     FV_ToggleCharChanged,
2092     FontViewBaseWinInfo,
2093     FontIsActive,
2094     FVAny,
2095     FontViewBase_Append,
2096     FontOfFilename,
2097     FVExtraEncSlots,
2098     FVExtraEncSlots,
2099     FVB_ChangeDisplayBitmap,
2100     FVB_ShowFilled,
2101     FVB_ReattachCVs,
2102     FVB_DeselectAll,
2103     FVB_DisplayChar,
2104     FVB_DisplayChar,
2105     FVB_DisplayChar,
2106     SFB_CloseAllInstrs
2107 };
2108 
2109 struct fv_interface *fv_interface = &noui_fv;
2110 
FF_SetFVInterface(struct fv_interface * fvi)2111 void FF_SetFVInterface(struct fv_interface *fvi) {
2112     fv_interface = fvi;
2113 }
2114 
2115 
2116 /******************************************************************************/
NoGlyphs(struct metricsview * UNUSED (mv))2117 static int NoGlyphs(struct metricsview *UNUSED(mv)) {
2118 return( 0 );
2119 }
2120 
Nothing(struct metricsview * UNUSED (mv),int UNUSED (i))2121 static SplineChar *Nothing(struct metricsview *UNUSED(mv), int UNUSED(i)) {
2122 return( NULL );
2123 }
2124 
NoReKern(struct splinefont * UNUSED (sf))2125 static void NoReKern(struct splinefont *UNUSED(sf)) {
2126 }
2127 
NoReFeature(struct splinefont * UNUSED (sf))2128 static void NoReFeature(struct splinefont *UNUSED(sf)) {
2129 }
2130 
NoCloseAll(struct splinefont * UNUSED (sf))2131 static void NoCloseAll(struct splinefont *UNUSED(sf)) {
2132 }
2133 
2134 struct mv_interface noui_mv = {
2135     NoGlyphs,
2136     Nothing,
2137     NoReKern,
2138     NoReFeature,
2139     NoCloseAll
2140 };
2141 
2142 struct mv_interface *mv_interface = &noui_mv;
2143 
FF_SetMVInterface(struct mv_interface * mvi)2144 void FF_SetMVInterface(struct mv_interface *mvi) {
2145     mv_interface = mvi;
2146 }
2147 
2148