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 "splinesaveafm.h"
31 
32 #include "autohint.h"
33 #include "chardata.h"
34 #include "featurefile.h"
35 #include "fontforgevw.h"		/* For Error */
36 #include "fvcomposite.h"
37 #include "fvfonts.h"
38 #include "gutils.h"
39 #include "lookups.h"
40 #include "macbinary.h"
41 #include "mem.h"
42 #include "mm.h"
43 #include "namelist.h"
44 #include "splinefont.h"
45 #include "splinesave.h"
46 #include "splineutil.h"
47 #include "tottf.h"
48 #include "tottfgpos.h"
49 #include "ttf.h"		/* For AnchorClassDecompose */
50 #include "ustring.h"
51 #include "utype.h"
52 #include "zapfnomen.h"
53 
54 #include <math.h>
55 #include <stdio.h>
56 #include <time.h>
57 
58 #include <sys/stat.h>
59 #include <sys/types.h>		/* For stat */
60 #include <unistd.h>
61 
62 #ifdef __CygWin
63  #include <sys/stat.h>
64  #include <sys/types.h>
65  #include <unistd.h>
66 #endif
67 
mygets(FILE * file,char * buffer,int size)68 static void *mygets(FILE *file,char *buffer,int size) {
69     char *end = buffer+size-1;
70     char *pt = buffer;
71     int ch;
72 
73     while ( (ch=getc(file))!=EOF && ch!='\r' && ch!='\n' && pt<end )
74 	*pt++ = ch;
75     *pt = '\0';
76     if ( ch==EOF && pt==buffer )
77 return( NULL );
78     if ( ch=='\r' ) {
79 	ch = getc(file);
80 	if ( ch!='\n' )
81 	    ungetc(ch,file);
82     }
83 return( buffer );
84 }
85 
86 /* ************************************************************************** */
87 /* **************************** Reading AFM files *************************** */
88 /* ************************************************************************** */
KPInsert(SplineChar * sc1,SplineChar * sc2,int off,int isv)89 static void KPInsert( SplineChar *sc1, SplineChar *sc2, int off, int isv ) {
90     KernPair *kp;
91     int32 script;
92 
93     if ( sc1!=NULL && sc2!=NULL ) {
94 	for ( kp=sc1->kerns; kp!=NULL && kp->sc!=sc2; kp = kp->next );
95 	if ( kp!=NULL )
96 	    kp->off = off;
97 	else if ( off!=0 ) {
98 	    kp = chunkalloc(sizeof(KernPair));
99 	    kp->sc = sc2;
100 	    kp->off = off;
101 	    script = SCScriptFromUnicode(sc1);
102 	    if ( script==DEFAULT_SCRIPT )
103 		script = SCScriptFromUnicode(sc2);
104 	    kp->subtable = SFSubTableFindOrMake(sc1->parent,
105 		    isv?CHR('v','k','r','n'):CHR('k','e','r','n'),
106 		    script, gpos_pair);
107 	    if ( isv ) {
108 		kp->next = sc1->vkerns;
109 		sc1->vkerns = kp;
110 	    } else {
111 		kp->next = sc1->kerns;
112 		sc1->kerns = kp;
113 	    }
114 	}
115     }
116 }
117 
LoadKerningDataFromAfm(SplineFont * sf,char * filename)118 int LoadKerningDataFromAfm(SplineFont *sf, char *filename) {
119     FILE *file = fopen(filename,"r");
120     char buffer[200], *pt, *ept, ch;
121     SplineChar *sc1, *sc2;
122     int off;
123     char name[44], second[44], lig[44], buf2[100];
124     PST *liga;
125     bigreal scale = (sf->ascent+sf->descent)/1000.0;
126 
127     if ( file==NULL )
128 return( 0 );
129     ff_progress_change_line2(_("Reading AFM file"));
130     while ( mygets(file,buffer,sizeof(buffer))!=NULL ) {
131 	if ( strncmp(buffer,"KPX",3)==0 || strncmp(buffer,"KPY",3)==0 ) {
132 	    int isv = strncmp(buffer,"KPY",3)==0;
133 	    for ( pt=buffer+3; isspace(*pt); ++pt);
134 	    for ( ept = pt; *ept!='\0' && !isspace(*ept); ++ept );
135 	    ch = *ept; *ept = '\0';
136 	    sc1 = SFGetChar(sf,-1,pt);
137 	    *ept = ch;
138 	    for ( pt=ept; isspace(*pt); ++pt);
139 	    for ( ept = pt; *ept!='\0' && !isspace(*ept); ++ept );
140 	    ch = *ept; *ept = '\0';
141 	    sc2 = SFGetChar(sf,-1,pt);
142 	    *ept = ch;
143 	    off = strtol(ept,NULL,10);
144 	    KPInsert(sc1,sc2,rint(off*scale),isv);
145 	} else if ( buffer[0]=='C' && isspace(buffer[1])) {
146 	    char *pt;
147 	    sc2 = NULL;
148 	    for ( pt= strchr(buffer,';'); pt!=NULL; pt=strchr(pt+1,';') ) {
149 		if ( sscanf( pt, "; N %40s", name )==1 )
150 		    sc2 = SFGetChar(sf,-1,name);
151 		else if ( sc2!=NULL &&
152 			sscanf( pt, "; L %40s %40s", second, lig)==2 ) {
153 		    sc1 = SFGetChar(sf,-1,lig);
154 		    if ( sc1!=NULL ) {
155 			sprintf( buf2, "%s %s", name, second);
156 			for ( liga=sc1->possub; liga!=NULL; liga=liga->next ) {
157 			    if ( liga->type == pst_ligature && strcmp(liga->u.lig.components,buf2)==0 )
158 			break;
159 			}
160 			if ( liga==NULL ) {
161 			    liga = chunkalloc(sizeof(PST));
162 			    liga->subtable = SFSubTableFindOrMake(sf,
163 				    CHR('l','i','g','a'),SCScriptFromUnicode(sc2),
164 				    gsub_ligature);
165 			    liga->subtable->lookup->store_in_afm = true;
166 			    liga->type = pst_ligature;
167 			    liga->next = sc1->possub;
168 			    sc1->possub = liga;
169 			    liga->u.lig.lig = sc1;
170 			    liga->u.lig.components = copy( buf2 );
171 			}
172 		    }
173 		}
174 	    }
175 	}
176     }
177     fclose(file);
178 return( 1 );
179 }
180 
CheckMMAfmFile(SplineFont * sf,char * amfm_filename,char * fontname)181 static void CheckMMAfmFile(SplineFont *sf,char *amfm_filename,char *fontname) {
182     /* the afm file should be in the same directory as the amfm file */
183     /*  with the fontname as the filename */
184     char *temp, *pt;
185 
186     free(sf->fontname);
187     sf->fontname = copy(fontname);
188 
189     temp = malloc(strlen(amfm_filename)+strlen(fontname)+strlen(".afm")+1);
190     strcpy(temp, amfm_filename);
191     pt = strrchr(temp,'/');
192     if ( pt==NULL ) pt = temp;
193     else ++pt;
194     strcpy(pt,fontname);
195     pt += strlen(pt);
196     strcpy(pt,".afm");
197     if ( !LoadKerningDataFromAfm(sf,temp) ) {
198 	strcpy(pt,".AFM");
199 	LoadKerningDataFromAfm(sf,temp);
200     }
201     free(temp);
202 }
203 
LoadKerningDataFromAmfm(SplineFont * sf,char * filename)204 int LoadKerningDataFromAmfm(SplineFont *sf, char *filename) {
205     FILE *file=NULL;
206     char buffer[280], *pt, lastname[257];
207     int index, i;
208     MMSet *mm = sf->mm;
209 
210     if ( mm!=NULL )
211 	file = fopen(filename,"r");
212     pt = strstrmatch(filename,".amfm");
213     if ( pt!=NULL ) {
214 	char *afmname = copy(filename);
215 	strcpy(afmname+(pt-filename),isupper(pt[1])?".AFM":".afm");
216 	LoadKerningDataFromAfm(mm->normal,afmname);
217 	free(afmname);
218     }
219     if ( file==NULL )
220 return( 0 );
221 
222     ff_progress_change_line2(_("Reading AFM file"));
223     while ( fgets(buffer,sizeof(buffer),file)!=NULL ) {
224 	if ( strstrmatch(buffer,"StartMaster")!=NULL )
225     break;
226     }
227     index = -1; lastname[0] = '\0';
228     while ( fgets(buffer,sizeof(buffer),file)!=NULL ) {
229 	if ( strstrmatch(buffer,"EndMaster")!=NULL ) {
230 	    if ( lastname[0]!='\0' && index!=-1 && index<mm->instance_count )
231 		CheckMMAfmFile(mm->instances[index],filename,lastname);
232 	    index = -1; lastname[0] = '\0';
233 	} else if ( sscanf(buffer,"FontName %256s", lastname )== 1 ) {
234 	    /* Do Nothing, all done */
235 	} else if ( (pt = strstr(buffer,"WeightVector"))!=NULL ) {
236 	    pt += strlen("WeightVector");
237 	    while ( *pt==' ' || *pt=='[' ) ++pt;
238 	    i = 0;
239 	    while ( *pt!=']' && *pt!='\0' ) {
240 		if ( *pt=='0' )
241 		    ++i;
242 		else if ( *pt=='1' ) {
243 		    index = i;
244 	    break;
245 		}
246 		++pt;
247 	    }
248 	}
249     }
250     fclose(file);
251 return( true );
252 }
253 
CheckAfmOfPostScript(SplineFont * sf,char * psname)254 int CheckAfmOfPostScript(SplineFont *sf,char *psname) {
255     char *new, *pt;
256     int ret;
257     int wasuc=false;
258 
259     new = malloc(strlen(psname)+6);
260     strcpy(new,psname);
261     pt = strrchr(new,'.');
262     if ( pt==NULL ) pt = new+strlen(new);
263     else wasuc = isupper(pt[1]);
264 
265     if ( sf->mm!=NULL ) {
266 	strcpy(pt,wasuc?".AMFM":".amfm");
267 	if ( !LoadKerningDataFromAmfm(sf,new)) {
268 	    strcpy(pt,wasuc?".amfm":".AMFM");
269 	    ret = LoadKerningDataFromAmfm(sf,new);
270 	} else
271 	    ret = true;
272 	/* The above routine reads from the afm file if one exist */
273     } else {
274 	strcpy(pt,wasuc?".AFM":".afm");
275 	if ( !LoadKerningDataFromAfm(sf,new)) {
276 	    strcpy(pt,wasuc?".afm":".AFM");
277 	    ret = LoadKerningDataFromAfm(sf,new);
278 	} else
279 	    ret = true;
280     }
281     free(new);
282 return( ret );
283 }
284 
SubsNew(SplineChar * to,enum possub_type type,int tag,char * components,SplineChar * default_script)285 void SubsNew(SplineChar *to,enum possub_type type,int tag,char *components,
286 	    SplineChar *default_script) {
287     PST *pst;
288 
289     pst = chunkalloc(sizeof(PST));
290     pst->type = type;
291     pst->subtable = SFSubTableFindOrMake(to->parent,tag,SCScriptFromUnicode(default_script),
292 	    type==pst_substitution ? gsub_single :
293 	    type==pst_alternate ? gsub_alternate :
294 	    type==pst_multiple ? gsub_multiple : gsub_ligature );
295     pst->u.alt.components = components;
296     if ( type == pst_ligature ) {
297 	pst->u.lig.lig = to;
298 	pst->subtable->lookup->store_in_afm = true;
299     }
300     pst->next = to->possub;
301     to->possub = pst;
302 }
303 
PosNew(SplineChar * to,int tag,int dx,int dy,int dh,int dv)304 void PosNew(SplineChar *to,int tag,int dx, int dy, int dh, int dv) {
305     PST *pst;
306 
307     pst = chunkalloc(sizeof(PST));
308     pst->type = pst_position;
309     pst->subtable = SFSubTableFindOrMake(to->parent,tag,SCScriptFromUnicode(to),
310 	    gpos_single );
311     pst->u.pos.xoff = dx;
312     pst->u.pos.yoff = dy;
313     pst->u.pos.h_adv_off = dh;
314     pst->u.pos.v_adv_off = dv;
315     pst->next = to->possub;
316     to->possub = pst;
317 }
318 
LigatureNew(SplineChar * sc3,SplineChar * sc1,SplineChar * sc2)319 static void LigatureNew(SplineChar *sc3,SplineChar *sc1,SplineChar *sc2) {
320     char *components = malloc(strlen(sc1->name)+strlen(sc2->name)+2);
321     strcpy(components,sc1->name);
322     strcat(components," ");
323     strcat(components,sc2->name);
324     SubsNew(sc3,pst_ligature,CHR('l','i','g','a'),components,sc1);
325 }
326 
327 /* ************************************************************************** */
328 /* **************************** Reading TFM files *************************** */
329 /* ************************************************************************** */
330 struct tfmdata {
331     int file_len;
332     int head_len;
333     int first, last;
334     int width_size;
335     int height_size;
336     int depth_size;
337     int italic_size;
338     int ligkern_size;
339     int kern_size;
340     int esize;
341     int param_size;
342 
343     uint8 *kerntab;
344     uint8 *ligkerntab;
345     uint8 *ext;
346     uint8 *ictab;
347     uint8 *dptab;
348     uint8 *httab;
349     uint8 *widtab;
350 
351     int *charlist;
352 };
353 
tfmDoLigKern(SplineFont * sf,int enc,int lk_index,struct tfmdata * tfmd,EncMap * map)354 static void tfmDoLigKern(SplineFont *sf, int enc, int lk_index,
355 	struct tfmdata *tfmd,EncMap *map) {
356     int enc2, k_index;
357     SplineChar *sc1, *sc2, *sc3;
358     real off;
359 
360     if ( enc>=map->enccount || map->map[enc]==-1 || (sc1=sf->glyphs[map->map[enc]])==NULL )
361 return;
362     if ( enc<tfmd->first || enc>tfmd->last )
363 return;
364     if ( lk_index>=tfmd->ligkern_size )
365 return;
366 
367     if ( tfmd->ligkerntab[lk_index*4+0]>128 )		/* Special case to get big indeces */
368 	lk_index = 256*tfmd->ligkerntab[lk_index*4+2] + tfmd->ligkerntab[lk_index*4+3];
369 
370     while ( 1 ) {
371 	if ( lk_index>=tfmd->ligkern_size )
372 return;
373 	enc2 = tfmd->ligkerntab[lk_index*4+1];
374 	if ( enc2>=map->enccount || map->map[enc2]==-1 || (sc2=sf->glyphs[map->map[enc2]])==NULL ||
375 		enc2<tfmd->first || enc2>tfmd->last )
376 	    /* Not much we can do. can't kern to a non-existant char */;
377 	else if ( tfmd->ligkerntab[lk_index*4+2]>=128 ) {
378 	    k_index = ((tfmd->ligkerntab[lk_index*4+2]-128)*256+
379 		    tfmd->ligkerntab[lk_index*4+3])*4;
380 	    if ( k_index>4*tfmd->kern_size )
381 return;
382 	    off = (sf->ascent+sf->descent) *
383 		    ((tfmd->kerntab[k_index]<<24) + (tfmd->kerntab[k_index+1]<<16) +
384 			(tfmd->kerntab[k_index+2]<<8) + tfmd->kerntab[k_index+3])/
385 		    (bigreal) 0x100000;
386  /* printf( "%s(%d) %s(%d) -> %g\n", sc1->name, sc1->enc, sc2->name, sc2->enc, off); */
387 	    KPInsert(sc1,sc2,rint(off),false);
388 	} else if ( tfmd->ligkerntab[lk_index*4+2]==0 &&
389 		tfmd->ligkerntab[lk_index*4+3]<map->enccount &&
390 		tfmd->ligkerntab[lk_index*4+3]>=tfmd->first &&
391 		tfmd->ligkerntab[lk_index*4+3]<=tfmd->last &&
392 		map->map[tfmd->ligkerntab[lk_index*4+3]]!=-1 &&
393 		(sc3=sf->glyphs[map->map[tfmd->ligkerntab[lk_index*4+3]]])!=NULL ) {
394 	    LigatureNew(sc3,sc1,sc2);
395 	}
396 	if ( tfmd->ligkerntab[lk_index*4]>=128 )
397     break;
398 	lk_index += tfmd->ligkerntab[lk_index*4] + 1;
399     }
400 }
401 
doesGlyphExpandHorizontally(SplineChar * UNUSED (sc))402 int doesGlyphExpandHorizontally(SplineChar *UNUSED(sc)) {
403 return( false );
404 }
405 
tfmDoCharList(SplineFont * sf,int i,struct tfmdata * tfmd,EncMap * map)406 static void tfmDoCharList(SplineFont *sf,int i,struct tfmdata *tfmd,EncMap *map) {
407     int used[256], ucnt, len, was;
408     char *components;
409     SplineChar *sc;
410     struct glyphvariants **gvbase;
411 
412     if ( i>=map->enccount || map->map[i]==-1 || sf->glyphs[map->map[i]]==NULL ||
413 	    i<tfmd->first || i>tfmd->last )
414 return;
415 
416     ucnt = 0, len=0;
417     while ( i!=-1 ) {
418 	if ( i<map->enccount && map->map[i]!=-1 && sf->glyphs[map->map[i]]!=NULL &&
419 		i>=tfmd->first && i<=tfmd->last ) {
420 	    used[ucnt++] = map->map[i];
421 	    len += strlen(sf->glyphs[map->map[i]]->name)+1;
422 	    /*sf->glyphs[map->map[i]]->is_extended_shape = true;*/	/* MS does not do this in their fonts */
423 	}
424 	was = i;
425 	i = tfmd->charlist[i];
426 	tfmd->charlist[was] = -1;
427     }
428     if ( ucnt<=1 )
429 return;
430 
431     sc = sf->glyphs[used[0]];
432     if ( sc==NULL )
433 return;
434     components = malloc(len+1); components[0] = '\0';
435     for ( i=1; i<ucnt; ++i ) {
436 	strcat(components,sf->glyphs[used[i]]->name);
437 	if ( i!=ucnt-1 )
438 	    strcat(components," ");
439     }
440     gvbase = doesGlyphExpandHorizontally(sc)?&sc->horiz_variants: &sc->vert_variants;
441     if ( *gvbase==NULL )
442 	*gvbase = chunkalloc(sizeof(struct glyphvariants));
443     (*gvbase)->variants = components;
444 }
445 
tfmDoExten(SplineFont * sf,int i,struct tfmdata * tfmd,int left,EncMap * map)446 static void tfmDoExten(SplineFont *sf,int i,struct tfmdata *tfmd,int left,EncMap *map) {
447     int j, k, gid, gid2, cnt;
448     SplineChar *bits[4], *bats[5];
449     uint8 *ext;
450     SplineChar *sc;
451     struct glyphvariants **gvbase;
452     int is_horiz;
453 
454     if ( i>=map->enccount || (gid=map->map[i])==-1 || sf->glyphs[gid]==NULL )
455 return;
456     if ( left>=tfmd->esize )
457 return;
458 
459     ext = tfmd->ext + 4*left;
460 
461     sc = sf->glyphs[gid];
462     if ( sc==NULL )
463 return;
464     is_horiz = doesGlyphExpandHorizontally(sc);
465     gvbase = is_horiz?&sc->horiz_variants: &sc->vert_variants;
466     if ( *gvbase==NULL )
467 	*gvbase = chunkalloc(sizeof(struct glyphvariants));
468 
469     memset(bits,0,sizeof(bits));
470     for ( j=0; j<4; ++j ) {
471 	k = ext[j];
472 	if ( k!=0 && k<map->enccount && (gid2 = map->map[k])!=-1 && sf->glyphs[gid2]!=NULL ) {
473 	    bits[j] = sf->glyphs[gid2];
474 	    /* bits[j]->is_extended_shape = true;*/	/* MS does not do this in their fonts */
475 	}
476     }
477     /* 0=>bottom, 1=>middle, 2=>top, 3=>extender */
478     cnt = 0;
479     if ( bits[0]!=NULL )
480 	bats[cnt++] = bits[0];
481     if ( bits[3]!=NULL )
482 	bats[cnt++] = bits[3];
483     if ( bits[1]!=NULL ) {
484 	bats[cnt++] = bits[1];
485 	if ( bits[3]!=NULL )
486 	    bats[cnt++] = bits[3];
487     }
488     if ( bits[2]!=NULL )
489 	bats[cnt++] = bits[2];
490 
491     (*gvbase)->part_cnt = cnt;
492     (*gvbase)->parts = calloc(cnt,sizeof(struct gv_part));
493     for ( j=0; j<cnt; ++j ) {
494 	DBounds b;
495 	bigreal len;
496 	SplineCharFindBounds(bats[j],&b);
497 	if ( is_horiz )
498 	    len = b.maxx;
499 	else
500 	    len = b.maxy;
501 	(*gvbase)->parts[j].component = copy(bats[j]->name);
502 	(*gvbase)->parts[j].is_extender = bats[j]==bits[3];
503 	(*gvbase)->parts[j].startConnectorLength = len/4;
504 	(*gvbase)->parts[j].endConnectorLength = len/4;
505 	(*gvbase)->parts[j].fullAdvance = len;
506     }
507 }
508 
509 #define BigEndianWord(pt) ((((uint8 *) pt)[0]<<24) | (((uint8 *) pt)[1]<<16) | (((uint8 *) pt)[2]<<8) | (((uint8 *) pt)[3]))
510 
LoadKerningDataFromTfm(SplineFont * sf,char * filename,EncMap * map)511 int LoadKerningDataFromTfm(SplineFont *sf, char *filename,EncMap *map) {
512     FILE *file = fopen(filename,"rb");
513     int i, tag, left, ictag;
514     struct tfmdata tfmd;
515     int charlist[256];
516     int height, depth;
517     real scale = (sf->ascent+sf->descent)/(bigreal) (1<<20);
518 
519     if ( file==NULL )
520 return( 0 );
521     tfmd.file_len = getushort(file);
522     tfmd.head_len = getushort(file);
523     tfmd.first = getushort(file);
524     tfmd.last = getushort(file);
525     tfmd.width_size = getushort(file);
526     tfmd.height_size = getushort(file);
527     tfmd.depth_size = getushort(file);
528     tfmd.italic_size = getushort(file);
529     tfmd.ligkern_size = getushort(file);
530     tfmd.kern_size = getushort(file);
531     tfmd.esize = getushort(file);
532     tfmd.param_size = getushort(file);
533     if ( tfmd.first-1>tfmd.last || tfmd.last>=256 ) {
534 	fclose(file);
535 return( 0 );
536     }
537     tfmd.kerntab = calloc(tfmd.kern_size,4*sizeof(uint8));
538     tfmd.ligkerntab = calloc(tfmd.ligkern_size,4*sizeof(uint8));
539     tfmd.ext = calloc(tfmd.esize,4*sizeof(uint8));
540     tfmd.ictab = calloc(tfmd.italic_size,4*sizeof(uint8));
541     tfmd.dptab = calloc(tfmd.depth_size,4*sizeof(uint8));
542     tfmd.httab = calloc(tfmd.height_size,4*sizeof(uint8));
543     tfmd.widtab = calloc(tfmd.width_size,4*sizeof(uint8));
544     tfmd.charlist = charlist;
545 
546     fseek( file,(6+1)*sizeof(int32),SEEK_SET);
547     sf->design_size = (5*getlong(file)+(1<<18))>>19;	/* TeX stores as <<20, adobe in decipoints */
548     fseek( file,
549 	    (6+tfmd.head_len+(tfmd.last-tfmd.first+1))*sizeof(int32),
550 	    SEEK_SET);
551     fread( tfmd.widtab,1,tfmd.width_size*sizeof(int32),file);
552     fread( tfmd.httab,1,tfmd.height_size*sizeof(int32),file);
553     fread( tfmd.dptab,1,tfmd.depth_size*sizeof(int32),file);
554     fread( tfmd.ictab,1,tfmd.italic_size*sizeof(int32),file);
555     fread( tfmd.ligkerntab,1,tfmd.ligkern_size*sizeof(int32),file);
556     fread( tfmd.kerntab,1,tfmd.kern_size*sizeof(int32),file);
557     fread( tfmd.ext,1,tfmd.esize*sizeof(int32),file);
558     for ( i=0; i<22 && i<tfmd.param_size; ++i )
559 	sf->texdata.params[i] = getlong(file);
560     if ( tfmd.param_size==22 ) sf->texdata.type = tex_math;
561     else if ( tfmd.param_size==13 ) sf->texdata.type = tex_mathext;
562     else if ( tfmd.param_size>=7 ) sf->texdata.type = tex_text;
563 
564     memset(charlist,-1,sizeof(charlist));
565 
566     fseek( file, (6+tfmd.head_len)*sizeof(int32), SEEK_SET);
567     for ( i=tfmd.first; i<=tfmd.last; ++i ) {
568 	/* width = */ getc(file);
569 	height = getc(file);
570 	depth = height&0xf; height >>= 4;
571 	ictag = getc(file);
572 	tag = (ictag&3);
573 	ictag>>=2;
574 	left = getc(file);
575 	if ( tag==1 )
576 	    tfmDoLigKern(sf,i,left,&tfmd,map);
577 	else if ( tag==2 )
578 	    charlist[i] = left;
579 	else if ( tag==3 )
580 	    tfmDoExten(sf,i,&tfmd,left,map);
581 	if ( map->map[i]!=-1 && sf->glyphs[map->map[i]]!=NULL ) {
582 	    SplineChar *sc = sf->glyphs[map->map[i]];
583 /* TFtoPL says very clearly: The actual width of a character is */
584 /*  width[width_index], in design-size units. It is not in design units */
585 /*  it is stored as a fraction of the design size in a fixed word */
586 	    if ( height<tfmd.height_size )
587 		sc->tex_height = BigEndianWord(tfmd.httab+4*height)*scale;
588 	    if ( depth<tfmd.depth_size )
589 		sc->tex_depth = BigEndianWord(tfmd.dptab+4*depth)*scale;
590 	    if ( ictag!=0 && ictag<tfmd.italic_size )
591 		sc->italic_correction = BigEndianWord(tfmd.ictab+4*ictag)*scale;
592 	}
593     }
594 
595     for ( i=tfmd.first; i<=tfmd.last; ++i ) {
596 	if ( charlist[i]!=-1 )
597 	    tfmDoCharList(sf,i,&tfmd,map);
598     }
599 
600     free( tfmd.ligkerntab); free(tfmd.kerntab); free(tfmd.ext); free(tfmd.ictab);
601     free( tfmd.dptab ); free( tfmd.httab ); free( tfmd.widtab );
602     fclose(file);
603 return( 1 );
604 }
605 
606 /* ************************************************************************** */
607 /* **************************** Reading OFM files *************************** */
608 /* ************************************************************************** */
609 #define LKShort(index,off) (((tfmd->ligkerntab+8*index+2*off)[0]<<8)|(tfmd->ligkerntab+8*index+2*off)[1])
610 
611 /* almost the same as the tfm version except that we deal with shorts rather */
612 /*  than bytes */
ofmDoLigKern(SplineFont * sf,int enc,int lk_index,struct tfmdata * tfmd,EncMap * map)613 static void ofmDoLigKern(SplineFont *sf, int enc, int lk_index,
614 	struct tfmdata *tfmd,EncMap *map) {
615     int enc2, k_index;
616     SplineChar *sc1, *sc2, *sc3;
617     real off;
618 
619     if ( enc>=map->enccount || map->map[enc]==-1 || (sc1=sf->glyphs[map->map[enc]])==NULL )
620 return;
621     if ( enc<tfmd->first || enc>tfmd->last )
622 return;
623     if ( lk_index>=2*tfmd->ligkern_size )
624 return;
625 
626     if ( LKShort(lk_index,0)>128 )		/* Special case to get big indeces */
627 	lk_index = 65536*LKShort(lk_index,2) + LKShort(lk_index,3);
628 
629     while ( 1 ) {
630 	if ( lk_index>=2*tfmd->ligkern_size )
631 return;
632 	enc2 = LKShort(lk_index,1);
633 	if ( enc2>=map->enccount || map->map[enc2]==-1 || (sc2=sf->glyphs[map->map[enc2]])==NULL ||
634 		enc2<tfmd->first || enc2>tfmd->last )
635 	    /* Not much we can do. can't kern to a non-existant char */;
636 	else if ( LKShort(lk_index,2)>=128 ) {
637 	    k_index = ((LKShort(lk_index,2)-128)*65536+LKShort(lk_index,3))*4;
638 	    if ( k_index>tfmd->kern_size )
639 return;
640 	    off = (sf->ascent+sf->descent) *
641 		    ((tfmd->kerntab[k_index]<<24) + (tfmd->kerntab[k_index+1]<<16) +
642 			(tfmd->kerntab[k_index+2]<<8) + tfmd->kerntab[k_index+3])/
643 		    (bigreal) 0x100000;
644  /* printf( "%s(%d) %s(%d) -> %g\n", sc1->name, sc1->enc, sc2->name, sc2->enc, off); */
645 	    KPInsert(sc1,sc2,rint(off),false);
646 	} else if ( LKShort(lk_index,2)==0 &&
647 		LKShort(lk_index,3)<map->enccount &&
648 		LKShort(lk_index,3)>=tfmd->first &&
649 		LKShort(lk_index,3)<=tfmd->last &&
650 		map->map[LKShort(lk_index,3)]!=-1 &&
651 		(sc3=sf->glyphs[map->map[LKShort(lk_index,3)]])!=NULL ) {
652 	    LigatureNew(sc3,sc1,sc2);
653 	}
654 	if ( LKShort(lk_index,0)>=128 )
655     break;
656 	lk_index += LKShort(lk_index,0) + 1;
657     }
658 }
659 #undef LKShort
660 
661 
662 #define ExtShort(off) (((ext+2*off)[0]<<8)|(ext+2*off)[1])
663 
664 /* almost the same as the tfm version except that we deal with shorts rather */
665 /*  than bytes */
ofmDoExten(SplineFont * sf,int i,struct tfmdata * tfmd,int left,EncMap * map)666 static void ofmDoExten(SplineFont *sf,int i,struct tfmdata *tfmd,int left,EncMap *map) {
667     int j, k, gid, gid2, cnt;
668     uint8 *ext;
669     SplineChar *sc, *bits[4], *bats[4];
670     struct glyphvariants **gvbase;
671     int is_horiz;
672 
673     if ( i>=map->enccount || (gid=map->map[i])==-1 || sf->glyphs[gid]==NULL )
674 return;
675     if ( left>=2*tfmd->esize )
676 return;
677 
678     ext = tfmd->ext + 4*left;
679 
680     sc = sf->glyphs[gid];
681     if ( sc==NULL )
682 return;
683     is_horiz = doesGlyphExpandHorizontally(sc);
684     gvbase = is_horiz?&sc->horiz_variants: &sc->vert_variants;
685     if ( *gvbase==NULL )
686 	*gvbase = chunkalloc(sizeof(struct glyphvariants));
687 
688     memset(bits,0,sizeof(bits));
689     for ( j=0; j<4; ++j ) {
690 	k = ExtShort(j);
691 	if ( k!=0 && k<map->enccount && (gid2 = map->map[k])!=-1 && sf->glyphs[gid2]!=NULL ) {
692 	    bits[j] = sf->glyphs[gid2];
693 	    /* bits[j]->is_extended_shape = true;*/	/* MS does not do this in their fonts */
694 	}
695     }
696     /* 0=>bottom, 1=>middle, 2=>top, 3=>extender */
697     cnt = 0;
698     if ( bits[0]!=NULL )
699 	bats[cnt++] = bits[0];
700     if ( bits[3]!=NULL )
701 	bats[cnt++] = bits[3];
702     if ( bits[1]!=NULL ) {
703 	bats[cnt++] = bits[1];
704 	if ( bits[3]!=NULL )
705 	    bats[cnt++] = bits[3];
706     }
707     if ( bits[2]!=NULL )
708 	bats[cnt++] = bits[1];
709 
710     (*gvbase)->part_cnt = cnt;
711     (*gvbase)->parts = calloc(cnt,sizeof(struct gv_part));
712     for ( j=0; j<cnt; ++j ) {
713 	DBounds b;
714 	bigreal len;
715 	SplineCharFindBounds(bats[j],&b);
716 	if ( is_horiz )
717 	    len = b.maxx;
718 	else
719 	    len = b.maxy;
720 	(*gvbase)->parts[j].component = copy(bats[j]->name);
721 	(*gvbase)->parts[j].is_extender = bats[j]==bits[3];
722 	(*gvbase)->parts[j].startConnectorLength = len/4;
723 	(*gvbase)->parts[j].endConnectorLength = len/4;
724 	(*gvbase)->parts[j].fullAdvance = len;
725     }
726 }
727 
LoadKerningDataFromOfm(SplineFont * sf,char * filename,EncMap * map)728 int LoadKerningDataFromOfm(SplineFont *sf, char *filename,EncMap *map) {
729     FILE *file = fopen(filename,"rb");
730     int i, tag, left, ictag;
731     int level;
732     int height, depth;
733     real scale = (sf->ascent+sf->descent)/(bigreal) (1<<20);
734     struct tfmdata tfmd;
735 
736     if ( file==NULL )
737 return( 0 );
738     /* No one bothered to mention this in the docs, but there appears to be */
739     /*  an initial 0 in an ofm file. I wonder if that is the level? */
740     /* according to the ofm2opl source, it is the level */
741     level = getlong(file);
742     tfmd.file_len = getlong(file);
743     tfmd.head_len = getlong(file);
744     tfmd.first = getlong(file);
745     tfmd.last = getlong(file);
746     tfmd.width_size = getlong(file);
747     tfmd.height_size = getlong(file);
748     tfmd.depth_size = getlong(file);
749     tfmd.italic_size = getlong(file);
750     tfmd.ligkern_size = getlong(file);
751     tfmd.kern_size = getlong(file);
752     tfmd.esize = getlong(file);
753     tfmd.param_size = getlong(file);
754     /* font_dir = */ getlong(file);
755     if ( tfmd.first-1>tfmd.last || tfmd.last>=65536 ) {
756 	fclose(file);
757 return( 0 );
758     }
759     if ( tfmd.file_len!=14+tfmd.head_len+2*(tfmd.last-tfmd.first+1)+tfmd.width_size+tfmd.height_size+tfmd.depth_size+
760 	    tfmd.italic_size+2*tfmd.ligkern_size+tfmd.kern_size+2*tfmd.esize+tfmd.param_size || level!=0 ) {
761 	int ncw, nki, nwi, nkf, nwf, nkm,nwm, nkr, nwr, nkg, nwg, nkp, nwp;
762 	int level1=0;
763 	/* nco = */ getlong(file);
764 	ncw = getlong(file);
765 	/* npc = */ getlong(file);
766 	nki = getlong(file);
767 	nwi = getlong(file);
768 	nkf = getlong(file);
769 	nwf = getlong(file);
770 	nkm = getlong(file);
771 	nwm = getlong(file);
772 	nkr = getlong(file);
773 	nwr = getlong(file);
774 	nkg = getlong(file);
775 	nwg = getlong(file);
776 	nkp = getlong(file);
777 	nwp = getlong(file);
778 	level1 = tfmd.file_len==29+tfmd.head_len+ncw+tfmd.width_size+tfmd.height_size+tfmd.depth_size+
779 	    tfmd.italic_size+2*tfmd.ligkern_size+tfmd.kern_size+2*tfmd.esize+tfmd.param_size +
780 	    nki + nwi + nkf + nwf + nkm + nwm + nkr + nwr + nkg + nwg + nkp + nwp;
781 	/* Level 2 appears to have the same structure as level 1 */
782 	if ( level1 || level==1 || level==2 )
783 	    ff_post_error(_("Unlikely Ofm File"),_("This looks like a level1 (or level2) ofm. FontForge only supports level0 files, and can't read a real level1 file."));
784 	else
785 	    ff_post_error(_("Unlikely Ofm File"),_("This doesn't look like an ofm file, I don't know how to read it."));
786 	fclose(file);
787 return( 0 );
788     }
789 
790     tfmd.kerntab = calloc(tfmd.kern_size,4*sizeof(uint8));
791     tfmd.ligkerntab = calloc(tfmd.ligkern_size,4*2*sizeof(uint8));
792     tfmd.ext = calloc(tfmd.esize,4*2*sizeof(uint8));
793     tfmd.ictab = calloc(tfmd.italic_size,4*sizeof(uint8));
794     tfmd.dptab = calloc(tfmd.depth_size,4*sizeof(uint8));
795     tfmd.httab = calloc(tfmd.height_size,4*sizeof(uint8));
796     tfmd.widtab = calloc(tfmd.width_size,4*sizeof(uint8));
797     fseek( file,(14+1)*sizeof(int32),SEEK_SET);
798     sf->design_size = (5*getlong(file)+(1<<18))>>19;	/* TeX stores as <<20, adobe in decipoints */
799     fseek( file,
800 	    (14+tfmd.head_len+2*(tfmd.last-tfmd.first+1))*sizeof(int32),
801 	    SEEK_SET);
802     fread( tfmd.widtab,1,tfmd.width_size*sizeof(int32),file);
803     fread( tfmd.httab,1,tfmd.height_size*sizeof(int32),file);
804     fread( tfmd.dptab,1,tfmd.depth_size*sizeof(int32),file);
805     fread( tfmd.ictab,1,tfmd.italic_size*sizeof(int32),file);
806     fread( tfmd.ligkerntab,1,tfmd.ligkern_size*2*sizeof(int32),file);
807     fread( tfmd.kerntab,1,tfmd.kern_size*sizeof(int32),file);
808     fread( tfmd.ext,1,tfmd.esize*2*sizeof(int32),file);
809     for ( i=0; i<22 && i<tfmd.param_size; ++i )
810 	sf->texdata.params[i] = getlong(file);
811     if ( tfmd.param_size==22 ) sf->texdata.type = tex_math;
812     else if ( tfmd.param_size==13 ) sf->texdata.type = tex_mathext;
813     else if ( tfmd.param_size>=7 ) sf->texdata.type = tex_text;
814 
815     tfmd.charlist = malloc(65536*sizeof(int32));
816     memset(tfmd.charlist,-1,65536*sizeof(int32));
817 
818     fseek( file, (14+tfmd.head_len)*sizeof(int32), SEEK_SET);
819     for ( i=tfmd.first; i<=tfmd.last; ++i ) {
820 	/* width = */ getushort(file);
821 	height = getc(file);
822 	depth = getc(file);
823 	ictag = getc(file);
824 	tag = getc(file)&0x3;		/* Remaining 6 bytes are "reserved for future use" I think */
825 	left = getushort(file);
826 	if ( tag==1 )
827 	    ofmDoLigKern(sf,i,left,&tfmd,map);
828 	else if ( tag==2 )
829 	    tfmd.charlist[i] = left;
830 	else if ( tag==3 )
831 	    ofmDoExten(sf,i,&tfmd,left,map);
832 	if ( map->map[i]!=-1 && sf->glyphs[map->map[i]]!=NULL ) {
833 	    SplineChar *sc = sf->glyphs[map->map[i]];
834 /* TFtoPL says very clearly: The actual width of a character is */
835 /*  width[width_index], in design-size units. It is not in design units */
836 /*  it is stored as a fraction of the design size in a fixed word */
837 	    if ( height<tfmd.height_size )
838 		sc->tex_height = BigEndianWord(tfmd.httab+4*height)*scale;
839 	    if ( depth<tfmd.depth_size )
840 		sc->tex_depth = BigEndianWord(tfmd.dptab+4*depth)*scale;
841 	    if ( ictag!=0 && ictag<tfmd.italic_size )
842 		sc->italic_correction = BigEndianWord(tfmd.ictab+4*ictag)*scale;
843 	}
844     }
845 
846     for ( i=tfmd.first; i<=tfmd.last; ++i ) {
847 	if ( tfmd.charlist[i]!=-1 )
848 	    tfmDoCharList(sf,i,&tfmd,map);
849     }
850 
851     free( tfmd.ligkerntab); free(tfmd.kerntab); free(tfmd.ext); free(tfmd.ictab);
852     free( tfmd.dptab ); free( tfmd.httab ); free( tfmd.widtab );
853     free( tfmd.charlist );
854     fclose(file);
855 return( 1 );
856 }
857 /* ************************************************************************** */
858 
EncodingName(Encoding * map)859 const char *EncodingName(Encoding *map) {
860     const char *name = map->iconv_name != NULL ? map->iconv_name : map->enc_name;
861     int len = strlen(name);
862     char *pt;
863 
864     if ( strmatch(name,"AdobeStandard")==0 )
865 return( "AdobeStandardEncoding" );
866     if (( strstr(name,"8859")!=NULL && name[len-1]=='1' &&
867 	     (!isdigit(name[len-2]) || name[len-2]=='9') ) ||
868 	    strstrmatch(name,"latin1")!=NULL )
869 return( "ISOLatin1Encoding" );
870     else if ( map->is_unicodebmp || map->is_unicodefull )
871 return( "ISO10646-1" );
872     else if ( strmatch(name,"mac")==0 || strmatch(name,"macintosh")==0 ||
873 	    strmatch(name,"macroman")==0 )
874 return( "MacRoman" );
875     else if ( strmatch(name,"ms-ansi")==0 || strstrmatch(name,"1252")!=NULL )
876 return( "WinRoman" );
877     else if ( strmatch(name,"sjis")==0 ||
878 	    ((pt = strstrmatch(name,"jp"))!=NULL && pt[2]=='\0' &&
879 		    strstr(name,"646")==NULL ))
880 return( "JISX0208.1997" );
881     else if ( map->is_japanese )
882 return( "JISX0212.1990" );
883     else if ( strmatch(name,"johab")==0 )
884 return( "Johab" );
885     else if ( map->is_korean )
886 return( "KSC5601.1992" );
887     else if ( map->is_simplechinese )
888 return( "GB2312.1980" );
889     else if ( strstrmatch(name,"hkscs")!=NULL )
890 return( "BIG5HKSCS.2001" );
891     else if ( map->is_tradchinese )
892 return( "BIG5" );			/* 2002? */
893 
894     if ( map->is_custom || map->is_original || map->is_compact )
895 return( "FontSpecific" );
896 
897 return( name );
898 }
899 
AfmLigOut(FILE * afm,SplineChar * sc)900 static void AfmLigOut(FILE *afm, SplineChar *sc) {
901     LigList *ll;
902     PST *lig;
903     char *pt, *eos;
904 
905     for ( ll=sc->ligofme; ll!=NULL; ll=ll->next ) {
906 	lig = ll->lig;
907 	if ( !lig->subtable->lookup->store_in_afm )
908     continue;
909 	pt = strchr(lig->u.lig.components,' ');
910 	eos = strrchr(lig->u.lig.components,' ');
911 	if ( pt!=NULL && eos==pt )
912 	    /* AFM files don't seem to support 3 (or more) letter combos */
913 	    fprintf( afm, " L %s %s ;", pt+1, lig->u.lig.lig->name );
914     }
915 }
916 
AfmSplineCharX(FILE * afm,SplineChar * sc,int enc,int layer)917 static void AfmSplineCharX(FILE *afm, SplineChar *sc, int enc, int layer) {
918     DBounds b;
919     int em = (sc->parent->ascent+sc->parent->descent);
920 
921     SplineCharLayerFindBounds(sc,layer,&b);
922     /*fprintf( afm, "CX <%04x> ; WX %d ; N %s ; B %d %d %d %d ;",*/
923     fprintf( afm, "C %d ; WX %d ; ", enc, sc->width*1000/em );
924     if ( sc->parent->hasvmetrics )
925 	fprintf( afm, "WY %d ; ", sc->vwidth*1000/em );
926     fprintf( afm, "N %s ; B %d %d %d %d ;",
927 	    sc->name,
928 	    (int) floor(b.minx*1000/em), (int) floor(b.miny*1000/em),
929 	    (int) ceil(b.maxx*1000/em), (int) ceil(b.maxy*1000/em) );
930     if (sc->ligofme!=NULL)
931 	AfmLigOut(afm,sc);
932     putc('\n',afm);
933     ff_progress_next();
934 }
935 
AfmZapfCharX(FILE * afm,int zi)936 static void AfmZapfCharX(FILE *afm, int zi) {
937 
938     /*fprintf( afm, "CX <%04x> ; WX %d ; N %s ; B %d %d %d %d ;\n",*/
939     fprintf( afm, "C %d ; WX %d ; N %s ; B %d %d %d %d ;\n",
940 	    0x2700+zi, zapfwx[zi], zapfnomen[zi],
941 	    zapfbb[zi][0], zapfbb[zi][1], zapfbb[zi][2], zapfbb[zi][3]);
942 }
943 
AfmSplineChar(FILE * afm,SplineChar * sc,int enc,int layer)944 static void AfmSplineChar(FILE *afm, SplineChar *sc, int enc,int layer) {
945     DBounds b;
946     int em = (sc->parent->ascent+sc->parent->descent);
947 
948     SplineCharLayerFindBounds(sc,layer,&b);
949     fprintf( afm, "C %d ; WX %d ; ", enc, sc->width*1000/em );
950     if ( sc->parent->hasvmetrics )
951 	fprintf( afm, "WY %d ; ", sc->vwidth*1000/em );
952     fprintf( afm, "N %s ; B %d %d %d %d ;",
953 	    sc->name,
954 	    (int) floor(b.minx*1000/em), (int) floor(b.miny*1000/em),
955 	    (int) ceil(b.maxx*1000/em), (int) ceil(b.maxy*1000/em) );
956     if (sc->ligofme!=NULL)
957 	AfmLigOut(afm,sc);
958     putc('\n',afm);
959     ff_progress_next();
960 }
961 
AfmCIDChar(FILE * afm,SplineChar * sc,int enc,int layer)962 static void AfmCIDChar(FILE *afm, SplineChar *sc, int enc,int layer) {
963     DBounds b;
964     int em = (sc->parent->ascent+sc->parent->descent);
965 
966     SplineCharLayerFindBounds(sc,layer,&b);
967     fprintf( afm, "C -1 ; WX %d ; ", sc->width*1000/em );
968     if ( sc->parent->hasvmetrics )
969 	fprintf( afm, "WY %d ; ", sc->vwidth*1000/em );
970     fprintf( afm, "N %d ; B %d %d %d %d ;",
971 	    enc,
972 	    (int) floor(b.minx*1000/em), (int) floor(b.miny*1000/em),
973 	    (int) ceil(b.maxx*1000/em), (int) ceil(b.maxy*1000/em) );
974     putc('\n',afm);
975     ff_progress_next();
976 }
977 
anykerns(SplineFont * sf,int isv)978 static int anykerns(SplineFont *sf,int isv) {
979     int i, cnt = 0;
980     KernPair *kp;
981 
982     for ( i=0; i<sf->glyphcnt; ++i ) {
983 	if ( sf->glyphs[i]!=NULL && strcmp(sf->glyphs[i]->name,".notdef")!=0 ) {
984 	    for ( kp = isv ? sf->glyphs[i]->vkerns : sf->glyphs[i]->kerns; kp!=NULL; kp = kp->next )
985 		if ( kp->off!=0 && strcmp(kp->sc->name,".notdef")!=0 &&
986 			(kp->sc->parent==sf || sf->cidmaster!=NULL) )
987 		    ++cnt;
988 	}
989     }
990 return( cnt );
991 }
992 
AfmKernPairs(FILE * afm,SplineChar * sc,int isv)993 static void AfmKernPairs(FILE *afm, SplineChar *sc, int isv) {
994     KernPair *kp;
995     int em = (sc->parent->ascent+sc->parent->descent);
996 
997     if ( strcmp(sc->name,".notdef")==0 )
998 return;
999 
1000     for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next ) {
1001 	if ( kp->sc->parent!=sc->parent && sc->parent->cidmaster==NULL )
1002     continue;		/* Can happen when saving multiple pfbs */
1003 	if ( strcmp(kp->sc->name,".notdef")!=0 && kp->off!=0 ) {
1004 	    if ( isv )
1005 		fprintf( afm, "KPY %s %s %d\n", sc->name, kp->sc->name, kp->off*1000/em );
1006 	    else
1007 		fprintf( afm, "KPX %s %s %d\n", sc->name, kp->sc->name, kp->off*1000/em );
1008 	}
1009     }
1010 }
1011 
SFFindNotdef(SplineFont * sf,int fixed)1012 int SFFindNotdef(SplineFont *sf, int fixed) {
1013     int notdefpos = -1, i, width=-1;
1014     /* If all glyphs have the same known width set fixed to it */
1015     /* If glyphs are proportional set fixed to -1 */
1016     /* If we don't know yet, set fixed to -2 */
1017 
1018     if ( fixed==-2 ) {		/* Unknown */
1019 	for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sf->glyphs[i]) ) {
1020 	    if ( strcmp(sf->glyphs[i]->name,".notdef")==0 ) {
1021 		if ( notdefpos==-1 ) notdefpos = i;
1022 	    } else if ( width==-1 )
1023 		width = sf->glyphs[i]->width;
1024 	    else if ( width!=sf->glyphs[i]->width )
1025 		width = -2;
1026 	}
1027 	if ( width>=0 && sf->glyphcnt>2 && notdefpos>=0) {
1028 	    if ( width!=sf->glyphs[notdefpos]->width ) {
1029 		notdefpos = -1;
1030 		for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sf->glyphs[i]) ) {
1031 		    if ( strcmp(sf->glyphs[i]->name,".notdef")==0 &&
1032 			    sf->glyphs[i]->width == width ) {
1033 			notdefpos = i;
1034 		break;
1035 		    }
1036 		}
1037 	    }
1038 	}
1039     } else if ( fixed>=0 ) {		/* Known, fixed width */
1040 	for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sf->glyphs[i]) ) {
1041 	    if ( strcmp(sf->glyphs[i]->name,".notdef")==0 &&
1042 		    sf->glyphs[i]->width == fixed )
1043 return( i );
1044 	}
1045     } else {				/* Known, variable width */
1046 	for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sf->glyphs[i]) ) {
1047 	    if ( strcmp(sf->glyphs[i]->name,".notdef")==0 )
1048 return( i );
1049 	}
1050     }
1051 
1052 return( notdefpos );
1053 }
1054 
SCDrawsSomething(SplineChar * sc)1055 int SCDrawsSomething(SplineChar *sc) {
1056     int layer,l;
1057     RefChar *ref;
1058 
1059     if ( sc==NULL )
1060 return( false );
1061     for ( layer = 0; layer<sc->layer_cnt; ++layer ) if ( !sc->layers[layer].background ) {
1062 	if ( sc->layers[layer].splines!=NULL || sc->layers[layer].images!=NULL )
1063 return( true );
1064 	for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1065 	    for ( l=0; l<ref->layer_cnt; ++l )
1066 		if ( ref->layers[l].splines!=NULL )
1067 return( true );
1068     }
1069 return( false );
1070 }
1071 
SCDrawsSomethingOnLayer(SplineChar * sc,int layer)1072 int SCDrawsSomethingOnLayer(SplineChar *sc, int layer) {
1073     int l;
1074     RefChar *ref;
1075 
1076     if ( sc==NULL )
1077 return( false );
1078     if (layer<sc->layer_cnt) {
1079 	if ( sc->layers[layer].splines!=NULL || sc->layers[layer].images!=NULL )
1080 return( true );
1081 	for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1082 	    for ( l=0; l<ref->layer_cnt; ++l )
1083 		if ( ref->layers[l].splines!=NULL )
1084 return( true );
1085     }
1086 return( false );
1087 }
1088 
SCWorthOutputting(SplineChar * sc)1089 int SCWorthOutputting(SplineChar *sc) {
1090 return( sc!=NULL &&
1091 	( SCDrawsSomething(sc) || sc->widthset || sc->anchor!=NULL ||
1092 #if HANYANG
1093 	    sc->compositionunit ||
1094 #endif
1095 	    sc->dependents!=NULL /*||
1096 	    sc->width!=sc->parent->ascent+sc->parent->descent*/ ) );
1097 }
1098 
SCHasData(SplineChar * sc)1099 int SCHasData(SplineChar *sc) {
1100     int layer,l;
1101 
1102     if ( sc==NULL )
1103 return( false );
1104     for ( layer = 0; layer<sc->layer_cnt; ++layer ) if ( sc->layers[layer].python_persistent ) return true;
1105     return false;
1106 }
1107 
LayerWorthOutputting(SplineFont * sf,int layer)1108 int LayerWorthOutputting(SplineFont *sf, int layer) {
1109   int glyphpos = 0;
1110   for (glyphpos = 0; glyphpos < sf->glyphcnt; glyphpos++) {
1111     if (SCDrawsSomethingOnLayer(sf->glyphs[glyphpos], layer)) return 1;
1112   }
1113   return 0;
1114 }
1115 
SCLWorthOutputtingOrHasData(SplineChar * sc,int layer)1116 int SCLWorthOutputtingOrHasData(SplineChar *sc, int layer) {
1117   if (sc == NULL) return 0;
1118   if (layer >= sc->layer_cnt) return 0;
1119   if (SCDrawsSomethingOnLayer(sc, layer)) return 1;
1120   if (sc->layers[layer].python_persistent) return 1;
1121   return 0;
1122 }
1123 
CIDWorthOutputting(SplineFont * cidmaster,int enc)1124 int CIDWorthOutputting(SplineFont *cidmaster, int enc) {
1125     int i;
1126 
1127     if ( enc<0 )
1128 return( -1 );
1129 
1130     if ( cidmaster->subfontcnt==0 )
1131 return( enc>=cidmaster->glyphcnt?-1:SCWorthOutputting(cidmaster->glyphs[enc])?0:-1 );
1132 
1133     for ( i=0; i<cidmaster->subfontcnt; ++i )
1134 	if ( enc<cidmaster->subfonts[i]->glyphcnt &&
1135 		SCWorthOutputting(cidmaster->subfonts[i]->glyphs[enc]))
1136 return( i );
1137 
1138 return( -1 );
1139 }
1140 
AfmSplineFontHeader(FILE * afm,SplineFont * sf,int formattype,EncMap * map,SplineFont * fullsf,int layer)1141 static void AfmSplineFontHeader(FILE *afm, SplineFont *sf, int formattype,
1142 	EncMap *map, SplineFont *fullsf,int layer) {
1143     DBounds b;
1144     real width;
1145     int i, j, cnt, max;
1146     bigreal caph, xh, ash, dsh;
1147     int iscid = ( formattype==ff_cid || formattype==ff_otfcid );
1148     int ismm = ( formattype==ff_mma || formattype==ff_mmb );
1149     time_t now;
1150     SplineChar *sc;
1151     int em = (sf->ascent+sf->descent);
1152 
1153     if ( iscid && sf->cidmaster!=NULL ) sf = sf->cidmaster;
1154 
1155     max = sf->glyphcnt;
1156     if ( iscid ) {
1157 	max = 0;
1158 	for ( i=0; i<sf->subfontcnt; ++i )
1159 	    if ( sf->subfonts[i]->glyphcnt>max )
1160 		max = sf->subfonts[i]->glyphcnt;
1161     }
1162     caph = SFCapHeight(sf,layer,true);
1163     xh   = SFXHeight(sf,layer,true);
1164     ash  = SFAscender(sf,layer,true);
1165     dsh  = SFDescender(sf,layer,true);
1166     cnt = 0;
1167     for ( i=0; i<max; ++i ) {
1168 	sc = NULL;
1169 	if ( iscid ) {
1170 	    for ( j=0; j<sf->subfontcnt; ++j )
1171 		if ( i<sf->subfonts[j]->glyphcnt && sf->subfonts[j]->glyphs[i]!=NULL ) {
1172 		    sc = sf->subfonts[j]->glyphs[i];
1173 	    break;
1174 		}
1175 	} else
1176 	    sc = sf->glyphs[i];
1177 	if ( sc!=NULL ) {
1178 	    if ( SCWorthOutputting(sc) || (iscid && i==0 && sc!=NULL))
1179 		++cnt;
1180 	}
1181     }
1182 
1183     fprintf( afm, ismm ? "StartMasterFontMetrics 4.0\n" :
1184 		  iscid ? "StartFontMetrics 4.1\n" :
1185 			  "StartFontMetrics 2.0\n" );
1186     fprintf( afm, "Comment Generated by FontForge %s\n", FONTFORGE_VERSION );
1187     now = GetTime();
1188     fprintf(afm,"Comment Creation Date: %s", ctime(&now));
1189     fprintf( afm, "FontName %s\n", sf->fontname );
1190     if ( sf->fullname!=NULL ) fprintf( afm, "FullName %s\n", sf->fullname );
1191     if ( sf->familyname!=NULL ) fprintf( afm, "FamilyName %s\n", sf->familyname );
1192     if ( sf->weight!=NULL ) fprintf( afm, "Weight %s\n", sf->weight );
1193     /* AFM lines are limited to 256 characters and US ASCII */
1194     if ( sf->copyright!=NULL ) {
1195 	char *pt, *start, *p;
1196 	for ( pt=start=sf->copyright; *pt && pt-start<200 && *pt!='\n'; ++pt );
1197 	fprintf( afm, "Notice (" );
1198 	for ( p=start; p<pt; ++p )
1199 	    if ( *p=='\xa9' ) fprintf(afm,"(C)");
1200 	    else if ( *p=='\t' || (*p>=' ' && *p<0x7f))
1201 		putc(*p,afm);
1202 	fprintf( afm, ")\n" );
1203 	while ( *pt ) {
1204 	    start = pt;
1205 	    if ( *start=='\n' ) ++start;
1206 	    for ( pt=start; *pt && pt-start<200 && *pt!='\n'; ++pt );
1207 	    fprintf( afm, "Comment " );
1208 	    for ( p=start; p<pt; ++p )
1209 		if ( *p=='\xa9' ) fprintf(afm,"(C)");
1210 		else if ( *p=='\t' || (*p>=' ' && *p<0x7f))
1211 		    putc(*p,afm);
1212 	    fprintf( afm, "\n" );
1213 	}
1214     }
1215     if ( iscid ) {
1216 	fprintf( afm, "Characters %d\n", cnt );
1217 	fprintf( afm, "Version %g\n", (double)sf->cidversion );
1218 	fprintf( afm, "CharacterSet %s-%s-%d\n", sf->cidregistry, sf->ordering, sf->supplement );
1219 	fprintf( afm, "IsBaseFont true\n" );
1220 	fprintf( afm, "IsCIDFont true\n" );
1221     }
1222     fprintf( afm, "ItalicAngle %g\n", (double) sf->italicangle );
1223     width = CIDOneWidth(sf);
1224     fprintf( afm, "IsFixedPitch %s\n", width==-1?"false":"true" );
1225     fprintf( afm, "UnderlinePosition %g\n", (double) sf->upos );
1226     fprintf( afm, "UnderlineThickness %g\n", (double) sf->uwidth );
1227     if ( !iscid ) {
1228 	if ( sf->version!=NULL ) fprintf( afm, "Version %s\n", sf->version );
1229 	fprintf( afm, "EncodingScheme %s\n", EncodingName(map->enc));
1230     }
1231     if ( iscid ) CIDLayerFindBounds(sf,layer,&b); else SplineFontLayerFindBounds(fullsf!=NULL?fullsf:sf,layer,&b);
1232     fprintf( afm, "FontBBox %d %d %d %d\n",
1233 	    (int) floor(b.minx*1000/em), (int) floor(b.miny*1000/em),
1234 	    (int) ceil(b.maxx*1000/em), (int) ceil(b.maxy*1000/em) );
1235     if ( caph!=-1e23 )
1236 	fprintf( afm, "CapHeight %d\n", (int) rint(caph*1000/em) );
1237     if ( xh!=-1e23 )
1238 	fprintf( afm, "XHeight %d\n", (int) rint(xh*1000/em) );
1239     if ( ash!=-1e23 )
1240 	fprintf( afm, "Ascender %d\n", (int) rint(ash*1000/em) );
1241     if ( dsh!=1e23 )
1242 	fprintf( afm, "Descender %d\n", (int) rint(dsh*1000/em) );
1243 }
1244 
1245 struct cc_accents {
1246     SplineChar *accent;
1247     real xoff, yoff;
1248     struct cc_accents *next;
1249 };
1250 
1251 struct cc_data {
1252     char *name;
1253     SplineChar *base;
1254     int acnt;
1255     struct cc_accents *accents;
1256 };
1257 
1258 struct cc_container {
1259     struct cc_data *ccs;
1260     int cnt, max;	 /* total number of ccs used/alocated */
1261     SplineChar ***marks; /* For each ac this is a list of all mark glyphs in it */
1262     int *mcnt;		 /* Count of the above list */
1263     int *mpos;
1264     SplineFont *sf;
1265 };
1266 
1267 #define AC_MAX	5	/* At most 5 Anchor classes may be used/glyph */
1268 
FigureName(int * unicode,const char * name,int u)1269 static int FigureName(int *unicode,const char *name,int u) {
1270     char *upt, *start, *end, ch;
1271 
1272     start = copy(name);
1273     if ( strchr(start,'_')!=NULL ) {
1274 	while ( (upt=strchr(start,'_'))!=NULL ) {
1275 	    *upt='\0';
1276 	    u = FigureName(unicode,start,u);
1277 	    *upt = '_';
1278 	    if ( u==-1 )
1279 return( -1 );
1280 	    start = upt+1;
1281 	}
1282     }
1283     if ( strncmp(start,"uni",3)==0 && (strlen(start)-3)%4==0 ) {
1284 	start+=3;
1285 	while ( *start ) {
1286 	    ch = start[4]; start[4] = '\0';
1287 	    unicode[u++] = strtol(start,&end,16);
1288 	    start[4] = ch;
1289 	    if ( *end!='\0' )
1290 return( -1 );
1291 	    start += 4;
1292 	}
1293 return( u );
1294     }
1295     unicode[u] = UniFromName(start,ui_none,&custom);
1296     if ( unicode[u]==-1 )
1297 return( -1 );
1298 
1299 return( u+1 );
1300 }
1301 
FigureUnicodes(int * unicode,SplineChar * sc,int u)1302 static int FigureUnicodes(int *unicode,SplineChar *sc,int u) {
1303     const unichar_t *upt;
1304 
1305     if ( u==-1 )
1306 return( -1 );
1307     if ( sc->unicodeenc==-1 )
1308 return( FigureName(unicode,sc->name,u));
1309     if ( isdecompositionnormative(sc->unicodeenc) && sc->unicodeenc>=65536 &&
1310 	    unicode_alternates[sc->unicodeenc>>8]!=NULL &&
1311 	    (upt = unicode_alternates[sc->unicodeenc>>8][sc->unicodeenc&0xff])!=NULL ) {
1312 	while ( *upt!='\0' )
1313 	    unicode[u++] = *upt++;
1314     } else
1315 	unicode[u++] = sc->unicodeenc;
1316 return( u );
1317 }
1318 
FindDecomposition(int * unicode,int u)1319 static int FindDecomposition(int *unicode, int u) {
1320     int uni;
1321     const unichar_t *upt;
1322     int i;
1323 
1324     for ( uni=0; uni<65536; ++uni ) {
1325 	if ( unicode_alternates[uni>>8]!=NULL &&
1326 		(upt = unicode_alternates[uni>>8][uni&0xff])!=NULL ) {
1327 	    for ( i=0; *upt!='\0' && i<u && *upt==(unichar_t)unicode[i]; ++i, ++upt );
1328 	    if ( *upt=='\0' && i==u )
1329 return( uni );
1330 	}
1331     }
1332 return( -1 );
1333 }
1334 
sortunis(int * unicode,int u)1335 static void sortunis(int *unicode,int u) {
1336     int i, j;
1337 
1338     for ( i=0; i<u; ++i ) {
1339 	unicode[i] = CanonicalCombiner(unicode[i]);
1340     }
1341 
1342     for ( i=0; i<u; ++i ) for ( j=i+1; j<u; ++j ) {
1343 	if ( unicode[i]>unicode[j] ) {
1344 	    int temp = unicode[i];
1345 	    unicode[i] = unicode[j];
1346 	    unicode[j] = temp;
1347 	}
1348     }
1349 }
1350 
NameFrom(struct cc_data * this,int * unicode,int u,int uni)1351 static char *NameFrom(struct cc_data *this,int *unicode,int u,int uni) {
1352     char *ret, *pt;
1353     char buffer[60];
1354     struct cc_accents *cca;
1355     int i,len;
1356 
1357     if ( uni!=-1 )
1358 return( copy( StdGlyphName(buffer,uni,ui_none,NULL)) );
1359     if ( u!=-1 && (unicode[0]<0x370 || unicode[0]>0x3ff) ) {
1360 	/* Don't use the unicode decomposition to get a name for greek */
1361 	/*  glyphs. We'd get acute for tonos, etc. */
1362 	ret = malloc(4+4*u);
1363 	strcpy(ret,"uni");
1364 	pt = ret+3;
1365 	for ( i=0; i<u; ++i ) {
1366 	    sprintf( pt, "%04X", unicode[i] );
1367 	    pt += 4;
1368 	}
1369 return( ret );
1370     }
1371     len = strlen( this->base->name ) +1;
1372     for ( cca = this->accents; cca!=NULL; cca = cca->next )
1373 	len += strlen( cca->accent->name ) +1;
1374     ret = malloc(len);
1375     strcpy(ret,this->base->name);
1376     pt = ret + strlen(ret);
1377     for ( cca = this->accents; cca!=NULL; cca = cca->next ) {
1378 	*pt++ = '_';
1379 	strcpy(pt,cca->accent->name);
1380 	pt = pt + strlen(pt);
1381     }
1382 return( ret );
1383 }
1384 
AfmBuildCCName(struct cc_data * this,struct cc_container * cc)1385 static int AfmBuildCCName(struct cc_data *this,struct cc_container *cc) {
1386     int unicode[4*AC_MAX];
1387     int u;
1388     int uni;
1389     struct cc_accents *cca;
1390 
1391     u = FigureUnicodes(unicode,this->base,0);
1392     for ( cca = this->accents; cca!=NULL; cca = cca->next )
1393 	u=FigureUnicodes(unicode,cca->accent,u);
1394     if ( u!=-1 ) {
1395 	unicode[u]= -1;
1396 	if ( unicode[0]==0x131 ) unicode[0] = 'i';
1397 	if ( unicode[0]==0x237 || unicode[0]==0xf6be ) unicode[0] = 'j';
1398 	sortunis(unicode+1,u-1);		/* Only sort the accents */
1399     }
1400     uni = FindDecomposition(unicode,u);
1401     if ( uni!=-1 )
1402 	if ( SFGetChar(cc->sf,uni,NULL)!=NULL )
1403 return( false );		/* Character already exists in font */
1404     this->name = NameFrom(this,unicode,u,uni);
1405     if ( SFGetChar(cc->sf,-1,this->name)!=NULL ) {
1406 	free(this->name);
1407 return( false );		/* Character already exists in font */
1408     }
1409 return( true );
1410 }
1411 
AfmBuildMarkCombos(SplineChar * sc,AnchorPoint * ap,struct cc_container * cc)1412 static void AfmBuildMarkCombos(SplineChar *sc,AnchorPoint *ap, struct cc_container *cc) {
1413     if ( ap==NULL ) {
1414 	AnchorPoint *ap;
1415 	struct cc_data *this = &cc->ccs[cc->cnt++];
1416 	int acnt=0;
1417 	AnchorPoint *map;
1418 
1419 	this->base = sc;
1420 	this->accents = NULL;
1421 	for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->ticked ) {
1422 	    struct cc_accents *cca = chunkalloc(sizeof(struct cc_accents));
1423 	    cca->accent = cc->marks[ap->anchor->ac_num][cc->mpos[ap->anchor->ac_num]];
1424 	    for ( map = cca->accent->anchor; map->anchor!=ap->anchor || map->type!=at_mark;
1425 		    map = map->next );
1426 	    if ( map!=NULL ) {
1427 		cca->xoff = ap->me.x - map->me.x;
1428 		cca->yoff = ap->me.y - map->me.y;
1429 	    }
1430 	    cca->next = this->accents;
1431 	    this->accents = cca;
1432 	    ++acnt;
1433 	}
1434 	if ( !AfmBuildCCName(this,cc)) {
1435 	    struct cc_accents *cca, *next;
1436 	    --cc->cnt;
1437 	    for ( cca = this->accents; cca!=NULL; cca = next ) {
1438 		next = cca->next;
1439 		chunkfree(cca,sizeof(struct cc_accents));
1440 	    }
1441 	} else
1442 	    this->acnt = acnt;
1443     } else if ( ap->ticked ) {
1444 	int ac_num = ap->anchor->ac_num;
1445 	for ( cc->mpos[ac_num] = 0; cc->mpos[ac_num]<cc->mcnt[ac_num]; ++cc->mpos[ac_num] )
1446 	    AfmBuildMarkCombos(sc,ap->next,cc);
1447     } else {
1448 	AfmBuildMarkCombos(sc,ap->next,cc);
1449     }
1450 }
1451 
AfmBuildCombos(SplineChar * sc,AnchorPoint * ap,struct cc_container * cc)1452 static void AfmBuildCombos(SplineChar *sc,AnchorPoint *ap, struct cc_container *cc) {
1453 
1454     if ( ap!=NULL ) {
1455 	AfmBuildCombos(sc,ap->next,cc);
1456 	if ( ap->type==at_basechar ) {
1457 	    ap->ticked = true;
1458 	    AfmBuildCombos(sc,ap->next,cc);
1459 	    ap->ticked = false;
1460 	}
1461     } else {
1462 	int ticks, cnt;
1463 	AnchorPoint *ap;
1464 
1465 	for ( ap=sc->anchor, ticks=0, cnt=1; ap!=NULL; ap=ap->next ) {
1466 	    if ( ap->ticked ) {
1467 		++ticks;
1468 		cnt *= cc->mcnt[ap->anchor->ac_num];
1469 	    }
1470 	}
1471 	if ( ticks==0 )		  /* No accents classes selected */
1472 return;
1473 	if ( ticks>AC_MAX || cnt>200 ) /* Too many selected. I fear combinatorial explosion */
1474 return;
1475 	if ( cc->cnt+cnt >= cc->max )
1476 	    cc->ccs = realloc(cc->ccs,(cc->max += cnt+200)*sizeof(struct cc_data));
1477 	AfmBuildMarkCombos(sc,sc->anchor,cc);
1478     }
1479 }
1480 
AfmFigureCCdata(SplineFont * sf,int * total)1481 static struct cc_data *AfmFigureCCdata(SplineFont *sf,int *total) {
1482     int ac_cnt, i;
1483     AnchorClass *ac;
1484     AnchorPoint *ap;
1485     SplineChar *sc;
1486     int *mmax;
1487     struct cc_container cc;
1488 
1489     memset(&cc,0,sizeof(cc));
1490     cc.sf = sf;
1491     for ( ac=sf->anchor, ac_cnt=0; ac!=NULL; ac=ac->next, ++ac_cnt)
1492 	ac->ac_num = ac_cnt;
1493     cc.mcnt = calloc(ac_cnt,sizeof(int));
1494     cc.mpos = calloc(ac_cnt,sizeof(int));
1495     mmax = calloc(ac_cnt,sizeof(int));
1496     cc.marks = calloc(ac_cnt,sizeof(SplineChar **));
1497     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1498 	for ( ap = sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->type==at_mark )
1499 	    ++mmax[ap->anchor->ac_num];
1500     }
1501     for ( i=0; i<ac_cnt; ++i )
1502 	cc.marks[i] = calloc(mmax[i],sizeof(SplineChar *));
1503     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1504 	for ( ap = sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->type==at_mark )
1505 	    cc.marks[ap->anchor->ac_num][cc.mcnt[ap->anchor->ac_num]++] = sc;
1506     }
1507     for ( i=0; i<sf->glyphcnt; ++i )
1508 	if ( (sc = sf->glyphs[i])!=NULL && sc->anchor!=NULL ) {
1509 	    for ( ap = sc->anchor; ap!=NULL; ap=ap->next )
1510 		ap->ticked = false;
1511 	    AfmBuildCombos(sc,sc->anchor,&cc);
1512 	}
1513     if ( cc.cnt+1 >= cc.max )
1514 	cc.ccs = realloc(cc.ccs,(cc.max += 1)*sizeof(struct cc_data));
1515     cc.ccs[cc.cnt].base = NULL;		/* End of list mark */
1516     for ( i=0; i<ac_cnt; ++i )
1517 	free(cc.marks[i]);
1518     free(cc.marks);
1519     free(cc.mcnt);
1520     free(cc.mpos);
1521     free(mmax);
1522     *total = cc.cnt;
1523 return( cc.ccs );
1524 }
1525 
CCFree(struct cc_data * cc)1526 static void CCFree(struct cc_data *cc) {
1527     int i;
1528     struct cc_accents *cca, *next;
1529 
1530     if ( cc==NULL )
1531 return;
1532     for ( i=0; cc[i].base!=NULL; ++i ) {
1533 	free(cc[i].name);
1534 	for ( cca = cc[i].accents; cca!=NULL; cca = next ) {
1535 	    next = cca->next;
1536 	    chunkfree(cca,sizeof(struct cc_accents));
1537 	}
1538     }
1539     free( cc );
1540 }
1541 
AfmComposites(FILE * afm,SplineFont * sf,struct cc_data * cc,int cc_cnt)1542 static void AfmComposites(FILE *afm, SplineFont *sf, struct cc_data *cc, int cc_cnt) {
1543     int i;
1544     struct cc_accents *cca;
1545     bigreal em = (sf->ascent+sf->descent);
1546 
1547     fprintf( afm, "StartComposites %d\n", cc_cnt );
1548     for ( i=0; i<cc_cnt; ++i ) {
1549 	fprintf( afm, "CC %s %d; PCC %s 0 0;",
1550 		cc[i].name, cc[i].acnt+1, cc[i].base->name );
1551 	for ( cca = cc[i].accents; cca!=NULL; cca = cca->next ) {
1552 	    fprintf( afm, " PCC %s %g %g;",
1553 		    cca->accent->name, rint(1000.0*cca->xoff/em), rint(1000.0*cca->yoff/em) );
1554 	}
1555 	putc('\n',afm);
1556     }
1557     fprintf( afm, "EndComposites\n" );
1558 }
1559 
AfmCompositeChar(FILE * afm,struct cc_data * cc,int layer)1560 static void AfmCompositeChar(FILE *afm,struct cc_data *cc,int layer) {
1561     DBounds b, b1;
1562     SplineChar *sc = cc->base;
1563     SplineFont *sf = sc->parent;
1564     int em = (sf->ascent+sf->descent);
1565     struct cc_accents *cca;
1566 
1567     SplineCharLayerFindBounds(sc,layer,&b);
1568     for ( cca = cc->accents; cca!=NULL; cca = cca->next ) {
1569 	SplineCharLayerFindBounds(cca->accent,layer,&b1);
1570 	if ( b1.minx+cca->xoff<b.minx ) b.minx = b1.minx+cca->xoff;
1571 	if ( b1.maxx+cca->xoff>b.maxx ) b.maxx = b1.maxx+cca->xoff;
1572 	if ( b1.miny+cca->yoff<b.miny ) b.miny = b1.miny+cca->yoff;
1573 	if ( b1.maxy+cca->yoff>b.maxy ) b.maxy = b1.maxy+cca->yoff;
1574     }
1575     fprintf( afm, "C %d ; WX %d ; ", -2, sc->width*1000/em );
1576     if ( sf->hasvmetrics )
1577 	fprintf( afm, "WY %d ; ", sc->vwidth*1000/em );
1578     fprintf( afm, "N %s ; B %d %d %d %d ;",
1579 	    cc->name,
1580 	    (int) floor(b.minx*1000/em), (int) floor(b.miny*1000/em),
1581 	    (int) ceil(b.maxx*1000/em), (int) ceil(b.maxy*1000/em) );
1582     putc('\n',afm);
1583 }
1584 
1585 static void LigatureClosure(SplineFont *sf);
1586 
AfmSplineFont(FILE * afm,SplineFont * sf,int formattype,EncMap * map,int docc,SplineFont * fullsf,int layer)1587 int AfmSplineFont(FILE *afm, SplineFont *sf, int formattype,EncMap *map,
1588 	int docc, SplineFont *fullsf, int layer) {
1589     int i, j, cnt, vcnt;
1590     int type0 = ( formattype==ff_ptype0 );
1591     int otf = (formattype==ff_otf);
1592     int encmax=(!type0 && !otf)?256:65536;
1593     int anyzapf;
1594     int iscid = ( formattype==ff_cid || formattype==ff_otfcid );
1595     SplineChar *sc;
1596     int cc_cnt = 0;
1597     struct cc_data *cc= NULL;
1598 
1599     SFLigaturePrepare(sf);
1600     LigatureClosure(sf);		/* Convert 3 character ligs to a set of two character ones when possible */
1601     SFKernClassTempDecompose(sf,false);	/* Undoes kern classes */
1602     SFKernClassTempDecompose(sf,true);
1603     if ( sf->anchor!=NULL && docc )
1604 	cc = AfmFigureCCdata(sf,&cc_cnt);
1605 
1606     if ( iscid && sf->cidmaster!=NULL ) sf = sf->cidmaster;
1607 
1608     AfmSplineFontHeader(afm,sf,formattype,map,fullsf,layer);
1609 
1610     cnt = 0;
1611     for ( i=0; i<map->enccount; ++i ) {
1612 	int gid = map->map[i];
1613 	if ( gid==-1 )
1614     continue;
1615 	sc = NULL;
1616 	if ( iscid ) {
1617 	    for ( j=0; j<sf->subfontcnt; ++j )
1618 		if ( gid<sf->subfonts[j]->glyphcnt && sf->subfonts[j]->glyphs[gid]!=NULL ) {
1619 		    sc = sf->subfonts[j]->glyphs[gid];
1620 	    break;
1621 		}
1622 	} else
1623 	    sc = sf->glyphs[gid];
1624 	if ( SCWorthOutputting(sc) || (iscid && i==0 && sc!=NULL))
1625 	    ++cnt;
1626     }
1627 
1628     anyzapf = false;
1629     if ( type0 && (map->enc->is_unicodebmp ||
1630 	    map->enc->is_unicodefull)) {
1631 	for ( i=0x2700; i<map->enccount && i<encmax && i<=0x27ff; ++i ) {
1632 	    int gid = map->map[i];
1633 	    if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) )
1634 		anyzapf = true;
1635 	}
1636 	if ( !anyzapf )
1637 	    for ( i=0; i<0xc0; ++i )
1638 		if ( zapfexists[i])
1639 		    ++cnt;
1640     }
1641 
1642     fprintf( afm, "StartCharMetrics %d\n", cnt+cc_cnt );
1643     if ( iscid ) {
1644 	for ( i=0; i<map->enccount; ++i ) {
1645 	    int gid = map->map[i];
1646 	    if ( gid==-1 )
1647 	continue;
1648 	    sc = NULL;
1649 	    for ( j=0; j<sf->subfontcnt; ++j )
1650 		if ( gid<sf->subfonts[j]->glyphcnt && sf->subfonts[j]->glyphs[gid]!=NULL ) {
1651 		    sc = sf->subfonts[j]->glyphs[gid];
1652 	    break;
1653 		}
1654 	    if ( SCWorthOutputting(sc) || (i==0 && sc!=NULL) )
1655 		AfmCIDChar(afm, sc, i,layer);
1656 	}
1657     } else if ( type0 && (map->enc->is_unicodebmp ||
1658 	    map->enc->is_unicodefull)) {
1659 	for ( i=0; i<map->enccount && i<encmax && i<0x2700; ++i ) {
1660 	    int gid = map->map[i];
1661 	    if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
1662 		AfmSplineCharX(afm,sf->glyphs[gid],i,layer);
1663 	    }
1664 	}
1665 	if ( !anyzapf ) {
1666 	    for ( i=0; i<0xc0; ++i ) if ( zapfexists[i] )
1667 		AfmZapfCharX(afm,i);
1668 	    i += 0x2700;
1669 	}
1670 	for ( ; i<map->enccount && i<encmax; ++i ) {
1671 	    int gid = map->map[i];
1672 	    if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
1673 		AfmSplineCharX(afm,sf->glyphs[gid],i,layer);
1674 	    }
1675 	}
1676     } else if ( type0 ) {
1677 	for ( i=0; i<map->enccount && i<encmax; ++i ) {
1678 	    int gid = map->map[i];
1679 	    if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
1680 		AfmSplineCharX(afm,sf->glyphs[gid],i,layer);
1681 	    }
1682 	}
1683     } else {
1684 	for ( i=0; i<map->enccount && i<encmax; ++i ) {
1685 	    int gid = map->map[i];
1686 	    if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
1687 		AfmSplineChar(afm,sf->glyphs[gid],i,layer);
1688 	    }
1689 	}
1690     }
1691     for ( ; i<map->enccount ; ++i ) {
1692 	int gid = map->map[i];
1693 	if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
1694 	    AfmSplineChar(afm,sf->glyphs[gid],-1,layer);
1695 	}
1696     }
1697     for ( i=0; i<cc_cnt; ++i )
1698 	AfmCompositeChar(afm,&cc[i],layer);
1699     fprintf( afm, "EndCharMetrics\n" );
1700     vcnt = anykerns(sf,true);
1701     if ( (cnt = anykerns(sf,false))>0 || vcnt>0 ) {
1702 	fprintf( afm, "StartKernData\n" );
1703 	if ( cnt>0 ) {
1704 	    fprintf( afm, "StartKernPairs%s %d\n", vcnt==0?"":"0", cnt );
1705 	    for ( i=0; i<map->enccount ; ++i ) {
1706 		int gid = map->map[i];
1707 		if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
1708 		    AfmKernPairs(afm,sf->glyphs[gid],false);
1709 		}
1710 	    }
1711 	    fprintf( afm, "EndKernPairs\n" );
1712 	}
1713 	if ( vcnt>0 ) {
1714 	    fprintf( afm, "StartKernPairs1 %d\n", vcnt );
1715 	    for ( i=0; i<map->enccount ; ++i ) {
1716 		int gid = map->map[i];
1717 		if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
1718 		    AfmKernPairs(afm,sf->glyphs[gid],true);
1719 		}
1720 	    }
1721 	    fprintf( afm, "EndKernPairs\n" );
1722 	}
1723 	fprintf( afm, "EndKernData\n" );
1724     }
1725     if ( cc!=NULL )
1726 	AfmComposites(afm,sf,cc,cc_cnt);
1727     fprintf( afm, "EndFontMetrics\n" );
1728 
1729     SFLigatureCleanup(sf);
1730     SFKernCleanup(sf,false);
1731     SFKernCleanup(sf,true);
1732     CCFree(cc);
1733 
1734 return( !ferror(afm));
1735 }
1736 
AmfmSplineFont(FILE * amfm,MMSet * mm,int formattype,EncMap * map,int layer)1737 int AmfmSplineFont(FILE *amfm, MMSet *mm, int formattype,EncMap *map,int layer) {
1738     int i,j;
1739 
1740     AfmSplineFontHeader(amfm,mm->normal,formattype,map,NULL,layer);
1741     fprintf( amfm, "Masters %d\n", mm->instance_count );
1742     fprintf( amfm, "Axes %d\n", mm->axis_count );
1743 
1744     fprintf( amfm, "WeightVector [%g", (double) mm->defweights[0] );
1745     for ( i=1; i<mm->instance_count; ++i )
1746 	fprintf( amfm, " %g", (double) mm->defweights[i]);
1747     fprintf( amfm, "]\n" );
1748 
1749     fprintf( amfm, "BlendDesignPositions [" );
1750     for ( i=0; i<mm->instance_count; ++i ) {
1751 	fprintf(amfm, "[%g", (double) mm->positions[i*mm->axis_count+0]);
1752 	for ( j=1; j<mm->axis_count; ++j )
1753 	    fprintf( amfm, " %g", (double) mm->positions[i*mm->axis_count+j]);
1754 	fprintf(amfm, i==mm->instance_count-1 ? "]" : "] " );
1755     }
1756     fprintf( amfm, "]\n" );
1757 
1758     fprintf( amfm, "BlendDesignMap [" );
1759     for ( i=0; i<mm->axis_count; ++i ) {
1760 	putc('[',amfm);
1761 	for ( j=0; j<mm->axismaps[i].points; ++j )
1762 	    fprintf(amfm, "[%g %g]", (double) mm->axismaps[i].designs[j], (double) mm->axismaps[i].blends[j]);
1763 	fprintf(amfm, i==mm->axis_count-1 ? "]" : "] " );
1764     }
1765     fprintf( amfm, "]\n" );
1766 
1767     fprintf( amfm, "BlendAxisTypes [/%s", mm->axes[0] );
1768     for ( j=1; j<mm->axis_count; ++j )
1769 	fprintf( amfm, " /%s", mm->axes[j]);
1770     fprintf( amfm, "]\n" );
1771 
1772     for ( i=0; i<mm->axis_count; ++i ) {
1773 	fprintf( amfm, "StartAxis\n" );
1774 	fprintf( amfm, "AxisType %s\n", mm->axes[i] );
1775 	fprintf( amfm, "AxisLabel %s\n", MMAxisAbrev(mm->axes[i]) );
1776 	fprintf( amfm, "EndAxis\n" );
1777     }
1778 
1779     for ( i=0; i<mm->instance_count; ++i ) {
1780 	fprintf( amfm, "StartMaster\n" );
1781 	fprintf( amfm, "FontName %s\n", mm->instances[i]->fontname );
1782 	if ( mm->instances[i]->fullname!=NULL )
1783 	    fprintf( amfm, "FullName %s\n", mm->instances[i]->fullname );
1784 	if ( mm->instances[i]->familyname!=NULL )
1785 	    fprintf( amfm, "FamilyName %s\n", mm->instances[i]->familyname );
1786 	if ( mm->instances[i]->version!=NULL )
1787 	    fprintf( amfm, "Version %s\n", mm->instances[i]->version );
1788 	fprintf( amfm, "WeightVector [%d", i==0 );
1789 	for ( j=1; j<mm->instance_count; ++j )
1790 	    fprintf( amfm, " %d", i==j );
1791 	fprintf( amfm, "]\n" );
1792 	fprintf( amfm, "EndMaster\n" );
1793     }
1794     fprintf( amfm, "EndMasterFontMetrics\n" );
1795 return( !ferror(amfm));
1796 }
1797 
SFLigatureCleanup(SplineFont * sf)1798 void SFLigatureCleanup(SplineFont *sf) {
1799     LigList *l, *next;
1800     struct splinecharlist *scl, *sclnext;
1801     int j;
1802 
1803     if (sf->internal_temp)
1804 return;
1805 
1806     for ( j=0; j<sf->glyphcnt; ++j ) if ( sf->glyphs[j]!=NULL ) {
1807 	for ( l = sf->glyphs[j]->ligofme; l!=NULL; l = next ) {
1808 	    next = l->next;
1809 	    for ( scl = l->components; scl!=NULL; scl = sclnext ) {
1810 		sclnext = scl->next;
1811 		chunkfree(scl,sizeof(struct splinecharlist));
1812 	    }
1813 	    if ( l->lig->temporary ) {
1814 		free(l->lig->u.lig.components);
1815 		chunkfree(l->lig,sizeof(PST));
1816 	    }
1817 	    free( l );
1818 	}
1819 	sf->glyphs[j]->ligofme = NULL;
1820     }
1821 }
1822 
SFLigaturePrepare(SplineFont * sf)1823 void SFLigaturePrepare(SplineFont *sf) {
1824     PST *lig;
1825     LigList *ll;
1826     int i,j,k,ch;
1827     char *pt, *ligstart;
1828     SplineChar *sc, *tsc;
1829     struct splinecharlist *head, *last;
1830     int ccnt, lcnt, lmax=20;
1831     LigList **all = malloc(lmax*sizeof(LigList *));
1832 
1833     /* First clear out any old stuff */
1834     for ( j=0; j<sf->glyphcnt; ++j ) if ( sf->glyphs[j]!=NULL )
1835 	sf->glyphs[j]->ligofme = NULL;
1836 
1837     /* Attach all the ligatures to the first character of their components */
1838     /* Figure out what the components are, and if they all exist */
1839     /* we're only interested in the lig if all components are worth outputting */
1840     for ( i=0 ; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sf->glyphs[i]) && sf->glyphs[i]->possub!=NULL ) {
1841 	for ( lig = sf->glyphs[i]->possub; lig!=NULL; lig=lig->next ) if ( lig->type==pst_ligature ) {
1842 	    ligstart = lig->u.lig.components;
1843 	    last = head = NULL; sc = NULL;
1844 	    for ( pt = ligstart; *pt!='\0'; ) {
1845 		char *start = pt;
1846 		for ( ; *pt!='\0' && *pt!=' '; ++pt );
1847 		ch = *pt; *pt = '\0';
1848 		tsc = SFGetChar(sf,-1,start);
1849 		*pt = ch;
1850 		if ( tsc!=NULL ) {
1851 		    if ( !SCWorthOutputting(tsc)) {
1852 			sc = NULL;
1853 	    break;
1854 		    }
1855 		    if ( sc==NULL ) {
1856 			sc = tsc;
1857 			ccnt = 1;
1858 		    } else {
1859 			struct splinecharlist *cur = chunkalloc(sizeof(struct splinecharlist));
1860 			if ( head==NULL )
1861 			    head = cur;
1862 			else
1863 			    last->next = cur;
1864 			last = cur;
1865 			cur->sc = tsc;
1866 			cur->next = NULL;
1867 			++ccnt;
1868 		    }
1869 		} else {
1870 		    sc = NULL;
1871 	    break;
1872 		}
1873 		while ( *pt==' ' ) ++pt;
1874 	    }
1875 	    if ( sc!=NULL ) {
1876 		ll = malloc(sizeof(LigList));
1877 		ll->lig = lig;
1878 		ll->next = sc->ligofme;
1879 		ll->first = sc;
1880 		ll->components = head;
1881 		ll->ccnt = ccnt;
1882 		sc->ligofme = ll;
1883 	    } else {
1884 		while ( head!=NULL ) {
1885 		    last = head->next;
1886 		    chunkfree(head,sizeof(*head));
1887 		    head = last;
1888 		}
1889 	    }
1890 	}
1891     }
1892     for ( i=0 ; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL && sc->ligofme!=NULL ) {
1893 	for ( ll=sc->ligofme, lcnt=0; ll!=NULL; ll=ll->next, ++lcnt );
1894 	/* Finally, order the list so that the longest ligatures are first */
1895 	if ( lcnt>1 ) {
1896 	    if ( lcnt>=lmax )
1897 		all = realloc(all,(lmax=lcnt+30)*sizeof(LigList *));
1898 	    for ( ll=sc->ligofme, k=0; ll!=NULL; ll=ll->next, ++k )
1899 		all[k] = ll;
1900 	    for ( k=0; k<lcnt-1; ++k ) for ( j=k+1; j<lcnt; ++j )
1901 		if ( all[k]->ccnt<all[j]->ccnt ) {
1902 		    ll = all[k];
1903 		    all[k] = all[j];
1904 		    all[j] = ll;
1905 		}
1906 	    sc->ligofme = all[0];
1907 	    for ( k=0; k<lcnt-1; ++k )
1908 		all[k]->next = all[k+1];
1909 	    all[k]->next = NULL;
1910 	}
1911     }
1912     free( all );
1913 }
1914 
LigatureClosure(SplineFont * sf)1915 static void LigatureClosure(SplineFont *sf) {
1916     /* AFM files can only deal with 2 character ligatures */
1917     /* Look for any three character ligatures (like ffi) which can be made up */
1918     /*  of a two character ligature and their final letter (like "ff" and "i")*/
1919     /* I'm not going to bother with 4 character ligatures which could be made */
1920     /*  of 2+1+1 because that doesn't happen in latin that I know of, and arabic */
1921     /*  really should be using a type2 font */
1922     int i;
1923     LigList *l, *l2, *l3;
1924     PST *lig;
1925     SplineChar *sc, *sublig;
1926 
1927     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
1928 	for ( l=sc->ligofme; l!=NULL; l=l->next ) if ( l->lig->subtable->lookup->store_in_afm ) {
1929 	    if ( l->ccnt==3 ) {
1930 		/* we've got a 3 character ligature */
1931 		for ( l2=l->next; l2!=NULL; l2=l2->next ) {
1932 		    if ( l2->lig->subtable==l->lig->subtable &&
1933 			    l2->ccnt == 2 && l2->components->sc==l->components->sc ) {
1934 			/* We've found a two character sub ligature */
1935 			sublig = l2->lig->u.lig.lig;
1936 			for ( l3=sublig->ligofme; l3!=NULL; l3=l3->next ) {
1937 			    if ( l3->ccnt==2 && l3->components->sc==l->components->next->sc &&
1938 				    l3->lig->subtable->lookup->store_in_afm)
1939 			break;
1940 			}
1941 			if ( l3!=NULL )	/* The ligature we want to add already exists */
1942 		break;
1943 			lig = chunkalloc(sizeof(PST));
1944 			*lig = *l->lig;
1945 			lig->temporary = true;
1946 			lig->next = NULL;
1947 			lig->u.lig.components = malloc(strlen(sublig->name)+
1948 					strlen(l->components->next->sc->name)+
1949 					2);
1950 			sprintf(lig->u.lig.components,"%s %s",sublig->name,
1951 				l->components->next->sc->name);
1952 			l3 = malloc(sizeof(LigList));
1953 			l3->lig = lig;
1954 			l3->next = sublig->ligofme;
1955 			l3->first = sublig;
1956 			l3->ccnt = 2;
1957 			sublig->ligofme = l3;
1958 			l3->components = chunkalloc(sizeof(struct splinecharlist));
1959 			l3->components->sc = l->components->next->sc;
1960 		break;
1961 		    }
1962 		}
1963 	    }
1964 	}
1965     }
1966 }
1967 
SFKernCleanup(SplineFont * sf,int isv)1968 void SFKernCleanup(SplineFont *sf,int isv) {
1969     int i;
1970     KernPair *kp, *p, *n;
1971     OTLookup *otl, *otlp, *otln;
1972 
1973     if (sf->internal_temp)
1974 return;
1975 
1976     if ( (!isv && sf->kerns==NULL) || (isv && sf->vkerns==NULL) )	/* can't have gotten messed up */
1977 return;
1978     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1979 	for ( kp = isv ? sf->glyphs[i]->vkerns : sf->glyphs[i]->kerns, p=NULL; kp!=NULL; kp = n ) {
1980 	    n = kp->next;
1981 	    if ( kp->kcid!=0 ) {
1982 		if ( p!=NULL )
1983 		    p->next = n;
1984 		else if ( isv )
1985 		    sf->glyphs[i]->vkerns = n;
1986 		else
1987 		    sf->glyphs[i]->kerns = n;
1988 		chunkfree(kp,sizeof(*kp));
1989 	    } else
1990 		p = kp;
1991 	}
1992     }
1993     for ( otl=sf->gpos_lookups, otlp = NULL; otl!=NULL; otl = otln ) {
1994 	otln = otl->next;
1995 	if ( otl->temporary_kern ) {
1996 	    if ( otlp!=NULL )
1997 		otlp->next = otln;
1998 	    else
1999 		sf->gpos_lookups = otln;
2000 	    OTLookupFree(otl);
2001 	} else
2002 	    otlp = otl;
2003     }
2004 }
2005 
KCSfree(SplineChar *** scs,int cnt)2006 static void KCSfree(SplineChar ***scs,int cnt) {
2007     int i;
2008     for ( i=1; i<cnt; ++i )
2009 	free( scs[i]);
2010     free(scs);
2011 }
2012 
KernClassToSC(SplineFont * sf,char ** classnames,int cnt)2013 static SplineChar ***KernClassToSC(SplineFont *sf, char **classnames, int cnt) {
2014     SplineChar ***scs, *sc;
2015     int i,j;
2016     char *pt, *end, ch;
2017 
2018     scs = malloc(cnt*sizeof(SplineChar **));
2019     for ( i=1; i<cnt; ++i ) {
2020 	for ( pt=classnames[i]-1, j=0; pt!=NULL; pt=strchr(pt+1,' ') )
2021 	    ++j;
2022 	scs[i] = malloc((j+1)*sizeof(SplineChar *));
2023 	for ( pt=classnames[i], j=0; *pt!='\0'; pt=end+1 ) {
2024 	    end = strchr(pt,' ');
2025 	    if ( end==NULL )
2026 		end = pt+strlen(pt);
2027 	    ch = *end;
2028 	    *end = '\0';
2029 	    sc = SFGetChar(sf,-1,pt);
2030 	    if ( sc!=NULL )
2031 		scs[i][j++] = sc;
2032 	    if ( ch=='\0' )
2033 	break;
2034 	    *end = ch;
2035 	}
2036 	scs[i][j] = NULL;
2037     }
2038 return( scs );
2039 }
2040 
AddTempKP(SplineChar * first,SplineChar * second,int16 offset,struct lookup_subtable * sub,uint16 kcid,int isv)2041 static void AddTempKP(SplineChar *first,SplineChar *second,
2042 	int16 offset, struct lookup_subtable *sub,uint16 kcid,int isv) {
2043     KernPair *kp;
2044 
2045     for ( kp=first->kerns; kp!=NULL; kp=kp->next )
2046 	if ( kp->sc == second )
2047     break;
2048     if ( kp==NULL ) {
2049 	kp = chunkalloc(sizeof(KernPair));
2050 	kp->sc = second;
2051 	kp->off = offset;
2052 	kp->subtable = sub;
2053 	kp->kcid = kcid;
2054 	if ( isv ) {
2055 	    kp->next = first->vkerns;
2056 	    first->vkerns = kp;
2057 	} else {
2058 	    kp->next = first->kerns;
2059 	    first->kerns = kp;
2060 	}
2061     }
2062 }
2063 
SFKernClassTempDecompose(SplineFont * sf,int isv)2064 void SFKernClassTempDecompose(SplineFont *sf,int isv) {
2065     KernClass *kc, *head= isv ? sf->vkerns : sf->kerns;
2066     KernPair *kp;
2067     SplineChar ***first, ***last;
2068     int i, j, k, l;
2069     OTLookup *otl;
2070 
2071     /* Make sure the temporary field is cleaned up. Otherwise we may lose kerning data */
2072     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2073 	for ( kp = isv ? sf->glyphs[i]->vkerns : sf->glyphs[i]->kerns; kp!=NULL; kp = kp->next ) {
2074 	    kp->kcid = false;
2075 	}
2076     }
2077     for ( kc = head, i=0; kc!=NULL; kc = kc->next )
2078 	kc->kcid = ++i;
2079     for ( kc = head; kc!=NULL; kc = kc->next ) {
2080 
2081 	otl = chunkalloc(sizeof(OTLookup));
2082 	otl->next = sf->gpos_lookups;
2083 	sf->gpos_lookups = otl;
2084 	otl->lookup_type = gpos_pair;
2085 	otl->lookup_flags = kc->subtable->lookup->lookup_flags;
2086 	otl->features = FeatureListCopy(kc->subtable->lookup->features);
2087 	otl->lookup_name = copy(_("<Temporary kerning>"));
2088 	otl->temporary_kern = otl->store_in_afm = true;
2089 	otl->subtables = chunkalloc(sizeof(struct lookup_subtable));
2090 	otl->subtables->lookup = otl;
2091 	otl->subtables->per_glyph_pst_or_kern = true;
2092 	otl->subtables->subtable_name = copy(_("<Temporary kerning>"));
2093 
2094 	first = KernClassToSC(sf,kc->firsts,kc->first_cnt);
2095 	last = KernClassToSC(sf,kc->seconds,kc->second_cnt);
2096 	for ( i=1; i<kc->first_cnt; ++i ) for ( j=1; j<kc->second_cnt; ++j ) {
2097 	    if ( kc->offsets[i*kc->second_cnt+j]!=0 ) {
2098 		for ( k=0; first[i][k]!=NULL; ++k )
2099 		    for ( l=0; last[j][l]!=NULL; ++l )
2100 			AddTempKP(first[i][k],last[j][l],
2101 				kc->offsets[i*kc->second_cnt+j],
2102 			        otl->subtables,kc->kcid,isv);
2103 	    }
2104 	}
2105 	KCSfree(first,kc->first_cnt);
2106 	KCSfree(last,kc->second_cnt);
2107     }
2108 }
2109 
2110 /* ************************************************************************** */
2111 /* **************************** Writing PFM files *************************** */
2112 /* ************************************************************************** */
getlshort(FILE * pfm)2113 static int getlshort(FILE *pfm) {
2114     int ch1;
2115     ch1 = getc(pfm);
2116 return( (getc(pfm)<<8)|ch1 );
2117 }
2118 
getlint(FILE * pfm)2119 static int getlint(FILE *pfm) {
2120     int ch1, ch2, ch3;
2121     ch1 = getc(pfm);
2122     ch2 = getc(pfm);
2123     ch3 = getc(pfm);
2124 return( (getc(pfm)<<24)|(ch3<<16)|(ch2<<8)|ch1 );
2125 }
2126 
putlshort(short val,FILE * pfm)2127 static void putlshort(short val,FILE *pfm) {
2128     putc(val&0xff,pfm);
2129     putc(val>>8,pfm);
2130 }
2131 
putlint(int val,FILE * pfm)2132 static void putlint(int val,FILE *pfm) {
2133     putc(val&0xff,pfm);
2134     putc((val>>8)&0xff,pfm);
2135     putc((val>>16)&0xff,pfm);
2136     putc((val>>24)&0xff,pfm);
2137 }
2138 
2139 static const unsigned short local_unicode_from_win[] = {
2140   0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
2141   0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
2142   0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
2143   0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
2144   0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
2145   0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
2146   0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
2147   0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
2148   0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
2149   0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
2150   0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
2151   0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
2152   0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
2153   0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
2154   0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
2155   0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
2156   0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
2157   0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x008e, 0x008f,
2158   0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
2159   0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x009e, 0x0178,
2160   0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
2161   0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
2162   0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
2163   0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
2164   0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
2165   0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
2166   0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
2167   0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
2168   0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
2169   0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
2170   0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
2171   0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
2172 };
2173 
inwin(SplineFont * sf,int winmap[256])2174 static int inwin(SplineFont *sf, int winmap[256]) {
2175     int i, j;
2176     int cnt;
2177 
2178     memset(winmap,-1,sizeof(int[256]));
2179     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2180 	int unienc = sf->glyphs[i]->unicodeenc;
2181 	if ( unienc==-1 || unienc>0x3000 )
2182     continue;
2183 	for ( j=255; j>=0; --j ) {
2184 	    if ( local_unicode_from_win[j]==unienc ) {
2185 		winmap[j] = i;
2186 	break;
2187 	    }
2188 	}
2189     }
2190     for ( i=0x80, cnt=0; i<0x100; ++i )
2191 	if ( winmap[i]!=-1 )
2192 	    ++cnt;
2193 return( cnt>64 );
2194 }
2195 
revwinmap(int winmap[256],int gid)2196 static int revwinmap(int winmap[256], int gid) {
2197     int i;
2198     for ( i=255; i>=0; --i )
2199 	if ( winmap[i]==gid )
2200     break;
2201 return( i );
2202 }
2203 
PfmSplineFont(FILE * pfm,SplineFont * sf,EncMap * map,int layer)2204 int PfmSplineFont(FILE *pfm, SplineFont *sf, EncMap *map,int layer) {
2205     int caph=0, xh=0, ash=0, dsh=0, cnt=0, first=-1, samewid=-1, maxwid= -1, last=0, wid=0, ymax=0, ymin=0;
2206     int kerncnt=0, spacepos=0x20;
2207     int i, ii;
2208     const char *pt;
2209     KernPair *kp;
2210     int winmap[256];
2211     /* my docs imply that pfm files can only handle 1byte fonts */
2212     /* I think they must be output as if the font were encoded in winansi */
2213     /* Ah, but Adobe's technical note 5178.PFM.PDF gives the two byte format */
2214     long size, devname, facename, extmetrics, exttable, driverinfo, kernpairs, pos;
2215     DBounds b;
2216     int style;
2217     int windows_encoding;
2218 
2219     if ( map->enc->is_japanese ||
2220 	    (sf->cidmaster!=NULL && strnmatch(sf->cidmaster->ordering,"Japan",5)==0 ))
2221 	windows_encoding = 128;
2222     else if ( map->enc->is_korean ||
2223 	    (sf->cidmaster!=NULL && strnmatch(sf->cidmaster->ordering,"Korea",5)==0 ))
2224 	windows_encoding = 129;
2225     else if ( map->enc->is_tradchinese ||
2226 	    (sf->cidmaster!=NULL && strnmatch(sf->cidmaster->ordering,"CNS",3)==0 ))
2227 	windows_encoding = 136;
2228     else if ( map->enc->is_simplechinese ||
2229 	    (sf->cidmaster!=NULL && strnmatch(sf->cidmaster->ordering,"GB",2)==0 ))
2230 	windows_encoding = 134;
2231     else if ( map->enc->is_custom )
2232 	windows_encoding = 2;
2233     else
2234 	windows_encoding = strmatch(map->enc->enc_name,"symbol")==0?2:0;
2235     if ( windows_encoding==0 )
2236 	if ( !inwin(sf,winmap))
2237 	    windows_encoding = 0xff;
2238     if ( windows_encoding!=0 ) {
2239 	memset(winmap,-1,sizeof(winmap));
2240 	for ( i=0; i<sf->glyphcnt; ++i )
2241 	    if ( (ii=map->backmap[i])!=-1 && ii<256 )
2242 		winmap[ii] = i;
2243     }
2244 
2245     SFKernClassTempDecompose(sf,false);
2246     for ( ii=0; ii<256; ++ii ) if ( (i=winmap[ii])!=-1 ) {
2247 	if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->unicodeenc==' ' )
2248 	    spacepos = ii;
2249 	if ( SCWorthOutputting(sf->glyphs[i]) ) {
2250 	    ++cnt;
2251 	    if ( sf->glyphs[i]->unicodeenc=='I' || sf->glyphs[i]->unicodeenc=='x' ||
2252 		    sf->glyphs[i]->unicodeenc=='H' || sf->glyphs[i]->unicodeenc=='d' ||
2253 		    sf->glyphs[i]->unicodeenc=='p' || sf->glyphs[i]->unicodeenc=='l' ) {
2254 		SplineCharLayerFindBounds(sf->glyphs[i],layer,&b);
2255 		if ( ymax<b.maxy ) ymax = b.maxy;
2256 		if ( ymin>b.miny ) ymin = b.miny;
2257 		if ( sf->glyphs[i]->unicodeenc=='I' || sf->glyphs[i]->unicodeenc=='H' )
2258 		    caph = b.maxy;
2259 		else if ( sf->glyphs[i]->unicodeenc=='x' )
2260 		    xh = b.maxy;
2261 		else if ( sf->glyphs[i]->unicodeenc=='d' || sf->glyphs[i]->unicodeenc=='l' )
2262 		    ash = b.maxy;
2263 		else
2264 		    dsh = b.miny;
2265 	    }
2266 	    if ( samewid==-1 )
2267 		samewid = sf->glyphs[i]->width;
2268 	    else if ( samewid!=sf->glyphs[i]->width )
2269 		samewid = -2;
2270 	    if ( maxwid<sf->glyphs[i]->width )
2271 		maxwid = sf->glyphs[i]->width;
2272 	    if ( first==-1 )
2273 		first = ii;
2274 	    wid += sf->glyphs[i]->width;
2275 	    last = ii;
2276 	    for ( kp=sf->glyphs[i]->kerns; kp!=NULL; kp = kp->next )
2277 		if ( revwinmap(winmap,kp->sc->orig_pos)!=-1 )
2278 		    ++kerncnt;
2279 	}
2280     }
2281     if ( spacepos<first ) first = spacepos;
2282     if ( first==-1 ) first = 0;
2283     if ( spacepos>last ) last = spacepos;
2284     if ( cnt!=0 ) wid /= cnt;
2285     if ( kerncnt>=512 ) kerncnt = 512;
2286 
2287     SFDefaultOS2Info(&sf->pfminfo,sf,sf->fontname);
2288 
2289     putlshort(0x100,pfm);		/* format version number */
2290     size = ftell(pfm);
2291     putlint(-1,pfm);			/* file size, fill in later */
2292     i=0;
2293     if ( sf->copyright!=NULL ) for ( pt=sf->copyright; *pt && i<60; ++i, ++pt )
2294 	putc(*pt,pfm);
2295     for ( ; i<60; ++i )
2296 	putc(' ',pfm);
2297     putlshort(0x81,pfm);		/* type flags */
2298     putlshort(10,pfm);			/* point size, not really meaningful */
2299     putlshort(300,pfm);			/* vert resolution */
2300     putlshort(300,pfm);			/* hor resolution */
2301     putlshort(ymax,pfm);		/* ascent (Adobe says the "ascent" is the max high in the font's bounding box) */
2302     if ( caph==0 ) caph = ash;
2303     if ( ymax-ymin>=sf->ascent+sf->descent )
2304 	putlshort(0,pfm);		/* Adobe says so */
2305     else
2306 	putlshort(sf->ascent+sf->descent-(ymax-ymin),pfm);	/* Internal leading */
2307     putlshort(196*(sf->ascent+sf->descent)/1000,pfm);	/* External leading, Adobe says 196 */
2308     style = MacStyleCode(sf,NULL);
2309     putc(style&sf_italic?1:0,pfm);	/* is italic */
2310     putc(0,pfm);			/* underline */
2311     putc(0,pfm);			/* strikeout */
2312     putlshort(sf->pfminfo.weight,pfm);	/* weight */
2313     putc(windows_encoding,pfm);		/* Some indication of the encoding */
2314     putlshort(/*samewid<0?sf->ascent+sf->descent:samewid*/0,pfm);	/* width */
2315     putlshort(sf->ascent+sf->descent,pfm);	/* height */
2316     putc(sf->pfminfo.pfmfamily,pfm);	/* family */
2317     putlshort(wid,pfm);			/* average width, Docs say "Width of "X", but that's wrong */
2318     putlshort(maxwid,pfm);		/* max width */
2319 
2320     if ( first>255 ) first=last = 0;
2321     else if ( last>255 ) { first=32; last = 255;}/* Yes, even for 2 byte fonts we do this (Adobe says so)*/
2322     putc(first,pfm);			/* first char */
2323     putc(last,pfm);
2324     if ( spacepos>=first && spacepos<=last ) {
2325 	putc(spacepos-first,pfm);	/* default char */
2326 	putc(spacepos-first,pfm);	/* wordbreak */
2327     } else {
2328 	putc(0,pfm);			/* default character. I set to space */
2329 	putc(0,pfm);			/* word break character. I set to space */
2330     }
2331     putlshort(0,pfm);			/* width bytes. Not meaningful for ps */
2332 
2333     devname = ftell(pfm);
2334     putlint(-1,pfm);			/* offset to device name, fill in later */
2335     facename = ftell(pfm);
2336     putlint(-1,pfm);			/* offset to face name, fill in later */
2337     putlint(0,pfm);			/* bits pointer. not used */
2338     putlint(0,pfm);			/* bits offset. not used */
2339 
2340 /* No width table */
2341 
2342 /* extensions */
2343     putlshort(0x1e,pfm);		/* size of extensions table */
2344     extmetrics = ftell(pfm);
2345     putlint(-1,pfm);			/* extent metrics. fill in later */
2346     exttable = ftell(pfm);
2347     putlint(-1,pfm);			/* extent table. fill in later */
2348     putlint(0,pfm);			/* origin table. not used */
2349     kernpairs = ftell(pfm);
2350     putlint(kerncnt==0?0:-1,pfm);	/* kern pairs. fill in later */
2351     putlint(0,pfm);			/* kern track. I don't understand it so I'm leaving it out */
2352     driverinfo = ftell(pfm);
2353     putlint(-1,pfm);			/* driver info. fill in later */
2354     putlint(0,pfm);			/* reserved. mbz */
2355 
2356 /* devicename */
2357     pos = ftell(pfm);
2358     fseek(pfm,devname,SEEK_SET);
2359     putlint(pos,pfm);
2360     fseek(pfm,pos,SEEK_SET);
2361     for ( pt="PostScript"/*"\273PostScript\253"*/; *pt; ++pt )
2362 	putc(*pt,pfm);
2363     putc('\0',pfm);
2364 
2365 /* facename */
2366     pos = ftell(pfm);
2367     fseek(pfm,facename,SEEK_SET);
2368     putlint(pos,pfm);
2369     fseek(pfm,pos,SEEK_SET);
2370     if ( sf->familyname!=NULL ) {
2371 	for ( pt=sf->familyname; *pt; ++pt )
2372 	    putc(*pt,pfm);
2373     } else {
2374 	for ( pt=sf->fontname; *pt; ++pt )
2375 	    putc(*pt,pfm);
2376     }
2377     putc('\0',pfm);
2378 
2379 /* extmetrics */
2380     pos = ftell(pfm);
2381     fseek(pfm,extmetrics,SEEK_SET);
2382     putlint(pos,pfm);
2383     fseek(pfm,pos,SEEK_SET);
2384     putlshort(0x34,pfm);		/* size */
2385     putlshort(240,pfm);			/* 12 point in twentieths of a point */
2386     putlshort(0,pfm);			/* any orientation */
2387     putlshort(sf->ascent+sf->descent,pfm);	/* master height */
2388     putlshort(3,pfm);			/* min scale */
2389     putlshort(1000,pfm);		/* max scale */
2390     putlshort(sf->ascent+sf->descent,pfm);	/* master units */
2391     putlshort(caph,pfm);		/* cap height */
2392     putlshort(xh,pfm);			/* x height */
2393     putlshort(ash,pfm);			/* lower case ascent height */
2394     putlshort(-dsh,pfm);		/* lower case descent height */
2395     putlshort((int) (10*sf->italicangle),pfm);	/* italic angle */
2396     putlshort(-xh,pfm);			/* super script */
2397     putlshort(xh/2,pfm);		/* sub script */
2398     putlshort(2*(sf->ascent+sf->descent)/3,pfm);	/* super size */
2399     putlshort(2*(sf->ascent+sf->descent)/3,pfm);	/* sub size */
2400     putlshort(-sf->upos,pfm);		/* underline pos */
2401     putlshort(sf->uwidth,pfm);		/* underline width */
2402     putlshort(-sf->upos,pfm);		/* real underline pos */
2403     putlshort(-sf->upos+2*sf->uwidth,pfm);	/* real underline second line pos */
2404     putlshort(sf->uwidth,pfm);		/* underline width */
2405     putlshort(sf->uwidth,pfm);		/* underline width */
2406     putlshort((xh+sf->uwidth)/2,pfm);	/* strike out top */
2407     putlshort(sf->uwidth,pfm);		/* strike out width */
2408     putlshort(kerncnt,pfm);		/* number of kerning pairs <= 512 */
2409     putlshort(0,pfm);			/* kerning tracks <= 16 */
2410 
2411 /* extent table */
2412     pos = ftell(pfm);
2413     fseek(pfm,exttable,SEEK_SET);
2414     putlint(pos,pfm);
2415     fseek(pfm,pos,SEEK_SET);
2416     for ( ii=first; ii<=last; ++ii ) {
2417 	if ( (i=winmap[ii])==-1 || sf->glyphs[i]==NULL )
2418 	    putlshort(0,pfm);
2419 	else
2420 	    putlshort(sf->glyphs[i]->width,pfm);
2421     }
2422 
2423 /* driver info */ /* == ps font name */
2424     pos = ftell(pfm);
2425     fseek(pfm,driverinfo,SEEK_SET);
2426     putlint(pos,pfm);
2427     fseek(pfm,pos,SEEK_SET);
2428     for ( pt=sf->fontname; *pt; ++pt )
2429 	putc(*pt,pfm);
2430     putc('\0',pfm);
2431 
2432 /* kern pairs */
2433     if ( kerncnt!=0 ) {
2434 	pos = ftell(pfm);
2435 	fseek(pfm,kernpairs,SEEK_SET);
2436 	putlint(pos,pfm);
2437 	fseek(pfm,pos,SEEK_SET);
2438 	putlshort(kerncnt,pfm);		/* number of kerning pairs <= 512 */
2439 	kerncnt = 0;
2440 	for ( ii=first; ii<last; ++ii ) if ( (i=winmap[ii])!=-1 && sf->glyphs[i]!=NULL ) {
2441 	    if ( SCWorthOutputting(sf->glyphs[i]) ) {
2442 		for ( kp=sf->glyphs[i]->kerns; kp!=NULL; kp = kp->next )
2443 		    if ( kerncnt<512 && revwinmap(winmap,kp->sc->orig_pos)!=-1 ) {
2444 			putc(ii,pfm);
2445 			putc(revwinmap(winmap,kp->sc->orig_pos),pfm);
2446 			putlshort(kp->off,pfm);
2447 			++kerncnt;
2448 		    }
2449 	    }
2450 	}
2451     }
2452 
2453 /* kern track */
2454     /* I'm ignoring this */
2455 
2456 /* file size */
2457     pos = ftell(pfm);
2458     fseek(pfm,size,SEEK_SET);
2459     putlint(pos,pfm);
2460 
2461     SFKernCleanup(sf,false);
2462 
2463 #ifdef __CygWin
2464     /* Modern versions of windows want the execute bit set on a pfm file */
2465     /* I've no idea what this corresponds to in windows, nor any idea on */
2466     /*  how to set it from the windows UI, but this seems to work */
2467     {
2468 	struct stat buf;
2469 	fstat(fileno(pfm),&buf);
2470 	fchmod(fileno(pfm),S_IXUSR | buf.st_mode );
2471     }
2472 #endif
2473 
2474 return( !ferror(pfm));
2475 }
2476 
2477 /* ************************************************************************** */
2478 /* **************************** Reading PFM files *************************** */
2479 /* ************************************************************************** */
LoadKerningDataFromPfm(SplineFont * sf,char * filename,EncMap * map)2480 int LoadKerningDataFromPfm(SplineFont *sf, char *filename,EncMap *map) {
2481     FILE *file = fopen(filename,"rb");
2482     int widthbytes, kernoff, i, kerncnt;
2483     int ch1, ch2, offset;
2484     int winmap[256];
2485     int encoding;
2486 
2487     if ( file==NULL )
2488 return( 0 );
2489     if ( getlshort(file)!=0x100 ) {
2490 	fclose(file);
2491 return( false );
2492     }
2493     /* filesize = */ getlint(file);
2494     for ( i=0; i<60; ++i ) getc(file);	/* Skip the copyright */
2495     /* flags = */	getlshort(file);
2496     /* ptsize = */	getlshort(file);
2497     /* vertres = */	getlshort(file);
2498     /* horres = */	getlshort(file);
2499     /* ascent = */	getlshort(file);
2500     /* int leading = */	getlshort(file);
2501     /* ext leading = */	getlshort(file);
2502     /* italic = */	getc(file);
2503     /* underline = */	getc(file);
2504     /* strikeout = */	getc(file);
2505     /* weight = */	getlshort(file);
2506     encoding =		getc(file);
2507     /* width = */	getlshort(file);
2508     /* height = */	getlshort(file);
2509     /* family = */	getc(file);
2510     /* avgwid = */	getlshort(file);
2511     /* maxwid = */	getlshort(file);
2512     /* first = */	getc(file);
2513     /* last = */	getc(file);
2514     /* space = */	getc(file);
2515     /* word break = */	getc(file);
2516     widthbytes =	getlshort(file);
2517     /* off to devname */getlint(file);
2518     /* off to facename */getlint(file);
2519     /* bitspointer */	getlint(file);
2520     /* bitsoffset */	getlint(file);
2521 
2522     for ( i=0; i<widthbytes; ++i )	/* Ignore the width table */
2523 	getc(file);
2524     if ( getlshort(file)<0x12 )
2525 	kernoff = 0;			/* Extensions table is too short to hold a kern pointer */
2526     else {
2527 	/* extmetrics = */	getlint(file);
2528 	/* exttable = */	getlint(file);
2529 	/* origin table = */	getlint(file);
2530 	kernoff =		getlint(file);
2531     }
2532     if ( kernoff!=0 && !feof(file) ) {
2533 	fseek(file,kernoff,SEEK_SET);
2534 	if ( encoding==0 )
2535 	    inwin(sf,winmap);
2536 	else {
2537 	    for ( i=0; i<256 && i<map->enccount; ++i )
2538 		winmap[i] = map->map[i];
2539 	    for ( i=0; i<256; ++i )
2540 		winmap[i] = -1;
2541 	}
2542 	kerncnt = getlshort(file);
2543 	/* Docs say at most 512 kerning pairs. Not worth posting a progress */
2544 	/*  dlg */
2545 	for ( i=0; i<kerncnt; ++i ) {
2546 	    ch1 = getc(file);
2547 	    ch2 = getc(file);
2548 	    offset = (short) getlshort(file);
2549 	    if ( !feof(file) && winmap[ch1]!=-1 && winmap[ch2]!=-1 )
2550 		KPInsert(sf->glyphs[winmap[ch1]],sf->glyphs[winmap[ch2]],offset,false);
2551 		/* No support for vertical kerning that I'm aware of */
2552 	}
2553     }
2554     fclose(file);
2555 return( true );
2556 }
2557 
2558 /* ************************************************************************** */
2559 /* **************************** Writing TFM files *************************** */
2560 /* ************************************************************************** */
2561 typedef uint32 fix_word;
2562 
2563 struct tfm_header {
2564     uint32 checksum;	/* don't know how to calculate this, use 0 to ignore it */
2565     fix_word design_size;	/* in points (10<<20 seems to be default) */
2566     char encoding[40];	/* first byte is length, rest are a string that names the encoding */
2567 	/* ASCII, TeX text, TeX math extension, XEROX, GRAPHIC, UNSPECIFIED */
2568     char family[20];	/* Font Family, preceded by a length byte */
2569     uint8 seven_bit_safe_flag;
2570     uint8 ignored[2];
2571     uint8 face; 	/* 0=>roman, 1=>italic */
2572     			/* 4=>light, 0=>medium, 2=>bold */
2573 			/* 6=>condensed, 0=>regular, 12=>extended */
2574 };
2575 
2576 struct tfm_params {
2577     fix_word slant;	/* -sin(italic_angle) (a small positive number) */
2578     fix_word space;	/* inter-word spacing (advance width of space) */
2579     fix_word space_stretch;	/* inter-word glue stretching */
2580 	/* About 1/2 space for cmr */
2581     fix_word space_shrink;	/* inter-word glue shrinking */
2582 	/* About 1/3 space for cmr */
2583     fix_word x_height;
2584     fix_word quad;	/* == 1.0 */
2585     fix_word extra_space;	/* added at end of sentences */
2586 	/* same as space_shrink for cmr */
2587 /* tex math and tex math extension have extra parameters. They are not */
2588 /*  explained (page 7) */
2589 };
2590 /* tfm files use uint8s, ofm files use uint16s */
2591 struct ligkern {
2592     uint16 skip;
2593     uint16 other_char;
2594     uint16 op;
2595     uint16 remainder;
2596     struct ligkern *next;
2597 };
2598 struct extension {
2599     uint16 extens[4];	/* top, mid, bottom & repeat */
2600 };
2601 
TfmAddKern(KernPair * kp,struct ligkern * last,double * kerns,int * _kcnt,EncMap * map,int maxc)2602 static struct ligkern *TfmAddKern(KernPair *kp,struct ligkern *last,double *kerns,
2603 	int *_kcnt, EncMap *map,int maxc) {
2604     struct ligkern *new = calloc(1,sizeof(struct ligkern));
2605     int i;
2606 
2607     new->other_char = map->backmap[kp->sc->orig_pos];
2608     for ( i=*_kcnt-1; i>=0 ; --i )
2609 	if ( kerns[i] == kp->off )
2610     break;
2611     if ( i<0 ) {
2612 	i = (*_kcnt)++;
2613 	kerns[i] = kp->off;
2614     }
2615     if ( maxc==256 ) {
2616 	new->remainder = i&0xff;
2617 	new->op = 128 + (i>>8);
2618     } else {
2619 	new->remainder = i&0xffff;
2620 	new->op = 128 + (i>>16);
2621     }
2622     new->next = last;
2623 return( new );
2624 }
2625 
TfmAddLiga(LigList * l,struct ligkern * last,EncMap * map,int maxc)2626 static struct ligkern *TfmAddLiga(LigList *l,struct ligkern *last,EncMap *map,
2627 	int maxc) {
2628     struct ligkern *new;
2629 
2630     if ( !l->lig->subtable->lookup->store_in_afm )
2631 return( last );
2632     if ( map->backmap[l->lig->u.lig.lig->orig_pos]>=maxc )
2633 return( last );
2634     if ( l->components==NULL ||  map->backmap[l->components->sc->orig_pos]>=maxc ||
2635 	    l->components->next!=NULL )
2636 return( last );
2637     new = calloc(1,sizeof(struct ligkern));
2638     new->other_char = map->backmap[l->components->sc->orig_pos];
2639     new->remainder = map->backmap[l->lig->u.lig.lig->orig_pos];
2640     new->next = last;
2641     new->op = 0*4 + 0*2 + 0;
2642 	/* delete next char, delete current char, start over and check the resultant ligature for more ligs */
2643 return( new );
2644 }
2645 
FindCharlists(SplineFont * sf,int * charlistindex,EncMap * map,int maxc)2646 static void FindCharlists(SplineFont *sf,int *charlistindex,EncMap *map,int maxc) {
2647     int i, last, ch;
2648     char *pt, *end, *variants;
2649 
2650     memset(charlistindex,-1,(maxc+1)*sizeof(int));
2651     for ( i=0; i<maxc && i<map->enccount; ++i ) if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) {
2652 	SplineChar *sc = sf->glyphs[map->map[i]];
2653 
2654 	variants = NULL;
2655 	if ( sc->vert_variants!=NULL && sc->vert_variants->variants!=NULL )
2656 	    variants = sc->vert_variants->variants;
2657 	else if ( sc->horiz_variants!=NULL && sc->horiz_variants->variants!=NULL )
2658 	    variants = sc->horiz_variants->variants;
2659 	if ( variants!=NULL ) {
2660 	    last = i;
2661 	    for ( pt=variants; *pt; pt = end ) {
2662 		end = strchr(pt,' ');
2663 		if ( end==NULL )
2664 		    end = pt+strlen(pt);
2665 		ch = *end;
2666 		*end = '\0';
2667 		sc = SFGetChar(sf,-1,pt);
2668 		*end = ch;
2669 		while ( *end==' ' ) ++end;
2670 		if ( sc!=NULL && map->backmap[sc->orig_pos]<maxc ) {
2671 		    charlistindex[last] = map->backmap[sc->orig_pos];
2672 		    last = map->backmap[sc->orig_pos];
2673 		}
2674 	    }
2675 	}
2676     }
2677 }
2678 
FindExtensions(SplineFont * sf,struct extension * extensions,int * extenindex,EncMap * map,int maxc)2679 static int FindExtensions(SplineFont *sf,struct extension *extensions,int *extenindex,
2680 	EncMap *map,int maxc) {
2681     int i;
2682     int j,k;
2683     char *foundnames[4];
2684     int16 founds[4]; int ecnt=0;
2685 
2686     memset(extenindex,-1,(maxc+1)*sizeof(int));
2687     for ( i=0; i<maxc && i<map->enccount; ++i ) if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) {
2688 	SplineChar *sc = sf->glyphs[map->map[i]];
2689 	struct glyphvariants *gv;
2690 
2691 	gv=NULL;
2692 	if ( sc->vert_variants!=NULL && sc->vert_variants->part_cnt>0 )
2693 	    gv = sc->vert_variants;
2694 	else if ( sc->horiz_variants!=NULL && sc->horiz_variants->part_cnt>0 )
2695 	    gv = sc->horiz_variants;
2696 	if ( gv!=NULL ) {
2697 	    foundnames[0] = foundnames[1] = foundnames[2] = foundnames[3] = NULL;
2698 	    for ( j=k=0; j<gv->part_cnt; ++j ) {
2699 		if ( !gv->parts[j].is_extender ) {
2700 		    if ( k>=3 ) {
2701 			k=4;
2702 	    break;
2703 		    } else if ( k==1 && j==gv->part_cnt-1 )
2704 			foundnames[2] = gv->parts[j].component;
2705 		    else
2706 			foundnames[k++] = gv->parts[j].component;
2707 		} else {
2708 		    if ( foundnames[3]==NULL || strcmp(foundnames[3],gv->parts[j].component)==0 ) {
2709 			foundnames[3] = gv->parts[j].component;
2710 			if ( k==0 )
2711 			    k=1;		/* Can't be first */
2712 		    } else {
2713 			k = 4;
2714 	    break;
2715 		    }
2716 		}
2717 	    }
2718 	    founds[0] = founds[1] = founds[2] = founds[3] = 0;
2719 	    for ( j=0; j<4; ++j ) if ( foundnames[j]!=NULL ) {
2720 		sc = SFGetChar(sf,-1,foundnames[j]);
2721 		if ( sc==NULL )
2722 		    k=4;
2723 		else if ( map->backmap[sc->orig_pos]<maxc &&
2724 			map->backmap[sc->orig_pos]!=-1 )
2725 		    founds[j] = map->backmap[sc->orig_pos];
2726 		else
2727 		    k=4;
2728 	    }
2729 	    if ( k!=4 ) {
2730 		extenindex[i] = ecnt;
2731 		memcpy(extensions[ecnt].extens,founds,sizeof(founds));
2732 		++ecnt;
2733 	    }
2734 	}
2735     }
2736 return( ecnt );
2737 }
2738 
CoalesceValues(double * values,int max,int * index,int maxc)2739 static int CoalesceValues(double *values,int max,int *index,int maxc) {
2740     int i,j,k,top, offpos,diff,eoz;
2741     int _backindex[257];
2742     double off, test;
2743     double _topvalues[257], _totvalues[257], *topvalues, *totvalues;
2744     int _cnt[257];
2745     int *backindex, *cnt;
2746 
2747     if ( maxc<=256 ) {
2748 	backindex = _backindex;
2749 	topvalues = _topvalues;
2750 	totvalues = _totvalues;
2751 	cnt = _cnt;
2752     } else {
2753 	backindex = malloc((maxc+1)*sizeof(int));
2754 	topvalues = malloc((maxc+1)*sizeof(double));
2755 	totvalues = malloc((maxc+1)*sizeof(double));
2756 	cnt = malloc((maxc+1)*sizeof(int));
2757     }
2758 
2759     values[maxc] = 0;
2760     for ( i=0; i<=maxc; ++i )
2761 	backindex[i] = i;
2762 
2763     /* Coalesce zeroes first. This speeds up the sort immensely */
2764     eoz = 0;
2765     for ( i=1; i<maxc; ++i ) {
2766 	if ( values[i]==0 ) {
2767 	    int l = backindex[i];
2768 	    backindex[i] = backindex[eoz];
2769 	    values[i] = values[eoz];
2770 	    backindex[eoz] = l;
2771 	    values[eoz] = 0;
2772 	    eoz++;
2773 	}
2774     }
2775     /* sort */
2776     for ( i=eoz; i<maxc; ++i ) for ( j=i+1; j<=maxc; ++j ) {
2777 	if ( values[i]>values[j] ) {
2778 	    int l = backindex[i];
2779 	    double val = values[i];
2780 	    backindex[i] = backindex[j];
2781 	    values[i] = values[j];
2782 	    backindex[j] = l;
2783 	    values[j] = val;
2784 	}
2785     }
2786     for ( i=0; i<=maxc; ++i )
2787 	index[backindex[i]] = i;
2788     top = maxc+1;
2789     for ( i=0; i<top; ++i ) {
2790 	for ( j=i+1; j<top && values[i]==values[j]; ++j );
2791 	if ( j>i+1 ) {
2792 	    int diff = j-i-1;
2793 	    for ( k=i+1; k+diff<top; ++k )
2794 		values[k] = values[k+diff];
2795 	    for ( k=0; k<=maxc; ++k ) {
2796 		if ( index[k]>=j )
2797 		    index[k] -= diff;
2798 		else if ( index[k]>i )
2799 		    index[k] = i;
2800 	    }
2801 	    top -= diff;
2802 	}
2803 	cnt[i] = j-i;
2804     }
2805     if ( top<=max ) {
2806 	if ( values[0]!=0 ) {
2807 	    for ( i=0; i<top && values[i]!=0; ++i );
2808 	    if ( i==top )
2809 		IError("zero must be present in tfm arrays");
2810 	    else {
2811 		values[i] = values[0];
2812 		values[0] = 0;
2813 		for ( k=0; k<=maxc; ++k ) {
2814 		    if ( index[k]==0 ) index[k] = i;
2815 		    else if ( index[k]==i ) index[k] = 0;
2816 		}
2817 	    }
2818 	}
2819 	if ( maxc>256 ) {
2820 	    free(backindex);
2821 	    free(topvalues);
2822 	    free(totvalues);
2823 	    free(cnt);
2824 	}
2825 return( top );
2826     }
2827 
2828     for ( i=0; i<top; ++i ) {
2829 	topvalues[i] = values[i];
2830 	totvalues[i] = cnt[i]*values[i];
2831     }
2832 
2833     while ( top>max ) {
2834 	off = fabs(topvalues[0]-values[1]);
2835 	offpos = 0;
2836 	for ( i=1; i<top-1; ++i ) {
2837 	    test = fabs(topvalues[i]-values[i+1]);
2838 	    if ( test<off ) {
2839 		off = test;
2840 		offpos = i;
2841 	    }
2842 	}
2843 	topvalues[offpos] = topvalues[offpos+1];
2844 	cnt[offpos] += cnt[offpos+1];
2845 	totvalues[offpos] += totvalues[offpos+1];
2846 	diff = 1;
2847 	for ( k=offpos+1; k+diff<top; ++k ) {
2848 	    values[k] = values[k+diff];
2849 	    topvalues[k] = topvalues[k+diff];
2850 	    cnt[k] = cnt[k+diff];
2851 	    totvalues[k] = totvalues[k+diff];
2852 	}
2853 	for ( k=0; k<=maxc; ++k ) {
2854 	    if ( index[k]>offpos )
2855 		index[k] -= diff;
2856 	}
2857 	top -= diff;
2858     }
2859     values[0] = 0;
2860     for ( i=1; i<top; ++i )
2861 	values[i] = totvalues[i]/cnt[i];
2862     if ( maxc>256 ) {
2863 	free(backindex);
2864 	free(topvalues);
2865 	free(totvalues);
2866 	free(cnt);
2867     }
2868 return( top );
2869 }
2870 
TeXDefaultParams(SplineFont * sf)2871 void TeXDefaultParams(SplineFont *sf) {
2872     int i, spacew;
2873     BlueData bd;
2874 
2875     if ( sf->texdata.type!=tex_unset )
2876 return;
2877 
2878     spacew = rint(.33*(1<<20));	/* 1/3 em for a space seems like a reasonable size */
2879     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->unicodeenc==' ' ) {
2880 	spacew = rint((sf->glyphs[i]->width<<20)/(sf->ascent+sf->descent));
2881     break;
2882     }
2883     QuickBlues(sf,ly_fore,&bd);
2884 
2885     memset(sf->texdata.params,0,sizeof(sf->texdata.params));
2886     sf->texdata.params[0] = rint( -sin(sf->italicangle)*(1<<20) );	/* slant */
2887     sf->texdata.params[1] = spacew;			/* space */
2888     sf->texdata.params[2] = rint(spacew/2);		/* stretch_space */
2889     sf->texdata.params[3] = rint(spacew/3);		/* shrink space */
2890     if ( bd.xheight>0 )
2891 	sf->texdata.params[4] = rint((((double) bd.xheight)*(1<<20))/(sf->ascent+sf->descent));
2892     sf->texdata.params[5] = 1<<20;			/* quad */
2893     sf->texdata.params[6] = rint(spacew/3);		/* extra space after sentence period */
2894 
2895     /* Let's provide some vaguely reasonable defaults for math fonts */
2896     /*  I'll ignore math ext fonts */
2897     /* hmm. TeX math fonts have space, stretch, shrink set to 0 */
2898     sf->texdata.params[7] = rint(.747*(1<<20));
2899     sf->texdata.params[8] = rint(.424*(1<<20));
2900     sf->texdata.params[9] = rint(.474*(1<<20));
2901     sf->texdata.params[10] = rint(.756*(1<<20));
2902     sf->texdata.params[11] = rint(.375*(1<<20));
2903     sf->texdata.params[12] = rint(.413*(1<<20));
2904     sf->texdata.params[13] = rint(.363*(1<<20));
2905     sf->texdata.params[14] = rint(.289*(1<<20));
2906     sf->texdata.params[15] = rint(.15*(1<<20));
2907     sf->texdata.params[16] = rint(.309*(1<<20));
2908     sf->texdata.params[17] = rint(.386*(1<<20));
2909     sf->texdata.params[18] = rint(.05*(1<<20));
2910     sf->texdata.params[19] = rint(2.39*(1<<20));
2911     sf->texdata.params[20] = rint(1.01*(1<<20));
2912     sf->texdata.params[21] = rint(.25*(1<<20));
2913 }
2914 
_OTfmSplineFont(FILE * tfm,SplineFont * sf,EncMap * map,int maxc,int layer)2915 static int _OTfmSplineFont(FILE *tfm, SplineFont *sf,EncMap *map,int maxc,int layer) {
2916     struct tfm_header header;
2917     char *full=NULL;
2918     const char *encname;
2919     int i;
2920     DBounds b;
2921     struct ligkern *_ligkerns[256], **ligkerns, *lk, *lknext;
2922     double _widths[257], _heights[257], _depths[257], _italics[257];
2923     double *widths, *heights, *depths, *italics;
2924     uint8 _tags[256], *tags;
2925     uint16 _lkindex[256], *lkindex;
2926     int _former[256], *former;
2927     struct extension _extensions[257], *extensions;
2928     int _charlistindex[257], _extenindex[257];
2929     int *charlistindex, *extenindex;
2930     int _widthindex[257], _heightindex[257], _depthindex[257], _italicindex[257];
2931     int *widthindex, *heightindex, *depthindex, *italicindex;
2932     double *kerns;
2933     int widcnt, hcnt, dcnt, icnt, kcnt, lkcnt, pcnt, ecnt, sccnt;
2934     int first, last;
2935     KernPair *kp;
2936     LigList *l;
2937     int style, any;
2938     uint32 *lkarray;
2939     struct ligkern *o_lkarray=NULL;
2940     char *familyname;
2941     int anyITLC;
2942     real scale = (1<<20)/(double) (sf->ascent+sf->descent);
2943     int toobig_warn = false;
2944 
2945     if ( maxc==256 ) {
2946 	ligkerns = _ligkerns;
2947 	widths = _widths;
2948 	heights = _heights;
2949 	depths = _depths;
2950 	italics = _italics;
2951 	tags = _tags;
2952 	lkindex = _lkindex;
2953 	former = _former;
2954 	charlistindex = _charlistindex;
2955 	extensions = _extensions;
2956 	extenindex = _extenindex;
2957 	widthindex = _widthindex;
2958 	heightindex = _heightindex;
2959 	depthindex = _depthindex;
2960 	italicindex = _italicindex;
2961     } else {
2962 	ligkerns = malloc(maxc*sizeof(struct ligkern *));
2963 	widths = malloc((maxc+1)*sizeof(double));
2964 	heights = malloc((maxc+1)*sizeof(double));
2965 	depths = malloc((maxc+1)*sizeof(double));
2966 	italics = malloc((maxc+1)*sizeof(double));
2967 	tags = malloc(maxc*sizeof(uint8));
2968 	lkindex = malloc(maxc*sizeof(uint16));
2969 	former = malloc(maxc*sizeof(int));
2970 	charlistindex = malloc((maxc+1)*sizeof(int));
2971 	extensions = malloc((maxc+1)*sizeof(struct extension));
2972 	extenindex = malloc((maxc+1)*sizeof(int));
2973 	widthindex = malloc((maxc+1)*sizeof(int));
2974 	heightindex = malloc((maxc+1)*sizeof(int));
2975 	depthindex = malloc((maxc+1)*sizeof(int));
2976 	italicindex = malloc((maxc+1)*sizeof(int));
2977     }
2978     SFLigaturePrepare(sf);
2979     LigatureClosure(sf);		/* Convert 3 character ligs to a set of two character ones when possible */
2980     SFKernClassTempDecompose(sf,false);	/* Undoes kern classes */
2981     TeXDefaultParams(sf);
2982 
2983     memset(&header,0,sizeof(header));
2984     header.checksum = 0;		/* don't check checksum (I don't know how to calculate it) */
2985     header.design_size = ((sf->design_size<<19)+2)/5;
2986     if ( header.design_size==0 ) header.design_size = 10<<20;
2987     encname=NULL;
2988     /* These first two encoding names appear magic to txtopl */
2989     /* I tried checking that the encodings were correct, name by name, but */
2990     /*  that doesn't work. People use non-standard names */
2991     if ( sf->texdata.type==tex_math ) encname = "TEX MATH SYMBOLS";
2992     else if ( sf->texdata.type==tex_mathext ) encname = "TEX MATH EXTENSION";
2993     else if ( sf->subfontcnt==0 &&  map->enc!=&custom )
2994 	encname = EncodingName( map->enc );
2995     if ( encname==NULL ) {
2996 	full = malloc(strlen(sf->fontname)+10);
2997 	strcpy(full,sf->fontname);
2998 	strcat(full,"-Enc");
2999 	encname = full;
3000     }
3001     header.encoding[0] = strlen(encname);
3002     if ( header.encoding[0]>39 ) {
3003 	header.encoding[0] = 39;
3004 	memcpy(header.encoding+1,encname,39);
3005     } else
3006 	strcpy(header.encoding+1,encname);
3007     if ( full ) free(full);
3008 
3009     familyname = sf->cidmaster ? sf->cidmaster->familyname : sf->familyname;
3010     header.family[0] = strlen(familyname);
3011     if ( header.family[0]>=19 ) {
3012 	header.family[0] = 19;
3013 	memcpy(header.family+1,familyname,19);
3014     } else
3015 	strcpy(header.family+1,familyname);
3016     for ( i=128; i<map->enccount && i<maxc; ++i )
3017 	if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]]))
3018     break;
3019     if ( i>=map->enccount || i>=maxc )
3020 	header.seven_bit_safe_flag = true;
3021     style = MacStyleCode(sf,NULL);
3022     if ( style&sf_italic )
3023 	header.face = 1;
3024     if ( style&sf_bold )
3025 	header.face+=2;
3026     else if ( strstrmatch(sf->fontname,"Ligh") ||
3027 	    strstrmatch(sf->fontname,"Thin") ||
3028 	    strstrmatch(sf->fontname,"Maigre") ||
3029 	    strstrmatch(sf->fontname,"Mager") )
3030 	header.face += 4;
3031     if ( style&sf_condense )
3032 	header.face += 6;
3033     else if ( style&sf_extend )
3034 	header.face += 12;
3035 
3036     pcnt = sf->texdata.type==tex_math ? 22 : sf->texdata.type==tex_mathext ? 13 : 7;
3037 
3038     memset(widths,0,maxc*sizeof(double));
3039     memset(heights,0,maxc*sizeof(double));
3040     memset(depths,0,maxc*sizeof(double));
3041     memset(italics,0,maxc*sizeof(double));
3042     memset(tags,0,maxc*sizeof(uint8));
3043     first = last = -1;
3044     /* Note: Text fonts for TeX and math fonts use the italic correction & width */
3045     /*  fields to mean different things */
3046     anyITLC = false;
3047     for ( i=0; i<maxc && i<map->enccount; ++i )
3048 	if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) {
3049 	    if ( sf->glyphs[map->map[i]]->italic_correction!=TEX_UNDEF ) {
3050 		anyITLC = true;
3051 	break;
3052 	    }
3053 	}
3054     for ( i=0; i<maxc && i<map->enccount; ++i ) {
3055 	if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) {
3056 	    SplineChar *sc = sf->glyphs[map->map[i]];
3057 	    if ( sc->tex_height==TEX_UNDEF || sc->tex_depth==TEX_UNDEF ||
3058 		    sc->italic_correction==TEX_UNDEF ) {
3059 		SplineCharLayerFindBounds(sc,layer,&b);
3060 		heights[i] = b.maxy*scale; depths[i] = -b.miny*scale;
3061 	    }
3062 	    if ( sc->tex_height!=TEX_UNDEF )
3063 		heights[i] = sc->tex_height*scale;
3064 	    if ( sc->tex_depth!=TEX_UNDEF )
3065 		depths[i] = sc->tex_depth*scale;
3066 	    if ( depths[i]<0 ) depths[i] = 0;		/* Werner says depth should never be negative. Something about how accents are positioned */
3067 	    if ( sc->width==0 )
3068 		widths[i] = 1;	/* TeX/Omega use a 0 width as a flag for non-existant character. Stupid. So zero width glyphs must be given the smallest posible non-zero width, to ensure they exists. GRRR. */
3069 	    else if ( sc->width*scale >= (16<<20) ) {
3070 		LogError( _("The width of %s is too big to fit in a tfm fix_word, it shall be truncated to the largest size allowed."), sc->name );
3071 		widths[i] = (16<<20)-1;
3072 	    } else
3073 		widths[i] = sc->width*scale;
3074 	    if ( sc->italic_correction!=TEX_UNDEF )
3075 		italics[i] = sc->italic_correction*scale;
3076 	    else if ( (style&sf_italic) && b.maxx>sc->width && !anyITLC )
3077 		italics[i] = ((b.maxx-sc->width) +
3078 			    (sf->ascent+sf->descent)/16.0)*scale;
3079 					/* With a 1/16 em white space after it */
3080 	    if ( widths[i]<0 ) widths[i] = 0;
3081 	    if ( first==-1 ) first = i;
3082 	    last = i;
3083 	    if ( widths[i]>=(16<<20) || heights[i]>=(16<<20) ||
3084 		    depths[i]>=(16<<20) || italics[i]>=(16<<20) ) {
3085 		if ( !toobig_warn ) {
3086 		    ff_post_error(_("Value exceeds tfm limitations"),_("The width, height, depth or italic correction of %s is too big. Tfm files may not contain values bigger than 16 times the em-size of the font. Width=%g, height=%g, depth=%g, italic correction=%g"),
3087 			sc->name, widths[i]/(1<<20), heights[i]/(1<<20), depths[i]/(1<<20), italics[i]/(1<<20) );
3088 		    toobig_warn = true;
3089 		}
3090 		if ( widths[i]>(16<<20)-1 )
3091 		    widths[i] = (16<<20)-1;
3092 		if ( heights[i]>(16<<20)-1 )
3093 		    heights[i] = (16<<20)-1;
3094 		if ( depths[i]>(16<<20)-1 )
3095 		    depths[i] = (16<<20)-1;
3096 		if ( italics[i]>(16<<20)-1 )
3097 		    italics[i] = (16<<20)-1;
3098 	    }
3099 	}
3100     }
3101     widcnt = CoalesceValues(widths,maxc,widthindex,maxc);
3102     hcnt = CoalesceValues(heights,maxc<=256?16:256,heightindex,maxc);
3103     dcnt = CoalesceValues(depths,maxc<=256?16:256,depthindex,maxc);
3104     icnt = CoalesceValues(italics,maxc<=256?64:256,italicindex,maxc);
3105     if ( last==-1 ) { first = 1; last = 0; }
3106 
3107     FindCharlists(sf,charlistindex,map,maxc);
3108     ecnt = FindExtensions(sf,extensions,extenindex,map,maxc);
3109 
3110     kcnt = 0;
3111     for ( i=0; i<maxc && i<map->enccount; ++i ) {
3112 	if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) {
3113 	    SplineChar *sc = sf->glyphs[map->map[i]];
3114 	    for ( kp=sc->kerns; kp!=NULL; kp=kp->next )
3115 		if ( kp->sc->orig_pos<sf->glyphcnt &&	/* Can happen when saving multiple pfbs */
3116 			map->backmap[kp->sc->orig_pos]<maxc ) ++kcnt;
3117 	}
3118     }
3119     kerns = NULL;
3120     if ( kcnt!=0 )
3121 	kerns = malloc(kcnt*sizeof(double));
3122     kcnt = lkcnt = 0;
3123     memset(ligkerns,0,maxc*sizeof(struct ligkern *));
3124     for ( i=0; i<maxc && i<map->enccount; ++i ) {
3125 	if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) {
3126 	    SplineChar *sc = sf->glyphs[map->map[i]];
3127 	    for ( kp=sc->kerns; kp!=NULL; kp=kp->next )
3128 		if ( kp->sc->orig_pos<sf->glyphcnt &&	/* Can happen when saving multiple pfbs */
3129 			map->backmap[kp->sc->orig_pos]<maxc )
3130 		    ligkerns[i] = TfmAddKern(kp,ligkerns[i],kerns,&kcnt,map,maxc);
3131 	    for ( l=sc->ligofme; l!=NULL; l=l->next )
3132 		ligkerns[i] = TfmAddLiga(l,ligkerns[i],map,maxc);
3133 	    if ( ligkerns[i]!=NULL ) {
3134 		tags[i] = 1;
3135 		for ( lk=ligkerns[i]; lk!=NULL; lk=lk->next )
3136 		    ++lkcnt;
3137 	    }
3138 	    if ( extenindex[i]!=-1 )
3139 		tags[i] = 3;
3140 	    else if ( charlistindex[i]!=-1 )
3141 		tags[i] = 2;
3142 	}
3143     }
3144     for ( i=sccnt=0; i<maxc && i<map->enccount; ++i )
3145 	if ( ligkerns[i]!=NULL )
3146 	    ++sccnt;
3147     if ( sccnt>=128 )	/* We need to use the special extension mechanism */
3148 	lkcnt += sccnt;
3149     memset(former,-1,maxc*sizeof(int));
3150     memset(lkindex,0,maxc*sizeof(uint16));
3151     if ( maxc==256 ) {
3152 	lkarray = malloc(lkcnt*sizeof(uint32));
3153 	if ( sccnt<128 ) {
3154 	    lkcnt = 0;
3155 	    do {
3156 		any = false;
3157 		for ( i=0; i<maxc; ++i ) if ( ligkerns[i]!=NULL ) {
3158 		    lk = ligkerns[i];
3159 		    ligkerns[i] = lk->next;
3160 		    if ( former[i]==-1 )
3161 			lkindex[i] = lkcnt;
3162 		    else {
3163 			lkarray[former[i]] |= (lkcnt-former[i]-1)<<24;
3164 			if ( lkcnt-former[i]-1 >= 128 )
3165 			    IError( " generating lig/kern array, jump too far.\n" );
3166 		    }
3167 		    former[i] = lkcnt;
3168 		    lkarray[lkcnt++] = ((lk->next==NULL?128U:0U)<<24) |
3169 					(lk->other_char<<16) |
3170 					(lk->op<<8) |
3171 					lk->remainder;
3172 		    free( lk );
3173 		    any = true;
3174 		}
3175 	    } while ( any );
3176 	} else {
3177 	    int lkcnt2 = sccnt;
3178 	    lkcnt = 0;
3179 	    for ( i=0; i<256; ++i ) if ( ligkerns[i]!=NULL ) {
3180 		lkindex[i] = lkcnt;
3181 		/* long pointer into big ligkern array */
3182 		lkarray[lkcnt++] = (129U<<24) |
3183 				    (0<<16) |
3184 				    lkcnt2;
3185 		for ( lk = ligkerns[i]; lk!=NULL; lk=lknext ) {
3186 		    lknext = lk->next;
3187 		    /* Here we will always skip to the next record, so the	*/
3188 		    /* skip_byte will always be 0 (well, or 128 for stop)	*/
3189 		    lkarray[lkcnt2++] = ((lknext==NULL?128:0)<<24) |
3190 					(lk->other_char<<16) |
3191 					(lk->op<<8) |
3192 					lk->remainder;
3193 		    free( lk );
3194 		}
3195 	    }
3196 	    if ( lkcnt>sccnt )
3197 		IError( "lig/kern mixup\n" );
3198 	    lkcnt = lkcnt2;
3199 	}
3200     } else {
3201 	o_lkarray = calloc(lkcnt,sizeof(struct ligkern));
3202 	if ( sccnt<128 ) {
3203 	    lkcnt = 0;
3204 	    do {
3205 		any = false;
3206 		for ( i=0; i<maxc; ++i ) if ( ligkerns[i]!=NULL ) {
3207 		    lk = ligkerns[i];
3208 		    ligkerns[i] = lk->next;
3209 		    if ( former[i]==-1 )
3210 			lkindex[i] = lkcnt;
3211 		    else {
3212 			o_lkarray[former[i]].skip |= lkcnt-former[i]-1;
3213 			if ( lkcnt-former[i]-1 >= 128 )
3214 			    IError( " generating lig/kern array, jump too far.\n" );
3215 		    }
3216 		    former[i] = lkcnt;
3217 		    o_lkarray[lkcnt].skip = lk->next==NULL ? 128U : 0U;
3218 		    o_lkarray[lkcnt].other_char = lk->other_char;
3219 		    o_lkarray[lkcnt].op = lk->op;
3220 		    o_lkarray[lkcnt++].remainder = lk->remainder;
3221 		    free( lk );
3222 		    any = true;
3223 		}
3224 	    } while ( any );
3225 	} else {
3226 	    int lkcnt2 = sccnt;
3227 	    lkcnt = 0;
3228 	    for ( i=0; i<maxc; ++i ) if ( ligkerns[i]!=NULL ) {
3229 		lkindex[i] = lkcnt;
3230 		/* long pointer into big ligkern array */
3231 		o_lkarray[lkcnt].skip = 128+1;
3232 		o_lkarray[lkcnt].other_char = 0;
3233 		o_lkarray[lkcnt].op = lkcnt2>>16;
3234 		o_lkarray[lkcnt++].remainder = lkcnt2&0xffff;
3235 		for ( lk = ligkerns[i]; lk!=NULL; lk=lknext ) {
3236 		    lknext = lk->next;
3237 		    /* Here we will always skip to the next record, so the	*/
3238 		    /* skip_byte will always be 0 (well, or 128 for stop)	*/
3239 		    former[i] = lkcnt;
3240 		    o_lkarray[lkcnt2].skip = (lknext==NULL?128:0);
3241 		    o_lkarray[lkcnt2].other_char = lk->other_char;
3242 		    o_lkarray[lkcnt2].op = lk->op;
3243 		    o_lkarray[lkcnt2++].remainder = lk->remainder;
3244 		    free( lk );
3245 		}
3246 	    }
3247 	    if ( lkcnt>sccnt )
3248 		IError( "lig/kern mixup\n" );
3249 	    lkcnt = lkcnt2;
3250 	}
3251     }
3252 
3253 /* Now output the file */
3254 	/* Table of contents */
3255     if ( maxc==256 ) {
3256 	putshort(tfm,
3257 		6+			/* Table of contents size */
3258 		18 +		/* header size */
3259 		(last-first+1) +	/* Per glyph data */
3260 		widcnt +		/* entries in the width table */
3261 		hcnt +		/* entries in the height table */
3262 		dcnt +		/* entries in the depth table */
3263 		icnt +		/* entries in the italic correction table */
3264 		lkcnt +		/* entries in the lig/kern table */
3265 		kcnt +		/* entries in the kern table */
3266 		ecnt +		/* No extensible characters here */
3267 		pcnt);		/* font parameter words */
3268 	putshort(tfm,18);
3269 	putshort(tfm,first);
3270 	putshort(tfm,last);
3271 	putshort(tfm,widcnt);
3272 	putshort(tfm,hcnt);
3273 	putshort(tfm,dcnt);
3274 	putshort(tfm,icnt);
3275 	putshort(tfm,lkcnt);
3276 	putshort(tfm,kcnt);
3277 	putshort(tfm,ecnt);
3278 	putshort(tfm,pcnt);
3279     } else {
3280 	int font_dir = 0;
3281 	    /* According to ofm2opl sources fontdir is: */
3282 	    /*  0=>TL, 1=>LT, 2=>TR, 3=>LB, 4=>BL, 5=>RT, 6=>BR, 7=>RB */
3283 	    /* And if bit 3 (8) is set then we have something called NFONTDIR */
3284 	    /*  no idea what that means */
3285 	    /* TL Means start at the top left of the page (standard L 2 R) */
3286 	    /* TR Means start at the top right of the page (standard R 2 L) */
3287 	    /* And I think RT is appropriate for vertical Japanese */
3288 	    /* (bit three might mean the reversed direction of English inside */
3289 	    /*  mongolian. It doesn't seem appropriate in a font though) */
3290 	    /* HOWEVER, all the ofm files I've seen, including arabic only ones*/
3291 	    /*  set fontdir to 0 (TL). So I shall too */
3292 	putlong(tfm,0);		/* Undocumented entry. Perhaps the level? */
3293 				/* ofm2opl says it is the level */
3294 	putlong(tfm,
3295 		14+		/* Table of contents size */
3296 		18 +		/* header size */
3297 		2*(last-first+1) +  /* Per glyph data */
3298 		widcnt +	/* entries in the width table */
3299 		hcnt +		/* entries in the height table */
3300 		dcnt +		/* entries in the depth table */
3301 		icnt +		/* entries in the italic correction table */
3302 		2*lkcnt +	/* entries in the lig/kern table */
3303 		kcnt +		/* entries in the kern table */
3304 		2*ecnt +	/* No extensible characters here */
3305 		pcnt);		/* font parameter words */
3306 	putlong(tfm,18);
3307 	putlong(tfm,first);
3308 	putlong(tfm,last);
3309 	putlong(tfm,widcnt);
3310 	putlong(tfm,hcnt);
3311 	putlong(tfm,dcnt);
3312 	putlong(tfm,icnt);
3313 	putlong(tfm,lkcnt);
3314 	putlong(tfm,kcnt);
3315 	putlong(tfm,ecnt);
3316 	putlong(tfm,pcnt);
3317 	putlong(tfm,font_dir);
3318     }
3319 	    /* header */
3320     putlong(tfm,header.checksum);
3321     putlong(tfm,header.design_size);
3322     fwrite(header.encoding,1,sizeof(header.encoding),tfm);
3323     fwrite(header.family,1,sizeof(header.family),tfm);
3324     fwrite(&header.seven_bit_safe_flag,1,4,tfm);
3325 	    /* per-glyph data */
3326     for ( i=first; i<=last ; ++i ) {
3327 	if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) {
3328 	    if ( maxc==256 ) {
3329 		putc(widthindex[i],tfm);
3330 		putc((heightindex[i]<<4)|depthindex[i],tfm);
3331 		putc((italicindex[i]<<2)|tags[i],tfm);
3332 		putc(tags[i]==0?0 :
3333 			tags[i]==1?lkindex[i] :
3334 			tags[i]==2?charlistindex[i] :
3335 			extenindex[i],tfm);
3336 	    } else {
3337 		putshort(tfm,widthindex[i]);
3338 		putc(heightindex[i],tfm);
3339 		putc(depthindex[i],tfm);
3340 		putc(italicindex[i],tfm);
3341 		putc(tags[i],tfm);
3342 		putshort(tfm,tags[i]==0?0 :
3343 			tags[i]==1?lkindex[i] :
3344 			tags[i]==2?charlistindex[i] :
3345 			extenindex[i]);
3346 	    }
3347 	} else {
3348 	    putlong(tfm,0);
3349 	    if ( maxc>256 )
3350 		putlong(tfm,0);
3351 	}
3352     }
3353 	    /* width table */
3354     for ( i=0; i<widcnt; ++i )
3355 	putlong(tfm,widths[i]);
3356 	    /* height table */
3357     for ( i=0; i<hcnt; ++i )
3358 	putlong(tfm,heights[i]);
3359 	    /* depth table */
3360     for ( i=0; i<dcnt; ++i )
3361 	putlong(tfm,depths[i]);
3362 	    /* italic correction table */
3363     for ( i=0; i<icnt; ++i )
3364 	putlong(tfm,italics[i]);
3365 
3366 	    /* lig/kern table */
3367     if ( maxc==256 ) {
3368 	for ( i=0; i<lkcnt; ++i )
3369 	    putlong(tfm,lkarray[i]);
3370     } else {
3371 	for ( i=0; i<lkcnt; ++i ) {
3372 	    putshort(tfm,o_lkarray[i].skip);
3373 	    putshort(tfm,o_lkarray[i].other_char);
3374 	    putshort(tfm,o_lkarray[i].op);
3375 	    putshort(tfm,o_lkarray[i].remainder);
3376 	}
3377     }
3378 
3379 	    /* kern table */
3380     for ( i=0; i<kcnt; ++i )
3381 	putlong(tfm,(kerns[i]*(1<<20))/(sf->ascent+sf->descent));
3382 
3383 	    /* extensible table */
3384     if ( maxc==256 ) {
3385 	for ( i=0; i<ecnt; ++i ) {
3386 	    putc(extensions[i].extens[0],tfm);
3387 	    putc(extensions[i].extens[1],tfm);
3388 	    putc(extensions[i].extens[2],tfm);
3389 	    putc(extensions[i].extens[3],tfm);
3390 	}
3391     } else {
3392 	for ( i=0; i<ecnt; ++i ) {
3393 	    putshort(tfm,extensions[i].extens[0]);
3394 	    putshort(tfm,extensions[i].extens[1]);
3395 	    putshort(tfm,extensions[i].extens[2]);
3396 	    putshort(tfm,extensions[i].extens[3]);
3397 	}
3398     }
3399 
3400 	    /* font parameters */
3401     for ( i=0; i<pcnt; ++i )
3402 	putlong(tfm,sf->texdata.params[i]);
3403 
3404     SFLigatureCleanup(sf);
3405     SFKernCleanup(sf,false);
3406 
3407     if ( maxc>256 ) {
3408 	free( o_lkarray );
3409 	free( ligkerns );
3410 	free( widths );
3411 	free( heights );
3412 	free( depths );
3413 	free( italics );
3414 	free( tags );
3415 	free( lkindex );
3416 	free( former );
3417 	free( charlistindex );
3418 	free( extensions );
3419 	free( extenindex );
3420 	free( widthindex );
3421 	free( heightindex );
3422 	free( depthindex );
3423 	free( italicindex );
3424     } else
3425 	free( lkarray );
3426 return( !ferror(tfm));
3427 }
3428 
TfmSplineFont(FILE * tfm,SplineFont * sf,EncMap * map,int layer)3429 int TfmSplineFont(FILE *tfm, SplineFont *sf, EncMap *map,int layer) {
3430 return( _OTfmSplineFont(tfm,sf,map,256,layer));
3431 }
3432 /* ************************************************************************** */
3433 /* **************************** Writing OFM files *************************** */
3434 /* ************************************************************************** */
3435 
OfmSplineFont(FILE * tfm,SplineFont * sf,EncMap * map,int layer)3436 int OfmSplineFont(FILE *tfm, SplineFont *sf, EncMap *map,int layer) {
3437 return( _OTfmSplineFont(tfm,sf,map,65536,layer));
3438 }
3439 
3440 /* ************************************************************************** */
3441 
3442 enum metricsformat { mf_none, mf_afm, mf_amfm, mf_tfm, mf_ofm, mf_pfm, mf_feat };
3443 
MetricsFormatType(char * filename)3444 static enum metricsformat MetricsFormatType(char *filename) {
3445     FILE *file = fopen(filename,"rb");
3446     unsigned char buffer[200];
3447     struct stat sb;
3448     int len;
3449 
3450     if ( file==NULL )
3451 return( mf_none );
3452 
3453     len = fread(buffer,1,sizeof(buffer)-1,file);
3454     buffer[len] = '\0';
3455     fstat(fileno(file),&sb);
3456     fclose(file);
3457 
3458     if ( strstr((char *) buffer,"StartFontMetrics")!=NULL )
3459 return( mf_afm );
3460     if ( strstr((char *) buffer,"StartMasterFontMetrics")!=NULL ||
3461 	    strstr((char *) buffer,"StarMasterFontMetrics")!=NULL )	/* ff had a bug and used this file header by mistake */
3462 return( mf_amfm );
3463 
3464     if ( len >= 48 && sb.st_size == 4*((buffer[0]<<8)|buffer[1]) &&
3465 	    ((buffer[0]<<8)|buffer[1]) == 6 +
3466 		    ((buffer[2]<<8)|buffer[3]) +
3467 		    ( ((buffer[6]<<8)|buffer[7]) - ((buffer[4]<<8)|buffer[5]) + 1 ) +
3468 		    ((buffer[8]<<8)|buffer[9]) +
3469 		    ((buffer[10]<<8)|buffer[11]) +
3470 		    ((buffer[12]<<8)|buffer[13]) +
3471 		    ((buffer[14]<<8)|buffer[15]) +
3472 		    ((buffer[16]<<8)|buffer[17]) +
3473 		    ((buffer[18]<<8)|buffer[19]) +
3474 		    ((buffer[20]<<8)|buffer[21]) +
3475 		    ((buffer[22]<<8)|buffer[23]) )
3476 return( mf_tfm );
3477 
3478     if ( len >= 48 && sb.st_size == 4*BigEndianWord(buffer+4) &&
3479 	    BigEndianWord(buffer) == 0 &&
3480 	    BigEndianWord(buffer+4) == 14 +
3481 		    BigEndianWord(buffer+8) +
3482 		    2*( BigEndianWord(buffer+16) - BigEndianWord(buffer+12) + 1 ) +
3483 		    BigEndianWord(buffer+20) +
3484 		    BigEndianWord(buffer+24) +
3485 		    BigEndianWord(buffer+28) +
3486 		    BigEndianWord(buffer+32) +
3487 		    2*BigEndianWord(buffer+36) +
3488 		    BigEndianWord(buffer+40) +
3489 		    2*BigEndianWord(buffer+44) +
3490 		    BigEndianWord(buffer+48) )
3491 return( mf_ofm );
3492 
3493     if ( len>= 6 && buffer[0]==0 && buffer[1]==1 &&
3494 	    (buffer[2]|(buffer[3]<<8)|(buffer[4]<<16)|(buffer[5]<<24))== sb.st_size )
3495 return( mf_pfm );
3496 
3497     /* I don't see any distinquishing marks for a feature file */
3498 
3499     if ( strstrmatch(filename,".afm")!=NULL )
3500 return( mf_afm );
3501     if ( strstrmatch(filename,".amfm")!=NULL )
3502 return( mf_amfm );
3503     if ( strstrmatch(filename,".tfm")!=NULL )
3504 return( mf_tfm );
3505     if ( strstrmatch(filename,".ofm")!=NULL )
3506 return( mf_ofm );
3507     if ( strstrmatch(filename,".pfm")!=NULL )
3508 return( mf_pfm );
3509     if ( strstrmatch(filename,".fea")!=NULL )
3510 return( mf_feat );
3511 
3512 return( mf_none );
3513 }
3514 
LoadKerningDataFromMetricsFile(SplineFont * sf,char * filename,EncMap * map)3515 int LoadKerningDataFromMetricsFile(SplineFont *sf,char *filename,EncMap *map) {
3516     int ret;
3517 
3518     switch ( MetricsFormatType(filename)) {
3519       case mf_afm:
3520 	ret = LoadKerningDataFromAfm(sf,filename);
3521       break;
3522       case mf_amfm:
3523 	ret = LoadKerningDataFromAmfm(sf,filename);
3524       break;
3525       case mf_tfm:
3526 	ret = LoadKerningDataFromTfm(sf,filename,map);
3527       break;
3528       case mf_ofm:
3529 	ret = LoadKerningDataFromOfm(sf,filename,map);
3530       break;
3531       case mf_pfm:
3532 	ret = LoadKerningDataFromPfm(sf,filename,map);
3533       break;
3534       case mf_feat:
3535 	SFApplyFeatureFilename(sf,filename);
3536 	ret = true;
3537       break;
3538       case mf_none:
3539       default:
3540 	/* If all else fails try a mac resource */
3541 	/* mac resources can be in so many different formats and even files */
3542 	/*  that I'm not even going to try to check for it here */
3543 	ret = LoadKerningDataFromMacFOND(sf,filename,map);
3544       break;
3545     }
3546     if ( ret ) {
3547 	FontInfo_Destroy(sf);
3548 	MVReKernAll(sf);
3549     }
3550 return( ret );
3551 }
3552