Permalink
Fetching contributors…
Cannot retrieve contributors at this time
3190 lines (2946 sloc) 101 KB
/* Copyright (C) 2000-2012 by George Williams */
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "macbinary.h"
#include "bvedit.h"
#include "crctab.h"
#include "dumppfa.h"
#include "encoding.h"
#include "fontforgevw.h"
#include "fvfonts.h"
#include "http.h"
#include "lookups.h"
#include "mem.h"
#include "parsepfa.h"
#include "parsettf.h"
#include "splinefill.h"
#include "splinesave.h"
#include "splinesaveafm.h"
#include "splineutil.h"
#include "splineutil2.h"
#include "tottf.h"
#include "tottfgpos.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ustring.h>
#include <gutils.h>
#include "ttf.h"
#include "psfont.h"
#if __Mac
# include <ctype.h>
# include "carbon.h"
#else
# include <utype.h>
#undef __Mac
#define __Mac 0
#endif
const int mac_dpi = 72;
/* I had always assumed that the mac still believed in 72dpi screens, but I */
/* see that in geneva under OS/9, the pointsize does not match the pixel */
/* size of the font. But the dpi is not constant (and the differences */
/* excede those supplied by rounding errors) varying between 96 and 84dpi */
/* A Mac Resource fork */
/* http://developer.apple.com/techpubs/mac/MoreToolbox/MoreToolbox-9.html */
/* begins with a 16 byte header containing: */
/* resource start offset */
/* map start offset */
/* resource length */
/* map length */
/* then 256-16 bytes of zeros */
/* the resource section consists of (many) */
/* 4 byte length count */
/* resource data */
/* the map section contains */
/* A copy of the 16 byte header */
/* a 4 byte mac internal value (I hope) */
/* another 4 bytes of mac internal values (I hope) */
/* a 2 byte offset from the start of the map section to the list of resource types */
/* a 2 byte offset from the start of the map section to the list of resource names */
/* The resource type list consists of */
/* a 2 byte count of the number of resource types (-1) */
/* (many copies of) */
/* a 4 byte resource type ('FOND' for example) */
/* a 2 byte count of the number of resources of this type (-1) */
/* a 2 byte offset from the type list start to the resource table */
/* a resource table looks like */
/* a 2 byte offset from the resource name table to a pascal */
/* string containing this resource's name (or 0xffff for none) */
/* 1 byte of resource flags */
/* 3 bytes of offset from the resource section to the length & */
/* data of this instance of the resource type */
/* 4 bytes of 0 */
/* The resource name section consists of */
/* a bunch of pascal strings (ie. preceded by a length byte) */
/* The POST resource isn't noticeably documented, it's pretty much a */
/* straight copy of the pfb file cut up into 0x800 byte chunks. */
/* (each section of the pfb file has it's own set of chunks, the last may be smaller than 0x800) */
/* The NFNT resource http://developer.apple.com/techpubs/mac/Text/Text-250.html */
/* The FOND resource http://developer.apple.com/techpubs/mac/Text/Text-269.html */
/* The sfnt resource is basically a copy of the ttf file */
/* A MacBinary file */
/* http://www.lazerware.com/formats/macbinary.html */
/* begins with a 128 byte header */
/* (which specifies lengths for data/resource forks) */
/* (and contains mac type/creator data) */
/* (and other stuff) */
/* (and finally a crc checksum) */
/* is followed by the data section (padded to a mult of 128 bytes) */
/* is followed by the resource section (padded to a mult of 128 bytes) */
/* Crc code taken from: */
/* http://www.ctan.org/tex-archive/tools/macutils/crc/ */
/* MacBinary files use the same CRC that binhex does (in the MacBinary header) */
/* ******************************** Creation ******************************** */
static uint16 HashToId(char *fontname,SplineFont *sf,EncMap *map) {
int low = 128, high = 0x3fff;
/* A FOND ID should be between these two numbers for roman script (I think) */
uint32 hash = 0;
int i, gid;
SplineChar *sc;
/* Figure out what language we've got */
/* I'm not bothering with all of the apple scripts, and I don't know */
/* what to do about cjk fonts */
if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
if ( sf->cidmaster != NULL ) sf = sf->cidmaster;
if ( sf->ordering != NULL ) {
if ( strstrmatch(sf->ordering,"Japan")!=NULL ) {
low = 0x4000; high = 0x41ff;
} else if ( strstrmatch(sf->ordering,"Korea")!=NULL ) {
low = 0x4400; high = 0x45ff;
} else if ( strstrmatch(sf->ordering,"CNS")!=NULL ) {
low = 0x4200; high = 0x43ff;
} else if ( strstrmatch(sf->ordering,"GB")!=NULL ) {
low = 0x7200; high = 0x73ff;
}
}
} else if ( map->enc->is_tradchinese ) {
low = 0x4200; high = 0x43ff;
} else if ( map->enc->is_japanese ) {
low = 0x4000; high = 0x41ff;
} else if ( map->enc->is_korean ) {
low = 0x4400; high = 0x45ff;
} else if ( map->enc->is_simplechinese ) {
low = 0x7200; high = 0x73ff;
} else for ( i=0; i<map->enccount && i<256; ++i ) if ( (gid=map->map[i])!=-1 && (sc = sf->glyphs[gid])!=NULL ) {
/* Japanese between 0x4000 and 0x41ff */
/* Trad Chinese 0x4200 and 0x43ff */
/* Simp Chinese 0x7200 and 0x73ff */
/* Korean 0x4400 and 0x45ff */
if (( sc->unicodeenc>=0x0600 && sc->unicodeenc<0x0700 ) ||
( sc->unicodeenc>=0xFB50 && sc->unicodeenc<0xfe00 )) {
/* arabic */
low = 0x4600; high = 0x47ff;
break;
} else if (( sc->unicodeenc>=0x0590 && sc->unicodeenc<0x0600 ) ||
( sc->unicodeenc>=0xFB1d && sc->unicodeenc<0xFB50 )) {
/* hebrew */
low = 0x4800; high = 0x49ff;
break;
} else if ((( sc->unicodeenc>=0x0370 && sc->unicodeenc<0x0400 ) ||
( sc->unicodeenc>=0x1f00 && sc->unicodeenc<0x2000 )) &&
sc->unicodeenc!=0x3c0 ) { /* In mac encoding */
/* greek */
low = 0x4a00; high = 0x4bff;
break;
} else if ( sc->unicodeenc>=0x0400 && sc->unicodeenc<0x0530 ) {
/* cyrillic */
low = 0x4c00; high = 0x4dff;
break;
/* hebrew/arabic symbols 4e00-4fff */
} else if ( sc->unicodeenc>=0x0900 && sc->unicodeenc<0x0980 ) {
/* devanagari */
low = 0x5000; high = 0x51ff;
break;
} else if ( sc->unicodeenc>=0x0980 && sc->unicodeenc<0x0a00 ) {
/* bengali: script=13 */
low = 0x5800; high = 0x59ff;
break;
}
}
while ( *fontname ) {
int temp = (hash>>28)&0xf;
hash = (hash<<4) | temp;
hash ^= *fontname++-' ';
}
hash %= (high-low+1);
hash += low;
return( hash );
}
static int IsMacMonospaced(SplineFont *sf,EncMap *map) {
/* Only look at first 256 */
int i;
double width = 0x80000000;
for ( i=0; i<256 && i<map->enccount; ++i ) {
int gid = map->map[i];
if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
if ( width == 0x80000000 )
width = sf->glyphs[gid]->width;
else if ( sf->glyphs[gid]->width!=width )
return( false );
}
}
return( true );
}
SplineChar *SFFindExistingCharMac(SplineFont *sf,EncMap *map,int unienc) {
int i, gid;
for ( i=0; i<map->enccount && i<256; ++i )
if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && sf->glyphs[gid]->unicodeenc==unienc )
return( sf->glyphs[gid] );
return( NULL );
}
static double SFMacWidthMax(SplineFont *sf, EncMap *map) {
/* Only look at first 256 */
int i, gid;
double width = -1;
for ( i=0; i<256 && i<map->enccount; ++i ) {
if ( (gid=map->map[i])!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
if ( sf->glyphs[gid]->width>width )
width = sf->glyphs[gid]->width;
}
}
if ( width<0 ) /* No chars, or widths the mac doesn't support */
return( 0 );
return( width );
}
static int SFMacAnyKerns(SplineFont *sf, EncMap *map) {
/* Only look at first 256 */
int i, cnt=0, gid;
KernPair *kp;
for ( i=0; i<256 && i<map->enccount; ++i ) {
if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
for ( kp=sf->glyphs[gid]->kerns; kp!=NULL; kp=kp->next )
if ( map->backmap[kp->sc->orig_pos]<256 )
++cnt;
}
}
return( cnt );
}
struct resource {
uint32 pos;
uint8 flags;
uint16 id;
char *name;
uint32 nameloc;
uint32 nameptloc;
};
struct resourcetype {
uint32 tag;
struct resource *res;
uint32 resloc;
};
struct macbinaryheader {
char *macfilename;
char *binfilename; /* if macfilename is null and this is set we will figure out macfilename by removing .bin */
uint32 type;
uint32 creator;
};
static struct resource *PSToResources(FILE *res,FILE *pfbfile) {
/* split the font up into as many small resources as we need and return */
/* an array pointing to the start of each */
struct stat statb;
int cnt, type;
struct resource *resstarts;
int len,i;
fstat(fileno(pfbfile),&statb);
cnt = 3*(statb.st_size+0x800)/(0x800-2)+1; /* should be (usually) a vast over estimate */
resstarts = calloc(cnt+1,sizeof(struct resource));
cnt = 0;
for (;;) {
if ( getc(pfbfile)!=0x80 ) {
IError("We made a pfb file, but didn't get one. Hunh?" );
return( NULL );
}
type = getc(pfbfile);
if ( type==3 ) {
/* 501 appears to be magic */
/* postscript resources seem to have flags of 0 */
resstarts[cnt].id = 501+cnt;
resstarts[cnt++].pos = ftell(res);
putlong(res,2); /* length */
putc(5,res); /* eof mark */
putc(0,res);
break;
}
len = getc(pfbfile);
len |= (getc(pfbfile))<<8;
len |= (getc(pfbfile))<<16;
len |= (getc(pfbfile))<<24;
while ( len>0 ) {
int ilen = len;
if ( ilen>0x800-2 )
ilen = 0x800-2;
len -= ilen;
resstarts[cnt].id = 501+cnt;
resstarts[cnt++].pos = ftell(res);
putlong(res,ilen+2); /* length */
putc(type,res); /* section type mark */
putc(0,res);
for ( i=0; i<ilen; ++i )
putc(getc(pfbfile),res);
}
}
resstarts[cnt].pos = 0;
return( resstarts );
}
static uint32 TTFToResource(FILE *res,FILE *ttffile) {
/* A truetype font just gets dropped into a resource */
struct stat statb;
int ch;
uint32 resstart;
fstat(fileno(ttffile),&statb);
resstart = ftell(res);
putlong(res,statb.st_size);
while ( (ch=getc(ttffile))!=EOF )
putc(ch,res);
return( resstart );
}
static int BDFCCopyBitmaps(uint8 **rows,int offset,BDFChar *bdfc, BDFFont *bdf) {
int i, r, y, ipos, j, c;
y = bdf->ascent-1; r = i = 0;
if ( bdfc->ymax > bdf->ascent-1 )
i = bdfc->ymax-(bdf->ascent-1);
else if ( bdfc->ymax<bdf->ascent-1 ) {
r = bdf->ascent-1-bdfc->ymax;
y = bdfc->ymax;
}
for ( ; y>=bdfc->ymin && y>=-bdf->descent; --y, ++i ) {
/* Mac characters may not extend above the ascent or below the descent */
/* but bdf chars can, so if a bdf char does, just ignore that part */
ipos = i*bdfc->bytes_per_line;
for ( j=0,c=offset; j<=bdfc->xmax-bdfc->xmin; ++j, ++c ) {
if ( bdfc->bitmap[ipos+(j>>3)] & (1<<(7-(j&7))) )
rows[r][c>>3] |= (1<<(7-(c&7)));
}
++r;
}
return( offset + bdfc->xmax-bdfc->xmin+1 );
}
static uint32 BDFToNFNT(FILE *res, BDFFont *bdf, EncMap *map) {
short widths[258], lbearings[258], locs[258]/*, idealwidths[256]*/;
uint8 **rows = malloc(bdf->pixelsize*sizeof(uint8 *));
int i, k, width, kernMax=1, descentMax=bdf->descent-1, rectMax=1, widMax=3;
uint32 rlenpos = ftell(res), end, owloc, owpos;
int gid;
BDFChar *bdfc;
for ( i=0; i<map->enccount; i++ ) if (( gid=map->map[i])!=-1 && ( bdfc = bdf->glyphs[gid] ) != NULL )
BCPrepareForOutput( bdfc,true );
for ( i=width=0; i<256 && i<map->enccount; ++i ) {
if ( (gid = map->map[i])!=-1 && gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL ) {
width += bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
if ( bdf->glyphs[gid]->width>widMax )
widMax = bdf->glyphs[gid]->width;
if ( bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin>rectMax )
rectMax = bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
if ( bdf->glyphs[gid]->xmin<kernMax )
kernMax = bdf->glyphs[gid]->xmin;
if ( bdf->glyphs[gid]->ymin<-descentMax )
descentMax = -bdf->glyphs[gid]->ymin;
}
}
if ( descentMax>bdf->descent ) descentMax = bdf->descent;
++width; /* For the "undefined character */
for ( k=0; k<bdf->pixelsize; ++k )
rows[k] = calloc((width+7)/8 + 4 , sizeof(uint8));
for ( i=width=0; i<256 ; ++i ) {
locs[i] = width;
if ( i>=map->enccount || (gid=map->map[i])==-1 || gid>=bdf->glyphcnt || bdf->glyphs[gid]==NULL ||
!SCWorthOutputting(bdf->glyphs[gid]->sc) ) {
lbearings[i] = 0xff;
widths[i] = 0xff;
/*idealwidths[i] = 1<<12; */ /* 1 em */
} else {
lbearings[i] = bdf->glyphs[gid]->xmin-kernMax;
widths[i] = bdf->glyphs[gid]->width<0?0:
bdf->glyphs[gid]->width>=256?255:
bdf->glyphs[gid]->width;
/*idealwidths[i] = bdf->glyphs[gid]->sc->width*(1<<12)/(bdf->sf->ascent+bdf->sf->descent);*/
width = BDFCCopyBitmaps(rows,width,bdf->glyphs[gid],bdf);
}
}
/* Now for the "undefined character", just a simple vertical bar */
locs[i] = width;
lbearings[i] = 1;
widths[i++] = 3;
/*idealwidths[i++] = (3<<12)/bdf->pixelsize;*/
for ( k = 1; k<bdf->pixelsize-1; ++k )
rows[k][width>>3] |= (1<<(7-(width&7)));
/* And one more entry to give a size to the last character */
locs[i] = ++width;
lbearings[i] = widths[i] = 0xff;
/*idealwidths[i] = 0;*/
/* Mac magic */
lbearings[0] = widths[0] = 0;
lbearings['\r'] = widths['\r'] = 0;
lbearings['\t'] = 0; widths['\t'] = 6;
for ( i=0; i<map->enccount; i++ ) if (( gid=map->map[i])!=-1 && ( bdfc = bdf->glyphs[gid] ) != NULL )
BCRestoreAfterOutput( bdfc );
/* We've finished the bitmap conversion, now save it... */
putlong(res,0); /* Length, to be filled in later */
putshort(res,IsMacMonospaced(bdf->sf,map)?0xb000:0x9000); /* fontType */
putshort(res,0);
putshort(res,255);
putshort(res,widMax);
putshort(res,kernMax);
putshort(res,-descentMax);
putshort(res,rectMax);
putshort(res,bdf->pixelsize);
owpos = ftell(res);
putshort(res,0);
putshort(res,bdf->ascent);
putshort(res,bdf->descent);
putshort(res,(short) (bdf->sf->pfminfo.linegap*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent)) );
putshort(res,(width+15)>>4);
/* bitmaps */
for ( k=0; k<bdf->pixelsize; ++k ) {
for ( i=0; i<((width+15)>>4) ; ++i ) {
putc(rows[k][2*i],res);
putc(rows[k][2*i+1],res);
}
}
for ( i=0; i<258; ++i )
putshort(res,locs[i]);
owloc = ftell(res); /* valgrind reports an error here (but not above). god knows why */
for ( i=0; i<258; ++i ) {
putc(lbearings[i],res);
putc(widths[i],res);
}
end = ftell(res);
fseek(res,rlenpos,SEEK_SET);
putlong(res,end-rlenpos-4);
fseek(res,owpos,SEEK_SET);
putshort(res,(owloc-owpos)/2);
fseek(res,0,SEEK_END);
for ( k=0; k<bdf->pixelsize; ++k )
free(rows[k]);
free(rows);
return(rlenpos);
}
static uint32 DummyNFNT(FILE *res, BDFFont *bdf, EncMap *map) {
/* This produces a stub NFNT which appears when the real data lives inside */
/* an sfnt (truetype) resource. We still need to produce an NFNT to tell */
/* the system that the pointsize is available. This NFNT has almost nothing */
/* in it, just the initial header, no metrics, no bitmaps */
int i, width, kernMax=1, descentMax=bdf->descent-1, rectMax=1, widMax=3;
uint32 rlenpos = ftell(res);
int gid;
for ( i=width=0; i<256 && i<map->enccount; ++i ) if ( (gid=map->map[i])!=-1 && gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL ) {
width += bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
if ( bdf->glyphs[gid]->width>widMax )
widMax = bdf->glyphs[gid]->width;
if ( bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin>rectMax )
rectMax = bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
if ( bdf->glyphs[gid]->xmin<kernMax )
kernMax = bdf->glyphs[gid]->xmin;
if ( bdf->glyphs[gid]->ymin<-descentMax )
descentMax = -bdf->glyphs[gid]->ymin;
}
if ( descentMax>bdf->descent ) descentMax = bdf->descent;
putlong(res,26); /* Length */
putshort(res,SFOneWidth(bdf->sf)!=-1?0xf000:0xd000); /* fontType */
putshort(res,0);
putshort(res,255);
putshort(res,widMax);
putshort(res,kernMax);
putshort(res,-descentMax);
putshort(res,rectMax);
putshort(res,bdf->pixelsize);
putshort(res,0);
putshort(res,bdf->ascent);
putshort(res,bdf->descent);
putshort(res,(short) (bdf->sf->pfminfo.linegap*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent)) );
putshort(res,0);
return(rlenpos);
}
static struct resource *SFToNFNTs(FILE *res, SplineFont *sf, int32 *sizes,
EncMap *map) {
int i, baseresid = HashToId(sf->fontname,sf,map);
struct resource *resstarts;
BDFFont *bdf;
if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
for ( i=0; sizes[i]!=0; ++i );
resstarts = calloc(i+1,sizeof(struct resource));
for ( i=0; sizes[i]!=0; ++i ) {
if ( (sizes[i]>>16)!=1 )
continue;
if ( (sizes[i]&0xffff)>=256 )
continue;
for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
if ( bdf==NULL )
continue;
resstarts[i].id = baseresid+bdf->pixelsize;
resstarts[i].pos = BDFToNFNT(res,bdf,map);
/* NFNTs seem to have resource flags of 0 */
}
return(resstarts);
}
static struct resource *SFsToNFNTs(FILE *res, struct sflist *sfs,int baseresid) {
int i, j, cnt;
struct resource *resstarts;
BDFFont *bdf;
struct sflist *sfi;
SplineFont *sf;
cnt = 0;
for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
if ( sfi->sizes!=NULL ) {
for ( i=0; sfi->sizes[i]!=0; ++i );
cnt += i;
sfi->ids = calloc(i+1,sizeof(int));
sfi->bdfs = calloc(i+1,sizeof(BDFFont *));
}
}
resstarts = calloc(cnt+1,sizeof(struct resource));
cnt = 0;
for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
sf = sfi->sf;
if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
j=0;
if ( sfi->sizes ) for ( i=0; sfi->sizes[i]!=0; ++i ) {
if ( (sfi->sizes[i]>>16)!=1 )
continue;
if ( (sfi->sizes[i]&0xffff)>=256 )
continue;
for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sfi->sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
if ( bdf==NULL )
continue;
sfi->ids[j] = baseresid;
sfi->bdfs[j] = bdf;
resstarts[cnt+j].id = baseresid++;
resstarts[cnt+j++].pos = BDFToNFNT(res,bdf,sfi->map);
/* NFNTs seem to have resource flags of 0 */
}
cnt += j;
}
return(resstarts);
}
static struct resource *BuildDummyNFNTlist(FILE *res, SplineFont *sf,
int32 *sizes, int baseresid, EncMap *map) {
int i;
struct resource *resstarts;
BDFFont *bdf;
if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
for ( i=0; sizes[i]!=0; ++i );
resstarts = calloc(i+1,sizeof(struct resource));
for ( i=0; sizes[i]!=0; ++i ) {
if ( (sizes[i]>>16)!=1 )
continue;
if ( (sizes[i]&0xffff)>=256 )
continue;
for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
if ( bdf==NULL )
continue;
resstarts[i].id = baseresid+(sizes[i]&0xffff);
resstarts[i].pos = DummyNFNT(res,bdf,map);
/* NFNTs seem to have resource flags of 0 */
}
return(resstarts);
}
static struct resource *BuildDummyNFNTfamilyList(FILE *res, struct sflist *sfs,
int baseresid) {
int i,j,cnt;
struct resource *resstarts;
BDFFont *bdf;
struct sflist *sfi;
SplineFont *sf;
cnt = 0;
for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
if ( sfi->sizes!=NULL ) {
for ( i=0; sfi->sizes[i]!=0; ++i );
cnt += i;
sfi->ids = calloc(i+1,sizeof(int));
sfi->bdfs = calloc(i+1,sizeof(BDFFont *));
}
}
resstarts = calloc(cnt+1,sizeof(struct resource));
cnt = 0;
for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
sf = sfi->sf;
j = 0;
if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
if ( sfi->sizes ) for ( i=0; sfi->sizes[i]!=0; ++i ) {
if ( (sfi->sizes[i]>>16)!=1 )
continue;
for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sfi->sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
if ( bdf==NULL )
continue;
sfi->ids[j] = baseresid;
sfi->bdfs[j] = bdf;
resstarts[cnt+j].id = baseresid++;
resstarts[cnt+j++].pos = DummyNFNT(res,bdf,sfi->map);
/* NFNTs seem to have resource flags of 0 */
}
cnt += j;
}
return(resstarts);
}
enum psstyle_flags { psf_bold = 1, psf_italic = 2, psf_outline = 4,
psf_shadow = 0x8, psf_condense = 0x10, psf_extend = 0x20 };
uint16 _MacStyleCode( const char *styles, SplineFont *sf, uint16 *psstylecode ) {
unsigned short stylecode= 0, psstyle=0;
if ( strstrmatch( styles, "Bold" ) || strstrmatch(styles,"Demi") ||
strstrmatch( styles,"Heav") || strstrmatch(styles,"Blac") ||
/* A few fonts have German/French styles in their names */
strstrmatch( styles,"Fett") || strstrmatch(styles,"Gras") ) {
stylecode = sf_bold;
psstyle = psf_bold;
} else if ( sf!=NULL && sf->weight!=NULL &&
(strstrmatch( sf->weight, "Bold" ) || strstrmatch(sf->weight,"Demi") ||
strstrmatch( sf->weight,"Heav") || strstrmatch(sf->weight,"Blac") ||
strstrmatch( sf->weight,"Fett") || strstrmatch(sf->weight,"Gras")) ) {
stylecode = sf_bold;
psstyle = psf_bold;
}
/* URW uses four leter abbreviations of Italic and Oblique */
/* Somebody else uses two letter abbrevs */
if ( (sf!=NULL && sf->italicangle!=0) ||
strstrmatch( styles, "Ital" ) ||
strstrmatch( styles, "Obli" ) ||
strstrmatch(styles, "Slanted") ||
strstrmatch(styles, "Kurs") ||
strstr( styles,"It" ) ) {
stylecode |= sf_italic;
psstyle |= psf_italic;
}
if ( strstrmatch( styles, "Underline" ) ) {
stylecode |= sf_underline;
}
if ( strstrmatch( styles, "Outl" ) ) {
stylecode |= sf_outline;
psstyle |= psf_outline;
}
if ( strstr(styles,"Shadow")!=NULL ) {
stylecode |= sf_shadow;
psstyle |= psf_shadow;
}
if ( strstrmatch( styles, "Cond" ) || strstr( styles,"Cn") ||
strstrmatch( styles, "Narrow") ) {
stylecode |= sf_condense;
psstyle |= psf_condense;
}
if ( strstrmatch( styles, "Exte" ) || strstr( styles,"Ex") ) {
stylecode |= sf_extend;
psstyle |= psf_extend;
}
if ( (psstyle&psf_extend) && (psstyle&psf_condense) ) {
if ( sf!=NULL )
LogError( _("Warning: %s(%s) is both extended and condensed. That's impossible.\n"),
sf->fontname, sf->origname );
else
LogError( _("Warning: Both extended and condensed. That's impossible.\n") );
psstyle &= ~psf_extend;
stylecode &= ~sf_extend;
}
if ( psstylecode!=NULL )
*psstylecode = psstyle;
return( stylecode );
}
uint16 MacStyleCode( SplineFont *sf, uint16 *psstylecode ) {
const char *styles;
if ( sf->cidmaster!=NULL )
sf = sf->cidmaster;
if ( sf->macstyle!=-1 ) {
if ( psstylecode!=NULL )
*psstylecode = (sf->macstyle&0x3)|((sf->macstyle&0x6c)>>1);
return( sf->macstyle );
}
styles = SFGetModifiers(sf);
return( _MacStyleCode(styles,sf,psstylecode));
}
static uint32 SFToFOND(FILE *res,SplineFont *sf,uint32 id,int dottf,
int32 *sizes, EncMap *map) {
uint32 rlenpos = ftell(res), widoffpos, widoffloc, kernloc, styleloc, end;
int i,j,k,cnt, strcnt, fontclass, stylecode, glyphenc, geoffset, realstylecode;
int gid;
KernPair *kp;
DBounds b;
char *pt;
/* Fonds are generally marked system heap and sometimes purgeable (resource flags) */
putlong(res,0); /* Fill in length later */
putshort(res,IsMacMonospaced(sf,map)?0x9000:0x1000);
putshort(res,id);
putshort(res,0); /* First character */
putshort(res,255); /* Last character */
putshort(res,(short) ((sf->ascent*(1<<12))/(sf->ascent+sf->descent)));
putshort(res,-(short) ((sf->descent*(1<<12))/(sf->ascent+sf->descent)));
putshort(res,(short) ((sf->pfminfo.linegap*(1<<12))/(sf->ascent+sf->descent)));
putshort(res,(short) ((SFMacWidthMax(sf,map)*(1<<12))/(sf->ascent+sf->descent)));
widoffpos = ftell(res);
putlong(res,0); /* Fill in width offset later */
putlong(res,0); /* Fill in kern offset later */
putlong(res,0); /* Fill in style offset later */
for ( i=0; i<9; ++i )
putshort(res,0); /* Extra width values */
putlong(res,0); /* Script for international */
putshort(res,2); /* FOND version */
/* Font association table */
stylecode = realstylecode = MacStyleCode( sf, NULL );
stylecode = 0; /* Debug !!!! */
for ( i=j=0; sizes!=NULL && sizes[i]!=0; ++i )
if ( (sizes[i]>>16)==1 && (sizes[i]&0xffff)<256 )
++j;
if ( dottf ) {
putshort(res,j+1-1); /* Number of faces */
putshort(res,0); /* it's scaleable */
putshort(res,stylecode);
putshort(res,id); /* Give it the same ID as the fond */
} else
putshort(res,j-1); /* Number of faces */
if ( sizes!=NULL ) {
for ( i=0; sizes[i]!=0; ++i ) if (( sizes[i]>>16) == 1 ) {
putshort(res,sizes[i]&0xffff);
putshort(res,stylecode);
putshort(res,id+(sizes[i]&0xffff)); /* make up a unique ID */
}
}
/* offset table */
putshort(res,1-1); /* One table */
putlong(res,6); /* Offset from start of otab to next byte */
/* bounding box table */
putshort(res,1-1); /* One bounding box */
SplineFontFindBounds(sf,&b);
putshort(res,stylecode);
putshort(res,b.minx*(1<<12)/(sf->ascent+sf->descent));
putshort(res,b.miny*(1<<12)/(sf->ascent+sf->descent));
putshort(res,b.maxx*(1<<12)/(sf->ascent+sf->descent));
putshort(res,b.maxy*(1<<12)/(sf->ascent+sf->descent));
widoffloc = ftell(res);
putshort(res,1-1); /* One style in the width table too */
putshort(res,stylecode);
for ( k=0; k<=256; ++k ) {
if ( k>=map->enccount || k==256 || (gid=map->map[k])==-1 || sf->glyphs[gid]==NULL )
putshort(res,1<<12); /* 1 em is default size */
else
putshort(res,sf->glyphs[gid]->width*(1<<12)/(sf->ascent+sf->descent));
}
kernloc = 0;
if (( cnt = SFMacAnyKerns(sf,map))>0 ) {
kernloc = ftell(res);
putshort(res,1-1); /* One style in the width table too */
putshort(res,stylecode); /* style */
putshort(res,cnt); /* Count of kerning pairs */
for ( k=0; k<256 && k<map->enccount; ++k ) {
if ( (gid=map->map[k])!=-1 && sf->glyphs[gid]!=NULL ) {
for ( kp=sf->glyphs[gid]->kerns; kp!=NULL; kp=kp->next )
if ( map->backmap[kp->sc->orig_pos]<256 ) {
putc(k,res);
putc(map->backmap[kp->sc->orig_pos],res);
putshort(res,kp->off*(1<<12)/(sf->ascent+sf->descent));
}
}
}
}
/* Fontographer referenced a postscript font even in truetype FONDs */
styleloc = ftell(res);
fontclass = 0x1; /* font name needs coordinating? Font has its own encoding */
if ( !(realstylecode&sf_outline) ) fontclass |= 4;
if ( realstylecode&sf_bold ) fontclass |= 0x18;
if ( realstylecode&psf_italic ) fontclass |= 0x40;
if ( realstylecode&psf_condense ) fontclass |= 0x80;
if ( realstylecode&psf_extend ) fontclass |= 0x100;
putshort(res,fontclass); /* fontClass */
geoffset = ftell(res);
putlong(res,0); /* Offset to glyph encoding table */ /* Fill in later */
putlong(res,0); /* Reserved, MBZ */
if ( !sf->familyname || strnmatch(sf->familyname,sf->fontname,strlen(sf->familyname))!=0 )
strcnt = 1;
else if ( strmatch(sf->familyname,sf->fontname)==0 )
strcnt = 1;
else if ( sf->fontname[strlen(sf->familyname)]=='-' )
strcnt = 4;
else
strcnt = 3;
for ( k=0; k<48; ++k )
putc(strcnt==1?1:2,res); /* All indeces point to this font */
putshort(res,strcnt); /* strcnt strings */
if ( strcnt==1 ) {
putc(strlen(sf->fontname),res); /* basename is full name */
/* Mac expects this to be upper case */
if ( islower(*sf->fontname)) putc(toupper(*sf->fontname),res);
else putc(*sf->fontname,res);
fwrite(sf->fontname+1,1,strlen(sf->fontname+1),res);
} else {
pt = sf->fontname+strlen(sf->familyname);
putc(strlen(sf->familyname),res);/* basename */
if ( islower(*sf->familyname)) putc(toupper(*sf->familyname),res);
else putc(*sf->familyname,res);
fwrite(sf->familyname+1,1,strlen(sf->familyname+1),res);
if ( strcnt==3 ) {
putc(1,res); /* index string is one byte long */
putc(3,res); /* plain name is basename with string 2 */
putc(strlen(pt),res); /* length of... */
fwrite(pt,1,strlen(pt),res); /* everything else */
} else {
putc(2,res); /* index string is two bytes long */
putc(3,res); /* plain name is basename with hyphen */
putc(4,res); /* and everything else */
putc(1,res); /* Length of ... */
putc('-',res); /* String containing hyphen */
++pt; /* skip over hyphen */
putc(strlen(pt),res); /* length of ... */
fwrite(pt,1,strlen(pt),res); /* everything else */
}
}
/* Greg: record offset for glyph encoding table */
/* We assume that the bitmap and postscript fonts are encoded similarly */
/* and so a null vector will do. */
/* GWW: Hmm. ATM refuses to use postscript fonts that have */
/* glyph encoding tables. Printer drivers use them ok. ATM will only */
/* work on fonts with mac roman encodings */
if ( strmatch(map->enc->enc_name,"mac")!=0 &&
strmatch(map->enc->enc_name,"macintosh")!=0 &&
strmatch(map->enc->enc_name,"macroman")!=0 ) {
if ( !dottf ) ff_post_notice(_("The generated font won't work with ATM"),_("ATM requires that fonts be encoded with the Macintosh Latin encoding. This postscript font will print fine, but only the bitmap versions will be displayed on the screen"));
glyphenc = ftell( res );
fseek(res,geoffset,SEEK_SET);
putlong(res,glyphenc-geoffset+2);
fseek(res,glyphenc,SEEK_SET);
putshort(res,0);
}
end = ftell(res);
fseek(res,widoffpos,SEEK_SET);
putlong(res,widoffloc-rlenpos-4); /* Fill in width offset */
putlong(res,kernloc!=0?kernloc-rlenpos-4:0); /* Fill in kern offset */
putlong(res,styleloc!=0?styleloc-rlenpos-4:0); /* Fill in style offset */
fseek(res,rlenpos,SEEK_SET);
putlong(res,end-rlenpos-4); /* resource length */
fseek(res,end,SEEK_SET);
return(rlenpos);
}
static void putpnsstring(FILE *res,char *fontname,int len) {
putc(len,res);
if ( *fontname && len>0 ) {
if ( islower(*fontname))
putc(toupper(*fontname),res);
else
putc(*fontname,res);
--len;
for ( ++fontname; *fontname && len>0; ++fontname, --len )
putc(*fontname,res);
}
}
static void putpsstring(FILE *res,char *fontname) {
putc(strlen(fontname),res);
if ( *fontname ) {
for ( ; *fontname; ++fontname )
putc(*fontname,res);
}
}
struct sflistlist {
struct sflist *sfs;
struct sflistlist *next;
char *fondname;
};
static struct sflistlist *FondSplitter(struct sflist *sfs,int *fondcnt) {
struct sflist *psfaces[48], *sfi, *last, *start;
struct sflistlist *sfsl=NULL, *lastl=NULL, *cur, *test;
uint16 psstyle;
int fc = 0;
sfi = sfs;
if ( sfi->sf->fondname==NULL ) {
memset(psfaces,0,sizeof(psfaces));
MacStyleCode(sfi->sf,&psstyle);
last = NULL;
while ( sfi->sf->fondname==NULL && psfaces[psstyle]==NULL ) {
psfaces[psstyle] = sfi;
last = sfi;
sfi = sfi->next;
if ( sfi==NULL )
break;
MacStyleCode(sfi->sf,&psstyle);
}
cur = calloc(1,sizeof(struct sflistlist));
cur->sfs = sfs;
last->next = NULL;
for ( last=sfi; last!=NULL; last=last->next )
if ( last->sf->fondname!=NULL && strcmp(last->sf->fondname,sfs->sf->familyname)==0 )
break;
cur->fondname = copy( last==NULL ? sfs->sf->familyname : sfs->sf->fontname );
lastl = sfsl = cur;
++fc;
}
while ( sfi!=NULL ) {
start = sfi;
if ( sfi->sf->fondname==NULL ) {
last = sfi;
sfi = sfi->next;
} else {
memset(psfaces,0,sizeof(psfaces));
MacStyleCode(sfi->sf,&psstyle);
while ( sfi!=NULL && sfi->sf->fondname!=NULL &&
strcmp(sfi->sf->fondname,start->sf->fondname)==0 &&
psfaces[psstyle]==NULL ) {
psfaces[psstyle] = sfi;
last = sfi;
sfi = sfi->next;
if ( sfi==NULL )
break;
MacStyleCode(sfi->sf,&psstyle);
}
}
cur = calloc(1,sizeof(struct sflistlist));
test = NULL;
if ( start->sf->fondname!=NULL ) {
for ( test = sfsl; test!=NULL; test=test->next )
if ( strcmp(test->fondname,start->sf->fondname)==0 )
break;
if ( test==NULL )
cur->fondname = copy(start->sf->fondname);
}
if ( cur->fondname==NULL )
cur->fondname = copy(start->sf->fontname);
if ( lastl!=NULL ) lastl->next = cur;
lastl = cur;
cur->sfs = start;
last->next = NULL;
if ( sfsl==NULL )
sfsl = cur;
++fc;
}
*fondcnt = fc;
return( sfsl );
}
static void SFListListFree(struct sflistlist *sfsl) {
struct sflist *last = NULL;
struct sflistlist *sfli, *sflnext;
/* free the fond list and restore the sfs list */
for ( sfli=sfsl; sfli!=NULL; sfli = sflnext ) {
sflnext = sfli->next;
if ( last!=NULL )
last->next = sfli->sfs;
for ( last = sfli->sfs; last->next!=NULL; last = last->next );
free(sfli->fondname);
free(sfli);
}
}
static uint32 SFsToFOND(FILE *res,struct sflist *sfs,uint32 id,int format) {
uint32 rlenpos = ftell(res), widoffpos, widoffloc, kernloc, styleloc, end;
int i,j,k,cnt, scnt, kcnt, pscnt, strcnt, fontclass, glyphenc, geoffset;
int gid;
int size;
uint16 psstyle, stylecode;
int exact, famlen, has_hyphen;
char *familyname;
KernPair *kp;
DBounds b;
/* Fonds are generally marked system heap and sometimes purgeable (resource flags) */
struct sflist *faces[96];
struct sflist *psfaces[48];
SplineFont *sf;
struct sflist *sfi;
char *pt;
memset(faces,0,sizeof(faces));
memset(psfaces,0,sizeof(psfaces));
for ( sfi = sfs ; sfi!=NULL; sfi = sfi->next ) {
stylecode = MacStyleCode(sfi->sf,&psstyle);
if ( sfs->next==NULL ) /* FONDs with a single entry should make that entry be "regular" no matter what we think it really is */
stylecode = psstyle = 0;
if ( faces[stylecode]==NULL )
faces[stylecode] = sfi;
if ( psfaces[psstyle]==NULL )
psfaces[psstyle] = sfi;
}
sf = faces[0]->sf;
putlong(res,0); /* Fill in length later */
putshort(res,IsMacMonospaced(sf,faces[0]->map)?0x9000:0x1000);
putshort(res,id);
putshort(res,0); /* First character */
putshort(res,255); /* Last character */
putshort(res,(short) ((sf->ascent*(1<<12))/(sf->ascent+sf->descent)));
putshort(res,-(short) ((sf->descent*(1<<12))/(sf->ascent+sf->descent)));
putshort(res,(short) ((sf->pfminfo.linegap*(1<<12))/(sf->ascent+sf->descent)));
putshort(res,(short) ((SFMacWidthMax(sf,faces[0]->map)*(1<<12))/(sf->ascent+sf->descent)));
widoffpos = ftell(res);
putlong(res,0); /* Fill in width offset later */
putlong(res,0); /* Fill in kern offset later */
putlong(res,0); /* Fill in style offset later */
for ( i=0; i<9; ++i )
putshort(res,0); /* Extra width values */
putlong(res,0); /* Script for international */
putshort(res,2); /* FOND version */
/* Font association table */
for ( i=cnt=scnt=kcnt=0; i<96; ++i ) if ( faces[i]!=NULL ) {
++scnt;
if ( faces[i]->id!=0 ) ++cnt;
if ( faces[i]->ids!=NULL )
for ( j=0; faces[i]->ids[j]!=0; ++j ) ++cnt;
if ( SFMacAnyKerns(faces[i]->sf,faces[i]->map)>0 )
++kcnt;
}
putshort(res,cnt-1); /* Number of faces */
/* do ttf faces (if any) first */
for ( i=cnt=0; i<96; ++i ) if ( faces[i]!=NULL && faces[i]->id!=0 ) {
putshort(res,0); /* it's scaleable */
putshort(res,i); /* style */
putshort(res,faces[i]->id);
}
/* then do bitmap faces (if any) */ /* Ordered by size damn it */
for ( size=1; size<256; ++size ) {
for ( i=0; i<96; ++i ) if ( faces[i]!=NULL && faces[i]->ids!=NULL ) {
for ( j=0; faces[i]->ids[j]!=0 ; ++j ) {
int pointsize = rint( (faces[i]->bdfs[j]->pixelsize*72.0/mac_dpi) );
if ( pointsize==size ) {
putshort(res,size);
putshort(res,i); /* style */
putshort(res,faces[i]->ids[j]);
}
}
}
}
/* offset table */
putshort(res,1-1); /* One table */
putlong(res,6); /* Offset from start of otab to next byte */
/* bounding box table */
putshort(res,scnt-1); /* One bounding box per style */
for ( i=0; i<96; ++i ) if ( faces[i]!=NULL ) {
SplineFontFindBounds(faces[i]->sf,&b);
putshort(res,i); /* style */
putshort(res,b.minx*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
putshort(res,b.miny*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
putshort(res,b.maxx*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
putshort(res,b.maxy*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
}
widoffloc = ftell(res);
putshort(res,scnt-1); /* One set of width metrics per style */
for ( i=0; i<96; ++i ) if ( faces[i]!=NULL ) {
putshort(res,i);
for ( k=0; k<=257; ++k ) {
if ( k>=faces[i]->map->enccount || k>=256 ||
(gid=faces[i]->map->map[k])==-1 || faces[i]->sf->glyphs[gid]==NULL )
putshort(res,1<<12); /* 1 em is default size */
else
putshort(res,faces[i]->sf->glyphs[gid]->width*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
}
}
kernloc = 0;
if ( kcnt>0 ) {
kernloc = ftell(res);
putshort(res,kcnt-1); /* Number of styles with kern pairs */
for ( i=0; i<96; ++i ) if ( faces[i]!=NULL && ( cnt = SFMacAnyKerns(faces[i]->sf,faces[i]->map))>0 ) {
putshort(res,i); /* style */
putshort(res,cnt); /* Count of kerning pairs */
for ( k=0; k<256 && k<faces[i]->map->enccount; ++k ) {
if ( (gid=faces[i]->map->map[k])!=-1 && faces[i]->sf->glyphs[gid]!=NULL ) {
for ( kp=faces[i]->sf->glyphs[gid]->kerns; kp!=NULL; kp=kp->next )
if ( faces[i]->map->backmap[kp->sc->orig_pos]<256 ) {
putc(k,res);
putc(faces[i]->map->backmap[kp->sc->orig_pos],res);
putshort(res,kp->off*(1<<12)/(sf->ascent+sf->descent));
}
}
}
}
}
/* Fontographer referenced a postscript font even in truetype FONDs */
styleloc = ftell(res);
exact = false;
familyname = psfaces[0]->sf->fontname;
famlen = strlen(familyname);
if ( (pt=strchr(familyname,'-'))!=NULL )
famlen = pt-familyname;
else if ( strnmatch(psfaces[0]->sf->familyname,psfaces[0]->sf->fontname,
strlen(psfaces[0]->sf->familyname))==0 )
famlen = strlen(psfaces[0]->sf->familyname);
has_hyphen = (familyname[famlen]=='-');
for ( i=pscnt=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
++pscnt;
if ( strncmp(psfaces[i]->sf->fontname,familyname,famlen)!=0 ) {
while ( famlen>0 ) {
--famlen;
if ( strncmp(psfaces[i]->sf->fontname,familyname,famlen)==0 )
break;
}
}
}
if ( famlen!=0 ) for ( i=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
if ( psfaces[i]->sf->fontname[famlen]==0 )
exact = true;
}
fontclass = 0x1;
if ( psfaces[psf_outline]==NULL ) fontclass |= 4;
if ( psfaces[psf_bold]!=NULL ) fontclass |= 0x18;
if ( psfaces[psf_italic]!=NULL ) fontclass |= 0x40;
if ( psfaces[psf_condense]!=NULL ) fontclass |= 0x80;
if ( psfaces[psf_extend]!=NULL ) fontclass |= 0x100;
putshort(res,fontclass); /* fontClass */
geoffset = ftell(res);
putlong(res,0); /* Offset to glyph encoding table */ /* Fill in later */
putlong(res,0); /* Reserved, MBZ */
strcnt = 1/* Family Name */ + pscnt-exact /* count of format strings */ +
has_hyphen +
pscnt-exact /* count of additional strings */;
/* indeces to format strings */
for ( i=0,pscnt=2; i<48; ++i )
if ( psfaces[i]!=NULL && psfaces[i]->sf->fontname[famlen]!=0 )
putc(pscnt++,res);
else if ( exact )
putc(1,res);
else
putc(2,res);
putshort(res,strcnt); /* strcnt strings */
putpnsstring(res,familyname,famlen);
if ( has_hyphen ) has_hyphen = pscnt++; /* Space for hyphen if present */
/* Now the format strings */
for ( i=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
if ( psfaces[i]->sf->fontname[famlen]!=0 ) {
if ( has_hyphen && psfaces[i]->sf->fontname[famlen]==' ' ) {
putc(2,res);
putc(has_hyphen,res);
putc(pscnt++,res);
} else {
putc(1,res); /* Familyname with the following */
putc(pscnt++,res);
}
}
}
if ( has_hyphen ) {
putc(1,res);
putc('-',res);
}
/* Now the additional names */
for ( i=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
if ( psfaces[i]->sf->fontname[famlen]!=0 )
putpsstring(res,psfaces[i]->sf->fontname+famlen);
}
/* Greg: record offset for glyph encoding table */
/* We assume that the bitmap and postscript fonts are encoded similarly */
/* and so a null vector will do. */
/* GWW: Hmm. ATM refuses to use postscript fonts that have */
/* glyph encoding tables. Printer drivers use them ok. ATM will only */
/* work on fonts with mac roman encodings */
if ( strmatch(psfaces[0]->map->enc->enc_name,"mac")!=0 &&
strmatch(psfaces[0]->map->enc->enc_name,"macintosh")!=0 &&
strmatch(psfaces[0]->map->enc->enc_name,"macroman")!=0 ) {
if ( format==ff_pfbmacbin )
ff_post_notice(_("The generated font won't work with ATM"),_("ATM requires that fonts be encoded with the Macintosh Latin encoding. This postscript font will print fine, but only the bitmap versions will be displayed on the screen"));
glyphenc = ftell( res );
fseek(res,geoffset,SEEK_SET);
putlong(res,glyphenc-geoffset+2);
fseek(res,glyphenc,SEEK_SET);
putshort(res,0); /* Greg: an empty Glyph encoding table */
}
end = ftell(res);
fseek(res,widoffpos,SEEK_SET);
putlong(res,widoffloc-rlenpos-4); /* Fill in width offset */
putlong(res,kernloc!=0?kernloc-rlenpos-4:0); /* Fill in kern offset */
putlong(res,styleloc!=0?styleloc-rlenpos-4:0); /* Fill in style offset */
fseek(res,rlenpos,SEEK_SET);
putlong(res,end-rlenpos-4); /* resource length */
fseek(res,end,SEEK_SET);
return(rlenpos);
}
/* I presume this routine is called after all resources have been written */
static void DumpResourceMap(FILE *res,struct resourcetype *rtypes,enum fontformat format) {
uint32 rfork_base = format>=ff_ttfdfont?0:128; /* space for mac binary header */
uint32 resource_base = rfork_base+0x100;
uint32 rend, rtypesstart, mend, namestart;
int i,j;
fseek(res,0,SEEK_END);
rend = ftell(res);
if ( format<ff_ttfdfont ) {
/* Duplicate resource header */
putlong(res,0x100); /* start of resource data */
putlong(res,rend-rfork_base); /* start of resource map */
putlong(res,rend-rfork_base-0x100); /* length of resource data */
putlong(res,0); /* don't know the length of the map section yet */
} else {
for ( i=0; i<16; ++i ) /* 16 bytes of zeroes */
putc(0,res);
}
putlong(res,0); /* Some mac specific thing I don't understand */
putshort(res,0); /* another */
putshort(res,0); /* another */
putshort(res,4+ftell(res)-rend); /* Offset to resource types */
putshort(res,0); /* Don't know where the names go yet */
rtypesstart = ftell(res);
for ( i=0; rtypes[i].tag!=0; ++i );
putshort(res,i-1); /* Count of different types */
for ( i=0; rtypes[i].tag!=0; ++i ) {
putlong(res,rtypes[i].tag); /* Resource type */
putshort(res,0); /* Number of resources of this type */
putshort(res,0); /* Offset to the resource list */
}
/* Now the resource lists... */
for ( i=0; rtypes[i].tag!=0; ++i ) {
rtypes[i].resloc = ftell(res);
for ( j=0; rtypes[i].res[j].pos!=0; ++j ) {
putshort(res,rtypes[i].res[j].id);
rtypes[i].res[j].nameptloc = ftell(res);
putshort(res,0xffff); /* assume no name at first */
putc(rtypes[i].res[j].flags,res); /* resource flags */
/* three byte resource offset */
putc( ((rtypes[i].res[j].pos-resource_base)>>16)&0xff, res );
putc( ((rtypes[i].res[j].pos-resource_base)>>8)&0xff, res );
putc( ((rtypes[i].res[j].pos-resource_base)&0xff), res );
putlong(res,0);
}
}
namestart = ftell(res);
/* Now the names, if any */
for ( i=0; rtypes[i].tag!=0; ++i ) {
for ( j=0; rtypes[i].res[j].pos!=0; ++j ) {
if ( rtypes[i].res[j].name!=NULL ) {
rtypes[i].res[j].nameloc = ftell(res);
putc(strlen(rtypes[i].res[j].name),res); /* Length */
fwrite(rtypes[i].res[j].name,1,strlen(rtypes[i].res[j].name),res);
}
}
}
mend = ftell(res);
/* Repeat the rtypes list now we know where they go */
fseek(res,rtypesstart+2,SEEK_SET); /* skip over the count */
for ( i=0; rtypes[i].tag!=0; ++i ) {
putlong(res,rtypes[i].tag); /* Resource type */
for ( j=0; rtypes[i].res[j].pos!=0; ++j );
putshort(res,j-1); /* Number of resources of this type */
putshort(res,rtypes[i].resloc-rtypesstart);
}
/* And go back and fixup any name pointers */
for ( i=0; rtypes[i].tag!=0; ++i ) {
for ( j=0; rtypes[i].res[j].pos!=0; ++j ) {
if ( rtypes[i].res[j].name!=NULL ) {
fseek(res,rtypes[i].res[j].nameptloc,SEEK_SET);
putshort(res,rtypes[i].res[j].nameloc-namestart);
}
}
}
fseek(res,rend,SEEK_SET);
/* Fixup duplicate header (and offset to the name list) */
if ( format<ff_ttfdfont ) {
putlong(res,0x100); /* start of resource data */
putlong(res,rend-rfork_base); /* start of resource map */
putlong(res,rend-rfork_base-0x100); /* length of resource data */
putlong(res,mend-rend); /* length of map section */
} else {
for ( i=0; i<16; ++i )
putc(0,res);
}
putlong(res,0); /* Some mac specific thing I don't understand */
putshort(res,0); /* another */
putshort(res,0); /* another */
putshort(res,4+ftell(res)-rend); /* Offset to resource types */
putshort(res,namestart-rend); /* name section */
fseek(res,rfork_base,SEEK_SET);
/* Fixup main resource header */
putlong(res,0x100); /* start of resource data */
putlong(res,rend-rfork_base); /* start of resource map */
putlong(res,rend-rfork_base-0x100); /* length of resource data */
putlong(res,mend-rend); /* length of map section */
}
long mactime(void) {
time_t now = GetTime();
/* convert from 1970 based time to 1904 based time */
now += (1970-1904)*365L*24*60*60+((1970-1904)>>2)*24*60*60;
/* Ignore any leap seconds -- Sorry Steve */
return( now );
}
static int DumpMacBinaryHeader(FILE *res,struct macbinaryheader *mb) {
#if !__Mac
uint8 header[128], *hpt; char buffer[256], *pt, *dpt;
uint32 len;
time_t now;
int crc;
if ( mb->macfilename==NULL ) {
char *pt = strrchr(mb->binfilename,'/');
if ( pt==NULL ) pt = mb->binfilename;
else ++pt;
strncpy(buffer,pt,sizeof(buffer)-1);
dpt = strrchr(buffer,'.');
if ( dpt==NULL ) {
buffer[0] = '_';
strcpy(buffer+1,pt);
} else
*dpt = '\0';
mb->macfilename = buffer;
buffer[63] = '\0';
}
memset(header,'\0',sizeof(header));
hpt = header;
*hpt++ = '\0'; /* version number */
/* Mac Filename */
pt = mb->macfilename;
*hpt++ = strlen( pt );
while ( *pt )
*hpt++ = *pt++;
while ( hpt<header+65 )
*hpt++ = '\0';
/* Mac File Type */
*hpt++ = mb->type>>24; *hpt++ = mb->type>>16; *hpt++ = mb->type>>8; *hpt++ = mb->type;
/* Mac Creator */
*hpt++ = mb->creator>>24; *hpt++ = mb->creator>>16; *hpt++ = mb->creator>>8; *hpt++ = mb->creator;
*hpt++ = '\0'; /* No finder flags set */
*hpt++ = '\0'; /* (byte 74) MBZ */
*hpt++ = '\0'; *hpt++ = '\0'; /* Vert Position in folder */
*hpt++ = '\0'; *hpt++ = '\0'; /* Hor Position in folder */
*hpt++ = '\0'; *hpt++ = '\0'; /* window or folder id??? */
*hpt++ = '\0'; /* protected bit ??? */
*hpt++ = '\0'; /* (byte 82) MBZ */
/* Data fork length */
*hpt++ = '\0'; *hpt++ = '\0'; *hpt++ = '\0'; *hpt++ = '\0';
/* Resource fork length */
fseek(res,0,SEEK_END);
len = ftell(res)-sizeof(header);
*hpt++ = len>>24; *hpt++ = len>>16; *hpt++ = len>>8; *hpt++ = len;
/* Pad resource fork to be a multiple of 128 bytes */
while ( (len&127)!=0 )
{ putc('\0',res); ++len; }
/* Creation time, (seconds from 1/1/1904) */
now = mactime();
*hpt++ = now>>24; *hpt++ = now>>16; *hpt++ = now>>8; *hpt++ = now;
/* Modification time, (seconds from 1/1/1904) */
*hpt++ = now>>24; *hpt++ = now>>16; *hpt++ = now>>8; *hpt++ = now;
*hpt++ = '\0'; *hpt++ = '\0'; /* Get Info comment length */
*hpt++ = 0; /* More finder flags */
/* MacBinary 3 */
memcpy(header+102,"mBIN",4);
header[106] = 0; /* Script. I assume 0 is latin */
header[107] = 0; /* extended finder flags */
/* End of MacBinary 3 */
header[122] = 130; /* MacBinary version 3, written in (129 is MB2) */
header[123] = 129; /* MacBinary Version 2, needed to read */
crc = binhex_crc(header,124);
header[124] = crc>>8;
header[125] = crc;
fseek(res,0,SEEK_SET);
fwrite(header,1,sizeof(header),res);
return( true );
#else
int ret;
FSRef ref, parentref;
#if __LP64__
FSIORefNum macfile;
#else
short macfile;
#endif
char *buf, *dirname, *pt, *fname;
HFSUniStr255 resforkname;
FSCatalogInfo info;
long len;
unichar_t *filename;
ByteCount whocares;
/* When on the mac let's just create a real resource fork. We do this by */
/* creating a mac file with a resource fork, opening that fork, and */
/* dumping all the data in the temporary file after the macbinary header */
/* The mac file routines are really lovely. I can't convert a pathspec to */
/* an FSRef unless the file exists. That is incredibly stupid and annoying of them */
/* But the directory should exist... */
fname = mb->macfilename?mb->macfilename:mb->binfilename;
dirname = copy(fname);
pt = strrchr(dirname,'/');
if ( pt!=NULL )
pt[1] = '\0';
else {
free(dirname);
dirname = copy(".");
}
ret=FSPathMakeRef( (uint8 *) dirname,&parentref,NULL);
free(dirname);
if ( ret!=noErr )
return( false );
memset(&info,0,sizeof(info));
((FInfo *) (info.finderInfo))->fdType = mb->type;
((FInfo *) (info.finderInfo))->fdCreator = mb->creator;
pt = strrchr(fname,'/');
filename = def2u_copy(pt==NULL?fname:pt+1);
{ UniChar *ucs2fn = malloc((u_strlen(filename)+1) * sizeof(UniChar));
int i;
for ( i=0; filename[i]!=0; ++i )
ucs2fn[i] = filename[i];
ucs2fn[i] = 0;
ret = FSCreateFileUnicode(&parentref,u_strlen(filename), ucs2fn,
kFSCatInfoFinderInfo, &info, &ref, NULL);
free(ucs2fn);
}
free(filename);
if ( ret==dupFNErr ) {
/* File already exists, create failed, didn't get an FSRef */
ret=FSPathMakeRef( (uint8 *) fname,&ref,NULL);
}
if ( ret!=noErr )
return( false );
FSGetResourceForkName(&resforkname);
FSCreateFork(&ref,resforkname.length,resforkname.unicode); /* I don't think this is needed, but it doesn't hurt... */
ret = FSOpenFork(&ref,resforkname.length,resforkname.unicode,fsWrPerm,&macfile);
if ( ret!=noErr )
return( false );
FSSetForkSize(macfile,fsFromStart,0);/* Truncate it just in case it existed... */
fseek(res,128,SEEK_SET); /* Everything after the mac binary header in */
/* the temp file is resource fork */
buf = malloc(8*1024);
while ( (len=fread(buf,1,8*1024,res))>0 )
FSWriteFork(macfile,fsAtMark,0,len,buf,&whocares);
FSCloseFork(macfile);
free(buf);
return( true );
#endif
}
static void WriteDummyMacHeaders(FILE *res) {
/* Leave space for the mac binary header (128bytes) and the mac resource */
/* file header (256 bytes) */
int i;
for ( i=0; i<128; ++i )
putc(0,res);
for ( i=0; i<256; ++i )
putc(0,res);
}
static void WriteDummyDFontHeaders(FILE *res) {
/* Leave space for the mac resource file header (256 bytes) */
/* dfonts have the format of a data fork resource file (which I've never */
/* seen documented, but appears to be just like a resource fork except */
/* the first 16 bytes are not duplicated at the map */
int i;
for ( i=0; i<256; ++i )
putc(0,res);
}
/* The mac has rules about what the filename should be for a postscript*/
/* font. If you deviate from those rules the font will not be found */
/* The font name must begin with a capital letter */
/* The filename is designed by modifying the font name */
/* After the initial capital there can be at most 4 lower case letters (or digits) */
/* in the filename, any additional lc letters (or digits) in the fontname are ignored */
/* Every subsequent capital will be followed by at most 2 lc letters */
/* special characters ("-$", etc.) are removed entirely */
/* So Times-Bold => TimesBol, HelveticaDemiBold => HelveDemBol */
/* MacBinary limits the name to 63 characters, I dunno what happens if */
/* we excede that */
static void MakeMacPSName(char buffer[63],SplineFont *sf) {
char *pt, *spt, *lcpt;
for ( pt = buffer, spt = sf->fontname; *spt && pt<buffer+63-1; ++spt ) {
if ( isupper(*spt) || spt==sf->fontname ) {
*pt++ = *spt;
lcpt = (spt==sf->fontname?spt+5:spt+3);
} else if ( (islower(*spt) || isdigit(*spt)) && spt<lcpt )
*pt++ = *spt;
}
*pt = '\0';
}
int WriteMacPSFont(char *filename,SplineFont *sf,enum fontformat format,
int flags,EncMap *map,int layer) {
FILE *res, *temppfb;
int ret = 1;
struct resourcetype resources[2];
struct macbinaryheader header;
int lcfn = false, lcfam = false;
char buffer[63];
#if __Mac
char *pt;
#endif
temppfb = tmpfile();
if ( temppfb==NULL )
return( 0 );
/* The mac has rules about what the filename should be for a postscript*/
/* font. If you deviate from those rules the font will not be found */
/* The font name must begin with a capital letter */
/* The filename is designed by modifying the font name */
/* After the initial capital there can be at most 4 lower case letters (or digits) */
/* in the filename, any additional lc letters (or digits) in the fontname are ignored */
/* Every subsequent capital will be followed by at most 2 lc letters */
/* special characters ("-$", etc.) are removed entirely */
/* So Times-Bold => TimesBol, HelveticaDemiBold => HelveDemBol */
/* MacBinary limits the name to 63 characters, I dunno what happens if */
/* we excede that */
if ( islower(*sf->fontname)) { *sf->fontname = toupper(*sf->fontname); lcfn = true; }
if ( islower(*sf->familyname)) { *sf->familyname = toupper(*sf->familyname); lcfam = true; }
MakeMacPSName(buffer,sf);
ret = _WritePSFont(temppfb,sf,ff_pfb,flags,map,NULL,layer);
if ( lcfn ) *sf->fontname = tolower(*sf->fontname);
if ( lcfam ) *sf->familyname = tolower(*sf->familyname);
if ( ret==0 || ferror(temppfb) ) {
fclose(temppfb);
return( 0 );
}
if ( __Mac && format==ff_pfbmacbin )
res = tmpfile();
else
res = fopen(filename,"wb+");
if ( res==NULL ) {
fclose(temppfb);
return( 0 );
}
WriteDummyMacHeaders(res);
memset(resources,'\0',sizeof(resources));
rewind(temppfb);
resources[0].tag = CHR('P','O','S','T');
resources[0].res = PSToResources(res,temppfb);
fclose(temppfb);
DumpResourceMap(res,resources,format);
free( resources[0].res );
#if __Mac
header.macfilename = malloc(strlen(filename)+strlen(buffer)+1);
strcpy(header.macfilename,filename);
pt = strrchr(header.macfilename,'/');
if ( pt==NULL ) pt=header.macfilename-1;
strcpy(pt+1,buffer);
#else
header.macfilename = buffer;
#endif
/* Adobe uses a creator of ASPF (Adobe Systems PostScript Font I assume) */
/* Fontographer uses ACp1 (Altsys Corp. PostScript type 1???) */
/* Both include an FREF, BNDL, ICON* and comment */
/* I shan't bother with that... It'll look ugly with no icon, but oh well */
header.type = CHR('L','W','F','N');
header.creator = CHR('G','W','p','1');
ret = DumpMacBinaryHeader(res,&header);
if ( ferror(res) ) ret = 0;
if ( fclose(res)==-1 ) ret = 0;
#if __Mac
free(header.macfilename);
#endif
return( ret );
}
int WriteMacTTFFont(char *filename,SplineFont *sf,enum fontformat format,
int32 *bsizes, enum bitmapformat bf,int flags,EncMap *map,int layer) {
FILE *res, *tempttf;
int ret = 1, r;
struct resourcetype resources[4];
struct resource rlist[3][2], *dummynfnts=NULL;
struct macbinaryheader header;
tempttf = tmpfile();
if ( tempttf==NULL )
return( 0 );
if ( _WriteTTFFont(tempttf,sf,format==ff_none?ff_none:
format==ff_ttfmacbin?ff_ttf:
format-1,bsizes,bf,flags,map,layer)==0 || ferror(tempttf) ) {
fclose(tempttf);
return( 0 );
}
if ( bf!=bf_ttf && bf!=bf_sfnt_dfont )
bsizes = NULL; /* as far as the FOND for the truetype is concerned anyway */
if ( (__Mac && format==ff_ttfmacbin) || strstr(filename,"://")!=NULL )
res = tmpfile();
else
res = fopen(filename,"wb+");
if ( res==NULL ) {
fclose(tempttf);
return( 0 );
}
if ( format!=ff_ttfmacbin )
WriteDummyDFontHeaders(res);
else
WriteDummyMacHeaders(res);
memset(rlist,'\0',sizeof(rlist));
memset(resources,'\0',sizeof(resources));
rewind(tempttf);
r = 0;
resources[r].tag = CHR('s','f','n','t');
resources[r++].res = rlist[0];
rlist[0][0].pos = TTFToResource(res,tempttf);
rlist[0][0].id = HashToId(sf->fontname,sf,map);
rlist[0][0].flags = 0x00; /* sfnts generally have resource flags 0x20 */
if ( bsizes!=NULL ) {
resources[r].tag = CHR('N','F','N','T');
resources[r++].res = dummynfnts = BuildDummyNFNTlist(res,sf,bsizes,rlist[0][0].id,map);
}
resources[r].tag = CHR('F','O','N','D');
resources[r].res = rlist[1];
rlist[1][0].pos = SFToFOND(res,sf,rlist[0][0].id,true,bsizes,map);
rlist[1][0].flags = 0x00; /* I've seen FONDs with resource flags 0, 0x20, 0x60 */
rlist[1][0].id = rlist[0][0].id;
rlist[1][0].name = sf->fondname ? sf->fondname : sf->familyname;
fclose(tempttf);
DumpResourceMap(res,resources,format);
free(dummynfnts);
ret = true;
if ( format==ff_ttfmacbin ) {
header.macfilename = NULL;
header.binfilename = filename;
/* Fontographer uses the old suitcase format for both bitmaps and ttf */
header.type = CHR('F','F','I','L');
header.creator = CHR('D','M','O','V');
ret = DumpMacBinaryHeader(res,&header);
}
if ( ferror(res) ) ret = false;
if ( ret && strstr(filename,"://")!=NULL )
ret = URLFromFile(filename,res);
if ( fclose(res)==-1 ) ret = 0;
return( ret );
}
int WriteMacBitmaps(char *filename,SplineFont *sf, int32 *sizes, int is_dfont,
EncMap *map) {
FILE *res;
int ret = 1;
struct resourcetype resources[3];
struct resource rlist[2][2];
struct macbinaryheader header;
char *binfilename, *pt, *dpt;
/* The filename we've been given is for the outline font, which might or */
/* might not be stuffed inside a bin file */
binfilename = malloc(strlen(filename)+strlen(".bmap.dfont")+1);
strcpy(binfilename,filename);
pt = strrchr(binfilename,'/');
if ( pt==NULL ) pt = binfilename; else ++pt;
dpt = strrchr(pt,'.');
if ( dpt==NULL )
dpt = pt+strlen(pt);
else if ( strmatch(dpt,".bin")==0 || strmatch(dpt,".dfont")==0 ) {
*dpt = '\0';
dpt = strrchr(pt,'.');
if ( dpt==NULL )
dpt = pt+strlen(pt);
}
strcpy(dpt,is_dfont?".bmap.dfont":__Mac?".bmap":".bmap.bin");
if ( __Mac && !is_dfont )
res = tmpfile();
else
res = fopen(binfilename,"wb+");
if ( res==NULL ) {
free(binfilename);
return( 0 );
}
if ( is_dfont )
WriteDummyDFontHeaders(res);
else
WriteDummyMacHeaders(res);
memset(rlist,'\0',sizeof(rlist));
memset(resources,'\0',sizeof(resources));
resources[0].tag = CHR('N','F','N','T');
resources[0].res = SFToNFNTs(res,sf,sizes,map);
resources[1].tag = CHR('F','O','N','D');
resources[1].res = rlist[1];
rlist[1][0].id = HashToId(sf->fontname,sf,map);
rlist[1][0].pos = SFToFOND(res,sf,rlist[1][0].id,false,sizes,map);
rlist[1][0].name = sf->fondname ? sf->fondname : sf->familyname;
DumpResourceMap(res,resources,is_dfont?ff_ttfdfont:ff_ttfmacbin);
ret = true;
if ( !is_dfont ) {
header.macfilename = NULL;
header.binfilename = binfilename;
/* Fontographer uses the old suitcase format for both bitmaps and ttf */
header.type = CHR('F','F','I','L');
header.creator = CHR('D','M','O','V');
ret = DumpMacBinaryHeader(res,&header);
}
if ( ferror(res)) ret = false;
if ( fclose(res)==-1 ) ret = 0;
free(resources[0].res);
free(binfilename);
return( ret );
}
/* We have to worry about these font formats:
ff_pfbmacbin, ff_ttfmacbin, ff_ttfdfont, ff_otfdfont, ff_otfciddfont, ff_none
bf_ttf, bf_sfnt_dfont, bf_nfntmacbin,
bf_nfntdfont I no long support this. OS/X doesn't support NFNTs so there's no point
*/
int WriteMacFamily(char *filename,struct sflist *sfs,enum fontformat format,
enum bitmapformat bf,int flags, int layer) {
FILE *res;
int ret = 1, r, i;
struct resourcetype resources[4];
struct resource *rlist;
struct macbinaryheader header;
struct sflist *sfi, *sfsub;
char buffer[80];
int freefilename = 0;
char *pt;
int id, fondcnt;
struct sflistlist *sfsl, *sfli;
if ( format==ff_pfbmacbin ) {
for ( sfi=sfs; sfi!=NULL; sfi = sfi->next ) {
char *tempname;
MakeMacPSName(buffer,sfi->sf);
#if !__Mac
strcat(buffer,".bin");
#endif
tempname = malloc(strlen(filename)+strlen(buffer)+1);
strcpy(tempname,filename);
pt = strrchr(tempname,'/');
if ( pt==NULL ) pt=tempname-1;
strcpy(pt+1,buffer);
if ( strcmp(tempname,filename)==0 ) {
char *tf = malloc(strlen(filename)+20);
strcpy(tf,filename);
filename = tf;
freefilename = true;
pt = strrchr(filename,'.');
if ( pt==NULL || pt<strrchr(filename,'/'))
pt = filename+strlen(filename)+1;
#if __Mac
strcpy(pt-1,".fam");
#else
strcpy(pt-1,".fam.bin");
#endif
}
if ( WriteMacPSFont(tempname,sfi->sf,format,flags,sfi->map,layer)==0 )
return( 0 );
free(tempname);
}
} else if ( format!=ff_none || bf==bf_sfnt_dfont ) {
for ( sfi=sfs; sfi!=NULL; sfi = sfi->next ) {
sfi->tempttf = tmpfile();
if ( sfi->tempttf==NULL ||
_WriteTTFFont(sfi->tempttf,sfi->sf,format==ff_none?ff_none:
format==ff_ttfmacbin?ff_ttf:
format-1,sfi->sizes,bf,flags,sfi->map,layer)==0 ||
ferror(sfi->tempttf) ) {
for ( sfsub=sfs; sfsub!=sfi; sfsub=sfsub->next )
fclose( sfsub->tempttf );
return( 0 );
}
rewind(sfi->tempttf);
}
}
if ( __Mac && (format==ff_ttfmacbin || format==ff_pfbmacbin ||
(format==ff_none && bf==bf_nfntmacbin)))
res = tmpfile();
else
res = fopen(filename,"wb+");
if ( res==NULL ) {
for ( sfsub=sfs; sfsub!=NULL; sfsub=sfsub->next )
fclose( sfsub->tempttf );
return( 0 );
}
if ( format==ff_ttfdfont || format==ff_otfdfont || format==ff_otfciddfont ||
bf==bf_sfnt_dfont /*|| (format==ff_none && bf==bf_nfntdfont)*/)
WriteDummyDFontHeaders(res);
else
WriteDummyMacHeaders(res);
memset(resources,'\0',sizeof(resources));
id = HashToId(sfs->sf->fontname,sfs->sf,sfs->map);
r = 0;
if ( format==ff_ttfmacbin || format==ff_ttfdfont || format==ff_otfdfont ||
format==ff_otfciddfont || (format==ff_none && bf==bf_sfnt_dfont )) {
resources[r].tag = CHR('s','f','n','t');
for ( sfi=sfs, i=0; sfi!=NULL; sfi=sfi->next, ++i );
resources[r].res = calloc(i+1,sizeof(struct resource));
for ( sfi=sfs, i=0; sfi!=NULL; sfi=sfi->next, ++i ) {
resources[r].res[i].pos = TTFToResource(res,sfi->tempttf);
resources[r].res[i].id = sfi->id = id+i;
resources[r].res[i].flags = 0x00; /* sfnts generally have resource flags 0x20 */
fclose(sfi->tempttf);
}
++r;
if ( bf==bf_ttf || bf==bf_sfnt_dfont ) {
resources[r].tag = CHR('N','F','N','T');
resources[r++].res = BuildDummyNFNTfamilyList(res,sfs,id);
}
}
if ( bf==bf_nfntmacbin /*|| bf==bf_nfntdfont */) {
resources[r].tag = CHR('N','F','N','T');
resources[r++].res = SFsToNFNTs(res,sfs,id);
}
sfsl = FondSplitter(sfs,&fondcnt);
rlist = calloc(fondcnt+1,sizeof(struct resource));
resources[r].tag = CHR('F','O','N','D');
resources[r++].res = rlist;
for ( i=0, sfli=sfsl; i<fondcnt && sfli!=NULL; ++i, sfli = sfli->next ) {
rlist[i].pos = SFsToFOND(res,sfli->sfs,id,format);
rlist[i].flags = 0x00; /* I've seen FONDs with resource flags 0, 0x20, 0x60 */
rlist[i].id = id+i;
rlist[i].name = sfli->fondname;
}
DumpResourceMap(res,resources,format!=ff_none?format:
bf==bf_nfntmacbin?ff_ttfmacbin:ff_ttfdfont);
SFListListFree(sfsl);
for ( i=0; i<r; ++i )
free(resources[i].res);
ret = true;
if ( format==ff_ttfmacbin || format==ff_pfbmacbin ||
(format==ff_none && bf==bf_nfntmacbin) ) {
header.macfilename = NULL;
header.binfilename = filename;
/* Fontographer uses the old suitcase format for both bitmaps and ttf */
header.type = CHR('F','F','I','L');
header.creator = CHR('D','M','O','V');
ret = DumpMacBinaryHeader(res,&header);
}
if ( ferror(res) ) ret = false;
if ( fclose(res)==-1 ) ret = 0;
if ( freefilename )
free(filename);
for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
free( sfi->ids );
free( sfi->bdfs );
}
return( ret );
}
void SfListFree(struct sflist *sfs) {
struct sflist *sfi;
while ( sfs!=NULL ) {
sfi = sfs->next;
free(sfs->sizes);
EncMapFree(sfs->map);
chunkfree(sfs,sizeof(struct sflist));
sfs = sfi;
}
}
/* ******************************** Reading ********************************* */
static SplineFont *SearchPostScriptResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
int flags) {
long here = ftell(f);
long *offsets, lenpos;
int rname = -1, tmp;
int ch1, ch2;
int len, type, i, j, rlen;
unsigned short id, *rsrcids;
/* I don't pretend to understand the rational behind the format of a */
/* postscript font. It appears to be split up into chunks where the */
/* maximum chunk size is 0x800, each section (ascii, binary, ascii, eof) */
/* has its own set of chunks (ie chunks don't cross sections) */
char *buffer=NULL;
int max = 0;
FILE *pfb;
FontDict *fd;
SplineFont *sf;
fseek(f,rlistpos,SEEK_SET);
rsrcids = calloc(subcnt,sizeof(short));
offsets = calloc(subcnt,sizeof(long));
for ( i=0; i<subcnt; ++i ) {
rsrcids[i] = getushort(f);
tmp = (short) getushort(f);
if ( rname==-1 ) rname = tmp;
/* flags = */ getc(f);
ch1 = getc(f); ch2 = getc(f);
offsets[i] = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
/* mbz = */ getlong(f);
}
pfb = tmpfile();
if ( pfb==NULL ) {
LogError( _("Can't open temporary file for postscript output\n") );
fseek(f,here,SEEK_SET );
free(offsets);
return(NULL);
}
putc(0x80,pfb);
putc(1,pfb);
lenpos = ftell(pfb);
putc(0,pfb);
putc(0,pfb);
putc(0,pfb);
putc(0,pfb);
len = 0; type = 1;
id = 501;
for ( i=0; i<subcnt; ++i ) {
for ( j=0; j<subcnt; ++j )
if ( rsrcids[j]==id )
break;
if ( j == subcnt ) {
LogError( _("Missing POST resource %u\n"), id );
break;
}
id = id + 1;
fseek(f,offsets[j],SEEK_SET);
rlen = getlong(f);
ch1 = getc(f); ch2 = getc(f);
rlen -= 2; /* those two bytes don't count as real data */
if ( ch1==type )
len += rlen;
else {
long hold = ftell(pfb);
fseek(pfb,lenpos,SEEK_SET);
putc(len>>24,pfb);
putc((len>>16)&0xff,pfb);
putc((len>>8)&0xff,pfb);
putc(len&0xff,pfb);
fseek(pfb,hold,SEEK_SET);
if ( ch1==5 ) /* end of font mark */
break;
putc(0x80,pfb);
putc(ch1,pfb);
lenpos = ftell(pfb);
putc(0,pfb);
putc(0,pfb);
putc(0,pfb);
putc(0,pfb);
type = ch1;
len = rlen;
}
if ( rlen>max ) {
free(buffer);
max = rlen;
if ( max<0x800 ) max = 0x800;
buffer=malloc(max);
if ( buffer==NULL ) {
LogError( _("Out of memory\n") );
exit( 1 );
}
}
fread(buffer,1,rlen,f);
fwrite(buffer,1,rlen,pfb);
}
free(buffer);
free(offsets);
free(rsrcids);
putc(0x80,pfb);
putc(3,pfb);
fseek(pfb,lenpos,SEEK_SET);
putc(len>>24,pfb);
putc((len>>16)&0xff,pfb);
putc((len>>8)&0xff,pfb);
putc(len&0xff,pfb);
fseek(f,here,SEEK_SET);
rewind(pfb);
if ( flags&ttf_onlynames )
return( (SplineFont *) _NamesReadPostScript(pfb) ); /* This closes the font for us */
fd = _ReadPSFont(pfb);
sf = NULL;
if ( fd!=NULL ) {
sf = SplineFontFromPSFont(fd);
PSFontFree(fd);
/* There is no FOND in a postscript file, so we can't read any kerning*/
fclose(pfb);
}
return( sf );
}
static SplineFont *SearchTtfResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
long name_list,char *filename,int flags,enum openflags openflags) {
long here, start = ftell(f);
long roff;
int ch1, ch2;
int len, i, rlen, ilen;
/* The sfnt resource is just a copy of the ttf file */
char *buffer=NULL;
int max = 0;
FILE *ttf;
SplineFont *sf;
int which = 0;
char **names;
char *pt,*lparen, *rparen;
char *chosenname=NULL;
fseek(f,rlistpos,SEEK_SET);
if ( subcnt>1 || (flags&ttf_onlynames) ) {
names = calloc(subcnt+1,sizeof(char *));
for ( i=0; i<subcnt; ++i ) {
/* resource id = */ getushort(f);
/* rname = (short) */ getushort(f);
/* flags = */ getc(f);
ch1 = getc(f); ch2 = getc(f);
roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
/* mbz = */ getlong(f);
here = ftell(f);
names[i] = TTFGetFontName(f,roff+4,roff+4);
if ( names[i]==NULL ) {
char buffer[32];
sprintf( buffer, "Nameless%d", i );
names[i] = copy(buffer);
}
fseek(f,here,SEEK_SET);
}
if ( flags&ttf_onlynames ) {
return( (SplineFont *) names );
}
if ((pt = strrchr(filename,'/'))==NULL ) pt = filename;
/* Someone gave me a font "Nafees Nastaleeq(Updated).ttf" and complained */
/* that ff wouldn't open it */
/* Now someone will complain about "Nafees(Updated).ttc(fo(ob)ar)" */
if ( (lparen = strrchr(pt,'('))!=NULL &&
(rparen = strrchr(lparen,')'))!=NULL &&
rparen[1]=='\0' ) {
char *find = copy(lparen+1);
pt = strchr(find,')');
if ( pt!=NULL ) *pt='\0';
for ( which=subcnt-1; which>=0; --which )
if ( strcmp(names[which],find)==0 )
break;
if ( which==-1 ) {
char *end;
which = strtol(find,&end,10);
if ( *end!='\0' )
which = -1;
}
if ( which==-1 ) {
char *fn = copy(filename);
fn[lparen-filename] = '\0';
ff_post_error(_("Not in Collection"),_("%s is not in %.100s"),find,fn);
free(fn);
}
free(find);
} else if ( no_windowing_ui )
which = 0;
else
which = ff_choose(_("Pick a font, any font..."),(const char **) names,subcnt,0,_("There are multiple fonts in this file, pick one"));
if ( lparen==NULL && which!=-1 )
chosenname = copy(names[which]);
for ( i=0; i<subcnt; ++i )
free(names[i]);
free(names);
fseek(f,rlistpos,SEEK_SET);
}
for ( i=0; i<subcnt; ++i ) {
/* resource id = */ getushort(f);
/* rname = */ (short) getushort(f);
/* flags = */ getc(f);
ch1 = getc(f); ch2 = getc(f);
roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
/* mbz = */ getlong(f);
if ( i!=which )
continue;
here = ftell(f);
ttf = tmpfile();
if ( ttf==NULL ) {
LogError( _("Can't open temporary file for truetype output.\n") );
continue;
}
fseek(f,roff,SEEK_SET);
ilen = rlen = getlong(f);
if ( rlen>16*1024 )
ilen = 16*1024;
if ( ilen>max ) {
free(buffer);
max = ilen;
if ( max<0x800 ) max = 0x800;
buffer=malloc(max);
}
for ( len=0; len<rlen; ) {
int temp = ilen;
if ( rlen-len<ilen ) temp = rlen-len;
temp = fread(buffer,1,temp,f);
if ( temp==EOF )
break;
fwrite(buffer,1,temp,ttf);
len += temp;
}
rewind(ttf);
sf = _SFReadTTF(ttf,flags,openflags,NULL,NULL);
fclose(ttf);
if ( sf!=NULL ) {
free(buffer);
fseek(f,start,SEEK_SET);
if ( sf->chosenname==NULL ) sf->chosenname = chosenname;
return( sf );
}
fseek(f,here,SEEK_SET);
}
free(chosenname);
free(buffer);
fseek(f,start,SEEK_SET);
return( NULL );
}
struct assoc {
short size, style, id;
/* size==0 => scalable */
/* style>>8 is the bit depth (0=>1, 1=>2, 2=>4, 3=>8) */
/* search order for ID is sfnt, NFNT, FONT */
};
struct stylewidths {
short style;
short *widthtab; /* 4.12 fixed number with the width specified as a fraction of an em */
};
struct kerns {
unsigned char ch1, ch2;
short offset; /* 4.12 */
};
struct stylekerns {
short style;
int kernpairs;
struct kerns *kerns;
};
typedef struct fond {
char *fondname;
int first, last;
int assoc_cnt;
struct assoc *assoc;
int stylewidthcnt;
struct stylewidths *stylewidths;
int stylekerncnt;
struct stylekerns *stylekerns;
char *psnames[48];
struct fond *next;
} FOND;
struct MacFontRec {
short fontType;
short firstChar;
short lastChar;
short widthMax;
short kernMax; /* bb learing */
short Descent; /* maximum negative distance below baseline*/
short fRectWidth; /* bounding box width */
short fRectHeight; /* bounding box height */
unsigned short *offsetWidths;/* offset to start of offset/width table */
/* 0xffff => undefined, else high byte is offset in locTable, */
/* low byte is width */
short ascent;
short descent;
short leading;
short rowWords; /* shorts per row */
unsigned short *fontImage; /* rowWords*fRectHeight */
/* Images for all characters plus one extra for undefined */
unsigned short *locs; /* lastchar-firstchar+3 words */
/* Horizontal offset to start of n'th character. Note: applies */
/* to each row. Missing characters have same loc as following */
};
static void FondListFree(FOND *list) {
FOND *next;
int i;
while ( list!=NULL ) {
next = list->next;
free(list->assoc);
for ( i=0; i<list->stylewidthcnt; ++i )
free(list->stylewidths[i].widthtab);
free(list->stylewidths);
for ( i=0; i<list->stylekerncnt; ++i )
free(list->stylekerns[i].kerns);
free(list->stylekerns);
for ( i=0; i<48; ++i )
free(list->psnames[i]);
free(list);
list = next;
}
}
/* There's probably only one fond in the file, but there could be more so be */
/* prepared... */
/* I want the fond: */
/* to get the fractional widths for the SWIDTH entry on bdf */
/* to get the font name */
/* to get the font association tables */
/* to get the style flags */
/* http://developer.apple.com/techpubs/mac/Text/Text-269.html */
static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos,
long name_list,int flags) {
long here, start = ftell(f);
long offset;
int rname = -1;
char name[300];
int ch1, ch2;
int i, j, k, cnt;
FOND *head=NULL, *cur;
long widoff, kernoff, styleoff;
fseek(f,rlistpos,SEEK_SET);
for ( i=0; i<subcnt; ++i ) {
/* resource id = */ getushort(f);
rname = (short) getushort(f);
/* flags = */ getc(f);
ch1 = getc(f); ch2 = getc(f);
offset = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
/* mbz = */ getlong(f);
here = ftell(f);
cur = calloc(1,sizeof(FOND));
cur->next = head;
head = cur;
if ( rname!=-1 ) {
fseek(f,name_list+rname,SEEK_SET);
ch1 = getc(f);
fread(name,1,ch1,f);
name[ch1] = '\0';
cur->fondname = copy(name);
}
offset += 4;
fseek(f,offset,SEEK_SET);
/* isfixed = */ getushort(f) /* &0x8000?1:0 */;
/* family id = */ getushort(f);
cur->first = getushort(f);
cur->last = getushort(f);
/* on a 1 point font... */
/* ascent = */ getushort(f);
/* descent = (short) */ getushort(f);
/* leading = */ getushort(f);
/* widmax = */ getushort(f);
if ( (widoff = getlong(f))!=0 ) widoff += offset;
if ( (kernoff = getlong(f))!=0 ) kernoff += offset;
if ( (styleoff = getlong(f))!=0 ) styleoff += offset;
for ( j=0; j<9; ++j )
getushort(f);
/* internal & undefined, for international scripts = */ getlong(f);
/* version = */ getushort(f);
cur->assoc_cnt = getushort(f)+1;
cur->assoc = calloc(cur->assoc_cnt,sizeof(struct assoc));
for ( j=0; j<cur->assoc_cnt; ++j ) {
cur->assoc[j].size = getushort(f);
cur->assoc[j].style = getushort(f);
cur->assoc[j].id = getushort(f);
}
if ( widoff!=0 ) {
fseek(f,widoff,SEEK_SET);
cnt = getushort(f)+1;
cur->stylewidthcnt = cnt;
cur->stylewidths = calloc(cnt,sizeof(struct stylewidths));
for ( j=0; j<cnt; ++j ) {
cur->stylewidths[j].style = getushort(f);
cur->stylewidths[j].widthtab = malloc((cur->last-cur->first+3)*sizeof(short));
for ( k=cur->first; k<=cur->last+2; ++k )
cur->stylewidths[j].widthtab[k] = getushort(f);
}
}
if ( kernoff!=0 && (flags&ttf_onlykerns) ) {
fseek(f,kernoff,SEEK_SET);
cnt = getushort(f)+1;
cur->stylekerncnt = cnt;
cur->stylekerns = calloc(cnt,sizeof(struct stylekerns));
for ( j=0; j<cnt; ++j ) {
cur->stylekerns[j].style = getushort(f);
cur->stylekerns[j].kernpairs = getushort(f);
cur->stylekerns[j].kerns = malloc(cur->stylekerns[j].kernpairs*sizeof(struct kerns));
for ( k=0; k<cur->stylekerns[j].kernpairs; ++k ) {
cur->stylekerns[j].kerns[k].ch1 = getc(f);
cur->stylekerns[j].kerns[k].ch2 = getc(f);
cur->stylekerns[j].kerns[k].offset = getushort(f);
}
}
}
if ( styleoff!=0 ) {
uint8 stringoffsets[48];
int strcnt, stringlen, format;
char **strings, *pt;
fseek(f,styleoff,SEEK_SET);
/* class = */ getushort(f);
/* glyph encoding offset = */ getlong(f);
/* reserved = */ getlong(f);
for ( j=0; j<48; ++j )
stringoffsets[j] = getc(f);
strcnt = getushort(f);
strings = malloc(strcnt*sizeof(char *));
for ( j=0; j<strcnt; ++j ) {
stringlen = getc(f);
strings[j] = malloc(stringlen+2);
strings[j][0] = stringlen;
strings[j][stringlen+1] = '\0';
for ( k=0; k<stringlen; ++k )
strings[j][k+1] = getc(f);
}
for ( j=0; j<48; ++j ) {
for ( k=j-1; k>=0; --k )
if ( stringoffsets[j]==stringoffsets[k] )
break;
if ( k!=-1 )
continue; /* this style doesn't exist */
format = stringoffsets[j]-1;
stringlen = strings[0][0];
if ( format!=0 )
for ( k=0; k<strings[format][0]; ++k )
stringlen += strings[ strings[format][k+1]-1 ][0];
pt = cur->psnames[j] = malloc(stringlen+1);
strcpy(pt,strings[ 0 ]+1);
pt += strings[ 0 ][0];
if ( format!=0 )
for ( k=0; k<strings[format][0]; ++k ) {
strcpy(pt,strings[ strings[format][k+1]-1 ]+1);
pt += strings[ strings[format][k+1]-1 ][0];
}
*pt = '\0';
}
for ( j=0; j<strcnt; ++j )
free(strings[j]);
free(strings);
}
fseek(f,here,SEEK_SET);
}
fseek(f,start,SEEK_SET);
return( head );
}
static BDFChar *NFNTCvtBitmap(struct MacFontRec *font,int index,SplineFont *sf,int gid) {
BDFChar *bdfc;
int i,j, bits, bite, bit;
bdfc = chunkalloc(sizeof(BDFChar));
memset( bdfc,'\0',sizeof( BDFChar ));
bdfc->xmin = (font->offsetWidths[index]>>8)+font->kernMax;
bdfc->xmax = bdfc->xmin + font->locs[index+1]-font->locs[index]-1;
if ( bdfc->xmax<bdfc->xmin )
bdfc->xmax = bdfc->xmin; /* Empty glyph mark */
bdfc->ymin = -font->descent;
bdfc->ymax = font->ascent-1;
bdfc->width = font->offsetWidths[index]&0xff;
bdfc->vwidth = font->ascent + font->descent;
bdfc->bytes_per_line = ((bdfc->xmax-bdfc->xmin)>>3) + 1;
bdfc->bitmap = calloc(bdfc->bytes_per_line*font->fRectHeight,sizeof(uint8));
bdfc->orig_pos = gid;
bdfc->sc = sf->glyphs[gid];
bits = font->locs[index]; bite = font->locs[index+1];
for ( i=0; i<font->fRectHeight; ++i ) {
uint16 *test = font->fontImage + i*font->rowWords;
uint8 *bpt = bdfc->bitmap + i*bdfc->bytes_per_line;
for ( bit=bits, j=0; bit<bite; ++bit, ++j ) {
if ( test[bit>>4]&(0x8000>>(bit&0xf)) )
bpt[j>>3] |= (0x80>>(j&7));
}
}
BCCompressBitmap(bdfc);
return( bdfc );
}
static void LoadNFNT(FILE *f,long offset, SplineFont *sf) {
long here = ftell(f);
long baseow;
long ow;
int i,gid;
struct MacFontRec font;
BDFFont *bdf;
SplineChar *sc;
offset += 4; /* skip over the length */
fseek(f,offset,SEEK_SET);
memset(&font,'\0',sizeof(struct MacFontRec));
font.fontType = getushort(f);
font.firstChar = getushort(f);
font.lastChar = getushort(f);
font.widthMax = getushort(f);
font.kernMax = (short) getushort(f);
font.Descent = (short) getushort(f);
font.fRectWidth = getushort(f);
font.fRectHeight = getushort(f);
baseow = ftell(f);
ow = getushort(f);
font.ascent = getushort(f);
font.descent = getushort(f);
if ( font.Descent>=0 ) {
ow |= (font.Descent<<16);
font.Descent = -font.descent; /* Possibly overkill, but should be safe */
}
font.leading = getushort(f);
font.rowWords = getushort(f);
if ( font.rowWords!=0 ) {
font.fontImage = calloc(font.rowWords*font.fRectHeight,sizeof(short));
font.locs = calloc(font.lastChar-font.firstChar+3,sizeof(short));
font.offsetWidths = calloc(font.lastChar-font.firstChar+3,sizeof(short));
for ( i=0; i<font.rowWords*font.fRectHeight; ++i )
font.fontImage[i] = getushort(f);
for ( i=0; i<font.lastChar-font.firstChar+3; ++i )
font.locs[i] = getushort(f);
fseek(f,baseow+2*ow,SEEK_SET);
for ( i=0; i<font.lastChar-font.firstChar+3; ++i )
font.offsetWidths[i] = getushort(f);
}
fseek(f,here,SEEK_SET);
if ( font.rowWords==0 )
return;
/* Now convert the FONT record to one of my BDF structs */
bdf = calloc(1,sizeof(BDFFont));
bdf->sf = sf;
bdf->next = sf->bitmaps;
sf->bitmaps = bdf;
bdf->glyphcnt = bdf->glyphmax = sf->glyphcnt;
bdf->pixelsize = font.ascent+font.descent;
bdf->glyphs = calloc(sf->glyphcnt,sizeof(BDFChar *));
bdf->ascent = font.ascent;
bdf->descent = font.descent;
bdf->res = 72;
for ( i=font.firstChar; i<=font.lastChar+1; ++i ) {
if ( i!=font.lastChar+1 )
sc = SFMakeChar(sf,sf->map,i);
else {
sc = SFGetChar(sf,-1,".notdef");
if ( sc==NULL )
break;
}
gid = sc->orig_pos;
bdf->glyphs[gid] = NFNTCvtBitmap(&font,i-font.firstChar,sf,gid);
if ( !sf->glyphs[gid]->widthset ) {
sf->glyphs[gid]->width = bdf->glyphs[gid]->width*(sf->ascent+sf->descent)/bdf->pixelsize;
sf->glyphs[gid]->widthset = true;
}
}
free(font.fontImage);
free(font.locs);
free(font.offsetWidths);
}
static char *BuildName(char *family,int style) {
char buffer[350];
strncpy(buffer,family,200);
if ( style!=0 )
strcat(buffer,"-");
if ( style&sf_bold )
strcat(buffer,"Bold");
if ( style&sf_italic )
strcat(buffer,"Italic");
if ( style&sf_underline )
strcat(buffer,"Underline");
if ( style&sf_outline )
strcat(buffer,"Outline");
if ( style&sf_shadow )
strcat(buffer,"Shadow");
if ( style&sf_condense )
strcat(buffer,"Condensed");
if ( style&sf_extend )
strcat(buffer,"Extended");
return( copy(buffer));
}
static int GuessStyle(char *fontname,int *styles,int style_cnt) {
int which, style;
const char *stylenames = _GetModifiers(fontname,NULL,NULL);
style = _MacStyleCode(stylenames,NULL,NULL);
for ( which = style_cnt; which>=0; --which )
if ( styles[which] == style )
return( which );
return( -1 );
}
static FOND *PickFOND(FOND *fondlist,char *filename,char **name, int *style) {
int i,j;
FOND *test;
uint8 stylesused[96];
char **names;
FOND **fonds, *fond;
int *styles;
int cnt, which;
char *pt, *lparen;
char *find = NULL;
if ((pt = strrchr(filename,'/'))!=NULL ) pt = filename;
if ( (lparen = strchr(filename,'('))!=NULL && strchr(lparen,')')!=NULL ) {
find = copy(lparen+1);
pt = strchr(find,')');
if ( pt!=NULL ) *pt='\0';
for ( test=fondlist; test!=NULL; test=test->next ) {
for ( i=0; i<48; ++i )
if ( test->psnames[i]!=NULL && strcmp(find,test->psnames[i])==0 ) {
*style = (i&3) | ((i&~3)<<1); /* PS styles skip underline bit */
*name = copy(test->psnames[i]);
return( test );
}
}
}
/* The file may contain multiple families, and each family may contain */
/* multiple styles (and each style may contain multiple sizes, but that's */
/* not an issue for us here) */
names = NULL;
for ( i=0; i<2; ++i ) {
cnt = 0;
for ( test=fondlist; test!=NULL; test=test->next ) if ( test->fondname!=NULL ) {
memset(stylesused,0,sizeof(stylesused));
for ( j=0; j<test->assoc_cnt; ++j ) {
if ( test->assoc[j].size!=0 && !stylesused[test->assoc[j].style]) {
stylesused[test->assoc[j].style]=true;
if ( names!=NULL ) {
names[cnt] = BuildName(test->fondname,test->assoc[j].style);
styles[cnt] = test->assoc[j].style;
fonds[cnt] = test;
}
++cnt;
}
}
}
if ( names==NULL ) {
names = calloc(cnt+1,sizeof(char *));
fonds = malloc(cnt*sizeof(FOND *));
styles = malloc(cnt*sizeof(int));
}
}
if ( find!=NULL ) {
for ( which=cnt-1; which>=0; --which )
if ( strcmp(names[which],find)==0 )
break;
if ( which==-1 && test!=NULL && strstrmatch(find,test->fondname)!=NULL )
which = GuessStyle(find,styles,cnt);
if ( which==-1 ) {
char *fn = copy(filename);
fn[lparen-filename] = '\0';
ff_post_error(_("Not in Collection"),_("%s is not in %.100s"),find,fn);
free(fn);
}
free(find);
} else if ( cnt==1 )
which = 0;
else if ( no_windowing_ui )
which = 0;
else
which = ff_choose(_("Pick a font, any font..."),(const char **) names,cnt,0,
_("There are multiple fonts in this file, pick one"));
if ( which!=-1 ) {
fond = fonds[which];
*name = copy(names[which]);
*style = styles[which];
}
for ( i=0; i<cnt; ++i )
free(names[i]);
free(names); free(fonds); free(styles);
if ( which==-1 )
return( NULL );
return( fond );
}
static SplineFont *SearchBitmapResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
long name_list,char *filename,FOND *fondlist,int flags) {
long start = ftell(f);
long roff;
int ch1, ch2;
int i,j;
int res_id;
char *name;
FOND *fond;
int style;
SplineFont *sf;
int find_id;
SplineChar *sc;
fond = PickFOND(fondlist,filename,&name,&style);
if ( fond==NULL )
return( NULL );
find_id=-1;
if ( flags&ttf_onlyonestrike ) {
int biggest = 0;
for ( i=0; i<fond->assoc_cnt; ++i ) {
if ( fond->assoc[i].style==style && fond->assoc[i].size>biggest ) {
biggest = fond->assoc[i].size;
find_id = fond->assoc[i].id;
}
}
}
sf = SplineFontBlank(257);
free(sf->fontname); sf->fontname = name;
free(sf->familyname); sf->familyname = copy(fond->fondname);
sf->fondname = copy(fond->fondname);
free(sf->fullname); sf->fullname = copy(name);
free(sf->origname); sf->origname = NULL;
if ( style & sf_bold ) {
free(sf->weight); sf->weight = copy("Bold");
}
free(sf->copyright); sf->copyright = NULL;
free(sf->comments); sf->comments = NULL;
sf->map = EncMapNew(257,257,FindOrMakeEncoding("mac"));
for ( i=0; i<fond->stylewidthcnt; ++i ) {
if ( fond->stylewidths[i].style == style ) {
short *widths = fond->stylewidths[i].widthtab;
for ( j=fond->first; j<=fond->last; ++j ) {
sc = SFMakeChar(sf,sf->map,j);
sc->width = ((widths[j-fond->first]*1000L+(1<<11))>>12);
sc->widthset = true;
}
sc = SFSplineCharCreate(sf);
sc->orig_pos = sf->glyphcnt;
sf->glyphs[sf->glyphcnt++] = sc;
sc->name = copy(".notdef");
sc->width = (widths[fond->last+1-fond->first]*1000L+(1<<11))>>12;
sc->widthset = true;
}
}
fseek(f,rlistpos,SEEK_SET);
for ( i=0; i<subcnt; ++i ) {
res_id = getushort(f);
/* rname = */ getushort(f);
/* flags = */ getc(f);
ch1 = getc(f); ch2 = getc(f);
roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
/* mbz = */ getlong(f);
for ( j=fond->assoc_cnt-1; j>=0; --j )
if ( (find_id!=-1 && res_id==find_id) ||
( fond->assoc[j].style==style && fond->assoc[j].id==res_id &&
fond->assoc[j].size!=0 ) )
LoadNFNT(f,roff,sf);
}
fseek(f,start,SEEK_SET);
sf->onlybitmaps = true;
SFOrderBitmapList(sf);
return( sf );
}
/* Look for kerning info and merge it into the currently existing font "into" */
static SplineFont *FindFamilyStyleKerns(SplineFont *into,EncMap *map,FOND *fondlist,char *filename) {
char *name;
int style;
FOND *fond;
int i,j;
int ch1, ch2, offset;
KernPair *kp;
SplineChar *sc1, *sc2;
fond = PickFOND(fondlist,filename,&name,&style);
if ( fond==NULL || into==NULL )
return( NULL );
for ( i=0; i<fond->stylekerncnt; ++i )
if ( fond->stylekerns[i].style==style )
break;
if ( i==fond->stylekerncnt ) {
LogError(_("No kerning table for %s\n"), name );
free(name);
return( NULL );
}
for ( j=0; j<fond->stylekerns[i].kernpairs; ++j ) {
ch1 = fond->stylekerns[i].kerns[j].ch1;
ch2 = fond->stylekerns[i].kerns[j].ch2;
offset = (fond->stylekerns[i].kerns[j].offset*(into->ascent+into->descent)+(1<<11))>>12;
sc1 = SFMakeChar(into,map,ch1);
sc2 = SFMakeChar(into,map,ch2);
for ( kp=sc1->kerns; kp!=NULL; kp=kp->next )
if ( kp->sc==sc2 )
break;
if ( kp==NULL ) {
uint32 script;
kp = chunkalloc(sizeof(KernPair));
kp->sc = sc2;
kp->next = sc1->kerns;
sc1->kerns = kp;
script = SCScriptFromUnicode(sc1);
if ( script==DEFAULT_SCRIPT )
script = SCScriptFromUnicode(sc2);
kp->subtable = SFSubTableFindOrMake(sc1->parent,CHR('k','e','r','n'),
script, gpos_pair);
}
kp->off = offset;
}
return( into );
}
/* Look for a bare truetype font in a binhex/macbinary wrapper */
static SplineFont *MightBeTrueType(FILE *binary,int32 pos,int32 dlen,int flags,
enum openflags openflags) {
FILE *temp = tmpfile();
char *buffer = malloc(8192);
int len;
SplineFont *sf;
if ( flags&ttf_onlynames ) {
char **ret;
char *temp = TTFGetFontName(binary,pos,pos);
if ( temp==NULL )
return( NULL );
ret = malloc(2*sizeof(char *));
ret[0] = temp;
ret[1] = NULL;
return( (SplineFont *) ret );
}
fseek(binary,pos,SEEK_SET);
while ( dlen>0 ) {
len = dlen > 8192 ? 8192 : dlen;
len = fread(buffer,1,dlen > 8192 ? 8192 : dlen,binary);
if ( len==0 )
break;
fwrite(buffer,1,len,temp);
dlen -= len;
}
rewind(temp);
sf = _SFReadTTF(temp,flags,openflags,NULL,NULL);
fclose(temp);
free(buffer);
return( sf );
}
static SplineFont *IsResourceFork(FILE *f, long offset,char *filename,int flags,
enum openflags openflags, SplineFont *into,EncMap *map) {
/* If it is a good resource fork then the first 16 bytes are repeated */
/* at the location specified in bytes 4-7 */
/* We include an offset because if we are looking at a mac binary file */
/* the resource fork will actually start somewhere in the middle of the */
/* file, not at the beginning */
unsigned char buffer[16], buffer2[16];
long rdata_pos, map_pos, type_list, name_list, rpos;
int32 rdata_len;
uint32 nfnt_pos, font_pos, fond_pos;
unsigned long tag;
int i, cnt, subcnt, nfnt_subcnt=0, font_subcnt=0, fond_subcnt=0;
SplineFont *sf;
FOND *fondlist=NULL;
fseek(f,offset,SEEK_SET);
if ( fread(buffer,1,16,f)!=16 )
return( NULL );
rdata_pos = offset + ((buffer[0]<<24)|(buffer[1]<<16)|(buffer[2]<<8)|buffer[3]);
map_pos = offset + ((buffer[4]<<24)|(buffer[5]<<16)|(buffer[6]<<8)|buffer[7]);
rdata_len = ((buffer[8]<<24)|(buffer[9]<<16)|(buffer[10]<<8)|buffer[11]);
/* map_len = ((buffer[12]<<24)|(buffer[13]<<16)|(buffer[14]<<8)|buffer[15]); */
if ( rdata_pos+rdata_len!=map_pos || rdata_len==0 )
return( NULL );
fseek(f,map_pos,SEEK_SET);
buffer2[15] = buffer[15]+1; /* make it be different */
if ( fread(buffer2,1,16,f)!=16 )
return( NULL );
/* Apple's data fork resources appear to have a bunch of zeroes here instead */
/* of a copy of the first 16 bytes */
for ( i=0; i<16; ++i )
if ( buffer2[i]!=0 )
break;
if ( i!=16 ) {
for ( i=0; i<16; ++i )
if ( buffer[i]!=buffer2[i] )
return( NULL );
}
getlong(f); /* skip the handle to the next resource map */
getushort(f); /* skip the file resource number */
getushort(f); /* skip the attributes */
type_list = map_pos + getushort(f);
name_list = map_pos + getushort(f);
fseek(f,type_list,SEEK_SET);
cnt = getushort(f)+1;
for ( i=0; i<cnt; ++i ) {
tag = getlong(f);
/* printf( "%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff );*/
subcnt = getushort(f)+1;
rpos = type_list+getushort(f);
sf = NULL;
if ( tag==CHR('P','O','S','T') && !(flags&(ttf_onlystrikes|ttf_onlykerns))) /* No FOND */
sf = SearchPostScriptResources(f,rpos,subcnt,rdata_pos,flags);
else if ( tag==CHR('s','f','n','t') && !(flags&ttf_onlykerns))
sf = SearchTtfResources(f,rpos,subcnt,rdata_pos,name_list,filename,flags,openflags);
else if ( tag==CHR('N','F','N','T') ) {
nfnt_pos = rpos;
nfnt_subcnt = subcnt;
} else if ( tag==CHR('F','O','N','T') ) {
font_pos = rpos;
font_subcnt = subcnt;
} else if ( tag==CHR('F','O','N','D') ) {
fond_pos = rpos;
fond_subcnt = subcnt;
}
if ( sf!=NULL )
return( sf );
}
if ( flags&ttf_onlynames ) /* Not interested in bitmap resources here */
return( NULL );
if ( flags&ttf_onlykerns ) { /* For kerns */
if ( fond_subcnt!=0 )
fondlist = BuildFondList(f,fond_pos,fond_subcnt,rdata_pos,name_list,flags);
into = FindFamilyStyleKerns(into,map,fondlist,filename);
FondListFree(fondlist);
return( into );
}
/* Ok. If no outline font, try for a bitmap */
if ( nfnt_subcnt==0 ) {
nfnt_pos = font_pos;
nfnt_subcnt = font_subcnt;
}
if ( nfnt_subcnt!=0 ) {
if ( fond_subcnt!=0 )
fondlist = BuildFondList(f,fond_pos,fond_subcnt,rdata_pos,name_list,flags);
sf = SearchBitmapResources(f,nfnt_pos,nfnt_subcnt,rdata_pos,name_list,
filename,fondlist,flags);
FondListFree(fondlist);
if ( sf!=NULL )
return( sf );
}
return( (SplineFont *) -1 ); /* It's a valid resource file, but just has no fonts */
}
#if __Mac
static SplineFont *HasResourceFork(char *filename,int flags,enum openflags openflags,
SplineFont *into,EncMap *map) {
/* If we're on a mac, we can try to see if we've got a real resource fork */
/* (if we do, copy it into a temporary data file and then manipulate that)*/
SplineFont *ret;
FILE *resfork;
char *tempfn=filename, *pt, *lparen, *respath;
if (( pt=strrchr(filename,'/'))==NULL ) pt = filename;
if ( (lparen = strchr(pt,'('))!=NULL && strchr(lparen,')')!=NULL ) {
tempfn = copy(filename);
tempfn[lparen-filename] = '\0';
}
respath = malloc(strlen(tempfn)+strlen("/..namedfork/rsrc")+1);
strcpy(respath,tempfn);
strcat(respath,"/..namedfork/rsrc");
resfork = fopen(respath,"r");
if ( resfork==NULL ) {
strcpy(respath,tempfn);
strcat(respath,"/rsrc");
resfork = fopen(respath,"r");
}
free(respath);
if ( tempfn!=filename )
free(tempfn);
if ( resfork==NULL )
return( NULL );
ret = IsResourceFork(resfork,0,filename,flags,openflags,into,map);
fclose(resfork);
return( ret );
}
#endif
static SplineFont *IsResourceInBinary(FILE *f,char *filename,int flags,
enum openflags openflags, SplineFont *into,EncMap *map) {
unsigned char header[128];
unsigned long offset, dlen, rlen;
if ( fread(header,1,128,f)!=128 )
return( NULL );
if ( header[0]!=0 || header[74]!=0 || header[82]!=0 || header[1]<=0 ||
header[1]>33 || header[63]!=0 || header[2+header[1]]!=0 )
return( NULL );
dlen = ((header[0x53]<<24)|(header[0x54]<<16)|(header[0x55]<<8)|header[0x56]);
rlen = ((header[0x57]<<24)|(header[0x58]<<16)|(header[0x59]<<8)|header[0x5a]);
/* 128 bytes for header, then the dlen is padded to a 128 byte boundary */
offset = 128 + ((dlen+127)&~127);
/* Look for a bare truetype font in a binhex/macbinary wrapper */
if ( dlen!=0 && rlen<=dlen) {
int pos = ftell(f);
fread(header,1,4,f);
header[5] = '\0';
if ( strcmp((char *) header,"OTTO")==0 || strcmp((char *) header,"true")==0 ||
strcmp((char *) header,"ttcf")==0 ||
(header[0]==0 && header[1]==1 && header[2]==0 && header[3]==0))
return( MightBeTrueType(f,pos,dlen,flags,openflags));
}
return( IsResourceFork(f,offset,filename,flags,openflags,into,map));
}
static int lastch=0, repeat = 0;
static void outchr(FILE *binary, int ch) {
int i;
if ( repeat ) {
if ( ch==0 ) {
/* no repeat, output a literal 0x90 (the repeat flag) */
lastch=0x90;
putc(lastch,binary);
} else {
for ( i=1; i<ch; ++i )
putc(lastch,binary);
}
repeat = 0;
} else if ( ch==0x90 ) {
repeat = 1;
} else {
putc(ch,binary);
lastch = ch;
}
}
static SplineFont *IsResourceInHex(FILE *f,char *filename,int flags,enum openflags openflags,
SplineFont *into,EncMap *map) {
/* convert file from 6bit to 8bit */
/* interesting data is enclosed between two colons */
FILE *binary = tmpfile();
char *sixbit = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
int ch, val, cnt, i, dlen, rlen;
unsigned char header[20]; char *pt;
SplineFont *ret;
if ( binary==NULL ) {
LogError( _("can't create temporary file\n") );
return( NULL );
}
lastch = repeat = 0;
while ( (ch=getc(f))!=':' ); /* There may be comments before file start */
cnt = val = 0;
while ( (ch=getc(f))!=':' ) {
if ( isspace(ch))
continue;
for ( pt=sixbit; *pt!=ch && *pt!='\0'; ++pt );
if ( *pt=='\0' ) {
fclose(binary);
return( NULL );
}
val = (val<<6) | (pt-sixbit);
if ( ++cnt==4 ) {
outchr(binary,(val>>16)&0xff);
outchr(binary,(val>>8)&0xff);
outchr(binary,val&0xff);
val = cnt = 0;
}
}
if ( cnt!=0 ) {
if ( cnt==1 )
outchr(binary,val<<2);
else if ( cnt==2 ) {
val<<=4;
outchr(binary,(val>>8)&0xff);
outchr(binary,val&0xff);
} else if ( cnt==3 ) {
val<<=6;
outchr(binary,(val>>16)&0xff);
outchr(binary,(val>>8)&0xff);
outchr(binary,val&0xff);
}
}
rewind(binary);
ch = getc(binary); /* Name length */
/* skip name */
for ( i=0; i<ch; ++i )
getc(binary);
if ( getc(binary)!='\0' ) {
fclose(binary);
return( NULL );
}
fread(header,1,20,binary);
dlen = (header[10]<<24)|(header[11]<<16)|(header[12]<<8)|header[13];
rlen = (header[14]<<24)|(header[15]<<16)|(header[16]<<8)|header[17];
/* Look for a bare truetype font in a binhex/macbinary wrapper */
if ( dlen!=0 && rlen<dlen ) {
int pos = ftell(binary);
fread(header,1,4,binary);
header[5] = '\0';
if ( strcmp((char *) header,"OTTO")==0 || strcmp((char *) header,"true")==0 ||
strcmp((char *) header,"ttcf")==0 ||
(header[0]==0 && header[1]==1 && header[2]==0 && header[3]==0)) {
ret = MightBeTrueType(binary,pos,dlen,flags,openflags);
fclose(binary);
return( ret );
}
}
if ( rlen==0 ) {
fclose(binary);
return( NULL );
}
ret = IsResourceFork(binary,ftell(binary)+dlen+2,filename,flags,openflags,into,map);
fclose(binary);
return( ret );
}
static SplineFont *IsResourceInFile(char *filename,int flags,enum openflags openflags,
SplineFont *into, EncMap *map) {
FILE *f;
char *spt, *pt;
SplineFont *sf;
char *temp=filename, *lparen;
if (( pt=strrchr(filename,'/'))==NULL ) pt = filename;
if ( (lparen = strchr(pt,'('))!=NULL && strchr(lparen,')')!=NULL ) {
temp = copy(filename);
temp[lparen-filename] = '\0';
}
f = fopen(temp,"rb");
if ( temp!=filename ) free(temp);
if ( f==NULL )
return( NULL );
spt = strrchr(filename,'/');
if ( spt==NULL ) spt = filename;
pt = strrchr(spt,'.');
if ( pt!=NULL && (pt[1]=='b' || pt[1]=='B') && (pt[2]=='i' || pt[2]=='I') &&
(pt[3]=='n' || pt[3]=='N') && (pt[4]=='\0' || pt[4]=='(') ) {
if ( (sf = IsResourceInBinary(f,filename,flags,openflags,into,map))) {
fclose(f);
return( sf );
}
} else if ( pt!=NULL && (pt[1]=='h' || pt[1]=='H') && (pt[2]=='q' || pt[2]=='Q') &&
(pt[3]=='x' || pt[3]=='X') && (pt[4]=='\0' || pt[4]=='(')) {
if ( (sf = IsResourceInHex(f,filename,flags,openflags,into,map))) {
fclose(f);
return( sf );
}
}
sf = IsResourceFork(f,0,filename,flags,openflags,into,map);
fclose(f);
#if __Mac
if ( sf==NULL )
sf = HasResourceFork(filename,flags,openflags,into,map);
#endif
return( sf );
}
static SplineFont *FindResourceFile(char *filename,int flags,enum openflags openflags,
SplineFont *into,EncMap *map) {
char *spt, *pt, *dpt;
char buffer[1400];
SplineFont *sf;
if ( (sf = IsResourceInFile(filename,flags,openflags,into,map)))
return( sf );
/* Well, look in the resource fork directory (if it exists), the resource */
/* fork is placed there in a separate file on (some) non-Mac disks */
strcpy(buffer,filename);
spt = strrchr(buffer,'/');
if ( spt==NULL ) { spt = buffer; pt = filename; }
else { ++spt; pt = filename + (spt-buffer); }
strcpy(spt,"resource.frk/");
strcat(spt,pt);
if ( (sf=IsResourceInFile(buffer,flags,openflags,into,map)))
return( sf );
/* however the resource fork does not appear to do long names properly */
/* names are always lower case 8.3, do some simple things to check */
spt = strrchr(buffer,'/')+1;
for ( pt=spt; *pt; ++pt )
if ( isupper( *pt ))
*pt = tolower( *pt );
dpt = strchr(spt,'.');
if ( dpt==NULL ) dpt = spt+strlen(spt);
if ( dpt-spt>8 || strlen(dpt)>4 ) {
char exten[8];
strncpy(exten,dpt,7);
exten[4] = '\0'; /* it includes the dot */
if ( dpt-spt>6 )
dpt = spt+6;
*dpt++ = '~';
*dpt++ = '1';
strcpy(dpt,exten);
}
return( IsResourceInFile(buffer,flags,openflags,into,map));
}
SplineFont *SFReadMacBinary(char *filename,int flags,enum openflags openflags) {
SplineFont *sf = FindResourceFile(filename,flags,openflags,NULL,NULL);
if ( sf==NULL )
LogError( _("Couldn't find a font file named %s\n"), filename );
else if ( sf==(SplineFont *) (-1) ) {
LogError( _("%s is a mac resource file but contains no postscript or truetype fonts\n"), filename );
sf = NULL;
}
return( sf );
}
int LoadKerningDataFromMacFOND(SplineFont *sf, char *filename,EncMap *map) {
if ( FindResourceFile(filename,ttf_onlykerns,0,sf,map)==NULL )
return ( false );
return( true );
}
char **NamesReadMacBinary(char *filename) {
return( (char **) FindResourceFile(filename,ttf_onlynames,0,NULL,NULL));
}