glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
if (ga < gb) return -1;
if (ga > gb) return 1;
+ /* For de-duping, we'd prefer to have the first glyph stay first */
+ if (*(unsigned short *)a < *(unsigned short *)b) return -1;
+ if (*(unsigned short *)a > *(unsigned short *)b) return 1;
return 0;
}
static int glyphsbyname_cmp_search(void const *a, void const *b) {
void *ptr, *end;
unsigned char *sptr;
char tmp[256];
- glyph *extraglyphs;
- unsigned nextras, i, g;
+ glyph *extraglyphs, prev, this;
+ unsigned nextras, i, g, suflen;
sf->glyphsbyname = sf->glyphsbyindex = NULL;
if (sfnt_findtable(sf, TAG_post, &ptr, &end)) {
cmp_glyphsbyindex = sf->glyphsbyindex;
qsort(sf->glyphsbyname, sf->nglyphs, sizeof(*sf->glyphsbyname),
glyphsbyname_cmp);
+ /*
+ * It's possible for fonts to specify the same name for multiple
+ * glyphs, which would make one of them inaccessible. Check for
+ * that, and rename all but one of each set.
+ *
+ * To ensure that we don't clash with any existing glyph names,
+ * our renaming involves appending the glyph number formatted with
+ * enough leading zeroes to make it longer than any all-digit
+ * suffix that already exists in the font.
+ */
+ suflen = 4;
+ for (i = 0; i < sf->nglyphs; i++) {
+ char const *p;
+ p = strrchr(glyph_extern(sfnt_indextoglyph(sf, i)), '.');
+ if (p && !(p+1)[strspn(p+1, "0123456789")] && strlen(p+1) > suflen)
+ suflen = strlen(p+1);
+ }
+ suflen++;
+ prev = sfnt_indextoglyph(sf, sf->glyphsbyname[0]);
+ for (i = 1; i < sf->nglyphs; i++) {
+ if (prev == (this = sfnt_indextoglyph(sf, sf->glyphsbyname[i]))) {
+ char const *basename;
+ char *buf;
+ basename = glyph_extern(this);
+ buf = snewn(strlen(basename) + 2 + suflen, char);
+ strcpy(buf, basename);
+ sprintf(buf + strlen(basename), ".%0*hu", suflen,
+ sf->glyphsbyname[i]);
+ sf->glyphsbyindex[sf->glyphsbyname[i]] = glyph_intern(buf);
+ sfree(buf);
+ }
+ prev = this;
+ }
+ /* We may have renamed some glyphs, so re-sort the array. */
+ qsort(sf->glyphsbyname, sf->nglyphs, sizeof(*sf->glyphsbyname),
+ glyphsbyname_cmp);
}
glyph sfnt_indextoglyph(sfnt *sf, unsigned idx) {
/*
* Get mapping data from 'cmap' table
*
- * We look for either a (0, 3), or (3, 1) table, both of these being
- * versions of UCS-2. We only handle format 4 of this table, since
- * that seems to be the only one in use.
+ * We look for either a (0, 0), (0, 2), (0, 3), or (3, 1) table, all
+ * of these being versions of UCS-2. We ignore (0, 1), since it's
+ * Unicode 1.1 with precomposed Hangul syllables. We only handle
+ * format 4 of this table, since that seems to be the only one in use.
*/
void sfnt_getmap(font_info *fi) {
sfnt *sf = fi->fontfile;
for (i = 0; i < cmap.numTables; i++) {
if (!decode(uint16_decode, (char *)base + esd[i].offset, end, &format))
goto bad;
- if ((esd[i].platformID == 0 && esd[i].encodingID == 3) ||
+ if ((esd[i].platformID == 0 && esd[i].encodingID == 0) ||
+ (esd[i].platformID == 0 && esd[i].encodingID == 2) ||
+ (esd[i].platformID == 0 && esd[i].encodingID == 3) ||
(esd[i].platformID == 3 && esd[i].encodingID == 1)) {
/* UCS-2 encoding */
if (!decode(uint16_decode, (char *)base + esd[i].offset, end,
for (k = startCode[j]; k <= endCode[j]; k++) {
idx = (k + idDelta[j]) & 0xffff;
if (idx != 0) {
- if (idx > sf->nglyphs) goto bad;
+ if (idx > sf->nglyphs) {
+ error(err_sfntbadglyph, &sf->pos, k);
+ continue;
+ }
fi->bmp[k] = sfnt_indextoglyph(sf, idx);
}
}
} else {
unsigned startidx = idRangeOffset[j]/2 - segcount + j;
for (k = startCode[j]; k <= endCode[j]; k++) {
+ if (startidx + k - startCode[j] >=
+ nglyphindex) {
+ error(err_sfntbadglyph, &sf->pos, k);
+ continue;
+ }
idx = glyphIndexArray[startidx + k - startCode[j]];
if (idx != 0) {
idx = (idx + idDelta[j]) & 0xffff;
- if (idx > sf->nglyphs) goto bad;
+ if (idx > sf->nglyphs) {
+ error(err_sfntbadglyph, &sf->pos, k);
+ continue;
+ }
fi->bmp[k] = sfnt_indextoglyph(sf, idx);
}
}