#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ttf2tfm.h"
#include "newobj.h"
#include "tfmaux.h"
#include "errormsg.h"
#undef PI
#define PI 3.14159265358979323846264338327
struct sf
{
long sf_code;
int position;
};
static long nextd;
static int lf, lh, nw, nh, nd, ni, nl, nk, ne, np;
static int bc, ec;
static long *header, *charinfo,
*width, *height, *depth,
*ligkern, *kerns, *tparam,
*italic;
static int source[257];
static int unsort[257];
static int
compare_sf(const void *a, const void *b)
{
return (int)(((struct sf *)b)->sf_code - ((struct sf *)a)->sf_code);
}
static long
scale(long what)
{
return ((what / 1000) * FIXFACTOR) +
(((what % 1000) * FIXFACTOR) + 500) / 1000;
}
static int
mincover(long *what,
register long d)
{
register int m;
register long l;
register long *p;
nextd = 0x7FFFFFFFL;
p = what+1;
m = 1;
while (*p < 0x7FFFFFFFL)
{
m++;
l = *p;
while (*++p <= l + d)
;
if (*p - l < nextd)
nextd = *p - l;
}
return m;
}
static void
remap(long *what,
int oldn,
int newn,
int *source,
int *unsort)
{
register int i, j;
register long d, l;
what[oldn] = 0x7FFFFFFFL;
for (i = oldn-1; i > 0; i--)
{
d = what[i];
for (j = i; what[j+1] < d; j++)
{
what[j] = what[j+1];
source[j] = source[j+1];
}
what[j] = d;
source[j] = i;
}
i = mincover(what, 0L);
d = nextd;
while (mincover(what, d + d) > newn)
d += d;
while (mincover(what, d) > newn)
d = nextd;
i = 1;
j = 0;
while (i < oldn)
{
j++;
l = what[i];
unsort[source[i]] = j;
while (what[++i] <= l + d)
{
unsort[source[i]] = j;
if (i - j == oldn - newn)
d = 0;
}
what[j] = (l + what[i-1])/2;
}
}
void
write16(register short what,
register FILE *out)
{
(void)fputc(what >> 8, out);
(void)fputc(what & 0xFF, out);
}
void
writearr(register long *p,
register int n,
register FILE *out)
{
while (n)
{
write16((short)(*p >> 16), out);
write16((short)(*p & 65535), out);
p++;
n--;
}
}
void
writesarr(long *what,
int len,
FILE *out)
{
register long *p;
int i;
p = what;
i = len;
while (i)
{
*p = scale(*p);
(void)scale(*p);
p++;
i--;
}
writearr(what, len, out);
}
static long *
makebcpl(register long *p,
register char *s,
register int n)
{
register long t;
register long sc;
if (strlen(s) < n)
n = strlen(s);
t = ((long)n) << 24;
sc = 16;
while (n > 0)
{
t |= ((long)(*(unsigned char *)s++)) << sc;
sc -= 8;
if (sc < 0)
{
*p++ = t;
t = 0;
sc = 24;
}
n--;
}
if (t)
*p++ = t;
return p;
}
static long
checksum(ttfinfo **array)
{
int i;
unsigned long s1 = 0, s2 = 0;
char *p;
ttfinfo *ti;
for (i = 0; i < 256; i++)
if (NULL != (ti = array[i]))
{
s1 = ((s1 << 1) ^ (s1 >> 31)) ^ ti->width;
s1 &= 0xFFFFFFFF;
for (p = ti->adobename; *p; p++)
s2 = (s2 * 3) + *p;
}
s1 = (s1 << 1) ^ s2;
return s1;
}
int
transform(register int x, register int y,
float ef, float sl)
{
register double acc;
acc = ef * x + sl * y;
return (int)(acc >= 0 ? floor(acc + 0.5) : ceil(acc - 0.5));
}
int
buildtfm(Font *fnt)
{
register int i, j;
register ttfinfo *ti;
int byte1, old_byte1, byte2;
long cksum;
double Slant;
char buffer[256];
struct sf sf_array[256];
if (fnt->subfont_ligs)
{
for (i = 0; i < 256; i++)
{
ti = fnt->inencptrs[i];
if (ti)
{
sf_array[i].sf_code = ti->charcode;
sf_array[i].position = i;
}
else
{
sf_array[i].sf_code = -1;
sf_array[i].position = -1;
}
}
qsort(sf_array, 256, sizeof (struct sf), compare_sf);
i = 0;
while (i < 256 && sf_array[i].sf_code > -1)
{
byte1 = sf_array[i].sf_code >> 8;
byte2 = sf_array[i].sf_code & 0xFF;
if (!fnt->inencptrs[byte1])
{
ti = newchar(fnt);
ti->llx = ti->lly = 0;
ti->urx = ti->ury = 0;
ti->width = 0;
fnt->inencptrs[byte1] = ti;
ti->incode = byte1;
ti->adobename = ".dummy";
}
if (!fnt->inencptrs[byte2])
{
ti = newchar(fnt);
ti->llx = ti->lly = 0;
ti->urx = ti->ury = 0;
ti->width = 0;
fnt->inencptrs[byte2] = ti;
ti->incode = byte2;
ti->adobename = ".dummy";
}
i++;
}
}
for (i = 0; i <= 0xFF && fnt->inencptrs[i] == NULL; i++)
;
bc = i;
for (i = 0xFF; i >= 0 && fnt->inencptrs[i] == NULL; i--)
;
ec = i;
if (ec < bc)
{
if (fnt->sfdname)
return 0;
else
oops("No TTF characters.");
}
header = (long *)mymalloc(40000L);
cksum = checksum(fnt->inencptrs);
header[0] = cksum;
header[1] = 0xA00000;
(void)makebcpl(header + 2, fnt->codingscheme, 39);
(void)makebcpl(header + 12, fnt->fullname, 19);
buffer[0] = '\0';
strncat(buffer, "Created by `", 12);
strncat(buffer, fnt->titlebuf, 255 - 12 - 1);
strncat(buffer, "'", 1);
charinfo = makebcpl(header + 18, buffer, 255);
lh = charinfo - header;
width = charinfo + (ec - bc + 1);
width[0] = 0;
nw = 1;
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
{
width[nw] = ti->width;
for (j = 1; width[j] != ti->width; j++)
;
ti->wptr = j;
if (j == nw)
nw++;
}
if (nw > 256)
oops("256 chars with different widths.");
depth = width + nw;
depth[0] = 0;
nd = 1;
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
{
depth[nd] = -ti->lly;
for (j = 0; depth[j] != -ti->lly; j++)
;
ti->dptr = j;
if (j == nd)
nd++;
}
if (nd > 16)
{
remap(depth, nd, 16, source, unsort);
nd = 16;
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
ti->dptr = unsort[ti->dptr];
}
height = depth + nd;
height[0] = 0;
nh = 1;
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
{
height[nh] = ti->ury;
for (j = 0; height[j] != ti->ury; j++)
;
ti->hptr = j;
if (j == nh)
nh++;
}
if (nh > 16)
{
remap(height, nh, 16, source, unsort);
nh = 16;
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
ti->hptr = unsort[ti->hptr];
}
italic = height + nh;
italic[0] = 0;
ni = 1;
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
{
italic[ni] = ti->urx - ti->width;
if (italic[ni] < 0)
italic[ni] = 0;
for (j = 0; italic[j] != italic[ni]; j++)
;
ti->iptr = j;
if (j == ni)
ni++;
}
if (ni > 64)
{
remap(italic, ni, 64, source, unsort);
ni = 64;
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
ti->iptr = unsort[ti->iptr];
}
for (i = bc; i <= ec; i++)
if (NULL != (ti = fnt->inencptrs[i]))
charinfo[i - bc] = ((long)(ti->wptr) << 24) +
((long)(ti->hptr) << 20) +
((long)(ti->dptr) << 16) +
((long)(ti->iptr) << 10);
else
charinfo[i - bc] = 0;
ligkern = italic + ni;
nl = 0;
if (fnt->subfont_ligs)
{
old_byte1 = -1;
while (nl < 256 && sf_array[nl].sf_code > -1)
{
byte1 = sf_array[nl].sf_code >> 8;
byte2 = sf_array[nl].sf_code & 0xFF;
if (byte1 != old_byte1)
{
charinfo[byte1 - bc] += 0x100L +
nl;
if (old_byte1 > -1)
ligkern[nl - 1] |= 0x80000000L;
}
ligkern[nl] = ((long)byte2 << 16) +
(long)sf_array[nl].position;
old_byte1 = byte1;
nl++;
}
ligkern[nl - 1] |= 0x80000000L;
}
kerns = ligkern + nl;
nk = 0;
Slant = fnt->slant - fnt->efactor * tan(fnt->italicangle * (PI / 180.0));
tparam = kerns + nk;
tparam[0] = (long)(FIXFACTOR * Slant + 0.5);
tparam[1] = scale((long)fnt->fontspace);
tparam[2] = (fnt->fixedpitch ? 0 : scale((long)(300 * fnt->efactor + 0.5)));
tparam[3] = (fnt->fixedpitch ? 0 : scale((long)(100 * fnt->efactor + 0.5)));
tparam[4] = scale((long)fnt->xheight);
tparam[5] = scale((long)(1000 * fnt->efactor + 0.5));
np = 6;
return 1;
}
void
writetfm(Font *fnt)
{
FILE *out;
char *tfm_name;
int len = 0;
if (fnt->tfm_path)
len += strlen(fnt->tfm_path);
len += strlen(fnt->fullname);
len += strlen(fnt->tfm_ext);
len++;
tfm_name = (char *)mymalloc(len);
tfm_name[0] = '\0';
if (fnt->tfm_path)
strcat(tfm_name, fnt->tfm_path);
strcat(tfm_name, fnt->fullname);
strcat(tfm_name, fnt->tfm_ext);
if ((out = fopen(tfm_name, "wb")) == NULL)
oops("Cannot open tfm file `%s'.", tfm_name);
free(tfm_name);
lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np;
write16(lf, out);
write16(lh, out);
write16(bc, out);
write16(ec, out);
write16(nw, out);
write16(nh, out);
write16(nd, out);
write16(ni, out);
write16(nl, out);
write16(nk, out);
write16(ne, out);
write16(np, out);
writearr(header, lh, out);
writearr(charinfo, ec - bc + 1, out);
writesarr(width, nw, out);
writesarr(height, nh, out);
writesarr(depth, nd, out);
writesarr(italic, ni, out);
writearr(ligkern, nl, out);
writesarr(kerns, nk, out);
writearr(tparam, np, out);
free(header);
fclose(out);
}