|
|
/***
** ** Module: Trans ** ** Description: ** This is a module of the T1 to TT font converter. The module ** contains functions that will convert T1 specific data into ** corresponding TT data, such as hints and font metrics. ** ** Author: Michael Jansson ** ** Created: 5/28/93 ** ***/
/**** INCLUDES */ /* General types and definitions. */ #include <string.h>
/* Special types and definitions. */ #include "titott.h"
#include "types.h"
#include "safemem.h"
#include "trig.h"
#include "metrics.h"
#include "encoding.h"
#include "builder.h"
#include "t1msg.h"
/* Module dependent types and prototypes. */ #include "trans.h"
#include "hints.h"
/***** CONSTANTS */
/* PitchAndFamily pitch values (low 4 bits) */ #define DEFAULT_PITCH 0x00
#define FIXED_PITCH 0x01
#define VARIABLE_PITCH 0x02
/* PitchAndFamily family values (high 4 bits) */ #define FF_DONTCARE 0x00
#define FF_ROMAN 0x10
#define FF_SWISS 0x20
#define FF_MODERN 0x30
#define FF_SCRIPT 0x40
#define FF_DECORATIVE 0x50
#define SWISS_LEADING 0x21
#define ROMAN_LEADING 0x11
#define NOCARE_PANOSE 0
#define NO_PANOSE 1
#define COVE_PANOSE 2
#define TEXT_PANOSE 2
#define DECORATIVE_PANOSE 4
#define SCRIPT_PANOSE 3
#define SANS_PANOSE 11
#define FIXED_PANOSE 9
#define BUFMARG 64
#define CLIMIT 8
#define CLIMIT2 4
#define SUBDIVIDE 0
#define CONVERT 1
#define FW_THIN 100
#define FW_EXTRALIGHT 200
#define FW_LIGHT 300
#define FW_NORMAL 400
#define FW_MEDIUM 500
#define FW_SEMIBOLD 600
#define FW_BOLD 700
#define FW_BLACK 900
#define FWIDTH_ULTRA_CONDENSED 1
#define FWIDTH_EXTRA_CONDENSED 2
#define FWIDTH_CONDENSED 3
#define FWIDTH_SEMI_CONDENSED 4
#define FWIDTH_NORMAL 5
#define FWIDTH_SEMI_EXPANDED 6
#define FWIDTH_EXPANDED 7
#define FWIDTH_EXTRA_EXPANDED 8
#define FWIDTH_ULTRA_EXPANDED 9
#define MAC_ITALIC 0x01
#define MAC_BOLD 0x02
#define FS_ITALIC 0x01
#define FS_BOLD 0x20
#define FS_NORMAL 0x40
#define CVTSIZE 5
/***** LOCAL TYPES */ /* None */
/***** MACROS */ #define ATMSCALE(v) (((v)*31)/32)
#define IP(v,x1,x2,x1p,x2p) /*lint -e776 */(short)((long)(v-x1)*(long)(x2p-x1p)/(long)(x2-x1)+(long)x1p)/*lint +e776*/
#define ADDCVT(val) ttm->cvt[ttm->cvt_cnt++] = (short)(val)
#define SGN(v) ((v)>0 ? 1 : -1)
#define DIR(v,w) (char)((ABS((v)-(w))<16) ? 0 : SGN((w) - (v)))
/***** PROTOTYPES */ static USHORT SplitSpline(Point *pts, ULONG *onoff, int i, USHORT length, const funit x0, const funit y0, const funit x1, const funit y1, const funit x2, const funit y2, const funit x3, const funit y3, const int delta);
/***** STATIC FUNCTIONS */
/***
** Function: LookupComposite ** ** Description: ** ***/ static struct encoding *LookupComposite(struct Composite *comp, char *name) { while (comp) { if (comp->oenc && !strcmp(LookupCharName(comp->oenc), name)) return comp->oenc; comp=comp->next; }
return NULL; }
/***
** Function: norm ** ** Description: ** Normalize an angle so that it falls within the ** range ~[-pi, pi] ***/ static int norm(int a) { if (a>PI) a -= 2*PI; if (a<-PI) a += 2*PI;
return ABS(a)/16; }
/***
** Function: CompareCurves ** ** Description: ** Make a estimate of the error between a cubic ** and a quadric curve, given four control points, ** and suggest an action (sub-division or convertion). ***/ static boolean FASTCALL CompareCurves(const funit x0, const funit y0, const funit x1, const funit y1, const funit x2, const funit y2, const funit x3, const funit y3, const funit nx, const funit ny, const int delta) { int a, b;
if ((ABS(ny-y0)>CLIMIT || ABS(nx-x0)>CLIMIT) && (ABS(ny-y3)>CLIMIT || ABS(nx-x3)>CLIMIT)) {
if (y0!=y1 || x0!=x1) a = norm(Atan2(ny-y0, nx-x0) - Atan2(y1-y0, x1-x0)) * (ABS(ny-y0) + ABS(nx-x0)); else if (y0!=y2 || x2!=x0) a = norm(Atan2(ny-y0, nx-x0) - Atan2(y2-y0, x2-x0)) * (ABS(ny-y0) + ABS(nx-x0)); else a = 0;
if (a>=delta) return SUBDIVIDE;
if (y2!=y3 || x2!=x3) b = norm(Atan2(y3-ny, x3-nx) - Atan2(y3-y2, x3-x2)) * (ABS(ny-y0) + ABS(nx-x0)); else if (y1!=y3 || x1!=x3) b = norm(Atan2(y3-ny, x3-nx) - Atan2(y3-y1, x3-x1)) * (ABS(ny-y0) + ABS(nx-x0)); else b = 0;
if (b>=delta) /* angle too big. */ return SUBDIVIDE; }
return CONVERT; }
/***
** Function: ConvertSpline ** ** Description: ** This function adds a spline to the current contour, by first ** converting it from a cubic to a quadric spline. ***/ static USHORT ConvertSpline(Point *pts, ULONG *onoff, USHORT length, int i, const funit x0, const funit y0, const funit x1, const funit y1, const funit x2, const funit y2, const funit x3, const funit y3, const int delta) { funit nx, ny; int oi = i; USHORT n = 0;
ny = (funit)(((-y0+y1+y2+((y1+y2)<<1)-y3 + 4002)/4) - (short)1000); nx = (funit)(((-x0+x1+x2+((x1+x2)<<1)-x3 + 4002)/4) - (short)1000); if (CompareCurves(x0, y0, x1, y1, x2, y2, x3, y3, nx, ny, delta)==SUBDIVIDE) { n = SplitSpline(pts, onoff, i, length, x0, y0, x1, y1, x2, y2, x3, y3, delta); } else /* CONVERT */ { if (i>1 && !OnCurve(onoff, i-2) && (short)(pts[i-1].x >= pts[i-2].x) != (short)(pts[i-1].x >= nx) && (short)(pts[i-1].y >= pts[i-2].y) != (short)(pts[i-1].y >= ny) && (short)(pts[i-1].x > pts[i-2].x) != (short)(pts[i-1].x > nx) && (short)(pts[i-1].y > pts[i-2].y) != (short)(pts[i-1].y > ny) && ABS(pts[i-1].x - (nx+pts[i-2].x)/2)<CLIMIT2 && ABS(pts[i-1].y - (ny+pts[i-2].y)/2)<CLIMIT2) { } SetOffPoint(onoff, i); pts[i].y = ny; pts[i].x = nx; i++; SetOnPoint(onoff, i); pts[i].y = y3; pts[i].x = x3; i++;
n = (USHORT)(i-oi); }
return n; }
/***
** Function: SplitSpline ** ** Description: ** This function converts a cubic spline by first ** creating two new cubic splines, using de Casteljau's ** algorithm, and then adding the two new splines to the ** current path. ***/ static USHORT SplitSpline(Point *pts, ULONG *onoff, int i, USHORT length, const funit x0, const funit y0, const funit x1, const funit y1, const funit x2, const funit y2, const funit x3, const funit y3, const int delta) { funit xt, yt; funit nx1, ny1; funit nx2, ny2; funit nx3, ny3; funit nx4, ny4; funit nx5, ny5; USHORT cnt;
xt = (funit)(((x1+x2+8001)/2)-4000); yt = (funit)(((y1+y2+8001)/2)-4000); nx1 = (funit)(((x0+x1+8001)/2)-4000); ny1 = (funit)(((y0+y1+8001)/2)-4000); nx2 = (funit)(((nx1+xt+8001)/2)-4000); ny2 = (funit)(((ny1+yt+8001)/2)-4000); nx5 = (funit)(((x2+x3+8001)/2)-4000); ny5 = (funit)(((y2+y3+8001)/2)-4000); nx4 = (funit)(((nx5+xt+8001)/2)-4000); ny4 = (funit)(((ny5+yt+8001)/2)-4000); nx3 = (funit)(((nx2+nx4+8001)/2)-4000); ny3 = (funit)(((ny2+ny4+8001)/2)-4000);
cnt = ConvertSpline(pts, onoff, length, i, x0, y0, (funit)nx1, (funit)ny1, (funit)nx2, (funit)ny2, (funit)nx3, (funit)ny3, delta); cnt = (USHORT)(cnt + ConvertSpline(pts, onoff, length, i+cnt, (funit)nx3, (funit)ny3, (funit)nx4, (funit)ny4, (funit)nx5, (funit)ny5, x3, y3, delta));
return cnt; }
/***
** Function: FreeOutline ** ** Description: ** This function frees the memory allocated for one ** contour. ** ***/ static void FreeOutline(Outline *path) { Outline *tmp;
while (path) { tmp = path; path=path->next; Free(tmp->pts); Free(tmp->onoff); Free(tmp); } }
/***
** Function: ConvertOutline ** ** Description: ** This function converts an outline by replacing the ** cubic splines with quadric splines, and by scaling the ** coordinates to the desired em-height. ** ***/ static errcode ConvertOutline(const struct T1Metrics *t1m, Outline *src, Outline **dst, const int delta, short *sideboard) { errcode status = SUCCESS; f16d16 *fmatrix; Outline *path; ULONG *onoff = NULL; Point *pts = NULL; USHORT count; USHORT i,j,n; USHORT tot = 0; USHORT t1tot = 0;
/* Get the T1 font transformation matrix. */ fmatrix = GetFontMatrix(t1m);
while (src) {
/* Skip paths with less than three points. */ if (src->count<3) { t1tot = (USHORT)(t1tot + src->count); src = src->next; continue; }
/* Allocate the needed resources */ count = (USHORT)((src->count+BUFMARG)&~0x0f); path = Malloc(sizeof(Outline)); pts = Malloc(count*sizeof(Point)); onoff = Malloc(ONOFFSIZE(count)); if (path==NULL || pts==NULL || onoff==NULL) { if (path) Free(path); if (pts) Free(pts); if (onoff) Free(onoff); FreeOutline((*dst)); (*dst) = NULL; SetError(status = NOMEM); break; } memset(onoff, '\0', ONOFFSIZE(count));
/* Convert the splines. */ /*lint -e771 */ i=0; j=0; while (i<src->count) { char prev = DIR(src->pts[(i-2+src->count)%src->count].y, src->pts[(i-1+src->count)%src->count].y); char this = DIR(src->pts[(i-1+src->count)%src->count].y, src->pts[i].y);
/* Double the local extremas so that diag-cntrl will work. */ if (prev && this && prev!=this) pts[j++] = src->pts[(i-1+src->count)%src->count];
if (OnCurve(src->onoff, i)) { pts[j++] = src->pts[i++]; } else { /* pts[j] = pts[j-1]; j++; */ n = ConvertSpline(pts, onoff, count, (int)j, src->pts[i-1].x, src->pts[i-1].y, src->pts[i-0].x, src->pts[i-0].y, src->pts[i+1].x, src->pts[i+1].y, src->pts[i+2].x, src->pts[i+2].y, delta);
/* Enforce horizontal and vertical tangents. */ if (OnCurve(onoff, j-1)) { if (src->pts[i-1].x==src->pts[i-0].x) pts[j].x = (funit)((pts[j].x + pts[j-1].x)/2); if (src->pts[i-1].y==src->pts[i-0].y) pts[j].y = (funit)((pts[j].y + pts[j-1].y)/2); } if (src->pts[i+1].x==src->pts[i+2].x) pts[j+n-2].x = (funit)((pts[j+n-1].x + pts[j+n-2].x)/2); if (src->pts[i+1].y==src->pts[i+2].y) pts[j+n-2].y = (funit)((pts[j+n-2].y + pts[j+n-1].y)/2);
j = (USHORT)(j + n); i += 3; }
/* Both a line and a curve end with an on-curve point. */ sideboard[t1tot+i-1] = (short)(j-1+tot);
/* Extend the pts/onoff arrays. */ if (j+BUFMARG/2>=count) { Point *newpts = NULL; ULONG *newonoff = NULL;
count += BUFMARG; newpts = Realloc(pts, count*sizeof(Point)); newonoff = Realloc(onoff, ONOFFSIZE(count)); if (newpts==NULL || newonoff==NULL) { if (newonoff) Free(newonoff); if (newpts) Free(newpts); /*lint -e644 */ if (onoff) Free(onoff); if (pts) Free(pts); /*lint +e644 */ FreeOutline((*dst)); (*dst) = NULL; SetError(status=NOMEM); break; } pts = newpts; onoff = newonoff; } }
if (status!=SUCCESS) break;
/* Scale the points. */ TransAllPoints(t1m, pts, j, fmatrix);
t1tot = (USHORT)(t1tot + src->count); src = src->next;
(*dst) = path; path->next = NULL; path->pts = pts; path->onoff = onoff; path->count = (USHORT)j; /*lint +e771 */ dst = &(path->next);
tot = (USHORT)(tot + j); }
return status; }
#ifdef MSDOS
#pragma auto_inline(off)
#endif
static long Mul2(long a, long b, long c, long d) { return a*b+c*d; } #ifdef MSDOS
#pragma auto_inline(on)
#endif
/***** FUNCTIONS */
/***
** Function: TransAllPoints ** ** Description: ** Translate a coordinate according to a transformation matrix. ***/ void FASTCALL TransAllPoints(const struct T1Metrics *t1m, Point *pts, const USHORT cnt, const f16d16 *fmatrix) { if (fmatrix==NULL) { register Point *p; register int i;
i = cnt; p = pts; while (i--) { p->x = (funit)((p->x<<1)+(((p->x<<1)+ p->x+(p->x/16)+ 8224)/64) - 128); p++; } i = cnt; p = pts; while (i--) { p->y = (funit)((p->y<<1)+(((p->y<<1)+ p->y+ (p->y/16)+ 8224)/64) - 128); p++; }
} else { Point *p; int i; long u,v;
i = cnt; p = pts; while (i--) { v = (GetUPEM(t1m) * (Mul2(fmatrix[0], (long)p->x, fmatrix[2], (long)p->y) + fmatrix[4]) + F16D16HALF) / 524288L; u = (GetUPEM(t1m) * (Mul2(fmatrix[1], (long)p->x, fmatrix[3], (long)p->y) + fmatrix[5]) + F16D16HALF) / 524288L; p->x = (funit)v; p->y = (funit)u; p++; } } }
/***
** Function: TransX ** ** Description: ** Translate a horizontal coordinate according to a transformation matrix. ***/ funit FASTCALL TransX(const struct T1Metrics *t1m, const funit x) { f16d16 *fmatrix = GetFontMatrix(t1m); funit pos;
if (fmatrix) { pos = (funit)((GetUPEM(t1m)* ATMSCALE(fmatrix[0] * x) + F16D16HALF) / F16D16BASE); } else { pos = (funit)(((int)x<<1)-((((int)x+((int)x/64)+8224)/64) - 128)); }
return pos; }
/***
** Function: TransY ** ** Description: ** Translate a vertical coordinate according to a transformation matrix. ***/ funit FASTCALL TransY(const struct T1Metrics *t1m, const funit y) { f16d16 *fmatrix = GetFontMatrix(t1m); funit pos;
if (fmatrix) { pos = (funit)((GetUPEM(t1m)*fmatrix[3] * y + F16D16HALF) / F16D16BASE); } else { pos = (funit)(((int)y<<1)+((((int)y<<1)+ (int)y+ ((int)y/16)+ 8224)/64) - 128); }
return pos; }
/***
** Function: ConvertGlyph ** ** Description: ** This function convertes the data associated to a T1 font glyph ** into the corresponding data used in a TT font glyph. ***/ errcode FASTCALL ConvertGlyph(struct T1Metrics *t1m, const struct T1Glyph *t1glyph, struct TTGlyph **ttglyph, const int delta) { errcode status = SUCCESS; struct encoding *code;
if ((code = LookupPSName(CurrentEncoding(t1m), EncodingSize(t1m), t1glyph->name))==NULL && (code = LookupComposite(Composites(t1m), t1glyph->name))==NULL && strcmp(t1glyph->name, ".notdef")) { LogError(MSG_INFO, MSG_BADENC, t1glyph->name); status = SUCCESS; } else {
if (((*ttglyph) = Malloc(sizeof(struct TTGlyph)))==NULL) { SetError(status = NOMEM); } else { short *sideboard = NULL; Outline *path; USHORT tot;
memset((*ttglyph), '\0', sizeof(struct TTGlyph)); if (t1glyph->width.y!=0) { LogError(MSG_WARNING, MSG_BADAW, NULL); } (*ttglyph)->aw = TransY(t1m, t1glyph->width.x); (*ttglyph)->lsb = TransY(t1m, t1glyph->lsb.x); (*ttglyph)->code = code; (*ttglyph)->num = 0; (*ttglyph)->twilights = 0;
/* Initiate the side board. */ for (path=t1glyph->paths, tot=0; path; path=path->next) tot = (USHORT)(tot + path->count); if (tot && (sideboard = Malloc((unsigned)tot*sizeof(short)))==NULL) { SetError(status=NOMEM); } else if ((status = ConvertOutline(t1m, t1glyph->paths, &((*ttglyph)->paths), delta, sideboard))==SUCCESS) status = ConvertHints(t1m, &t1glyph->hints, t1glyph->paths, (*ttglyph)->paths, sideboard, &(*ttglyph)->hints, &(*ttglyph)->num, &(*ttglyph)->stack, &(*ttglyph)->twilights);
if (sideboard) Free(sideboard);
/* Pick default std widths. */ if (t1glyph->name[0]=='l' && t1glyph->name[1]=='\0') { if (GetStdVW(t1m)==0 && t1glyph->hints.vstems) SetDefStdVW(t1m, t1glyph->hints.vstems->width); } if (t1glyph->name[0]=='z' && t1glyph->name[1]=='\0') { if (GetStdHW(t1m)==0) { if (t1glyph->hints.hstems && t1glyph->hints.hstems->width) SetDefStdHW(t1m, t1glyph->hints.hstems->width); else if (t1glyph->hints.vstems && t1glyph->hints.vstems->width) SetDefStdHW(t1m, t1glyph->hints.vstems->width); } } } }
return status; }
/***
** Function: ConvertComposite ** ** Description: ** This function convertes the data associated to a T1 font seac glyph ** into the corresponding data used in a TT font composite glyph. ** ***/ errcode FASTCALL ConvertComposite(struct T1Metrics *t1m, const struct Composite *comp, struct TTComposite *ttcomp) { Point pt;
pt.x = comp->adx; pt.y = comp->ady; TransAllPoints(t1m, &pt, 1, GetFontMatrix(t1m)); ttcomp->dx = pt.x + (pt.x - TransX(t1m, comp->adx)); ttcomp->dy = pt.y; ttcomp->aw = TransY(t1m, comp->aw); ttcomp->lsb = TransY(t1m, comp->asbx); ttcomp->aenc = LookupPSName(CurrentEncoding(t1m), EncodingSize(t1m), comp->achar); ttcomp->benc = LookupPSName(CurrentEncoding(t1m), EncodingSize(t1m), comp->bchar); if ((ttcomp->cenc = LookupPSName(CurrentEncoding(t1m), EncodingSize(t1m), comp->cchar))==NULL) { LogError(MSG_INFO, MSG_BADENC, comp->cchar); } ttcomp->oenc = comp->oenc;
if (ttcomp->aenc && ttcomp->benc) return SUCCESS; return SKIP; }
/***
** Function: ConvertMetrics ** ** Description: ** ***/ errcode FASTCALL ConvertMetrics(const struct TTHandle *tt, struct T1Metrics *t1m, struct TTMetrics *ttm, const char *tag) { const AlignmentControl *align; const Blues *blues; USHORT prep_size; UBYTE *prep = NULL; errcode status = SUCCESS; Point bbox[2]; funit em; funit PostAsc; USHORT i, j;
ttm->Encoding = CurrentEncoding(t1m); ttm->encSize = EncodingSize(t1m); ttm->version.ver = t1m->version.ver; ttm->version.rev = t1m->version.rev;
if ((ttm->verstr = Malloc(strlen(tag)+4+1+4+1))==NULL) { SetError(status = NOMEM); } else { strcpy(ttm->verstr, tag); (void)_itoa((int)ttm->version.ver, &ttm->verstr[strlen(ttm->verstr)], 4); strcat(ttm->verstr, "."); (void)_itoa((int)ttm->version.rev, &ttm->verstr[strlen(ttm->verstr)], 4); ttm->created.a = 0; ttm->created.b = 0; ttm->family = t1m->family; ttm->copyright = t1m->copyright; ttm->name = t1m->name; ttm->id = t1m->id; ttm->notice = t1m->notice; ttm->fullname = t1m->fullname; ttm->weight = t1m->weight; ttm->angle = t1m->angle; ttm->underline = TransY(t1m, t1m->underline); ttm->uthick = TransY(t1m, t1m->uthick); ttm->usWidthClass = (USHORT)(strstr(t1m->fullname, "Ultra-condensed") ? FWIDTH_ULTRA_CONDENSED : ((strstr(t1m->fullname, "Extra-condensed") ? FWIDTH_EXTRA_CONDENSED : ((strstr(t1m->fullname, "Condensed") ? FWIDTH_CONDENSED : ((strstr(t1m->fullname, "Semi-condensed") ? FWIDTH_SEMI_CONDENSED : ((strstr(t1m->fullname, "Semi-expanded") ? FWIDTH_SEMI_EXPANDED : ((strstr(t1m->fullname, "Expanded") ? FWIDTH_EXPANDED : ((strstr(t1m->fullname, "Extra-expanded") ? FWIDTH_EXTRA_EXPANDED : ((strstr(t1m->fullname, "Ultra-expanded") ? FWIDTH_ULTRA_EXPANDED : FWIDTH_NORMAL)))))))))))))));
/* Window based metrics. */
// ps driver does not compute asc and desc based on the
// windows charset. So, we will not do it either. We will
// also use the all glyhs supported in the font.
// Ps driver acutally trusts the values found in .pfm file.
// These values, according to afm->pfm converter code, are computed
// over all glyphs. However, some vendors ship buggy pfm's with
// zero ascenders or negative descenders. If we took these values
// literally, as ps driver does, the true type driver would
// shave off portions of glyphs and the conversion would appear broken.
// Pcl printing and screen output would be totally broken.
// Turns out that for these buggy fonts ATM on win31 also
// corrects the value from .pfm files for screen and pcl printer.
// [bodind]
// total bbox: [bodind], replaced WindowsBBox function:
GlobalBBox(tt, bbox);
ttm->winAscender = ABS(bbox[1].y); ttm->winDescender = ABS(bbox[0].y);
ttm->panose[0] = NOCARE_PANOSE; ttm->panose[1] = NOCARE_PANOSE; ttm->panose[2] = NOCARE_PANOSE; ttm->panose[3] = NOCARE_PANOSE; ttm->panose[4] = NOCARE_PANOSE; ttm->panose[5] = NOCARE_PANOSE; ttm->panose[6] = NOCARE_PANOSE; ttm->panose[6] = NOCARE_PANOSE; ttm->panose[7] = NOCARE_PANOSE; ttm->panose[8] = NOCARE_PANOSE; ttm->panose[9] = NOCARE_PANOSE; /* Fixed pitch fonts are not given a panose by ATM. */ if (!(t1m->fixedPitch)) { switch (t1m->pitchfam & 0xf0) { case FF_DECORATIVE: ttm->panose[0] = (UBYTE)DECORATIVE_PANOSE; ttm->panose[1] = (UBYTE)NO_PANOSE; break; case FF_ROMAN: ttm->panose[0] = (UBYTE)TEXT_PANOSE; ttm->panose[1] = (UBYTE)COVE_PANOSE; break; case FF_SWISS: ttm->panose[0] = (UBYTE)TEXT_PANOSE; ttm->panose[1] = (UBYTE)SANS_PANOSE; break; case FF_SCRIPT: ttm->panose[0] = (UBYTE)SCRIPT_PANOSE; ttm->panose[1] = (UBYTE)SANS_PANOSE; break; case FF_MODERN: ttm->panose[0] = (UBYTE)TEXT_PANOSE; ttm->panose[1] = (UBYTE)SANS_PANOSE; break; } } ttm->isFixPitched = t1m->fixedPitch; ttm->panose[2] = (UBYTE)((t1m->tmweight - 500) * 12 / 900 + 6);
/* Mac based metrics. */ MacBBox(tt, bbox); ttm->macLinegap = TransY(t1m, (funit)(t1m->extLeading + (ttm->winAscender + ttm->winDescender) - (bbox[1].y-bbox[0].y)));
/* Typographical metrics. */ ttm->emheight = GetUPEM(t1m); if (t1m->flags==DEFAULTMETRICS) { ttm->usWeightClass = (USHORT)(strstr(t1m->fullname, "Thin") ? FW_THIN : ((strstr(t1m->fullname, "light") ? FW_EXTRALIGHT : ((strstr(t1m->fullname, "Light") ? FW_LIGHT : ((strstr(t1m->fullname, "Medium") ? FW_MEDIUM : ((strstr(t1m->fullname, "emi-bold") ? FW_SEMIBOLD : ((strstr(t1m->fullname, "Bold") ? FW_BOLD : ((strstr(t1m->fullname, "Black") ? FW_BLACK : FW_NORMAL))))))))))))); ttm->macStyle = (USHORT)(((ttm->usWeightClass>FW_MEDIUM)?MAC_BOLD : 0) | ((ttm->angle != 0) ? MAC_ITALIC : 0)); ttm->fsSelection = (USHORT)(((ttm->angle != 0) ? FS_ITALIC : 0) | ((ttm->usWeightClass > FW_MEDIUM) ? FS_BOLD : 0) | ((ttm->usWeightClass==FW_NORMAL) ? FS_NORMAL : 0)); ttm->typAscender = TypographicalAscender(tt); ttm->typDescender = TypographicalDescender(tt); em = ttm->typAscender - ttm->typDescender; ttm->superoff.y = (funit)(em / 2); ttm->superoff.x = 0; ttm->supersize.y = (funit)(em * 2 / 3); ttm->supersize.x = (funit)(em * 3 / 4); ttm->suboff.y = (funit)(em / 5); ttm->suboff.x = 0; ttm->subsize.y = (funit)(em * 2 / 3); ttm->subsize.x = (funit)(em * 3 / 4); ttm->strikeoff = (funit)(ttm->typAscender / 2); ttm->strikesize = (funit)(ttm->typAscender / 10); } else { ttm->usWeightClass = t1m->tmweight; ttm->macStyle = (USHORT)(((t1m->tmweight>FW_MEDIUM)?MAC_BOLD : 0) | ((ttm->angle != 0) ? MAC_ITALIC : 0)); ttm->fsSelection = (USHORT)(((ttm->angle != 0) ? FS_ITALIC : 0) | ((ttm->usWeightClass > FW_MEDIUM) ? FS_BOLD : 0) | ((ttm->usWeightClass==FW_NORMAL) ? FS_NORMAL : 0)); ttm->typAscender = TransY(t1m, (funit)(t1m->ascent - t1m->intLeading)); ttm->typDescender = (funit)(-TransY(t1m, t1m->descent)-1); ttm->typLinegap = TransY(t1m, (funit)(t1m->intLeading + t1m->extLeading)); ttm->superoff.y = ABS(TransY(t1m, t1m->superoff)); ttm->superoff.x = 0; ttm->supersize.y = TransY(t1m, t1m->supersize); ttm->supersize.x = (funit)(TransY(t1m, t1m->supersize) * 3 / 4); ttm->suboff.y = ABS(TransY(t1m, t1m->suboff)); ttm->suboff.x = 0; ttm->subsize.y = TransY(t1m, t1m->subsize); ttm->subsize.x = (funit)(TransY(t1m, t1m->subsize) * 3 / 4); ttm->strikeoff = ABS(TransY(t1m, t1m->strikeoff)); ttm->strikesize = TransY(t1m, t1m->strikesize);
// Adjust usWinAscent so that internal leading matches up.
// For fonts that do not have buggy pfm files, this adjustment
// will do nothing, for those for which intLeading is
// incorrectly set to zero, taking max means that the tops will not
// be chopped off in the converted font. ttfd shaves off anything
// that extends beyond ascender or descender. For fonts with buggy
// pfm's, tt conversions may have bogus internal leadings, but this
// is better than having glyph bottoms or tops shaved off. [bodind]
PostAsc = ttm->emheight + TransY(t1m, t1m->intLeading) - ttm->winDescender;
if (PostAsc > ttm->winAscender) ttm->winAscender = PostAsc; }
/* Gray-scale threshold. */ if (GetStdVW(t1m)!=0 || GetDefStdVW(t1m)!=0) { ttm->onepix = (USHORT)(1 + GetUPEM(t1m)*3/2 / TransY(t1m, ((GetStdVW(t1m) ? GetStdVW(t1m) : GetDefStdVW(t1m))))); }
// needed in producing the correct ifimetrics for tt conversion
ttm->DefaultChar = t1m->DefaultChar; ttm->BreakChar = t1m->BreakChar; ttm->CharSet = t1m->CharSet; // essential for correct font mapping
/* Character widths. */ if (t1m->flags!=DEFAULTMETRICS) { ttm->FirstChar = t1m->firstChar; ttm->LastChar = t1m->lastChar; if ((ttm->widths = Malloc(sizeof(funit)* (t1m->lastChar-t1m->firstChar+1)))==NULL) { SetError(status = NOMEM); } else { for (i=0; i<=(unsigned)(t1m->lastChar-t1m->firstChar); i++) { ttm->widths[i] = TransY(t1m, t1m->widths[i]); } } }
/* Pair kerning. */ if (t1m->flags!=DEFAULTMETRICS && t1m->kerns!=NULL) { if ((ttm->kerns = Malloc(sizeof(struct kerning)* t1m->kernsize))==NULL) { SetError(status = NOMEM); } else { for (i=0; i<t1m->kernsize; i++) { ttm->kerns[i].left = t1m->kerns[i].left; ttm->kerns[i].right = t1m->kerns[i].right; ttm->kerns[i].delta = TransY(t1m, t1m->kerns[i].delta); } ttm->kernsize = t1m->kernsize; } }
/* Pre program. */ if ((prep = GetPrep(PREPSIZE))!=NULL && (prep_size = BuildPreProgram(t1m, GetWeight(t1m), GetBlues(t1m), GetAlignment(t1m), &prep, PREPSIZE, &(ttm->maxprepstack)))>0) {
/* Store the pre-program. */ UsePrep(ttm, prep, prep_size); }
/* CVT entries. */ blues = GetBlues(t1m); if (status!=NOMEM && (ttm->cvt = Malloc(blues->align.cvt * CVTSIZE)) == NULL) { SetError(status = NOMEM); } else { ADDCVT(0); /* TMPCVT */ ADDCVT((GetStdVW(t1m)==0) ? TransX(t1m, GetDefStdVW(t1m))/2 : TransX(t1m, GetStdVW(t1m))/2); ADDCVT((GetStdHW(t1m)==0) ? TransY(t1m, GetDefStdHW(t1m))/2 : TransY(t1m, GetStdHW(t1m))/2); for (i=0; i<t1m->snapv_cnt; i++) ADDCVT(TransY(t1m, t1m->stemsnapv[i])/2); for (i=0; i<t1m->snaph_cnt; i++) ADDCVT(TransY(t1m, t1m->stemsnaph[i])/2);
/* Align the top zones. */ align = GetAlignment(t1m); for (i=0; i<blues->blue_cnt/2; i++) { /* Skip empty zones. */ if (align->top[i].cnt==0) continue; ttm->cvt[align->top[i].blue_cvt] = (short)TransY(t1m, blues->bluevalues[i*2]); ttm->cvt[align->top[i].blue_cvt+1] = (short)TransY(t1m, blues->bluevalues[i*2+1]); for (j=0; j<align->top[i].cnt; j++) { funit pos; int k;
/* Get the closest family. */ k = MatchingFamily(blues->bluevalues[i*2], blues->familyblues, blues->fblue_cnt);
/* Compute the position in the zone w.r.t. the family blues. */ if (blues->bluevalues[i*2] != blues->bluevalues[i*2+1]) pos = IP(align->top[i].pos[j].y, blues->bluevalues[i*2], blues->bluevalues[i*2+1], blues->familyblues[k], blues->familyblues[k+1]); else pos = blues->familyblues[k];
ttm->cvt[align->top[i].pos[j].cvt] = (short)TransY(t1m, align->top[i].pos[j].y); ttm->cvt[align->top[i].pos[j].cvt+1] = (short)TransY(t1m, pos); } }
/* Align the bottom zones. */ for (i=0; i<blues->oblue_cnt/2; i++) { /* Skip empty zones. */ if (align->bottom[i].cnt==0) continue; ttm->cvt[align->bottom[i].blue_cvt] = (short)TransY(t1m, blues->otherblues[i*2+1]); for (j=0; j<align->bottom[i].cnt; j++) { funit pos; int k;
/* Get the closest family. */ k = MatchingFamily(blues->otherblues[i*2], blues->familyotherblues, blues->foblue_cnt);
/* Compute the position in the zone w.r.t. the family blues. */ if (blues->otherblues[i*2] != blues->otherblues[i*2+1]) pos = IP(align->bottom[i].pos[j].y, blues->otherblues[i*2], blues->otherblues[i*2+1], blues->familyotherblues[k], blues->familyotherblues[k+1]); else pos = blues->familyotherblues[k];
ttm->cvt[align->bottom[i].pos[j].cvt] = (short)TransY(t1m, align->bottom[i].pos[j].y); ttm->cvt[align->bottom[i].pos[j].cvt+1] = (short)TransY(t1m, pos); } }
/* Add the family zones. */ for (i=0; i<blues->fblue_cnt/2; i++) { if (blues->family_cvt[i]!=UNDEF_CVT) { ttm->cvt[blues->family_cvt[i]] = (short)TransY(t1m, blues->familyblues[i*2]); ttm->cvt[blues->family_cvt[i]+1] = (short)TransY(t1m, blues->familyblues[i*2+1]); } }
/* Add the family other zones. */ for (i=0; i<blues->foblue_cnt/2; i++) { if (blues->familyother_cvt[i]!=UNDEF_CVT) { ttm->cvt[blues->familyother_cvt[i]] = (short)TransY(t1m, blues->familyotherblues[i*2+1]); } }
ttm->cvt_cnt = blues->align.cvt; ttm->maxstorage = t1m->stems.storage;
/* Store the font-program. */ SetFPGM(ttm, GetFontProg(), GetFontProgSize(), GetNumFuns()); } }
return status; }
|