}
#define d_uint32 decode_uint32, 4
-#if 0 /* unused */
static void decode_int32(void *src, void *dest) {
signed char *cp = src;
unsigned char *ucp = src;
*(int *)dest = (cp[0] << 24) + (ucp[1] << 16) + (ucp[2] << 8) + ucp[3];
}
#define d_int32 decode_int32, 4
-#endif
static void decode_skip(void *src, void *dest) {
IGNORE(src);
};
#define sfnt_00010000 0x00010000
+#define TAG_OS_2 0x4f532f32
#define TAG_cmap 0x636d6170
#define TAG_glyf 0x676c7966
#define TAG_head 0x68656164
{ d_end }
};
+/* OS/2 and Windows compatibility table */
+typedef struct t_OS_2_Tag t_OS_2;
+struct t_OS_2_Tag {
+ unsigned version;
+ int sTypoAscender, sTypoDescender;
+ int sxHeight, sCapHeight;
+};
+sfnt_decode t_OS_2_v0_decode[] = {
+ { d_uint16, offsetof(t_OS_2, version) },
+ { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
+ /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
+ /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
+ /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
+ /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
+ /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
+ { d_end }
+};
+sfnt_decode t_OS_2_v1_decode[] = {
+ { d_uint16, offsetof(t_OS_2, version) },
+ { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
+ /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
+ /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
+ /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
+ /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
+ /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
+ { d_int16, offsetof(t_OS_2, sTypoAscender) },
+ { d_int16, offsetof(t_OS_2, sTypoDescender) },
+ { d_skip(14) }, /* sTypoLineGap, usWinAscent, usWinDescent, */
+ /* ulCodePageRange1, ulCodePageRange2 */
+ { d_end }
+};
+sfnt_decode t_OS_2_v2_decode[] = {
+ { d_uint16, offsetof(t_OS_2, version) },
+ { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
+ /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
+ /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
+ /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
+ /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
+ /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
+ { d_int16, offsetof(t_OS_2, sTypoAscender) },
+ { d_int16, offsetof(t_OS_2, sTypoDescender) },
+ { d_skip(14) }, /* sTypoLineGap, usWinAscent, usWinDescent, */
+ /* ulCodePageRange1, ulCodePageRange2 */
+ { d_int16, offsetof(t_OS_2, sxHeight) },
+ { d_int16, offsetof(t_OS_2, sCapHeight) },
+ { d_skip(6) }, /* usDefaultChar, usBreakChar, usMaxContext */
+ { d_end }
+};
+
/* Character to Glyph ('cmap') table */
typedef struct t_cmap_Tag t_cmap;
struct t_cmap_Tag {
typedef struct t_post_Tag t_post;
struct t_post_Tag {
unsigned format;
- unsigned italicAngle;
+ int italicAngle;
int underlinePosition;
int underlineThickness;
unsigned isFixedPitch;
};
sfnt_decode t_post_decode[] = {
{ d_uint32, offsetof(t_post, format) },
- { d_uint32, offsetof(t_post, italicAngle) },
+ { d_int32, offsetof(t_post, italicAngle) },
{ d_int16, offsetof(t_post, underlinePosition) },
{ d_int16, offsetof(t_post, underlineThickness) },
{ d_uint32, offsetof(t_post, isFixedPitch) },
unsigned short index;
} glyphmap;
-typedef struct sfnt_Tag sfnt;
struct sfnt_Tag {
void *data;
size_t len;
return NULL;
}
+static unsigned short *cmp_glyphsbyindex;
+static int glyphsbyname_cmp(void const *a, void const *b) {
+ glyph ga = cmp_glyphsbyindex[*(unsigned short *)a];
+ glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
+ if (ga < gb) return -1;
+ if (ga > gb) return 1;
+ return 0;
+}
+static int glyphsbyname_cmp_search(void const *a, void const *b) {
+ glyph ga = *(glyph *)a;
+ glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
+ if (ga < gb) return -1;
+ if (ga > gb) return 1;
+ return 0;
+}
+
/*
* Extract data from the 'post' table (mostly glyph mappings)
*
* TODO: cope better with duplicated glyph names (usually .notdef)
* TODO: when presented with format 3.0, try to use 'CFF' if present.
*/
-static void sfnt_mapglyphs(sfnt *sf) {
+static void sfnt_mapglyphs(font_info *fi) {
+ sfnt *sf = fi->fontfile;
t_post post;
void *ptr, *end;
unsigned char *sptr;
if (!sfnt_findtable(sf, TAG_post, &ptr, &end))
abort();
ptr = decode(t_post_decode, ptr, end, &post);
+
sf->minmem = post.minMemType42;
sf->maxmem = post.maxMemType42;
+ fi->italicangle = post.italicAngle / 65536.0;
if (ptr == NULL) abort();
switch (post.format) {
case 0x00010000:
default:
abort();
}
+ /* Construct glyphsbyname */
+ sf->glyphsbyname = snewn(sf->nglyphs, unsigned short);
+ for (i = 0; i < sf->nglyphs; i++)
+ sf->glyphsbyname[i] = i;
+ cmp_glyphsbyindex = sf->glyphsbyindex;
+ qsort(sf->glyphsbyname, sf->nglyphs, sizeof(*sf->glyphsbyname),
+ glyphsbyname_cmp);
+}
+
+glyph sfnt_indextoglyph(sfnt *sf, unsigned idx) {
+ return sf->glyphsbyindex[idx];
+}
+
+unsigned sfnt_nglyphs(sfnt *sf) {
+ return sf->nglyphs;
+}
+
+unsigned sfnt_glyphtoindex(sfnt *sf, glyph g) {
+ cmp_glyphsbyindex = sf->glyphsbyindex;
+ return *(unsigned short *)bsearch(&g, sf->glyphsbyname, sf->nglyphs,
+ sizeof(*sf->glyphsbyname),
+ glyphsbyname_cmp_search);
}
/*
- * Get data from 'hhea' and 'hmtx' tables
+ * Get data from 'hhea', 'hmtx', and 'OS/2' tables
*/
void sfnt_getmetrics(font_info *fi) {
sfnt *sf = fi->fontfile;
t_hhea hhea;
+ t_OS_2 OS_2;
void *ptr, *end;
unsigned i, j;
unsigned *hmtx;
+ /* First, the bounding box from the 'head' table. */
+ fi->fontbbox[0] = sf->head.xMin * FUNITS_PER_PT / sf->head.unitsPerEm;
+ fi->fontbbox[1] = sf->head.yMin * FUNITS_PER_PT / sf->head.unitsPerEm;
+ fi->fontbbox[2] = sf->head.xMax * FUNITS_PER_PT / sf->head.unitsPerEm;
+ fi->fontbbox[3] = sf->head.yMax * FUNITS_PER_PT / sf->head.unitsPerEm;
if (!sfnt_findtable(sf, TAG_hhea, &ptr, &end))
abort();
if (decode(t_hhea_decode, ptr, end, &hhea) == NULL)
abort();
for (i = 0; i < sf->nglyphs; i++) {
glyph_width *w = snew(glyph_width);
- w->glyph = sf->glyphsbyindex[i];
+ w->glyph = sfnt_indextoglyph(sf, i);
j = i < hhea.numOfLongHorMetrics ? i : hhea.numOfLongHorMetrics - 1;
w->width = hmtx[j] * UNITS_PER_PT / sf->head.unitsPerEm;
add234(fi->widths, w);
}
+ /* Now see if the 'OS/2' table has any useful metrics */
+ if (!sfnt_findtable(sf, TAG_OS_2, &ptr, &end))
+ return;
+ if (decode(uint16_decode, ptr, end, &OS_2.version) == NULL)
+ return;
+ if (OS_2.version >= 2) {
+ if (decode(t_OS_2_v2_decode, ptr, end, &OS_2) == NULL)
+ return;
+ fi->xheight = OS_2.sxHeight * FUNITS_PER_PT / sf->head.unitsPerEm;
+ fi->capheight = OS_2.sCapHeight * FUNITS_PER_PT / sf->head.unitsPerEm;
+ } else if (OS_2.version == 1) {
+ if (decode(t_OS_2_v1_decode, ptr, end, &OS_2) == NULL)
+ return;
+ } else
+ return;
+ fi->ascent = OS_2.sTypoAscender * FUNITS_PER_PT / sf->head.unitsPerEm;
+ fi->descent = OS_2.sTypoDescender * FUNITS_PER_PT / sf->head.unitsPerEm;
}
/*
idx = (k + idDelta[j]) & 0xffff;
if (idx != 0) {
if (idx > sf->nglyphs) abort();
- fi->bmp[k] = sf->glyphsbyindex[idx];
+ fi->bmp[k] = sfnt_indextoglyph(sf, idx);
}
}
} else {
if (idx != 0) {
idx = (idx + idDelta[j]) & 0xffff;
if (idx > sf->nglyphs) abort();
- fi->bmp[k] = sf->glyphsbyindex[idx];
+ fi->bmp[k] = sfnt_indextoglyph(sf, idx);
}
}
}
if ((sf->head.version & 0xffff0000) != 0x00010000)
abort();
fi->name = sfnt_psname(fi);
- sfnt_mapglyphs(sf);
+ sfnt_mapglyphs(fi);
sfnt_getmetrics(fi);
sfnt_getmap(fi);
fi->next = all_fonts;
size_t *breaks, glyfoff, glyflen;
void *glyfptr, *glyfend, *locaptr, *locaend;
unsigned *loca;
+ int cc = 0;
/* XXX Unclear that this is the correct format. */
fprintf(ofp, "%%!PS-TrueTypeFont-%u-%u\n", sf->osd.scaler_type,
(double)sf->head.yMax / sf->head.unitsPerEm);
} else {
/* Non-sensible font. */
- fprintf(ofp, "/FontBBox [0 0 0 0] readonly def");
+ fprintf(ofp, "/FontBBox [0 0 0 0] readonly def\n");
}
fprintf(ofp, "/PaintType 0 def\n");
fprintf(ofp, "/CharStrings %u dict dup begin\n", sf->nglyphs);
+ fprintf(ofp, "0 1 %u{currentfile token pop exch def}bind for\n",
+ sf->nglyphs - 1);
for (i = 0; i < sf->nglyphs; i++)
- fprintf(ofp, "/%s %u def\n", glyph_extern(sf->glyphsbyindex[i]), i);
- fprintf(ofp, "end readonly def\n");
+ ps_token(ofp, &cc, "/%s", glyph_extern(sfnt_indextoglyph(sf, i)));
+ fprintf(ofp, "\nend readonly def\n");
fprintf(ofp, "/sfnts [<");
breaks = snewn(sf->osd.numTables + sf->nglyphs, size_t);
for (i = 0; i < sf->osd.numTables; i++) {
sfree(breaks);
fprintf(ofp, "end /%s exch definefont\n", fi->name);
}
+
+void sfnt_data(font_info *fi, char **bufp, size_t *lenp) {
+ sfnt *sf = fi->fontfile;
+ *bufp = sf->data;
+ *lenp = sf->len;
+}