1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "savefont.h"
31 
32 #include "autohint.h"
33 #include "cvundoes.h"
34 #include "dumpbdf.h"
35 #include "dumppfa.h"
36 #include "fontforgevw.h"
37 #include "fvfonts.h"
38 #include "gfile.h"
39 #include "gio.h"
40 #include "gresource.h"
41 #include "macbinary.h"
42 #include "namelist.h"
43 #include "palmfonts.h"
44 #include "psfont.h"
45 #include "splinefill.h"
46 #include "splineoverlap.h"
47 #include "splinesaveafm.h"
48 #include "splineutil.h"
49 #include "svg.h"
50 #include "tottf.h"
51 #include "ustring.h"
52 #include "utype.h"
53 #include "winfonts.h"
54 #include "woff.h"
55 
56 #include <math.h>
57 #include <stdlib.h>
58 #include <string.h>
59 
60 int old_sfnt_flags = ttf_flag_otmode;
61 int old_ps_flags = ps_flag_afm|ps_flag_round;
62 int old_psotb_flags = ps_flag_afm;
63 
64 int oldformatstate = ff_pfb;
65 int oldbitmapstate = 0;
66 #if __Mac
67 const char *savefont_extensions[] = { ".pfa", ".pfb", ".res", "%s.pfb", ".pfa", ".pfb", ".pt3", ".ps",
68 	".cid", ".cff", ".cid.cff",
69 	".t42", ".t11",
70 	".ttf", ".ttf", ".suit", ".ttc", ".dfont", ".otf", ".otf.dfont", ".otf",
71 	".otf.dfont", ".svg", ".ufo", ".ufo2", ".ufo3", ".woff",
72 #ifdef FONTFORGE_CAN_USE_WOFF2
73 	".woff2",
74 #else
75         NULL,
76 #endif
77 	NULL };
78 const char *bitmapextensions[] = { "-*.bdf", ".ttf", ".dfont", ".ttf", ".otb", ".bmap", ".dfont", ".fon", "-*.fnt", ".pdb", "-*.pt3", ".none", NULL };
79 #else
80 // NOTE: The order here must match the fontformat enum
81 const char *savefont_extensions[] = { ".pfa", ".pfb", ".bin", "%s.pfb", ".pfa", ".pfb", ".pt3", ".ps",
82 	".cid", ".cff", ".cid.cff",
83 	".t42", ".t11",
84 	".ttf", ".ttf", ".ttf.bin", ".ttc", ".dfont", ".otf", ".otf.dfont", ".otf",
85 	".otf.dfont", ".svg",
86 	".ufo",
87 	".ufo2",
88 	".ufo3",
89 	".woff",
90 #ifdef FONTFORGE_CAN_USE_WOFF2
91 	".woff2",
92 #else
93         NULL,
94 #endif
95 NULL };
96 const char *bitmapextensions[] = { "-*.bdf", ".ttf", ".dfont", ".ttf", ".otb", ".bmap.bin", ".fon", "-*.fnt", ".pdb", "-*.pt3", ".none", NULL };
97 #endif
98 
WriteAfmFile(char * filename,SplineFont * sf,int formattype,EncMap * map,int flags,SplineFont * fullsf,int layer)99 static int WriteAfmFile(char *filename,SplineFont *sf, int formattype,
100 	EncMap *map, int flags, SplineFont *fullsf, int layer) {
101     char *buf = malloc(strlen(filename)+6), *pt, *pt2;
102     FILE *afm;
103     int ret;
104     int subtype = formattype;
105 
106     if ( (formattype==ff_mma || formattype==ff_mmb) && sf->mm!=NULL ) {
107 	sf = sf->mm->normal;
108 	subtype = ff_pfb;
109     }
110 
111     strcpy(buf,filename);
112     pt = strrchr(buf,'.');
113     if ( pt!=NULL && (pt2=strrchr(buf,'/'))!=NULL && pt<pt2 )
114 	pt = NULL;
115     if ( pt==NULL )
116 	strcat(buf,".afm");
117     else
118 	strcpy(pt,".afm");
119     ff_progress_change_line1(_("Saving AFM File"));
120     ff_progress_change_line2(buf);
121     afm = fopen(buf,"w");
122     if ( afm==NULL ) {
123 	free(buf);
124 return( false );
125     }
126     ret = AfmSplineFont(afm,sf,subtype,map,flags&ps_flag_afmwithmarks,fullsf,layer);
127     free(buf);
128     if ( fclose(afm)==-1 )
129 return( false );
130     if ( !ret )
131 return( false );
132 
133     if ( (formattype==ff_mma || formattype==ff_mmb) && sf->mm!=NULL ) {
134 	MMSet *mm = sf->mm;
135 	int i;
136 	for ( i=0; i<mm->instance_count; ++i ) {
137 	    sf = mm->instances[i];
138 	    buf = malloc(strlen(filename)+strlen(sf->fontname)+4+1);
139 	    strcpy(buf,filename);
140 	    pt = strrchr(buf,'/');
141 	    if ( pt==NULL ) pt = buf;
142 	    else ++pt;
143 	    strcpy(pt,sf->fontname);
144 	    strcat(pt,".afm");
145 	    ff_progress_change_line2(buf);
146 	    afm = fopen(buf,"w");
147 	    free(buf);
148 	    if ( afm==NULL )
149 return( false );
150 	    ret = AfmSplineFont(afm,sf,subtype,map,flags&ps_flag_afmwithmarks,NULL,layer);
151 	    if ( fclose(afm)==-1 )
152 return( false );
153 	    if ( !ret )
154 return( false );
155 	}
156 	buf = malloc(strlen(filename)+8);
157 
158 	strcpy(buf,filename);
159 	pt = strrchr(buf,'.');
160 	if ( pt!=NULL && (pt2=strrchr(buf,'/'))!=NULL && pt<pt2 )
161 	    pt = NULL;
162 	if ( pt==NULL )
163 	    strcat(buf,".amfm");
164 	else
165 	    strcpy(pt,".amfm");
166 	ff_progress_change_line2(buf);
167 	afm = fopen(buf,"w");
168 	free(buf);
169 	if ( afm==NULL )
170 return( false );
171 	ret = AmfmSplineFont(afm,mm,formattype,map,layer);
172 	if ( fclose(afm)==-1 )
173 return( false );
174     }
175 return( ret );
176 }
177 
WriteTfmFile(char * filename,SplineFont * sf,EncMap * map,int layer)178 static int WriteTfmFile(char *filename,SplineFont *sf, EncMap *map,int layer) {
179     char *buf = malloc(strlen(filename)+6), *pt, *pt2;
180     FILE *tfm, *enc;
181     int ret;
182     int i;
183     const char *encname;
184 
185     strcpy(buf,filename);
186     pt = strrchr(buf,'.');
187     if ( pt!=NULL && (pt2=strrchr(buf,'/'))!=NULL && pt<pt2 )
188 	pt = NULL;
189     if ( pt==NULL )
190 	strcat(buf,".tfm");
191     else
192 	strcpy(pt,".tfm");
193     ff_progress_change_line1(_("Saving TFM File"));
194     ff_progress_change_line2(buf);
195     ff_progress_next();	/* Forces a refresh */
196     tfm = fopen(buf,"wb");
197     if ( tfm==NULL )
198 return( false );
199     ret = TfmSplineFont(tfm,sf,map,layer);
200     if ( fclose(tfm)==-1 )
201 	ret = 0;
202 
203     pt = strrchr(buf,'.');
204     strcpy(pt,".enc");
205     enc = fopen(buf,"wb");
206     free(buf);
207     if ( enc==NULL )
208 return( false );
209 
210     encname=NULL;
211     if ( sf->subfontcnt==0 && map->enc!=&custom )
212 	encname = EncodingName(map->enc );
213     if ( encname==NULL )
214 	fprintf( enc, "/%s-Enc [\n", sf->fontname );
215     else
216 	fprintf( enc, "/%s [\n", encname );
217     for ( i=0; i<map->enccount && i<256; ++i ) {
218 	if ( map->map[i]==-1 || !SCWorthOutputting(sf->glyphs[map->map[i]]) )
219 	    fprintf( enc, " /.notdef" );
220 	else
221 	    fprintf( enc, " /%s", sf->glyphs[map->map[i]]->name );
222 	if ( (i&0xf)==0 )
223 	    fprintf( enc, "\t\t%% 0x%02x", i );
224 	putc('\n',enc);
225     }
226     while ( i<256 ) {
227 	fprintf( enc, " /.notdef" );
228 	if ( (i&0xf0)==0 )
229 	    fprintf( enc, "\t\t%% 0x%02x", i );
230 	putc('\n',enc);
231 	++i;
232     }
233     fprintf( enc, "] def\n" );
234 
235     if ( fclose(enc)==-1 )
236 	ret = 0;
237 return( ret );
238 }
239 
WriteOfmFile(char * filename,SplineFont * sf,EncMap * map,int layer)240 static int WriteOfmFile(char *filename,SplineFont *sf, EncMap *map,int layer) {
241     char *buf = malloc(strlen(filename)+6), *pt, *pt2;
242     FILE *tfm, *enc;
243     int ret;
244     int i;
245     const char *encname;
246     const char *texparamnames[] = { "SLANT", "SPACE", "STRETCH", "SHRINK", "XHEIGHT", "QUAD", "EXTRASPACE", NULL };
247 
248     strcpy(buf,filename);
249     pt = strrchr(buf,'.');
250     if ( pt!=NULL && (pt2=strrchr(buf,'/'))!=NULL && pt<pt2 )
251 	pt = NULL;
252     if ( pt==NULL )
253 	strcat(buf,".ofm");
254     else
255 	strcpy(pt,".ofm");
256     ff_progress_change_line1(_("Saving OFM File"));
257     ff_progress_change_line2(buf);
258     ff_progress_next();	/* Forces a refresh */
259     tfm = fopen(buf,"wb");
260     if ( tfm==NULL )
261 return( false );
262     ret = OfmSplineFont(tfm,sf,map,layer);
263     if ( fclose(tfm)==-1 )
264 	ret = 0;
265 
266     pt = strrchr(buf,'.');
267     strcpy(pt,".cfg");
268     enc = fopen(buf,"wb");
269     free(buf);
270     if ( enc==NULL )
271 return( false );
272 
273     fprintf( enc, "VTITLE %s\n", sf->fontname );
274     fprintf( enc, "FAMILY %s\n", sf->familyname );
275     encname=NULL;
276     if ( sf->subfontcnt==0 && map->enc!=&custom )
277 	encname = EncodingName(map->enc );
278     fprintf( enc, "CODINGSCHEME %s\n", encname==NULL?encname:"FONT-SPECIFIC" );
279 
280     /* OfmSplineFont has already called TeXDefaultParams, so we don't have to */
281     fprintf( enc, "EPSILON 0.090\n" );		/* I have no idea what this means */
282     for ( i=0; texparamnames[i]!=NULL; ++i )
283 	fprintf( enc, "%s %g\n", texparamnames[i], sf->texdata.params[i]/(double) (1<<20) );
284 
285     for ( i=0; i<map->enccount && i<65536; ++i ) {
286 	if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]]) )
287 	    fprintf( enc, "%04X N %s\n", i, sf->glyphs[map->map[i]]->name );
288     }
289 
290     if ( fclose(enc)==-1 )
291 	ret = 0;
292 return( ret );
293 }
294 
295 #ifndef FONTFORGE_CONFIG_WRITE_PFM
296 static
297 #endif
WritePfmFile(char * filename,SplineFont * sf,EncMap * map,int layer)298 int WritePfmFile(char *filename,SplineFont *sf, EncMap *map,int layer) {
299     char *buf = malloc(strlen(filename)+6), *pt, *pt2;
300     FILE *pfm;
301     int ret;
302 
303     strcpy(buf,filename);
304     pt = strrchr(buf,'.');
305     if ( pt!=NULL && (pt2=strrchr(buf,'/'))!=NULL && pt<pt2 )
306 	pt = NULL;
307     if ( pt==NULL )
308 	strcat(buf,".pfm");
309     else
310 	strcpy(pt,".pfm");
311     ff_progress_change_line2(buf);
312     pfm = fopen(buf,"wb");
313     free(buf);
314     if ( pfm==NULL )
315 return( false );
316     ret = PfmSplineFont(pfm,sf,map,layer);
317     if ( fclose(pfm)==-1 )
318 return( 0 );
319 return( ret );
320 }
321 
WriteFontLog(char * filename,SplineFont * sf)322 static int WriteFontLog(char *filename,SplineFont *sf) {
323     char *buf = malloc(strlen(filename)+12), *pt;
324     FILE *flog;
325 
326     if ( sf->fontlog==NULL || *sf->fontlog=='\0' ) {
327       free(buf);
328 return( true );
329     }
330 
331     strcpy(buf,filename);
332     pt = strrchr(buf,'/');
333     if ( pt==NULL )
334 	strcat(buf,"FONTLOG.txt");
335     else
336 	strcpy(pt+1,"FONTLOG.txt");
337     flog = fopen(buf,"a"); // We changed this to append if the file exists.
338     free(buf);
339     if ( flog==NULL )
340 return( false );
341 
342     for ( pt=sf->fontlog; *pt; ++pt )
343 	putc(*pt,flog);
344     if ( fclose(flog)!=0 )
345 return( false );
346 
347 return( true );
348 }
349 
WriteBitmaps(char * filename,SplineFont * sf,int32 * sizes,int res,int bf,EncMap * map)350 static int WriteBitmaps(char *filename,SplineFont *sf, int32 *sizes,int res,
351 	int bf, EncMap *map) {
352     char *buf = malloc(strlen(filename)+30), *pt, *pt2;
353     int i;
354     BDFFont *bdf;
355     const char *ext;
356 
357     if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
358 
359     for ( i=0; sizes[i]!=0; ++i );
360     ff_progress_change_stages(i);
361     for ( i=0; sizes[i]!=0; ++i ) {
362 	for ( bdf=sf->bitmaps; bdf!=NULL &&
363 		(bdf->pixelsize!=(sizes[i]&0xffff) || BDFDepth(bdf)!=(sizes[i]>>16));
364 		bdf=bdf->next );
365 	if ( bdf==NULL ) {
366 	    ff_post_notice(_("Missing Bitmap"),_("Attempt to save a pixel size that has not been created (%d@%d)"),
367 		    sizes[i]&0xffff, sizes[i]>>16);
368 	    free(buf);
369 return( false );
370 	}
371 
372 	if ( bf==bf_ptype3 && bdf->clut!=NULL ) {
373 	    ff_post_notice(_("Missing Bitmap"),_("Currently, FontForge only supports bitmap (not bytemap) type3 output") );
374 return( false );
375 	}
376 
377 	strcpy(buf,filename);
378 	pt = strrchr(buf,'.');
379 	if ( pt!=NULL && (pt2=strrchr(buf,'/'))!=NULL && pt<pt2 )
380 	    pt = NULL;
381 	if ( pt==NULL )
382 	    pt = buf+strlen(buf);
383 	if ( strcmp(pt-4,".otf.dfont")==0 || strcmp(pt-4,".ttf.bin")==0 ) pt-=4;
384 	if ( pt-2>buf && pt[-2]=='-' && pt[-1]=='*' )
385 	    pt -= 2;
386 	ext = bf==bf_bdf ? ".bdf" : bf==bf_ptype3 ? ".pt3" : ".fnt";
387 	if ( bdf->clut==NULL )
388 	    sprintf( pt, "-%d%s", bdf->pixelsize, ext );
389 	else
390 	    sprintf( pt, "-%d@%d%s", bdf->pixelsize, BDFDepth(bdf), ext );
391 
392 	ff_progress_change_line2(buf);
393 	if ( bf==bf_bdf )
394 	    BDFFontDump(buf,bdf,map,res);
395 	else if ( bf==bf_ptype3 )
396 	    PSBitmapDump(buf,bdf,map);
397 	else if ( bf==bf_fnt )
398 	    FNTFontDump(buf,bdf,map,res);
399 	else
400 	    IError( "Unexpected font type" );
401 	ff_progress_next_stage();
402     }
403     free(buf);
404 return( true );
405 }
406 
ParseWernerSFDFile(char * wernerfilename,SplineFont * sf,int * max,char *** _names,EncMap * map)407 static int32 *ParseWernerSFDFile(char *wernerfilename,SplineFont *sf,int *max,
408 	char ***_names, EncMap *map) {
409     /* one entry for each char, >=1 => that subfont, 0=>not mapped, -1 => end of char mark */
410     int cnt=0, subfilecnt=0, thusfar;
411     int k, warned = false;
412     int r1,r2,i,modi;
413     SplineFont *_sf;
414     int32 *mapping;
415     FILE *file;
416     char buffer[200], *bpt;
417     char *end, *pt;
418     char *orig;
419     struct remap *remap;
420     char **names;
421     int loop;
422     static const char *pfaeditflag = "SplineFontDB:";
423 
424     file = fopen(wernerfilename,"r");
425     if ( file==NULL ) {
426 	ff_post_error(_("No Sub Font Definition file"),_("No Sub Font Definition file"));
427 return( NULL );
428     }
429 
430     k = 0;
431     do {
432 	_sf = sf->subfontcnt==0 ? sf : sf->subfonts[k++];
433 	if ( _sf->glyphcnt>cnt ) cnt = _sf->glyphcnt;
434     } while ( k<sf->subfontcnt );
435 
436     mapping = calloc(cnt+1,sizeof(int32));
437     memset(mapping,-1,(cnt+1)*sizeof(int32));
438     mapping[cnt] = -2;
439     *max = 0;
440 
441     while ( fgets(buffer,sizeof(buffer),file)!=NULL )
442 	++subfilecnt;
443     names = malloc((subfilecnt+1)*sizeof(char *));
444 
445     rewind(file);
446     subfilecnt = 0;
447     while ( fgets(buffer,sizeof(buffer),file)!=NULL ) {
448 	if ( strncmp(buffer,pfaeditflag,strlen(pfaeditflag))== 0 ) {
449 	    ff_post_error(_("Wrong type of SFD file"),_("This looks like one of FontForge's SplineFont DataBase files.\nNot one of TeX's SubFont Definition files.\nAn unfortunate confusion of extensions."));
450 	    free(mapping);
451 return( NULL );
452 	}
453 	pt=buffer+strlen(buffer)-1;
454 	bpt = buffer;
455 	if (( *pt!='\n' && *pt!='\r') || (pt>buffer && pt[-1]=='\\') ||
456 		(pt>buffer+1 && pt[-2]=='\\' && isspace(pt[-1])) ) {
457 	    bpt = copy("");
458 	    for (;;) {
459 		loop = false;
460 		if (( *pt!='\n' && *pt!='\r') || (pt>buffer && pt[-1]=='\\') ||
461 			(pt>buffer+1 && pt[-2]=='\\' && isspace(pt[-1])) )
462 		    loop = true;
463 		if ( *pt=='\n' || *pt=='\r') {
464 		    if ( pt[-1]=='\\' )
465 			pt[-1] = '\0';
466 		    else if ( pt[-2]=='\\' )
467 			pt[-2] = '\0';
468 		}
469 		bpt = realloc(bpt,strlen(bpt)+strlen(buffer)+10);
470 		strcat(bpt,buffer);
471 		if ( !loop )
472 	    break;
473 		if ( fgets(buffer,sizeof(buffer),file)==NULL )
474 	    break;
475 		pt=buffer+strlen(buffer)-1;
476 	    }
477 	}
478 	if ( bpt[0]=='#' || bpt[0]=='\0' || isspace(bpt[0]))
479     continue;
480 	for ( pt = bpt; !isspace(*pt) && *pt!='\0'; ++pt );
481 	if ( *pt=='\0' || *pt=='\r' || *pt=='\n' )
482     continue;
483 	names[subfilecnt] = copyn(bpt,pt-bpt);
484 	if ( subfilecnt>*max ) *max = subfilecnt;
485 	end = pt;
486 	thusfar = 0;
487 	while ( *end!='\0' ) {
488 	    while ( isspace(*end)) ++end;
489 	    if ( *end=='\0' )
490 	break;
491 	    orig = end;
492 	    r1 = strtoul(end,&end,0);
493 	    if ( orig==end )
494 	break;
495 	    while ( isspace(*end)) ++end;
496 	    if ( *end==':' ) {
497 		if ( r1>=256 || r1<0)
498 		    LogError( _("Bad offset: %d for subfont %s\n"), r1, names[subfilecnt]);
499 		else
500 		    thusfar = r1;
501 		r1 = strtoul(end+1,&end,0);
502 	    }
503 	    if ( *end=='_' || *end=='-' )
504 		r2 = strtoul(end+1,&end,0);
505 	    else
506 		r2 = r1;
507 	    for ( i=r1; i<=r2; ++i ) {
508 		modi = i;
509 		if ( map->remap!=NULL ) {
510 		    for ( remap = map->remap; remap->infont!=-1; ++remap ) {
511 			if ( i>=(int)remap->firstenc && i<=(int)remap->lastenc ) {
512 			    modi = i-remap->firstenc + remap->infont;
513 		    break;
514 			}
515 		    }
516 		}
517 		if ( modi<map->enccount )
518 		    modi = map->map[modi];
519 		else if ( sf->subfontcnt!=0 )
520 		    modi = modi;
521 		else
522 		    modi = -1;
523 		if ( modi<cnt && modi!=-1 ) {
524 		    if ( mapping[modi]!=-1 && !warned ) {
525 			if (( i==0xffff || i==0xfffe ) &&
526 				(map->enc->is_unicodebmp || map->enc->is_unicodefull))
527 			    /* Not a character anyway. just ignore it */;
528 			else {
529 			    LogError( _("Warning: Encoding %d (0x%x) is mapped to at least two locations (%s@0x%02x and %s@0x%02x)\n Only one will be used here.\n"),
530 				    i, i, names[subfilecnt], thusfar, names[(mapping[modi]>>8)], mapping[modi]&0xff );
531 			    warned = true;
532 			}
533 		    }
534 		    mapping[modi] = (subfilecnt<<8) | thusfar;
535 		}
536 		thusfar++;
537 	    }
538 	}
539 	if ( thusfar>256 )
540 	    LogError( _("More than 256 entries in subfont %s\n"), names[subfilecnt] );
541 	++subfilecnt;
542 	if ( bpt!=buffer )
543 	    free(bpt);
544     }
545     names[subfilecnt]=NULL;
546     *_names = names;
547     fclose(file);
548 return( mapping );
549 }
550 
SaveSubFont(SplineFont * sf,char * newname,int32 * mapping,int subfont,char ** names,int layer)551 static int SaveSubFont(SplineFont *sf,char *newname,
552 	int32 *mapping, int subfont, char **names,int layer) {
553     SplineFont temp;
554     SplineChar *chars[256], **newchars;
555     SplineFont *_sf;
556     int k, i, used, base, extras;
557     char *filename;
558     char *spt, *pt, buf[8];
559     RefChar *ref;
560     int err = 0;
561     enum fontformat subtype = strstr(newname,".pfa")!=NULL ? ff_pfa : ff_pfb ;
562     EncMap encmap;
563     int32 _mapping[256], _backmap[256];
564 
565     memset(&encmap,0,sizeof(encmap));
566     encmap.enccount = encmap.encmax = encmap.backmax = 256;
567     encmap.map = _mapping; encmap.backmap = _backmap;
568     memset(_mapping,-1,sizeof(_mapping));
569     memset(_backmap,-1,sizeof(_backmap));
570     encmap.enc = &custom;
571 
572     temp = *sf;
573     temp.glyphcnt = 0;
574     temp.glyphmax = 256;
575     temp.glyphs = chars;
576     temp.bitmaps = NULL;
577     temp.subfonts = NULL;
578     temp.subfontcnt = 0;
579     temp.uniqueid = 0;
580     memset(chars,0,sizeof(chars));
581     temp.glyphnames = NULL;
582     used = 0;
583     for ( i=0; mapping[i]!=-2; ++i ) if ( (mapping[i]>>8)==subfont ) {
584 	k = 0;
585 	do {
586 	    _sf = sf->subfontcnt==0 ? sf : sf->subfonts[k++];
587 	    if ( i<_sf->glyphcnt && _sf->glyphs[i]!=NULL )
588 	break;
589 	} while ( k<sf->subfontcnt );
590 	if ( temp.glyphcnt<256 ) {
591 	    if ( i<_sf->glyphcnt ) {
592 		if ( _sf->glyphs[i]!=NULL ) {
593 		    _sf->glyphs[i]->parent = &temp;
594 		    _sf->glyphs[i]->orig_pos = temp.glyphcnt;
595 		    chars[temp.glyphcnt] = _sf->glyphs[i];
596 		    _mapping[mapping[i]&0xff] = temp.glyphcnt;
597 		    _backmap[temp.glyphcnt] = mapping[i]&0xff;
598 		    ++temp.glyphcnt;
599 		    ++used;
600 		}
601 	    }
602 	}
603     }
604     if ( used==0 )
605 return( 0 );
606 
607     /* check for any references to things outside this subfont and add them */
608     /*  as unencoded chars */
609     /* We could just replace with splines, I suppose but that would make */
610     /*  korean fonts huge */
611     for (;;) {
612 	extras = 0;
613 	for ( i=0; i<temp.glyphcnt; ++i ) if ( temp.glyphs[i]!=NULL ) {
614 	    for ( ref=temp.glyphs[i]->layers[ly_fore].refs; ref!=NULL; ref=ref->next )
615 		if ( ref->sc->parent!=&temp )
616 		    ++extras;
617 	}
618 	if ( extras == 0 )
619     break;
620 	newchars = calloc(temp.glyphcnt+extras,sizeof(SplineChar *));
621 	memcpy(newchars,temp.glyphs,temp.glyphcnt*sizeof(SplineChar *));
622 	if ( temp.glyphs!=chars ) free(temp.glyphs );
623 	base = temp.glyphcnt;
624 	temp.glyphs = newchars;
625 	extras = 0;
626 	for ( i=0; i<base; ++i ) if ( temp.glyphs[i]!=NULL ) {
627 	    for ( ref=temp.glyphs[i]->layers[ly_fore].refs; ref!=NULL; ref=ref->next )
628 		if ( ref->sc->parent!=&temp ) {
629 		    temp.glyphs[base+extras] = ref->sc;
630 		    ref->sc->parent = &temp;
631 		    ref->sc->orig_pos = base+extras++;
632 		}
633 	}
634 	temp.glyphcnt += extras;	/* this might be a slightly different value from that found before if some references get reused. N'importe */
635 	temp.glyphmax = temp.glyphcnt;
636     }
637 
638     filename = malloc(strlen(newname)+strlen(names[subfont])+10);
639     strcpy(filename,newname);
640     pt = strrchr(filename,'.');
641     spt = strrchr(filename,'/');
642     if ( spt==NULL ) spt = filename; else ++spt;
643     if ( pt>spt )
644 	*pt = '\0';
645     pt = strstr(spt,"%d");
646     if ( pt==NULL )
647 	pt = strstr(spt,"%s");
648     if ( pt==NULL )
649 	strcat(filename,names[subfont]);
650     else {
651 	int len = strlen(names[subfont]);
652 	int l;
653 	if ( len>2 ) {
654 	    for ( l=strlen(pt); l>=2 ; --l )
655 		pt[l+len-2] = pt[l];
656 	} else if ( len<2 )
657 	    strcpy(pt+len,pt+2);
658 	memcpy(pt,names[subfont],len);
659     }
660     temp.fontname = copy(spt);
661     temp.fullname = malloc(strlen(temp.fullname)+strlen(names[subfont])+3);
662     strcpy(temp.fullname,sf->fullname);
663     strcat(temp.fullname," ");
664     strcat(temp.fullname,names[subfont]);
665     strcat(spt,subtype==ff_pfb ? ".pfb" : ".pfa" );
666     ff_progress_change_line2(filename);
667 
668     if ( sf->xuid!=NULL ) {
669 	sprintf( buf, "%d", subfont );
670 	temp.xuid = malloc(strlen(sf->xuid)+strlen(buf)+5);
671 	strcpy(temp.xuid,sf->xuid);
672 	pt = temp.xuid + strlen( temp.xuid )-1;
673 	while ( pt>temp.xuid && *pt==' ' ) --pt;
674 	if ( *pt==']' ) --pt;
675 	*pt = ' ';
676 	strcpy(pt+1,buf);
677 	strcat(pt,"]");
678     }
679 
680     err = !WritePSFont(filename,&temp,subtype,old_ps_flags,&encmap,sf,layer);
681     if ( err )
682 	ff_post_error(_("Save Failed"),_("Save Failed"));
683     if ( !err && (old_ps_flags&ps_flag_afm) && ff_progress_next_stage()) {
684 	if ( !WriteAfmFile(filename,&temp,oldformatstate,&encmap,old_ps_flags,sf,layer)) {
685 	    ff_post_error(_("Afm Save Failed"),_("Afm Save Failed"));
686 	    err = true;
687 	}
688     }
689     if ( !err && (old_ps_flags&ps_flag_tfm) ) {
690 	if ( !WriteTfmFile(filename,&temp,&encmap,layer)) {
691 	    ff_post_error(_("Tfm Save Failed"),_("Tfm Save Failed"));
692 	    err = true;
693 	}
694     }
695     /* ??? Bitmaps */
696     if ( !ff_progress_next_stage())
697 	err = -1;
698 
699     if ( temp.glyphs!=chars )
700 	free(temp.glyphs);
701     GlyphHashFree( &temp );
702     free( temp.xuid );
703     free( temp.fontname );
704     free( temp.fullname );
705     free( filename );
706 
707     /* SaveSubFont messes up the parent and orig_pos fields. Fix 'em up */
708     /* Do this after every save, else afm,tfm files might produce extraneous kerns */
709     k = 0;
710     do {
711 	_sf = sf->subfontcnt==0 ? sf : sf->subfonts[k++];
712 	for ( i=0; i<_sf->glyphcnt; ++i ) if ( _sf->glyphs[i]!=NULL ) {
713 	    _sf->glyphs[i]->parent = _sf;
714 	    _sf->glyphs[i]->orig_pos = i;
715 	}
716     } while ( k<sf->subfontcnt );
717 
718 return( err );
719 }
720 
721 /* ttf2tfm supports multiple sfd files. I do not. */
WriteMultiplePSFont(SplineFont * sf,char * newname,int32 * sizes,char * wernerfilename,EncMap * map,int layer)722 static int WriteMultiplePSFont(SplineFont *sf,char *newname,int32 *sizes,
723 	char *wernerfilename,EncMap *map, int layer) {
724     int err=0, tofree=false, max, filecnt;
725     int32 *mapping;
726     char *path;
727     int i;
728     char **names;
729     char *pt;
730 
731     pt = strrchr(newname,'.');
732     if ( pt==NULL ||
733 	    (strcmp(pt,".pfa")!=0 && strcmp(pt,".pfb")!=0 && strcmp(pt,".mult")!=0)) {
734 	ff_post_error(_("Bad Extension"),_("You must specify a standard type1 extension (.pfb or .pfa)"));
735 return( 0 );
736     }
737     if ( wernerfilename==NULL )
738 return( 0 );
739     mapping = ParseWernerSFDFile(wernerfilename,sf,&max,&names,map);
740     if ( tofree ) free(wernerfilename);
741     if ( mapping==NULL )
742 return( 1 );
743 
744     if ( sf->cidmaster!=NULL )
745 	sf = sf->cidmaster;
746 
747     filecnt = 1;
748     if ( (old_ps_flags&ps_flag_afm) )
749 	filecnt = 2;
750     path = def2utf8_copy(newname);
751     ff_progress_start_indicator(10,_("Saving font"),
752 	    _("Saving Multiple PostScript Fonts"),
753 	    path,256,(max+1)*filecnt );
754     free(path);
755 
756     for ( i=0; i<=max && !err; ++i )
757 	err = SaveSubFont(sf,newname,mapping,i,names,layer);
758 
759     free(mapping);
760     for ( i=0; names[i]!=NULL; ++i ) free(names[i]);
761     free(names);
762     free( sizes );
763     ff_progress_end_indicator();
764     if ( !err )
765 	SavePrefs(true);
766 return( err );
767 }
768 
CheckIfTransparent(SplineFont * sf)769 int CheckIfTransparent(SplineFont *sf) {
770     /* Type3 doesn't support translucent fills */
771     int i,j;
772     char *buts[3];
773     buts[0] = _("_Yes");
774     buts[1] = _("_Cancel");
775     buts[2] = NULL;
776 
777     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
778 	SplineChar *sc = sf->glyphs[i];
779 	for ( j=ly_fore; j<sc->layer_cnt; ++j ) {
780 	    if ( sc->layers[j].fill_brush.opacity!=1 || sc->layers[j].stroke_pen.brush.opacity!=1 ) {
781 		if ( ff_ask(_("Bad Drawing Operation"),(const char **) buts,0,1,_("This font contains at least one translucent layer, but type3 does not support that (anything translucent or transparent is treated as opaque). Do you want to proceed anyway?"))==1 )
782 return( true );
783 
784 return( false );
785 	    }
786 	}
787     }
788 return( false );
789 }
790 
_DoSave(SplineFont * sf,char * newname,int32 * sizes,int res,EncMap * map,char * subfontdefinition,int layer)791 int _DoSave(SplineFont *sf,char *newname,int32 *sizes,int res,
792 	EncMap *map, char *subfontdefinition,int layer) {
793     char *path;
794     int err=false;
795     int iscid = oldformatstate==ff_cid || oldformatstate==ff_cffcid ||
796 	    oldformatstate==ff_otfcid || oldformatstate==ff_otfciddfont;
797     int flags = 0;
798     int tmpstore = 0;
799 
800     if ( oldformatstate == ff_multiple )
801 return( WriteMultiplePSFont(sf,newname,sizes,subfontdefinition,map,layer));
802 
803     if ( oldformatstate<=ff_cffcid )
804 	flags = old_ps_flags;
805     else if ( oldformatstate<=ff_ttfdfont )
806 	flags = old_sfnt_flags;
807     else if ( oldformatstate!=ff_none )
808 	flags = old_sfnt_flags;
809     else
810 	flags = old_sfnt_flags&~(ttf_flag_ofm);
811     if ( oldformatstate<=ff_cffcid && oldbitmapstate==bf_otb )
812 	flags = old_psotb_flags;
813 
814     path = def2utf8_copy(newname);
815     ff_progress_start_indicator(10,_("Saving font"),
816 		oldformatstate==ff_ttf || oldformatstate==ff_ttfsym ||
817 		     oldformatstate==ff_ttfmacbin ?_("Saving TrueType Font") :
818 		 oldformatstate==ff_otf || oldformatstate==ff_otfdfont ?_("Saving OpenType Font"):
819 		 oldformatstate==ff_cid || oldformatstate==ff_cffcid ||
820 		  oldformatstate==ff_otfcid || oldformatstate==ff_otfciddfont ?_("Saving CID keyed font") :
821 		  oldformatstate==ff_mma || oldformatstate==ff_mmb ?_("Saving multi-master font") :
822 		  oldformatstate==ff_svg ?_("Saving SVG font") :
823 		  oldformatstate==ff_ufo ?_("Saving Unified Font Object") :
824 		  oldformatstate==ff_ufo2 ?_("Saving Unified Font Object 2") :
825 		  oldformatstate==ff_ufo3 ?_("Saving Unified Font Object 3") :
826 		 _("Saving PostScript Font"),
827 	    path,sf->glyphcnt,1);
828     free(path);
829     if ( oldformatstate!=ff_none ) {
830 	int oerr = 0;
831 	int bmap = oldbitmapstate;
832 	if ( bmap==bf_otb ) bmap = bf_none;
833 	if ( !oerr ) switch ( oldformatstate ) {
834 	  case ff_mma: case ff_mmb:
835 	    sf = sf->mm->instances[0];
836 	  case ff_pfa: case ff_pfb: case ff_ptype3: case ff_ptype0:
837 	  case ff_cid:
838 	  case ff_type42: case ff_type42cid:
839 	    if ( sf->multilayer && CheckIfTransparent(sf))
840 return( true );
841 	    oerr = !WritePSFont(newname,sf,oldformatstate,flags,map,NULL,layer);
842 	  break;
843 	  case ff_ttf: case ff_ttfsym: case ff_otf: case ff_otfcid:
844 	  case ff_cff: case ff_cffcid:
845 	    oerr = !WriteTTFFont(newname,sf,oldformatstate,sizes,bmap,
846 		flags,map,layer);
847 	  break;
848 	  case ff_woff:
849 	    oerr = !WriteWOFFFont(newname,sf,oldformatstate,sizes,bmap,
850 		flags,map,layer);
851 	  break;
852 #ifdef FONTFORGE_CAN_USE_WOFF2
853 	  case ff_woff2:
854 	    oerr = !WriteWOFF2Font(newname,sf,oldformatstate,sizes,bmap,
855 		flags,map,layer);
856 	  break;
857 #endif
858 	  case ff_pfbmacbin:
859 	    oerr = !WriteMacPSFont(newname,sf,oldformatstate,flags,map,layer);
860 	  break;
861 	  case ff_ttfmacbin: case ff_ttfdfont: case ff_otfdfont: case ff_otfciddfont:
862 	    oerr = !WriteMacTTFFont(newname,sf,oldformatstate,sizes,
863 		    bmap,flags,map,layer);
864 	  break;
865 	  case ff_svg:
866 	    oerr = !WriteSVGFont(newname,sf,oldformatstate,flags,map,layer);
867 	  break;
868 	  case ff_ufo2:
869 	    tmpstore = sf->preferred_kerning; // We toggle this flag in order to force native kerning output.
870 	    if (flags & ttf_native_kern) sf->preferred_kerning = 1; // 1 flags native kerning.
871 	    sf->preferred_kerning |= 4; // 4 flags old-style naming for the starting name in UFONameKerningClasses.
872 	    oerr = !WriteUFOFont(newname,sf,oldformatstate,flags,map,layer,2);
873 	    if (flags & ttf_native_kern) sf->preferred_kerning = tmpstore;
874 	  break;
875 	  case ff_ufo:
876 	  case ff_ufo3:
877 	    tmpstore = sf->preferred_kerning; // We toggle this flag in order to force native kerning output.
878 	    if (flags & ttf_native_kern) sf->preferred_kerning = 1; // 1 flags native kerning.
879 	    oerr = !WriteUFOFont(newname,sf,oldformatstate,flags,map,layer,3);
880 	    if (flags & ttf_native_kern) sf->preferred_kerning = tmpstore;
881 	  break;
882 	  default:
883 	  break;
884 	}
885 	if ( oerr ) {
886 	    ff_post_error(_("Save Failed"),_("Save Failed"));
887 	    err = true;
888 	}
889     }
890     if ( !err && (flags&ps_flag_tfm) ) {
891 	if ( !WriteTfmFile(newname,sf,map,layer)) {
892 	    ff_post_error(_("Tfm Save Failed"),_("Tfm Save Failed"));
893 	    err = true;
894 	}
895     }
896     if ( !err && (flags&ttf_flag_ofm) ) {
897 	if ( !WriteOfmFile(newname,sf,map,layer)) {
898 	    ff_post_error(_("Ofm Save Failed"),_("Ofm Save Failed"));
899 	    err = true;
900 	}
901     }
902     if ( !err && (flags&ps_flag_afm) ) {
903 	ff_progress_increment(-sf->glyphcnt);
904 	if ( !WriteAfmFile(newname,sf,oldformatstate,map,flags,NULL,layer)) {
905 	    ff_post_error(_("Afm Save Failed"),_("Afm Save Failed"));
906 	    err = true;
907 	}
908     }
909     if ( !err && (flags&ps_flag_outputfontlog) ) {
910 	if ( !WriteFontLog(newname,sf)) {
911 	    ff_post_error(_("FontLog Save Failed"),_("FontLog Save Failed"));
912 	    err = true;
913 	}
914     }
915     if ( !err && (flags&ps_flag_pfm) && !iscid ) {
916 	ff_progress_change_line1(_("Saving PFM File"));
917 	ff_progress_increment(-sf->glyphcnt);
918 	if ( !WritePfmFile(newname,sf,map,layer)) {
919 	    ff_post_error(_("Pfm Save Failed"),_("Pfm Save Failed"));
920 	    err = true;
921 	}
922     }
923     if ( oldbitmapstate==bf_otb || oldbitmapstate==bf_sfnt_ms ) {
924 	char *temp = newname;
925 	if ( newname[strlen(newname)-1]=='.' ) {
926 	    temp = malloc(strlen(newname)+8);
927 	    strcpy(temp,newname);
928 	    strcat(temp,oldbitmapstate==bf_otb ? "otb" : "ttf" );
929 	}
930 	if ( !WriteTTFFont(temp,sf,ff_none,sizes,oldbitmapstate,flags,map,layer) )
931 	    err = true;
932 	if ( temp!=newname )
933 	    free(temp);
934     } else if ( oldbitmapstate==bf_sfnt_dfont ) {
935 	char *temp = newname;
936 	if ( newname[strlen(newname)-1]=='.' ) {
937 	    temp = malloc(strlen(newname)+8);
938 	    strcpy(temp,newname);
939 	    strcat(temp,"dfont");
940 	}
941 	if ( !WriteMacTTFFont(temp,sf,ff_none,sizes,oldbitmapstate,flags,map,layer) )
942 	    err = true;
943 	if ( temp!=newname )
944 	    free(temp);
945     } else if ( (oldbitmapstate==bf_bdf || oldbitmapstate==bf_fnt ||
946 	    oldbitmapstate==bf_ptype3 ) && !err ) {
947 	ff_progress_change_line1(_("Saving Bitmap Font(s)"));
948 	ff_progress_increment(-sf->glyphcnt);
949 	if ( !WriteBitmaps(newname,sf,sizes,res,oldbitmapstate,map))
950 	    err = true;
951     } else if ( oldbitmapstate==bf_fon && !err ) {
952 	if ( !FONFontDump(newname,sf,sizes,res,map))
953 	    err = true;
954     } else if ( oldbitmapstate==bf_palm && !err ) {
955 	if ( !WritePalmBitmaps(newname,sf,sizes,map))
956 	    err = true;
957     } else if ( (oldbitmapstate==bf_nfntmacbin /*|| oldbitmapstate==bf_nfntdfont*/) &&
958 	    !err ) {
959 	if ( !WriteMacBitmaps(newname,sf,sizes,false/*oldbitmapstate==bf_nfntdfont*/,map))
960 	    err = true;
961     }
962     free( sizes );
963     ff_progress_end_indicator();
964     if ( !err )
965 	SavePrefs(true);
966 return( err );
967 }
968 
PrepareUnlinkRmOvrlp(SplineFont * sf,const char * filename,int layer)969 void PrepareUnlinkRmOvrlp(SplineFont *sf,const char *filename,int layer) {
970     int gid;
971     SplineChar *sc;
972     RefChar *ref, *refnext;
973     int old_nwui = no_windowing_ui, old_maxundoes = maxundoes;
974 
975 #if !defined(_NO_PYTHON)
976     PyFF_CallDictFunc(sf->python_temporary,"generateFontPostHook","fs",sf->fv,filename);
977 #endif
978 
979     if ( maxundoes==0 ) maxundoes = 1;		/* Force undoes */
980 
981     for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL && sc->unlink_rm_ovrlp_save_undo ) {
982 	if ( autohint_before_generate && sc!=NULL &&
983 		sc->changedsincelasthinted && !sc->manualhints ) {
984 	    no_windowing_ui = true;
985 	    SplineCharAutoHint(sc,layer,NULL);	/* Do this now, else we get an unwanted undo on the stack from hinting */
986 	}
987 	no_windowing_ui = false;
988 	SCPreserveLayer(sc,layer,false);
989 	no_windowing_ui = true;			/* Clustering wants to create an undo that I don't need */
990 	for ( ref= sc->layers[layer].refs; ref!=NULL; ref=refnext ) {
991 	    refnext = ref->next;
992 	    SCRefToSplines(sc,ref,layer);
993 	}
994 #if 0
995 	// We await testing on the necessity of this operation.
996 	SCRoundToCluster(sc,layer,false,.03,.12);
997 #endif // 0
998 	sc->layers[layer].splines = SplineSetRemoveOverlap(sc,sc->layers[layer].splines,over_remove);
999 	no_windowing_ui = false;
1000 	if ( !sc->manualhints )
1001 	    sc->changedsincelasthinted = false;
1002     }
1003     no_windowing_ui = old_nwui;
1004     maxundoes = old_maxundoes;
1005 }
1006 
RestoreUnlinkRmOvrlp(SplineFont * sf,const char * filename,int layer)1007 void RestoreUnlinkRmOvrlp(SplineFont *sf,const char *filename,int layer) {
1008     int gid;
1009     SplineChar *sc;
1010 
1011     for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL && sc->unlink_rm_ovrlp_save_undo ) {
1012 	SCDoUndo(sc,layer);
1013 	if ( !sc->manualhints )
1014 	    sc->changedsincelasthinted = false;
1015     }
1016 #if !defined(_NO_PYTHON)
1017     PyFF_CallDictFunc(sf->python_temporary,"generateFontPostHook","fs",sf->fv,filename);
1018 #endif
1019 }
1020 
AllBitmapSizes(SplineFont * sf)1021 static int32 *AllBitmapSizes(SplineFont *sf) {
1022     int32 *sizes=NULL;
1023     BDFFont *bdf;
1024     int i,cnt;
1025 
1026     for ( i=0; i<2; ++i ) {
1027 	cnt = 0;
1028 	for ( bdf=sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
1029 	    if ( sizes!=NULL )
1030 		sizes[cnt] = bdf->pixelsize | (BDFDepth(bdf)<<16);
1031 	    ++cnt;
1032 	}
1033 	if ( i==1 )
1034     break;
1035 	sizes = malloc((cnt+1)*sizeof(int32));
1036     }
1037     sizes[cnt] = 0;
1038 return( sizes );
1039 }
1040 
GenerateScript(SplineFont * sf,char * filename,const char * bitmaptype,int fmflags,int res,char * subfontdefinition,struct sflist * sfs,EncMap * map,NameList * rename_to,int layer)1041 int GenerateScript(SplineFont *sf,char *filename,const char *bitmaptype, int fmflags,
1042 	int res, char *subfontdefinition, struct sflist *sfs,EncMap *map,
1043 	NameList *rename_to,int layer) {
1044     int i;
1045     static const char *bitmaps[] = {"bdf", "ttf", "dfont", "ttf", "otb", "bin", "fon", "fnt", "pdb", "pt3", NULL };
1046     int32 *sizes=NULL;
1047     char *end = filename+strlen(filename);
1048     struct sflist *sfi;
1049     char *freeme = NULL;
1050     int ret;
1051     struct sflist *sfl;
1052     char **former;
1053 
1054     if ( sf->bitmaps==NULL ) i = bf_none;
1055     else if ( strmatch(bitmaptype,"otf")==0 ) i = bf_ttf;
1056     else if ( strmatch(bitmaptype,"ms")==0 ) i = bf_ttf;
1057     else if ( strmatch(bitmaptype,"apple")==0 ) i = bf_ttf;
1058     else if ( strmatch(bitmaptype,"sbit")==0 ) i = bf_sfnt_dfont;
1059     else if ( strmatch(bitmaptype,"nfnt")==0 ) i = bf_nfntmacbin;
1060     else if ( strmatch(bitmaptype,"ps")==0 ) i = bf_ptype3;
1061     else for ( i=0; bitmaps[i]!=NULL; ++i ) {
1062 	if ( strmatch(bitmaptype,bitmaps[i])==0 )
1063     break;
1064     }
1065     oldbitmapstate = i;
1066 
1067     for ( i=0; savefont_extensions[i]!=NULL; ++i ) {
1068 	if ( strlen( savefont_extensions[i])>0 &&
1069              end-filename>=(ptrdiff_t)strlen(savefont_extensions[i]) &&
1070 		strmatch(end-strlen(savefont_extensions[i]),savefont_extensions[i])==0 )
1071     break;
1072     }
1073     if ( end-filename>8 && strmatch(end-strlen(".ttf.bin"),".ttf.bin")==0 )
1074 	i = ff_ttfmacbin;
1075     else if ( end-filename>5 && strmatch(end-strlen(".suit"),".suit")==0 )	/* Different extensions for Mac/non Mac, support both always */
1076 	i = ff_ttfmacbin;
1077     else if ( end-filename>4 && strmatch(end-strlen(".bin"),".bin")==0 )
1078 	i = ff_pfbmacbin;
1079     else if ( end-filename>4 && strmatch(end-strlen(".res"),".res")==0 )
1080 	i = ff_pfbmacbin;
1081     else if ( end-filename>8 && strmatch(end-strlen(".sym.ttf"),".sym.ttf")==0 )
1082 	i = ff_ttfsym;
1083     else if ( end-filename>8 && strmatch(end-strlen(".cid.cff"),".cid.cff")==0 )
1084 	i = ff_cffcid;
1085     else if ( end-filename>8 && strmatch(end-strlen(".cid.t42"),".cid.t42")==0 )
1086 	i = ff_type42cid;
1087     else if ( end-filename>7 && strmatch(end-strlen(".mm.pfa"),".mm.pfa")==0 )
1088 	i = ff_mma;
1089     else if ( end-filename>7 && strmatch(end-strlen(".mm.pfb"),".mm.pfb")==0 )
1090 	i = ff_mmb;
1091     else if ( end-filename>7 && strmatch(end-strlen(".mult"),".mult")==0 )
1092 	i = ff_multiple;
1093     else if (( i==ff_pfa || i==ff_pfb ) && strstr(filename,"%s")!=NULL )
1094 	i = ff_multiple;
1095     if ( savefont_extensions[i]==NULL ) {
1096 	for ( i=0; bitmaps[i]!=NULL; ++i ) {
1097 	    if ( end-filename>(ptrdiff_t)strlen(bitmaps[i]) &&
1098 		    strmatch(end-strlen(bitmaps[i]),bitmaps[i])==0 )
1099 	break;
1100 	}
1101 	if ( *filename=='\0' || end[-1]=='.' )
1102 	    i = ff_none;
1103 	else if ( bitmaps[i]==NULL )
1104 	    i = ff_pfb;
1105 	else {
1106 	    oldbitmapstate = i;
1107 	    i = ff_none;
1108 	}
1109     }
1110     if ( i==ff_ttfdfont && strmatch(end-strlen(".otf.dfont"),".otf.dfont")==0 )
1111 	i = ff_otfdfont;
1112     if ( sf->cidmaster!=NULL ) {
1113 	if ( i==ff_otf ) i = ff_otfcid;
1114 	else if ( i==ff_otfdfont ) i = ff_otfciddfont;
1115     }
1116     if ( (i==ff_none || sf->onlybitmaps) && oldbitmapstate==bf_ttf )
1117 	oldbitmapstate = bf_sfnt_ms;
1118     oldformatstate = i;
1119 
1120     if ( oldformatstate==ff_none && end[-1]=='.' &&
1121 	    (oldbitmapstate==bf_ttf || oldbitmapstate==bf_sfnt_dfont || oldbitmapstate==bf_otb)) {
1122 	freeme = malloc(strlen(filename)+8);
1123 	strcpy(freeme,filename);
1124 	if ( strmatch(bitmaptype,"otf")==0 )
1125 	    strcat(freeme,"otf");
1126 	else if ( oldbitmapstate==bf_otb )
1127 	    strcat(freeme,"otb");
1128 	else if ( oldbitmapstate==bf_sfnt_dfont )
1129 	    strcat(freeme,"dfont");
1130 	else
1131 	    strcat(freeme,"ttf");
1132 	filename = freeme;
1133     } else if ( sf->onlybitmaps && sf->bitmaps!=NULL &&
1134 	    (oldformatstate==ff_ttf || oldformatstate==ff_otf) &&
1135 	    (oldbitmapstate == bf_none || oldbitmapstate==bf_ttf ||
1136 	     oldbitmapstate==bf_sfnt_dfont || oldbitmapstate==bf_otb)) {
1137 	if ( oldbitmapstate==ff_ttf )
1138 	    oldbitmapstate = bf_ttf;
1139 	oldformatstate = ff_none;
1140     }
1141 
1142     if ( oldbitmapstate==bf_sfnt_dfont )
1143 	oldformatstate = ff_none;
1144 
1145     if ( fmflags==-1 ) {
1146 	/* Default to what we did last time */
1147     } else {
1148 	if ( oldformatstate==ff_ttf && (fmflags&fm_flag_symbol))
1149 	    oldformatstate = ff_ttfsym;
1150 	if ( oldformatstate<=ff_cffcid ) {
1151 	    old_ps_flags = 0;
1152 	    if ( fmflags&fm_flag_afm ) old_ps_flags |= ps_flag_afm;
1153 	    if ( fmflags&fm_flag_pfm ) old_ps_flags |= ps_flag_pfm;
1154 	    if ( fmflags&fm_flag_tfm ) old_ps_flags |= ps_flag_tfm;
1155 	    if ( fmflags&fm_flag_nohintsubs ) old_ps_flags |= ps_flag_nohintsubs;
1156 	    if ( fmflags&fm_flag_noflex ) old_ps_flags |= ps_flag_noflex;
1157 	    if ( fmflags&fm_flag_nopshints ) old_ps_flags |= ps_flag_nohints;
1158 	    if ( fmflags&fm_flag_restrict256 ) old_ps_flags |= ps_flag_restrict256;
1159 	    if ( fmflags&fm_flag_round ) old_ps_flags |= ps_flag_round;
1160 	    if ( fmflags&fm_flag_afmwithmarks ) old_ps_flags |= ps_flag_afmwithmarks;
1161 	    if ( i==bf_otb ) {
1162 		old_sfnt_flags = 0;
1163 		switch ( fmflags&(fm_flag_apple|fm_flag_opentype) ) {
1164 		  case fm_flag_opentype:
1165 		    old_sfnt_flags |= ttf_flag_applemode|ttf_flag_otmode;
1166 		  break;
1167 		  case fm_flag_apple|fm_flag_opentype:
1168 		    /* Neither */;
1169 		  break;
1170 		  case fm_flag_apple:
1171 		    old_sfnt_flags |= ttf_flag_applemode;
1172 		  break;
1173 		  case 0x00:
1174 		    old_sfnt_flags |= ttf_flag_otmode;
1175 		  break;
1176 		  default:
1177 		  break;
1178 		}
1179 		if ( fmflags&fm_flag_shortps ) old_sfnt_flags |= ttf_flag_shortps;
1180 		if ( fmflags&fm_flag_pfed_comments ) old_sfnt_flags |= ttf_flag_pfed_comments;
1181 		if ( fmflags&fm_flag_pfed_colors ) old_sfnt_flags |= ttf_flag_pfed_colors;
1182 		if ( fmflags&fm_flag_TeXtable ) old_sfnt_flags |= ttf_flag_TeXtable;
1183 		if ( fmflags&fm_flag_ofm ) old_sfnt_flags |= ttf_flag_ofm;
1184 		if ( (fmflags&fm_flag_applemode) && !(old_sfnt_flags&ttf_flag_applemode) )
1185 		    old_sfnt_flags |= ttf_flag_oldkern;
1186 		if ( fmflags&fm_flag_symbol ) old_sfnt_flags |= ttf_flag_symbol;
1187 		if ( fmflags&fm_flag_dummyDSIG ) old_sfnt_flags |= ttf_flag_dummyDSIG;
1188 		if ( fmflags&fm_flag_nofftm ) old_sfnt_flags |= ttf_flag_noFFTMtable;
1189 		if ( fmflags&fm_flag_pfed_lookups ) old_sfnt_flags |= ttf_flag_pfed_lookupnames;
1190 		if ( fmflags&fm_flag_pfed_guides ) old_sfnt_flags |= ttf_flag_pfed_guides;
1191 		if ( fmflags&fm_flag_pfed_layers ) old_sfnt_flags |= ttf_flag_pfed_layers;
1192 		if ( fmflags&fm_flag_winkern ) old_sfnt_flags |= ttf_flag_oldkernmappedonly;
1193 		if ( fmflags&fm_flag_nomacnames ) old_sfnt_flags |= ttf_flag_nomacnames;
1194 	    }
1195 	} else {
1196 	    old_sfnt_flags = 0;
1197 		/* Applicable postscript flags */
1198 	    if ( fmflags&fm_flag_afm ) old_sfnt_flags |= ps_flag_afm;
1199 	    if ( fmflags&fm_flag_pfm ) old_sfnt_flags |= ps_flag_pfm;
1200 	    if ( fmflags&fm_flag_nohintsubs ) old_sfnt_flags |= ps_flag_nohintsubs;
1201 	    if ( fmflags&fm_flag_noflex ) old_sfnt_flags |= ps_flag_noflex;
1202 	    if ( fmflags&fm_flag_nopshints ) old_sfnt_flags |= ps_flag_nohints;
1203 	    if ( fmflags&fm_flag_round ) old_sfnt_flags |= ps_flag_round;
1204 	    if ( fmflags&fm_flag_afmwithmarks ) old_sfnt_flags |= ps_flag_afmwithmarks;
1205 		/* Applicable truetype flags */
1206 	    switch ( fmflags&(fm_flag_apple|fm_flag_opentype) ) {
1207 	      case fm_flag_opentype:
1208 		old_sfnt_flags |= ttf_flag_applemode|ttf_flag_otmode;
1209 	      break;
1210 	      case fm_flag_apple|fm_flag_opentype:
1211 		/* Neither */;
1212 	      break;
1213 	      case fm_flag_apple:
1214 		old_sfnt_flags |= ttf_flag_applemode;
1215 	      break;
1216 	      case 0x00:
1217 		old_sfnt_flags |= ttf_flag_otmode;
1218 	      break;
1219               default:
1220 	      break;
1221 	    }
1222 	    if ( fmflags&fm_flag_shortps ) old_sfnt_flags |= ttf_flag_shortps;
1223 	    if ( fmflags&fm_flag_nottfhints ) old_sfnt_flags |= ttf_flag_nohints;
1224 	    if ( fmflags&fm_flag_pfed_comments ) old_sfnt_flags |= ttf_flag_pfed_comments;
1225 	    if ( fmflags&fm_flag_pfed_colors ) old_sfnt_flags |= ttf_flag_pfed_colors;
1226 	    if ( fmflags&fm_flag_glyphmap ) old_sfnt_flags |= ttf_flag_glyphmap;
1227 	    if ( fmflags&fm_flag_TeXtable ) old_sfnt_flags |= ttf_flag_TeXtable;
1228 	    if ( fmflags&fm_flag_ofm ) old_sfnt_flags |= ttf_flag_ofm;
1229 	    if ( (fmflags&fm_flag_applemode) && !(old_sfnt_flags&ttf_flag_applemode) )
1230 		old_sfnt_flags |= ttf_flag_oldkern;
1231 	    if ( fmflags&fm_flag_symbol ) old_sfnt_flags |= ttf_flag_symbol;
1232 	    if ( fmflags&fm_flag_dummyDSIG ) old_sfnt_flags |= ttf_flag_dummyDSIG;
1233 	    if ( fmflags&fm_flag_nofftm ) old_sfnt_flags |= ttf_flag_noFFTMtable;
1234 	    if ( fmflags&fm_flag_pfed_lookups ) old_sfnt_flags |= ttf_flag_pfed_lookupnames;
1235 	    if ( fmflags&fm_flag_pfed_guides ) old_sfnt_flags |= ttf_flag_pfed_guides;
1236 	    if ( fmflags&fm_flag_pfed_layers ) old_sfnt_flags |= ttf_flag_pfed_layers;
1237 	    if ( fmflags&fm_flag_winkern ) old_sfnt_flags |= ttf_flag_oldkernmappedonly;
1238 	    if ( fmflags&fm_flag_nomacnames ) old_sfnt_flags |= ttf_flag_nomacnames;
1239 	}
1240     }
1241 
1242     if ( oldbitmapstate!=bf_none ) {
1243 	if ( sfs!=NULL ) {
1244 	    for ( sfi=sfs; sfi!=NULL; sfi=sfi->next )
1245 		sfi->sizes = AllBitmapSizes(sfi->sf);
1246 	} else
1247 	    sizes = AllBitmapSizes(sf);
1248     }
1249 
1250     former = NULL;
1251     if ( sfs!=NULL ) {
1252 	for ( sfl=sfs; sfl!=NULL; sfl=sfl->next ) {
1253 	    PrepareUnlinkRmOvrlp(sfl->sf,filename,layer);
1254 	    if ( rename_to!=NULL )
1255 		sfl->former_names = SFTemporaryRenameGlyphsToNamelist(sfl->sf,rename_to);
1256 	}
1257     } else {
1258 	PrepareUnlinkRmOvrlp(sf,filename,layer);
1259 	if ( rename_to!=NULL )
1260 	    former = SFTemporaryRenameGlyphsToNamelist(sf,rename_to);
1261     }
1262 
1263     if ( sfs!=NULL ) {
1264 	int flags = 0;
1265 	if ( oldformatstate<=ff_cffcid )
1266 	    flags = old_ps_flags;
1267 	else
1268 	    flags = old_sfnt_flags;
1269 	ret = WriteMacFamily(filename,sfs,oldformatstate,oldbitmapstate,flags,layer);
1270     } else {
1271 	ret = !_DoSave(sf,filename,sizes,res,map,subfontdefinition,layer);
1272     }
1273     free(freeme);
1274 
1275     if ( sfs!=NULL ) {
1276 	for ( sfl=sfs; sfl!=NULL; sfl=sfl->next ) {
1277 	    RestoreUnlinkRmOvrlp(sfl->sf,filename,layer);
1278 	    if ( rename_to!=NULL )
1279 		SFTemporaryRestoreGlyphNames(sfl->sf,sfl->former_names);
1280 	}
1281     } else {
1282 	RestoreUnlinkRmOvrlp(sf,filename,layer);
1283 	if ( rename_to!=NULL )
1284 	    SFTemporaryRestoreGlyphNames(sf,former);
1285     }
1286 
1287     if ( oldbitmapstate!=bf_none ) {
1288 	if ( sfs!=NULL ) {
1289 	    for ( sfi=sfs; sfi!=NULL; sfi=sfi->next )
1290 		free(sfi->sizes);
1291 	}
1292     }
1293 return( ret );
1294 }
1295