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