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