/fontforge/parsettfatt.c
C | 5088 lines | 4680 code | 265 blank | 143 comment | 1181 complexity | bcd8c971aa241c24bd2daa76023c09a3 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
- #include <config.h>
- // This file is part of the Sorts Mill Tools.
- //
- // Sorts Mill Tools is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 3 of the License, or
- // (at your option) any later version.
- //
- // Sorts Mill Tools is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program; if not, see <http://www.gnu.org/licenses/>.
- /* 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 "fontforge.h"
- #include <chardata.h>
- #include <utype.h>
- #include <ustring.h>
- #include <math.h>
- #include <locale.h>
- #include <stdlib.h>
- #include "ttf.h"
- static uint16_t *
- getAppleClassTable (FILE *ttf, int classdef_offset, int cnt, int sub, int div,
- struct ttfinfo *info)
- {
- uint16_t *class = xcalloc (cnt, sizeof (uint16_t));
- int first, i, n;
- /* Apple stores its class tables as containing offsets. I find it hard to */
- /* think that way and convert them to indeces (by subtracting off a base */
- /* offset and dividing by the item's size) before doing anything else */
- fseek (ttf, classdef_offset, SEEK_SET);
- first = getushort (ttf);
- n = getushort (ttf);
- if (first + n - 1 >= cnt)
- {
- LogError (_("Bad Apple Kern Class\n"));
- info->bad_gx = true;
- }
- for (i = 0; i < n && i + first < cnt; ++i)
- class[first + i] = (getushort (ttf) - sub) / div;
- return class;
- }
- static char **
- ClassToNames (struct ttfinfo *info, int class_cnt, uint16_t *class,
- int glyph_cnt)
- {
- char **ret = xmalloc (class_cnt * sizeof (char *));
- int *lens = xcalloc (class_cnt, sizeof (int));
- int i;
- ret[0] = NULL;
- for (i = 0; i < glyph_cnt; ++i)
- if (class[i] != 0 && info->chars[i] != NULL && class[i] < class_cnt)
- lens[class[i]] += strlen (info->chars[i]->name) + 1;
- for (i = 1; i < class_cnt; ++i)
- ret[i] = xmalloc (lens[i] + 1);
- memset (lens, 0, class_cnt * sizeof (int));
- for (i = 0; i < glyph_cnt; ++i)
- if (class[i] != 0 && info->chars[i] != NULL)
- {
- if (class[i] < class_cnt)
- {
- strcpy (ret[class[i]] + lens[class[i]], info->chars[i]->name);
- lens[class[i]] += strlen (info->chars[i]->name) + 1;
- ret[class[i]][lens[class[i]] - 1] = ' ';
- }
- else
- {
- LogError (_("Class index out of range %d (must be <%d)\n"),
- class[i], class_cnt);
- info->bad_ot = true;
- }
- }
- for (i = 1; i < class_cnt; ++i)
- if (lens[i] == 0)
- ret[i][0] = '\0';
- else
- ret[i][lens[i] - 1] = '\0';
- free (lens);
- return ret;
- }
- static char *
- CoverageMinusClasses (uint16_t *coverageglyphs, uint16_t *classed,
- struct ttfinfo *info)
- {
- int i, j, len;
- uint8_t *glyphs = xcalloc (info->glyph_cnt, sizeof (uint8_t));
- char *ret;
- for (i = 0; coverageglyphs[i] != 0xffff; ++i)
- glyphs[coverageglyphs[i]] = 1;
- for (i = 0; i < info->glyph_cnt; ++i)
- if (classed[i] != 0)
- glyphs[i] = 0;
- for (i = 0; i < info->glyph_cnt; ++i)
- if (glyphs[i] != 0)
- break;
- /* coverage table matches glyphs in classes. No need for special treatment */
- if (i == info->glyph_cnt)
- {
- free (glyphs);
- return NULL;
- }
- /* Otherwise we need to generate a class string of glyph names in the coverage */
- /* table but not in any class. These become the glyphs in class 0 */
- ret = NULL;
- for (j = 0; j < 2; ++j)
- {
- len = 0;
- for (i = 0; i < info->glyph_cnt; ++i)
- {
- if (glyphs[i] != 0)
- {
- if (j)
- {
- strcpy (ret + len, info->chars[i]->name);
- strcat (ret + len, " ");
- }
- len += strlen (info->chars[i]->name) + 1;
- }
- }
- if (j == 0)
- ret = xmalloc (len + 1);
- else
- ret[len - 1] = '\0';
- }
- free (glyphs);
- return ret;
- }
- static int
- ClassFindCnt (uint16_t *class, int tot)
- {
- int i, max = 0;
- for (i = 0; i < tot; ++i)
- if (class[i] > max)
- max = class[i];
- return max + 1;
- }
- static int
- uint16_t_cmp (const void *u1, const void *u2)
- {
- return ((int) *((const uint16_t *) u1)) - ((int) *((const uint16_t *) u2));
- }
- static char *
- GlyphsToNames (struct ttfinfo *info, uint16_t *glyphs, int make_uniq)
- {
- int i, j, len, off;
- char *ret, *pt;
- if (glyphs == NULL)
- return xstrdup ("");
- /* Adobe produces coverage tables containing duplicate glyphs in */
- /* GaramondPremrPro.otf. We want unique glyphs, so enforce that */
- if (make_uniq)
- {
- for (i = 0; glyphs[i] != 0xffff; ++i);
- qsort (glyphs, i, sizeof (uint16_t), uint16_t_cmp);
- for (i = 0; glyphs[i] != 0xffff; ++i)
- {
- if (glyphs[i + 1] == glyphs[i])
- {
- for (j = i + 1; glyphs[j] == glyphs[i]; ++j);
- off = j - i - 1;
- for (j = i + 1;; ++j)
- {
- glyphs[j] = glyphs[j + off];
- if (glyphs[j] == 0xffff)
- break;
- }
- }
- }
- }
- for (i = len = 0; glyphs[i] != 0xffff; ++i)
- {
- if (glyphs[i] >= info->glyph_cnt)
- {
- if (!info->bad_ot)
- {
- LogError (_("Glyph %d out of range [0, %d)"),
- glyphs[i], info->glyph_cnt);
- info->bad_ot = true;
- }
- return xstrdup ("");
- }
- if (info->chars[glyphs[i]] != NULL)
- len += strlen (info->chars[glyphs[i]]->name) + 1;
- }
- ret = pt = xmalloc (len + 1);
- *pt = '\0';
- for (i = 0; glyphs[i] != 0xffff; ++i)
- if (info->chars[glyphs[i]] != NULL)
- {
- strcpy (pt, info->chars[glyphs[i]]->name);
- pt += strlen (pt);
- *pt++ = ' ';
- }
- if (pt > ret)
- pt[-1] = '\0';
- return ret;
- }
- struct language
- { /* normal entry with lang tag 'dflt' */
- uint32_t tag;
- uint32_t offset;
- uint16_t req; /* required feature index. 0xffff for null */
- int fcnt;
- uint16_t *features;
- };
- struct scripts
- {
- uint32_t offset;
- uint32_t tag;
- int langcnt; /* the default language is included as a */
- struct language *languages;
- };
- struct feature
- {
- uint32_t offset;
- uint32_t tag;
- int lcnt;
- uint16_t *lookups;
- };
- struct lookup
- {
- uint16_t type;
- uint32_t flags; /* low order 16 bits: traditional flags, high order: mark filtering set index if pst_usemarkfilteringset */
- uint32_t offset;
- int subtabcnt;
- int32_t *subtab_offsets;
- OTLookup *otlookup;
- };
- static uint16_t *
- getCoverageTable (FILE *ttf, int coverage_offset, struct ttfinfo *info)
- {
- int format, cnt, i, j, rcnt;
- uint16_t *glyphs = NULL;
- int start, end, ind, max;
- fseek (ttf, coverage_offset, SEEK_SET);
- format = getushort (ttf);
- if (format == 1)
- {
- cnt = getushort (ttf);
- glyphs = xmalloc ((cnt + 1) * sizeof (uint16_t));
- if (ftell (ttf) + 2 * cnt > info->g_bounds)
- {
- LogError (_("coverage table extends beyond end of table\n"));
- info->bad_ot = true;
- if (ftell (ttf) > info->g_bounds)
- return NULL;
- cnt = (info->g_bounds - ftell (ttf)) / 2;
- }
- for (i = 0; i < cnt; ++i)
- {
- if (cnt & 0xffff0000)
- {
- LogError (_("Bad count.\n"));
- info->bad_ot = true;
- }
- glyphs[i] = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file found in coverage table.\n"));
- info->bad_ot = true;
- free (glyphs);
- return NULL;
- }
- if (glyphs[i] >= info->glyph_cnt)
- {
- LogError (_("Bad coverage table. Glyph %d out of range [0, %d)"),
- glyphs[i], info->glyph_cnt);
- info->bad_ot = true;
- glyphs[i] = 0;
- }
- }
- }
- else if (format == 2)
- {
- max = 256;
- glyphs = xcalloc (max, sizeof (uint16_t));
- rcnt = getushort (ttf);
- cnt = 0;
- if (ftell (ttf) + 6 * rcnt > info->g_bounds)
- {
- LogError (_("coverage table extends beyond end of table\n"));
- info->bad_ot = true;
- rcnt = (info->g_bounds - ftell (ttf)) / 6;
- }
- for (i = 0; i < rcnt; ++i)
- {
- start = getushort (ttf);
- end = getushort (ttf);
- ind = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file found in coverage table.\n"));
- info->bad_ot = true;
- free (glyphs);
- return NULL;
- }
- if (start > end || end >= info->glyph_cnt)
- {
- LogError (_("Bad coverage table. "
- "Glyph range %d-%d out of range [0, %d)"),
- start, end, info->glyph_cnt);
- info->bad_ot = true;
- start = end = 0;
- }
- if (ind + end - start + 2 >= max)
- {
- int oldmax = max;
- max = ind + end - start + 2;
- glyphs = xrealloc (glyphs, max * sizeof (uint16_t));
- memset (glyphs + oldmax, 0, (max - oldmax) * sizeof (uint16_t));
- }
- for (j = start; j <= end; ++j)
- {
- glyphs[j - start + ind] = j;
- if (j >= info->glyph_cnt)
- glyphs[j - start + ind] = 0;
- }
- if (ind + end - start + 1 > cnt)
- cnt = ind + end - start + 1;
- }
- }
- else
- {
- LogError (_("Bad format for coverage table %d\n"), format);
- info->bad_ot = true;
- return NULL;
- }
- glyphs[cnt] = 0xffff;
- return glyphs;
- }
- struct valuerecord
- {
- int16_t xplacement, yplacement;
- int16_t xadvance, yadvance;
- uint16_t offXplaceDev, offYplaceDev;
- uint16_t offXadvanceDev, offYadvanceDev;
- };
- static uint16_t *
- getClassDefTable (FILE *ttf, int classdef_offset, struct ttfinfo *info)
- {
- int format, i, j;
- uint16_t start, glyphcnt, rangecnt, end, class;
- uint16_t *glist = NULL;
- int warned = false;
- int cnt = info->glyph_cnt;
- uint32_t g_bounds = info->g_bounds;
- fseek (ttf, classdef_offset, SEEK_SET);
- glist = xcalloc (cnt, sizeof (uint16_t)); /* Class 0 is default */
- format = getushort (ttf);
- if (format == 1)
- {
- start = getushort (ttf);
- glyphcnt = getushort (ttf);
- if (start + (int) glyphcnt > cnt)
- {
- LogError (_("Bad class def table. start=%d cnt=%d, max glyph=%d\n"),
- start, glyphcnt, cnt);
- info->bad_ot = true;
- glyphcnt = cnt - start;
- }
- else if (ftell (ttf) + 2 * glyphcnt > g_bounds)
- {
- LogError (_
- ("Class definition sub-table extends beyond end of table\n"));
- info->bad_ot = true;
- glyphcnt = (g_bounds - ftell (ttf)) / 2;
- }
- for (i = 0; i < glyphcnt; ++i)
- glist[start + i] = getushort (ttf);
- }
- else if (format == 2)
- {
- rangecnt = getushort (ttf);
- if (ftell (ttf) + 6 * rangecnt > g_bounds)
- {
- LogError (_
- ("Class definition sub-table extends beyond end of table\n"));
- info->bad_ot = true;
- rangecnt = (g_bounds - ftell (ttf)) / 6;
- }
- for (i = 0; i < rangecnt; ++i)
- {
- start = getushort (ttf);
- end = getushort (ttf);
- if (start > end || end >= cnt)
- {
- LogError (_("Bad class def table. "
- "Glyph range %d-%d out of range [0, %d)"),
- start, end, cnt);
- info->bad_ot = true;
- }
- class = getushort (ttf);
- for (j = start; j <= end; ++j)
- if (j < cnt)
- glist[j] = class;
- }
- }
- else
- {
- LogError (_("Unknown class table format: %d\n"), format);
- info->bad_ot = true;
- /* Put everything in class 0 and return that */
- }
- /* Do another validity test */
- for (i = 0; i < cnt; ++i)
- {
- if (glist[i] >= cnt + 1)
- {
- if (!warned)
- {
- LogError (_
- ("Nonsensical class assigned to a glyph-- class=%d is too big. Glyph=%d\n"),
- glist[i], i);
- info->bad_ot = true;
- warned = true;
- }
- glist[i] = 0;
- }
- }
- return glist;
- }
- static void
- readvaluerecord (struct valuerecord *vr, int vf, FILE *ttf)
- {
- memset (vr, '\0', sizeof (struct valuerecord));
- if (vf & 1)
- vr->xplacement = getushort (ttf);
- if (vf & 2)
- vr->yplacement = getushort (ttf);
- if (vf & 4)
- vr->xadvance = getushort (ttf);
- if (vf & 8)
- vr->yadvance = getushort (ttf);
- if (vf & 0x10)
- vr->offXplaceDev = getushort (ttf);
- if (vf & 0x20)
- vr->offYplaceDev = getushort (ttf);
- if (vf & 0x40)
- vr->offXadvanceDev = getushort (ttf);
- if (vf & 0x80)
- vr->offYadvanceDev = getushort (ttf);
- }
- static void
- ReadDeviceTable (FILE *ttf, DeviceTable *adjust, uint32_t devtab,
- struct ttfinfo *info)
- {
- long here;
- int pack;
- int w, b, i, c;
- if (devtab == 0)
- return;
- here = ftell (ttf);
- fseek (ttf, devtab, SEEK_SET);
- adjust->first_pixel_size = getushort (ttf);
- adjust->last_pixel_size = getushort (ttf);
- pack = getushort (ttf);
- if (adjust->first_pixel_size > adjust->last_pixel_size || pack == 0
- || pack > 3)
- {
- LogError (_("Bad device table\n"));
- info->bad_ot = true;
- adjust->first_pixel_size = adjust->last_pixel_size = 0;
- }
- else
- {
- c = adjust->last_pixel_size - adjust->first_pixel_size + 1;
- adjust->corrections = xmalloc (c);
- if (pack == 1)
- {
- for (i = 0; i < c; i += 8)
- {
- w = getushort (ttf);
- for (b = 0; b < 8 && i + b < c; ++b)
- adjust->corrections[i + b] =
- ((int16_t) ((w << (b * 2)) & 0xc000)) >> 14;
- }
- }
- else if (pack == 2)
- {
- for (i = 0; i < c; i += 4)
- {
- w = getushort (ttf);
- for (b = 0; b < 4 && i + b < c; ++b)
- adjust->corrections[i + b] =
- ((int16_t) ((w << (b * 4)) & 0xf000)) >> 12;
- }
- }
- else
- {
- for (i = 0; i < c; ++i)
- adjust->corrections[i] = (int8_t) getc (ttf);
- }
- }
- fseek (ttf, here, SEEK_SET);
- }
- static ValDevTab *
- readValDevTab (FILE *ttf, struct valuerecord *vr, uint32_t base,
- struct ttfinfo *info)
- {
- ValDevTab *ret;
- if (vr->offXplaceDev == 0 && vr->offYplaceDev == 0 &&
- vr->offXadvanceDev == 0 && vr->offYadvanceDev == 0)
- return NULL;
- ret = xzalloc (sizeof (ValDevTab));
- if (vr->offXplaceDev != 0)
- ReadDeviceTable (ttf, &ret->xadjust, base + vr->offXplaceDev, info);
- if (vr->offYplaceDev != 0)
- ReadDeviceTable (ttf, &ret->yadjust, base + vr->offYplaceDev, info);
- if (vr->offXadvanceDev != 0)
- ReadDeviceTable (ttf, &ret->xadv, base + vr->offXadvanceDev, info);
- if (vr->offYadvanceDev != 0)
- ReadDeviceTable (ttf, &ret->yadv, base + vr->offYadvanceDev, info);
- return ret;
- }
- static void
- addPairPos (struct ttfinfo *info, int glyph1, int glyph2,
- struct lookup *l, struct lookup_subtable *subtable,
- struct valuerecord *vr1, struct valuerecord *vr2, uint32_t base,
- FILE *ttf)
- {
- if (glyph1 < info->glyph_cnt && glyph2 < info->glyph_cnt &&
- info->chars[glyph1] != NULL && info->chars[glyph2] != NULL)
- {
- PST *pos = xzalloc (sizeof (PST));
- pos->type = pst_pair;
- pos->subtable = subtable;
- pos->next = info->chars[glyph1]->possub;
- info->chars[glyph1]->possub = pos;
- pos->u.pair.vr = xzalloc (sizeof (ValueRecord[2]));
- pos->u.pair.paired = xstrdup_or_null (info->chars[glyph2]->name);
- pos->u.pair.vr[0].xoff = vr1->xplacement;
- pos->u.pair.vr[0].yoff = vr1->yplacement;
- pos->u.pair.vr[0].h_adv_off = vr1->xadvance;
- pos->u.pair.vr[0].v_adv_off = vr1->yadvance;
- pos->u.pair.vr[1].xoff = vr2->xplacement;
- pos->u.pair.vr[1].yoff = vr2->yplacement;
- pos->u.pair.vr[1].h_adv_off = vr2->xadvance;
- pos->u.pair.vr[1].v_adv_off = vr2->yadvance;
- pos->u.pair.vr[0].adjust = readValDevTab (ttf, vr1, base, info);
- pos->u.pair.vr[1].adjust = readValDevTab (ttf, vr2, base, info);
- }
- else
- {
- LogError (_("Bad pair position: glyphs %d & %d should have been < %d\n"),
- glyph1, glyph2, info->glyph_cnt);
- info->bad_ot = true;
- }
- }
- static void
- gposKernSubTable (FILE *ttf, int stoffset, struct ttfinfo *info,
- struct lookup *l, struct lookup_subtable *subtable)
- {
- int coverage, cnt, pair_cnt, vf1, vf2, glyph2;
- int cd1, cd2, c1_cnt, c2_cnt;
- uint16_t format;
- uint16_t *ps_offsets;
- uint16_t *glyphs, *class1, *class2;
- struct valuerecord vr1, vr2;
- long foffset;
- format = getushort (ttf);
- if (format != 1 && format != 2) /* Unknown subtable format */
- return;
- coverage = getushort (ttf);
- vf1 = getushort (ttf);
- vf2 = getushort (ttf);
- if (format == 1)
- {
- subtable->per_glyph_pst_or_kern = true;
- cnt = getushort (ttf);
- ps_offsets = xmalloc (cnt * sizeof (uint16_t));
- for (int i = 0; i < cnt; ++i)
- ps_offsets[i] = getushort (ttf);
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- /* TRANSLATORS: This continues a multi-line error message, hence the leading space */
- LogError (_(" Bad pairwise kerning table, ignored\n"));
- return;
- }
- for (int i = 0; i < cnt; ++i)
- if (glyphs[i] < info->glyph_cnt)
- {
- fseek (ttf, stoffset + ps_offsets[i], SEEK_SET);
- pair_cnt = getushort (ttf);
- for (int j = 0; j < pair_cnt; ++j)
- {
- glyph2 = getushort (ttf);
- readvaluerecord (&vr1, vf1, ttf);
- readvaluerecord (&vr2, vf2, ttf);
- addPairPos (info, glyphs[i], glyph2, l, subtable, &vr1, &vr2,
- stoffset, ttf);
- }
- }
- free (ps_offsets);
- free (glyphs);
- }
- else if (format == 2)
- { /* Class-based kerning */
- cd1 = getushort (ttf);
- cd2 = getushort (ttf);
- foffset = ftell (ttf);
- class1 = getClassDefTable (ttf, stoffset + cd1, info);
- class2 = getClassDefTable (ttf, stoffset + cd2, info);
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- /* TRANSLATORS: This continues a multi-line error message, hence the leading space */
- LogError (_(" Bad kerning class table, ignored\n"));
- return;
- }
- fseek (ttf, foffset, SEEK_SET); /* come back */
- c1_cnt = getushort (ttf);
- c2_cnt = getushort (ttf);
- subtable->per_glyph_pst_or_kern = true;
- // TODO: read this as class kerning instead of expanding it as we do now.
- for (int i = 0; i < c1_cnt; ++i)
- {
- for (int j = 0; j < c2_cnt; ++j)
- {
- readvaluerecord (&vr1, vf1, ttf);
- readvaluerecord (&vr2, vf2, ttf);
- if (vr1.xadvance != 0 || vr1.xplacement != 0
- || vr1.yadvance != 0 || vr1.yplacement != 0
- || vr2.xadvance != 0 || vr2.xplacement != 0
- || vr2.yadvance != 0 || vr2.yplacement != 0)
- for (int k = 0; glyphs[k] != 0xffff; ++k)
- if (class1[glyphs[k]] == i)
- for (int m = 0; m < info->glyph_cnt; ++m)
- if (class2[m] == j)
- addPairPos (info, glyphs[k], m, l, subtable, &vr1, &vr2,
- stoffset, ttf);
- }
- }
- free (class1);
- free (class2);
- free (glyphs);
- }
- }
- static AnchorPoint *
- readAnchorPoint (FILE *ttf, uint32_t base, AnchorClass * class,
- enum anchor_type type, AnchorPoint *last, struct ttfinfo *info)
- {
- AnchorPoint *ap;
- int format;
- fseek (ttf, base, SEEK_SET);
- ap = xzalloc (sizeof (AnchorPoint));
- ap->anchor = class;
- /* All anchor types have the same initial 3 entries, format */
- /* x,y pos. format 2 contains a truetype positioning point, and */
- /* format==3 may also have device tables */
- format = getushort (ttf);
- ap->me.x = (int16_t) getushort (ttf);
- ap->me.y = (int16_t) getushort (ttf);
- ap->type = type;
- if (format == 2)
- {
- ap->ttf_pt_index = getushort (ttf);
- ap->has_ttf_pt = true;
- }
- else if (format == 3)
- {
- int devoff;
- devoff = getushort (ttf);
- if (devoff != 0)
- ReadDeviceTable (ttf, &ap->xadjust, base + devoff, info);
- devoff = getushort (ttf);
- if (devoff != 0)
- ReadDeviceTable (ttf, &ap->yadjust, base + devoff, info);
- }
- ap->next = last;
- return ap;
- }
- static void
- gposCursiveSubTable (FILE *ttf, int stoffset, struct ttfinfo *info,
- struct lookup *l, struct lookup_subtable *subtable)
- {
- int coverage, cnt, format, i;
- struct ee_offsets
- {
- int entry, exit;
- } *offsets;
- uint16_t *glyphs;
- AnchorClass *class;
- SplineChar *sc;
- char buf[50];
- format = getushort (ttf);
- if (format != 1) /* Unknown subtable format */
- return;
- coverage = getushort (ttf);
- cnt = getushort (ttf);
- if (cnt == 0)
- return;
- offsets = xmalloc (cnt * sizeof (struct ee_offsets));
- for (i = 0; i < cnt; ++i)
- {
- offsets[i].entry = getushort (ttf);
- offsets[i].exit = getushort (ttf);
- }
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- /* TRANSLATORS: This continues a multi-line error message, hence the leading space */
- LogError (_(" Bad cursive alignment table, ignored\n"));
- free (offsets);
- return;
- }
- class = xzalloc (sizeof (AnchorClass));
- snprintf (buf, sizeof (buf), _("Cursive-%d"), info->anchor_class_cnt++);
- class->name = xstrdup_or_null (buf);
- subtable->anchor_classes = true;
- class->subtable = subtable;
- if (info->ahead == NULL)
- info->ahead = class;
- else
- info->alast->next = class;
- info->alast = class;
- for (i = 0; i < cnt; ++i)
- {
- sc = info->chars[glyphs[i]];
- if (offsets[i].entry != 0)
- {
- sc->anchor = readAnchorPoint (ttf, stoffset + offsets[i].entry, class,
- at_centry, sc->anchor, info);
- }
- if (offsets[i].exit != 0)
- {
- sc->anchor = readAnchorPoint (ttf, stoffset + offsets[i].exit, class,
- at_cexit, sc->anchor, info);
- }
- }
- free (offsets);
- free (glyphs);
- }
- static AnchorClass **
- MarkGlyphsProcessMarks (FILE *ttf, int markoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, uint16_t *markglyphs,
- int classcnt)
- {
- AnchorClass **classes = xcalloc (classcnt, sizeof (AnchorClass *)), *ac;
- char buf[50];
- int i, cnt;
- struct mr
- {
- uint16_t class, offset;
- } *at_offsets;
- SplineChar *sc;
- for (i = 0; i < classcnt; ++i)
- {
- snprintf (buf, sizeof (buf), _("Anchor-%d"), info->anchor_class_cnt + i);
- classes[i] = ac = xzalloc (sizeof (AnchorClass));
- ac->name = xstrdup_or_null (buf);
- subtable->anchor_classes = true;
- ac->subtable = subtable;
- /*ac->merge_with = info->anchor_merge_cnt+1; */
- /* I don't distinguish between mark to base and mark to lig */
- if (info->ahead == NULL)
- info->ahead = ac;
- else
- info->alast->next = ac;
- info->alast = ac;
- }
- fseek (ttf, markoffset, SEEK_SET);
- cnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Bad mark table.\n"));
- info->bad_ot = true;
- return NULL;
- }
- at_offsets = xmalloc (cnt * sizeof (struct mr));
- for (i = 0; i < cnt; ++i)
- {
- at_offsets[i].class = getushort (ttf);
- at_offsets[i].offset = getushort (ttf);
- if (at_offsets[i].class >= classcnt)
- {
- at_offsets[i].class = 0;
- if (markglyphs[i] >= info->glyph_cnt)
- LogError (_("Class out of bounds in GPOS mark sub-table\n"));
- else
- LogError (_
- ("Class out of bounds in GPOS mark sub-table for mark %.30s\n"),
- info->chars[markglyphs[i]]->name);
- info->bad_ot = true;
- }
- }
- for (i = 0; i < cnt; ++i)
- {
- if (markglyphs[i] >= info->glyph_cnt)
- continue;
- sc = info->chars[markglyphs[i]];
- if (sc == NULL || at_offsets[i].offset == 0)
- continue;
- sc->anchor = readAnchorPoint (ttf, markoffset + at_offsets[i].offset,
- classes[at_offsets[i].class], at_mark,
- sc->anchor, info);
- }
- free (at_offsets);
- return classes;
- }
- static void
- MarkGlyphsProcessBases (FILE *ttf, int baseoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, uint16_t *baseglyphs,
- int classcnt, AnchorClass ** classes,
- enum anchor_type at)
- {
- int basecnt, i, j, ibase;
- uint16_t *offsets;
- SplineChar *sc;
- fseek (ttf, baseoffset, SEEK_SET);
- basecnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Bad base table.\n"));
- info->bad_ot = true;
- return;
- }
- offsets = xmalloc (basecnt * classcnt * sizeof (uint16_t));
- for (i = 0; i < basecnt * classcnt; ++i)
- offsets[i] = getushort (ttf);
- for (i = ibase = 0; i < basecnt; ++i, ibase += classcnt)
- {
- if (baseglyphs[i] >= info->glyph_cnt)
- continue;
- sc = info->chars[baseglyphs[i]];
- if (sc == NULL)
- continue;
- for (j = 0; j < classcnt; ++j)
- if (offsets[ibase + j] != 0)
- {
- sc->anchor = readAnchorPoint (ttf, baseoffset + offsets[ibase + j],
- classes[j], at, sc->anchor, info);
- }
- }
- free (offsets);
- }
- static void
- MarkGlyphsProcessLigs (FILE *ttf, int baseoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, uint16_t *baseglyphs,
- int classcnt, AnchorClass ** classes)
- {
- int basecnt, compcnt, i, j, k, kbase;
- uint16_t *loffsets, *aoffsets;
- SplineChar *sc;
- fseek (ttf, baseoffset, SEEK_SET);
- basecnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Bad ligature base table.\n"));
- info->bad_ot = true;
- return;
- }
- loffsets = xmalloc (basecnt * sizeof (uint16_t));
- for (i = 0; i < basecnt; ++i)
- loffsets[i] = getushort (ttf);
- for (i = 0; i < basecnt; ++i)
- {
- sc = info->chars[baseglyphs[i]];
- if (baseglyphs[i] >= info->glyph_cnt || sc == NULL)
- continue;
- fseek (ttf, baseoffset + loffsets[i], SEEK_SET);
- compcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Bad ligature anchor count.\n"));
- info->bad_ot = true;
- continue;
- }
- aoffsets = xmalloc (compcnt * classcnt * sizeof (uint16_t));
- for (k = 0; k < compcnt * classcnt; ++k)
- aoffsets[k] = getushort (ttf);
- for (k = kbase = 0; k < compcnt; ++k, kbase += classcnt)
- {
- for (j = 0; j < classcnt; ++j)
- if (aoffsets[kbase + j] != 0)
- {
- sc->anchor =
- readAnchorPoint (ttf,
- baseoffset + loffsets[i] + aoffsets[kbase +
- j],
- classes[j], at_baselig, sc->anchor, info);
- sc->anchor->lig_index = k;
- }
- }
- free (aoffsets);
- }
- free (loffsets);
- }
- static void
- gposMarkSubTable (FILE *ttf, uint32_t stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable)
- {
- int markcoverage, basecoverage, classcnt, markoffset, baseoffset;
- uint16_t *markglyphs, *baseglyphs;
- AnchorClass **classes;
- /* The header for the three different mark tables is the same */
- /* Type = */ getushort (ttf);
- markcoverage = getushort (ttf);
- basecoverage = getushort (ttf);
- classcnt = getushort (ttf);
- markoffset = getushort (ttf);
- baseoffset = getushort (ttf);
- markglyphs = getCoverageTable (ttf, stoffset + markcoverage, info);
- baseglyphs = getCoverageTable (ttf, stoffset + basecoverage, info);
- if (baseglyphs == NULL || markglyphs == NULL)
- {
- free (baseglyphs);
- free (markglyphs);
- LogError (_(" Bad mark attachment table, ignored\n"));
- return;
- }
- /* as is the (first) mark table */
- classes = MarkGlyphsProcessMarks (ttf, stoffset + markoffset,
- info, l, subtable, markglyphs, classcnt);
- if (classes == NULL)
- return;
- switch (l->otlookup->lookup_type)
- {
- case gpos_mark2base:
- case gpos_mark2mark:
- MarkGlyphsProcessBases (ttf, stoffset + baseoffset,
- info, l, subtable, baseglyphs, classcnt, classes,
- l->otlookup->lookup_type ==
- gpos_mark2base ? at_basechar : at_basemark);
- break;
- case gpos_mark2ligature:
- MarkGlyphsProcessLigs (ttf, stoffset + baseoffset,
- info, l, subtable, baseglyphs, classcnt, classes);
- break;
- }
- info->anchor_class_cnt += classcnt;
- ++info->anchor_merge_cnt;
- free (markglyphs);
- free (baseglyphs);
- free (classes);
- }
- static void
- gposSimplePos (FILE *ttf, int stoffset, struct ttfinfo *info,
- struct lookup *l, struct lookup_subtable *subtable)
- {
- int coverage, cnt, i, vf;
- uint16_t format;
- uint16_t *glyphs;
- struct valuerecord *vr = NULL, _vr, *which;
- format = getushort (ttf);
- if (format != 1 && format != 2) /* Unknown subtable format */
- return;
- coverage = getushort (ttf);
- vf = getushort (ttf);
- if (vf == 0)
- return;
- if (format == 1)
- {
- memset (&_vr, 0, sizeof (_vr));
- readvaluerecord (&_vr, vf, ttf);
- }
- else
- {
- cnt = getushort (ttf);
- vr = xcalloc (cnt, sizeof (struct valuerecord));
- for (i = 0; i < cnt; ++i)
- readvaluerecord (&vr[i], vf, ttf);
- }
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- free (vr);
- LogError (_(" Bad simple positioning table, ignored\n"));
- return;
- }
- for (i = 0; glyphs[i] != 0xffff; ++i)
- if (glyphs[i] < info->glyph_cnt && info->chars[glyphs[i]] != NULL)
- {
- PST *pos = xzalloc (sizeof (PST));
- pos->type = pst_position;
- pos->subtable = subtable;
- pos->next = info->chars[glyphs[i]]->possub;
- info->chars[glyphs[i]]->possub = pos;
- which = format == 1 ? &_vr : &vr[i];
- pos->u.pos.xoff = which->xplacement;
- pos->u.pos.yoff = which->yplacement;
- pos->u.pos.h_adv_off = which->xadvance;
- pos->u.pos.v_adv_off = which->yadvance;
- pos->u.pos.adjust = readValDevTab (ttf, which, stoffset, info);
- }
- subtable->per_glyph_pst_or_kern = true;
- free (vr);
- free (glyphs);
- }
- static void
- ProcessSubLookups (FILE *ttf, struct ttfinfo *info, int gpos,
- struct lookup *alllooks, struct seqlookup *sl)
- {
- int i;
- i = (intptr_t) sl->lookup;
- if (i < 0 || i >= info->lookup_cnt)
- {
- LogError (_
- ("Attempt to reference lookup %d (within a contextual lookup), but there are\n only %d lookups in %s\n"),
- i, info->lookup_cnt, gpos ? "'GPOS'" : "'GSUB'");
- info->bad_ot = true;
- sl->lookup = NULL;
- return;
- }
- sl->lookup = alllooks[i].otlookup;
- }
- static void
- g___ContextSubTable1 (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks, int gpos)
- {
- int i, j, k, rcnt, cnt;
- uint16_t coverage;
- uint16_t *glyphs;
- struct subrule
- {
- uint32_t offset;
- int gcnt;
- int scnt;
- uint16_t *glyphs;
- struct seqlookup *sl;
- };
- struct rule
- {
- uint32_t offsets;
- int scnt;
- struct subrule *subrules;
- } *rules;
- FPST *fpst;
- struct fpst_rule *rule;
- int warned = false, warned2 = false;
- coverage = getushort (ttf);
- rcnt = getushort (ttf); /* glyph count in coverage table */
- rules = xmalloc (rcnt * sizeof (struct rule));
- for (i = 0; i < rcnt; ++i)
- rules[i].offsets = getushort (ttf) + stoffset;
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- /* TRANSLATORS: This continues a multi-line error message, hence the leading space */
- LogError (_(" Bad contextual table, ignored\n"));
- return;
- }
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- {
- fseek (ttf, rules[i].offsets, SEEK_SET);
- rules[i].scnt = getushort (ttf);
- cnt += rules[i].scnt;
- rules[i].subrules = xmalloc (rules[i].scnt * sizeof (struct subrule));
- for (j = 0; j < rules[i].scnt; ++j)
- rules[i].subrules[j].offset = getushort (ttf) + rules[i].offsets;
- for (j = 0; j < rules[i].scnt; ++j)
- {
- fseek (ttf, rules[i].subrules[j].offset, SEEK_SET);
- rules[i].subrules[j].gcnt = getushort (ttf);
- rules[i].subrules[j].scnt = getushort (ttf);
- rules[i].subrules[j].glyphs =
- xmalloc ((rules[i].subrules[j].gcnt + 1) * sizeof (uint16_t));
- rules[i].subrules[j].glyphs[0] = glyphs[i];
- for (k = 1; k < rules[i].subrules[j].gcnt; ++k)
- {
- rules[i].subrules[j].glyphs[k] = getushort (ttf);
- if (rules[i].subrules[j].glyphs[k] >= info->glyph_cnt)
- {
- if (!warned)
- LogError (_("Bad contextual or chaining sub table. "
- "Glyph %d out of range [0, %d)"),
- rules[i].subrules[j].glyphs[k], info->glyph_cnt);
- info->bad_ot = true;
- warned = true;
- rules[i].subrules[j].glyphs[k] = 0;
- }
- }
- rules[i].subrules[j].glyphs[k] = 0xffff;
- rules[i].subrules[j].sl =
- xmalloc (rules[i].subrules[j].scnt * sizeof (struct seqlookup));
- for (k = 0; k < rules[i].subrules[j].scnt; ++k)
- {
- rules[i].subrules[j].sl[k].seq = getushort (ttf);
- if (rules[i].subrules[j].sl[k].seq >=
- rules[i].subrules[j].gcnt + 1)
- if (!warned2)
- {
- LogError (_
- ("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
- rules[i].subrules[j].sl[k].seq,
- rules[i].subrules[j].gcnt);
- info->bad_ot = true;
- warned2 = true;
- }
- rules[i].subrules[j].sl[k].lookup =
- (void *) (intptr_t) getushort (ttf);
- }
- }
- }
- if (justinuse == git_justinuse)
- {
- /* Nothing to do. This lookup doesn't really reference any glyphs */
- /* any lookups it invokes will be processed on their own */
- }
- else
- {
- fpst = xzalloc (sizeof (FPST));
- fpst->type = gpos ? pst_contextpos : pst_contextsub;
- fpst->format = pst_glyphs;
- fpst->subtable = subtable;
- fpst->next = info->possub;
- info->possub = fpst;
- subtable->fpst = fpst;
- fpst->rules = rule = xcalloc (cnt, sizeof (struct fpst_rule));
- fpst->rule_cnt = cnt;
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- for (j = 0; j < rules[i].scnt; ++j)
- {
- rule[cnt].u.glyph.names =
- GlyphsToNames (info, rules[i].subrules[j].glyphs, false);
- rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
- rule[cnt].lookups = rules[i].subrules[j].sl;
- rules[i].subrules[j].sl = NULL;
- for (k = 0; k < rule[cnt].lookup_cnt; ++k)
- ProcessSubLookups (ttf, info, gpos, alllooks,
- &rule[cnt].lookups[k]);
- ++cnt;
- }
- }
- for (i = 0; i < rcnt; ++i)
- {
- for (j = 0; j < rules[i].scnt; ++j)
- {
- free (rules[i].subrules[j].glyphs);
- free (rules[i].subrules[j].sl);
- }
- free (rules[i].subrules);
- }
- free (rules);
- free (glyphs);
- }
- static void
- g___ChainingSubTable1 (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks, int gpos)
- {
- int i, j, k, rcnt, cnt, which;
- uint16_t coverage;
- uint16_t *glyphs;
- struct subrule
- {
- uint32_t offset;
- int gcnt, bcnt, fcnt;
- int scnt;
- uint16_t *glyphs, *bglyphs, *fglyphs;
- struct seqlookup *sl;
- };
- struct rule
- {
- uint32_t offsets;
- int scnt;
- struct subrule *subrules;
- } *rules;
- FPST *fpst;
- struct fpst_rule *rule;
- int warned = false, warned2 = false;
- coverage = getushort (ttf);
- rcnt = getushort (ttf); /* glyph count in coverage table */
- rules = xmalloc (rcnt * sizeof (struct rule));
- for (i = 0; i < rcnt; ++i)
- rules[i].offsets = getushort (ttf) + stoffset;
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- free (rules);
- LogError (_(" Bad contextual chaining table, ignored\n"));
- return;
- }
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- {
- fseek (ttf, rules[i].offsets, SEEK_SET);
- rules[i].scnt = getushort (ttf);
- cnt += rules[i].scnt;
- rules[i].subrules = xmalloc (rules[i].scnt * sizeof (struct subrule));
- for (j = 0; j < rules[i].scnt; ++j)
- rules[i].subrules[j].offset = getushort (ttf) + rules[i].offsets;
- for (j = 0; j < rules[i].scnt; ++j)
- {
- fseek (ttf, rules[i].subrules[j].offset, SEEK_SET);
- rules[i].subrules[j].bcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_
- ("Unexpected end of file in contextual chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- rules[i].subrules[j].bglyphs =
- xmalloc ((rules[i].subrules[j].bcnt + 1) * sizeof (uint16_t));
- for (k = 0; k < rules[i].subrules[j].bcnt; ++k)
- rules[i].subrules[j].bglyphs[k] = getushort (ttf);
- rules[i].subrules[j].bglyphs[k] = 0xffff;
- rules[i].subrules[j].gcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_
- ("Unexpected end of file in contextual chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- rules[i].subrules[j].glyphs =
- xmalloc ((rules[i].subrules[j].gcnt + 1) * sizeof (uint16_t));
- rules[i].subrules[j].glyphs[0] = glyphs[i];
- for (k = 1; k < rules[i].subrules[j].gcnt; ++k)
- rules[i].subrules[j].glyphs[k] = getushort (ttf);
- rules[i].subrules[j].glyphs[k] = 0xffff;
- rules[i].subrules[j].fcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_
- ("Unexpected end of file in contextual chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- rules[i].subrules[j].fglyphs =
- xmalloc ((rules[i].subrules[j].fcnt + 1) * sizeof (uint16_t));
- for (k = 0; k < rules[i].subrules[j].fcnt; ++k)
- rules[i].subrules[j].fglyphs[k] = getushort (ttf);
- rules[i].subrules[j].fglyphs[k] = 0xffff;
- for (which = 0; which < 3; ++which)
- {
- for (k = 0; k < (&rules[i].subrules[j].gcnt)[which]; ++k)
- {
- if ((&rules[i].subrules[j].glyphs)[which][k] >=
- info->glyph_cnt)
- {
- if (!warned)
- LogError (_("Bad contextual or chaining sub table. "
- "Glyph %d out of range [0, %d)"),
- (&rules[i].subrules[j].glyphs)[which][k],
- info->glyph_cnt);
- info->bad_ot = true;
- warned = true;
- (&rules[i].subrules[j].glyphs)[which][k] = 0;
- }
- }
- }
- rules[i].subrules[j].scnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_
- ("Unexpected end of file in contextual chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- rules[i].subrules[j].sl =
- xmalloc (rules[i].subrules[j].scnt * sizeof (struct seqlookup));
- for (k = 0; k < rules[i].subrules[j].scnt; ++k)
- {
- rules[i].subrules[j].sl[k].seq = getushort (ttf);
- if (rules[i].subrules[j].sl[k].seq >=
- rules[i].subrules[j].gcnt + 1)
- if (!warned2)
- {
- LogError (_
- ("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
- rules[i].subrules[j].sl[k].seq,
- rules[i].subrules[j].gcnt);
- info->bad_ot = true;
- warned2 = true;
- }
- rules[i].subrules[j].sl[k].lookup =
- (void *) (intptr_t) getushort (ttf);
- }
- }
- }
- if (justinuse == git_justinuse)
- {
- /* Nothing to do. This lookup doesn't really reference any glyphs */
- /* any lookups it invokes will be processed on their own */
- }
- else
- {
- fpst = xzalloc (sizeof (FPST));
- fpst->type = gpos ? pst_chainpos : pst_chainsub;
- fpst->format = pst_glyphs;
- fpst->subtable = subtable;
- fpst->next = info->possub;
- info->possub = fpst;
- subtable->fpst = fpst;
- fpst->rules = rule = xcalloc (cnt, sizeof (struct fpst_rule));
- fpst->rule_cnt = cnt;
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- for (j = 0; j < rules[i].scnt; ++j)
- {
- rule[cnt].u.glyph.back =
- GlyphsToNames (info, rules[i].subrules[j].bglyphs, false);
- rule[cnt].u.glyph.names =
- GlyphsToNames (info, rules[i].subrules[j].glyphs, false);
- rule[cnt].u.glyph.fore =
- GlyphsToNames (info, rules[i].subrules[j].fglyphs, false);
- rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
- rule[cnt].lookups = rules[i].subrules[j].sl;
- rules[i].subrules[j].sl = NULL;
- for (k = 0; k < rule[cnt].lookup_cnt; ++k)
- ProcessSubLookups (ttf, info, gpos, alllooks,
- &rule[cnt].lookups[k]);
- ++cnt;
- }
- }
- for (i = 0; i < rcnt; ++i)
- {
- for (j = 0; j < rules[i].scnt; ++j)
- {
- free (rules[i].subrules[j].bglyphs);
- free (rules[i].subrules[j].glyphs);
- free (rules[i].subrules[j].fglyphs);
- free (rules[i].subrules[j].sl);
- }
- free (rules[i].subrules);
- }
- free (rules);
- free (glyphs);
- }
- static void
- g___ContextSubTable2 (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks, int gpos)
- {
- int i, j, k, rcnt, cnt;
- uint16_t coverage;
- uint16_t classoff;
- struct subrule
- {
- uint32_t offset;
- int ccnt;
- int scnt;
- uint16_t *classindeces;
- struct seqlookup *sl;
- };
- struct rule
- {
- uint32_t offsets;
- int scnt;
- struct subrule *subrules;
- } *rules;
- FPST *fpst;
- struct fpst_rule *rule;
- uint16_t *glyphs, *class;
- int warned2 = false;
- coverage = getushort (ttf);
- classoff = getushort (ttf);
- rcnt = getushort (ttf); /* class count in coverage table *//* == number of top level rules */
- rules = xcalloc (rcnt, sizeof (struct rule));
- for (i = 0; i < rcnt; ++i)
- rules[i].offsets = getushort (ttf) + stoffset;
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- if (rules[i].offsets != stoffset)
- { /* some classes might be unused */
- fseek (ttf, rules[i].offsets, SEEK_SET);
- rules[i].scnt = getushort (ttf);
- if (rules[i].scnt < 0)
- {
- LogError (_("Bad count in context chaining sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- cnt += rules[i].scnt;
- rules[i].subrules = xmalloc (rules[i].scnt * sizeof (struct subrule));
- for (j = 0; j < rules[i].scnt; ++j)
- rules[i].subrules[j].offset = getushort (ttf) + rules[i].offsets;
- for (j = 0; j < rules[i].scnt; ++j)
- {
- fseek (ttf, rules[i].subrules[j].offset, SEEK_SET);
- rules[i].subrules[j].ccnt = getushort (ttf);
- rules[i].subrules[j].scnt = getushort (ttf);
- if (rules[i].subrules[j].ccnt < 0)
- {
- LogError (_
- ("Bad class count in contextual chaining sub-table.\n"));
- info->bad_ot = true;
- free (rules);
- return;
- }
- rules[i].subrules[j].classindeces =
- xmalloc (rules[i].subrules[j].ccnt * sizeof (uint16_t));
- rules[i].subrules[j].classindeces[0] = i;
- for (k = 1; k < rules[i].subrules[j].ccnt; ++k)
- rules[i].subrules[j].classindeces[k] = getushort (ttf);
- if (rules[i].subrules[j].scnt < 0)
- {
- LogError (_("Bad count in contextual chaining sub-table.\n"));
- info->bad_ot = true;
- free (rules);
- return;
- }
- rules[i].subrules[j].sl =
- xmalloc (rules[i].subrules[j].scnt * sizeof (struct seqlookup));
- for (k = 0; k < rules[i].subrules[j].scnt; ++k)
- {
- rules[i].subrules[j].sl[k].seq = getushort (ttf);
- if (rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].ccnt)
- if (!warned2)
- {
- LogError (_
- ("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
- rules[i].subrules[j].sl[k].seq,
- rules[i].subrules[j].ccnt - 1);
- info->bad_ot = true;
- warned2 = true;
- }
- rules[i].subrules[j].sl[k].lookup =
- (void *) (intptr_t) getushort (ttf);
- }
- }
- }
- if (justinuse == git_justinuse)
- {
- /* Nothing to do. This lookup doesn't really reference any glyphs */
- /* any lookups it invokes will be processed on their own */
- }
- else
- {
- fpst = xzalloc (sizeof (FPST));
- fpst->type = gpos ? pst_contextpos : pst_contextsub;
- fpst->format = pst_class;
- fpst->subtable = subtable;
- subtable->fpst = fpst;
- fpst->next = info->possub;
- info->possub = fpst;
- fpst->rules = rule = xcalloc (cnt, sizeof (struct fpst_rule));
- fpst->rule_cnt = cnt;
- class = getClassDefTable (ttf, stoffset + classoff, info);
- fpst->nccnt = ClassFindCnt (class, info->glyph_cnt);
- fpst->nclass = ClassToNames (info, fpst->nccnt, class, info->glyph_cnt);
- fpst->nclassnames = xcalloc (fpst->nccnt, sizeof (char *));
- /* Just in case they used the coverage table to redefine class 0 */
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- /* TRANSLATORS: This continues a multi-line error message, hence the leading space */
- LogError (_(" Bad contextual substitution table, ignored\n"));
- return;
- }
- fpst->nclass[0] = CoverageMinusClasses (glyphs, class, info);
- free (glyphs);
- free (class);
- class = NULL;
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- for (j = 0; j < rules[i].scnt; ++j)
- {
- rule[cnt].u.class.nclasses = rules[i].subrules[j].classindeces;
- rule[cnt].u.class.ncnt = rules[i].subrules[j].ccnt;
- rules[i].subrules[j].classindeces = NULL;
- rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
- rule[cnt].lookups = rules[i].subrules[j].sl;
- rules[i].subrules[j].sl = NULL;
- for (k = 0; k < rule[cnt].lookup_cnt; ++k)
- ProcessSubLookups (ttf, info, gpos, alllooks,
- &rule[cnt].lookups[k]);
- ++cnt;
- }
- }
- for (i = 0; i < rcnt; ++i)
- {
- for (j = 0; j < rules[i].scnt; ++j)
- {
- free (rules[i].subrules[j].classindeces);
- free (rules[i].subrules[j].sl);
- }
- free (rules[i].subrules);
- }
- free (rules);
- }
- static void
- g___ChainingSubTable2 (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks, int gpos)
- {
- int i, j, k, rcnt, cnt;
- uint16_t coverage, offset;
- uint16_t bclassoff, classoff, fclassoff;
- struct subrule
- {
- uint32_t offset;
- int ccnt, bccnt, fccnt;
- int scnt;
- uint16_t *classindeces, *bci, *fci;
- struct seqlookup *sl;
- };
- struct rule
- {
- uint32_t offsets;
- int scnt;
- struct subrule *subrules;
- } *rules;
- FPST *fpst;
- struct fpst_rule *rule;
- uint16_t *glyphs, *class;
- int warned2 = false;
- coverage = getushort (ttf);
- bclassoff = getushort (ttf);
- classoff = getushort (ttf);
- fclassoff = getushort (ttf);
- rcnt = getushort (ttf); /* class count *//* == max number of top level rules */
- rules = xcalloc (rcnt, sizeof (struct rule));
- for (i = 0; i < rcnt; ++i)
- {
- offset = getushort (ttf);
- rules[i].offsets = offset == 0 ? 0 : offset + stoffset;
- }
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- if (rules[i].offsets != 0)
- { /* some classes might be unused */
- fseek (ttf, rules[i].offsets, SEEK_SET);
- rules[i].scnt = getushort (ttf);
- if (rules[i].scnt < 0)
- {
- LogError (_("Bad count in context chaining sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- cnt += rules[i].scnt;
- rules[i].subrules = xmalloc (rules[i].scnt * sizeof (struct subrule));
- for (j = 0; j < rules[i].scnt; ++j)
- rules[i].subrules[j].offset = getushort (ttf) + rules[i].offsets;
- for (j = 0; j < rules[i].scnt; ++j)
- {
- fseek (ttf, rules[i].subrules[j].offset, SEEK_SET);
- rules[i].subrules[j].bccnt = getushort (ttf);
- if (rules[i].subrules[j].bccnt < 0)
- {
- LogError (_
- ("Bad class count in contextual chaining sub-table.\n"));
- info->bad_ot = true;
- free (rules);
- return;
- }
- rules[i].subrules[j].bci =
- xmalloc (rules[i].subrules[j].bccnt * sizeof (uint16_t));
- for (k = 0; k < rules[i].subrules[j].bccnt; ++k)
- rules[i].subrules[j].bci[k] = getushort (ttf);
- rules[i].subrules[j].ccnt = getushort (ttf);
- if (rules[i].subrules[j].ccnt < 0)
- {
- LogError (_
- ("Bad class count in contextual chaining sub-table.\n"));
- info->bad_ot = true;
- free (rules);
- return;
- }
- rules[i].subrules[j].classindeces =
- xmalloc (rules[i].subrules[j].ccnt * sizeof (uint16_t));
- rules[i].subrules[j].classindeces[0] = i;
- for (k = 1; k < rules[i].subrules[j].ccnt; ++k)
- rules[i].subrules[j].classindeces[k] = getushort (ttf);
- rules[i].subrules[j].fccnt = getushort (ttf);
- if (rules[i].subrules[j].fccnt < 0)
- {
- LogError (_
- ("Bad class count in contextual chaining sub-table.\n"));
- info->bad_ot = true;
- free (rules);
- return;
- }
- rules[i].subrules[j].fci =
- xmalloc (rules[i].subrules[j].fccnt * sizeof (uint16_t));
- for (k = 0; k < rules[i].subrules[j].fccnt; ++k)
- rules[i].subrules[j].fci[k] = getushort (ttf);
- rules[i].subrules[j].scnt = getushort (ttf);
- if (rules[i].subrules[j].scnt < 0)
- {
- LogError (_("Bad count in contextual chaining sub-table.\n"));
- info->bad_ot = true;
- free (rules);
- return;
- }
- rules[i].subrules[j].sl =
- xmalloc (rules[i].subrules[j].scnt * sizeof (struct seqlookup));
- for (k = 0; k < rules[i].subrules[j].scnt; ++k)
- {
- rules[i].subrules[j].sl[k].seq = getushort (ttf);
- if (rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].ccnt)
- if (!warned2)
- {
- LogError (_
- ("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
- rules[i].subrules[j].sl[k].seq,
- rules[i].subrules[j].ccnt - 1);
- info->bad_ot = true;
- warned2 = true;
- }
- rules[i].subrules[j].sl[k].lookup =
- (void *) (intptr_t) getushort (ttf);
- }
- }
- }
- if (justinuse == git_justinuse)
- {
- /* Nothing to do. This lookup doesn't really reference any glyphs */
- /* any lookups it invokes will be processed on their own */
- }
- else
- {
- fpst = xzalloc (sizeof (FPST));
- fpst->type = gpos ? pst_chainpos : pst_chainsub;
- fpst->format = pst_class;
- fpst->subtable = subtable;
- subtable->fpst = fpst;
- fpst->next = info->possub;
- info->possub = fpst;
- fpst->rules = rule = xcalloc (cnt, sizeof (struct fpst_rule));
- fpst->rule_cnt = cnt;
- class = getClassDefTable (ttf, stoffset + classoff, info);
- fpst->nccnt = ClassFindCnt (class, info->glyph_cnt);
- fpst->nclass = ClassToNames (info, fpst->nccnt, class, info->glyph_cnt);
- fpst->nclassnames = xcalloc (fpst->nccnt, sizeof (char *));
- /* Just in case they used the coverage table to redefine class 0 */
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- /* TRANSLATORS: This continues a multi-line error message, hence the leading space */
- LogError (_
- (" Bad contextual chaining substitution table, ignored\n"));
- return;
- }
- fpst->nclass[0] = CoverageMinusClasses (glyphs, class, info);
- free (glyphs);
- free (class);
- class = NULL;
- /* The docs don't mention this, but in mangal.ttf fclassoff==0 NULL */
- if (bclassoff != 0)
- class = getClassDefTable (ttf, stoffset + bclassoff, info);
- else
- class = xcalloc (info->glyph_cnt, sizeof (uint16_t));
- fpst->bccnt = ClassFindCnt (class, info->glyph_cnt);
- fpst->bclass = ClassToNames (info, fpst->bccnt, class, info->glyph_cnt);
- fpst->bclassnames = xcalloc (fpst->bccnt, sizeof (char *));
- free (class);
- if (fclassoff != 0)
- class = getClassDefTable (ttf, stoffset + fclassoff, info);
- else
- class = xcalloc (info->glyph_cnt, sizeof (uint16_t));
- fpst->fccnt = ClassFindCnt (class, info->glyph_cnt);
- fpst->fclass = ClassToNames (info, fpst->fccnt, class, info->glyph_cnt);
- fpst->fclassnames = xcalloc (fpst->fccnt, sizeof (char *));
- free (class);
- cnt = 0;
- for (i = 0; i < rcnt; ++i)
- for (j = 0; j < rules[i].scnt; ++j)
- {
- rule[cnt].u.class.nclasses = rules[i].subrules[j].classindeces;
- rule[cnt].u.class.ncnt = rules[i].subrules[j].ccnt;
- rules[i].subrules[j].classindeces = NULL;
- rule[cnt].u.class.bclasses = rules[i].subrules[j].bci;
- rule[cnt].u.class.bcnt = rules[i].subrules[j].bccnt;
- rules[i].subrules[j].bci = NULL;
- rule[cnt].u.class.fclasses = rules[i].subrules[j].fci;
- rule[cnt].u.class.fcnt = rules[i].subrules[j].fccnt;
- rules[i].subrules[j].fci = NULL;
- rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
- rule[cnt].lookups = rules[i].subrules[j].sl;
- rules[i].subrules[j].sl = NULL;
- for (k = 0; k < rule[cnt].lookup_cnt; ++k)
- ProcessSubLookups (ttf, info, gpos, alllooks,
- &rule[cnt].lookups[k]);
- ++cnt;
- }
- }
- for (i = 0; i < rcnt; ++i)
- {
- for (j = 0; j < rules[i].scnt; ++j)
- {
- free (rules[i].subrules[j].classindeces);
- free (rules[i].subrules[j].sl);
- }
- free (rules[i].subrules);
- }
- free (rules);
- }
- static void
- g___ContextSubTable3 (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks, int gpos)
- {
- int i, k, scnt, gcnt;
- uint16_t *coverage;
- struct seqlookup *sl;
- uint16_t *glyphs;
- FPST *fpst;
- struct fpst_rule *rule;
- int warned2 = false;
- gcnt = getushort (ttf);
- scnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file in context chaining sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- coverage = xmalloc (gcnt * sizeof (uint16_t));
- for (i = 0; i < gcnt; ++i)
- coverage[i] = getushort (ttf);
- sl = xmalloc (scnt * sizeof (struct seqlookup));
- for (k = 0; k < scnt; ++k)
- {
- sl[k].seq = getushort (ttf);
- if (sl[k].seq >= gcnt && !warned2)
- {
- LogError (_
- ("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d, max=%d\n"),
- sl[k].seq, gcnt - 1);
- info->bad_ot = true;
- warned2 = true;
- }
- sl[k].lookup = (void *) (intptr_t) getushort (ttf);
- }
- if (justinuse == git_justinuse)
- {
- /* Nothing to do. This lookup doesn't really reference any glyphs */
- /* any lookups it invokes will be processed on their own */
- }
- else
- {
- fpst = xzalloc (sizeof (FPST));
- fpst->type = gpos ? pst_contextpos : pst_contextsub;
- fpst->format = pst_coverage;
- fpst->subtable = subtable;
- subtable->fpst = fpst;
- fpst->next = info->possub;
- info->possub = fpst;
- fpst->rules = rule = xcalloc (1, sizeof (struct fpst_rule));
- fpst->rule_cnt = 1;
- rule->u.coverage.ncnt = gcnt;
- rule->u.coverage.ncovers = xmalloc (gcnt * sizeof (char **));
- for (i = 0; i < gcnt; ++i)
- {
- glyphs = getCoverageTable (ttf, stoffset + coverage[i], info);
- rule->u.coverage.ncovers[i] = GlyphsToNames (info, glyphs, true);
- free (glyphs);
- }
- rule->lookup_cnt = scnt;
- rule->lookups = sl;
- for (k = 0; k < scnt; ++k)
- ProcessSubLookups (ttf, info, gpos, alllooks, &sl[k]);
- }
- free (coverage);
- }
- static void
- g___ChainingSubTable3 (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks, int gpos)
- {
- int i, k, scnt, gcnt, bcnt, fcnt;
- uint16_t *coverage, *bcoverage, *fcoverage;
- struct seqlookup *sl;
- uint16_t *glyphs;
- FPST *fpst;
- struct fpst_rule *rule;
- int warned2 = false;
- bcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file in context chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- bcoverage = xmalloc (bcnt * sizeof (uint16_t));
- for (i = 0; i < bcnt; ++i)
- bcoverage[i] = getushort (ttf);
- gcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file in context chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- coverage = xmalloc (gcnt * sizeof (uint16_t));
- for (i = 0; i < gcnt; ++i)
- coverage[i] = getushort (ttf);
- fcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file in context chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- fcoverage = xmalloc (fcnt * sizeof (uint16_t));
- for (i = 0; i < fcnt; ++i)
- fcoverage[i] = getushort (ttf);
- scnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file in context chaining subtable.\n"));
- info->bad_ot = true;
- return;
- }
- sl = xmalloc (scnt * sizeof (struct seqlookup));
- for (k = 0; k < scnt; ++k)
- {
- sl[k].seq = getushort (ttf);
- if (sl[k].seq >= gcnt && !warned2)
- {
- LogError (_
- ("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d, max=%d\n"),
- sl[k].seq, gcnt - 1);
- info->bad_ot = true;
- warned2 = true;
- }
- sl[k].lookup = (void *) (intptr_t) getushort (ttf);
- }
- if (justinuse == git_justinuse)
- {
- /* Nothing to do. This lookup doesn't really reference any glyphs */
- /* any lookups it invokes will be processed on their own */
- }
- else
- {
- fpst = xzalloc (sizeof (FPST));
- fpst->type = gpos ? pst_chainpos : pst_chainsub;
- fpst->format = pst_coverage;
- fpst->subtable = subtable;
- subtable->fpst = fpst;
- fpst->next = info->possub;
- info->possub = fpst;
- fpst->rules = rule = xcalloc (1, sizeof (struct fpst_rule));
- fpst->rule_cnt = 1;
- rule->u.coverage.bcnt = bcnt;
- rule->u.coverage.bcovers = xmalloc (bcnt * sizeof (char **));
- for (i = 0; i < bcnt; ++i)
- {
- glyphs = getCoverageTable (ttf, stoffset + bcoverage[i], info);
- rule->u.coverage.bcovers[i] = GlyphsToNames (info, glyphs, true);
- free (glyphs);
- }
- rule->u.coverage.ncnt = gcnt;
- rule->u.coverage.ncovers = xmalloc (gcnt * sizeof (char **));
- for (i = 0; i < gcnt; ++i)
- {
- glyphs = getCoverageTable (ttf, stoffset + coverage[i], info);
- rule->u.coverage.ncovers[i] = GlyphsToNames (info, glyphs, true);
- free (glyphs);
- }
- rule->u.coverage.fcnt = fcnt;
- rule->u.coverage.fcovers = xmalloc (fcnt * sizeof (char **));
- for (i = 0; i < fcnt; ++i)
- {
- glyphs = getCoverageTable (ttf, stoffset + fcoverage[i], info);
- rule->u.coverage.fcovers[i] = GlyphsToNames (info, glyphs, true);
- free (glyphs);
- }
- rule->lookup_cnt = scnt;
- rule->lookups = sl;
- for (k = 0; k < scnt; ++k)
- ProcessSubLookups (ttf, info, gpos, alllooks, &sl[k]);
- }
- free (bcoverage);
- free (coverage);
- free (fcoverage);
- }
- static void
- gposContextSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, struct lookup *alllooks)
- {
- switch (getushort (ttf))
- {
- case 1:
- g___ContextSubTable1 (ttf, stoffset, info, l, subtable, git_normal,
- alllooks, true);
- break;
- case 2:
- g___ContextSubTable2 (ttf, stoffset, info, l, subtable, git_normal,
- alllooks, true);
- break;
- case 3:
- g___ContextSubTable3 (ttf, stoffset, info, l, subtable, git_normal,
- alllooks, true);
- break;
- }
- }
- static void
- gposChainingSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, struct lookup *alllooks)
- {
- switch (getushort (ttf))
- {
- case 1:
- g___ChainingSubTable1 (ttf, stoffset, info, l, subtable, git_normal,
- alllooks, true);
- break;
- case 2:
- g___ChainingSubTable2 (ttf, stoffset, info, l, subtable, git_normal,
- alllooks, true);
- break;
- case 3:
- g___ChainingSubTable3 (ttf, stoffset, info, l, subtable, git_normal,
- alllooks, true);
- break;
- }
- }
- static struct
- {
- uint32_t tag;
- char *str;
- } tagstr[] =
- {
- {
- CHR ('v', 'r', 't', '2'), "vert"},
- {
- CHR ('s', 'm', 'c', 'p'), "sc"},
- {
- CHR ('s', 'm', 'c', 'p'), "small"},
- {
- CHR ('o', 'n', 'u', 'm'), "oldstyle"},
- {
- CHR ('s', 'u', 'p', 's'), "superior"},
- {
- CHR ('s', 'u', 'b', 's'), "inferior"},
- {
- CHR ('s', 'w', 's', 'h'), "swash"},
- {
- 0, NULL}
- };
- static bool
- glyphNameExists (struct ttfinfo *info, char *name)
- {
- for (int i = 0; i < info->glyph_cnt; ++i)
- if (info->chars[i] != NULL && info->chars[i]->name != NULL)
- if (strcmp (info->chars[i]->name, name) == 0)
- return true;
- return false;
- }
- static void
- gsubSimpleSubTable (FILE *ttf, int stoffset, struct ttfinfo *info,
- struct lookup *l, struct lookup_subtable *subtable,
- int justinuse)
- {
- int coverage, cnt, i, j, which;
- uint16_t format;
- uint16_t *glyphs, *glyph2s = NULL;
- int delta = 0;
- format = getushort (ttf);
- if (format != 1 && format != 2) /* Unknown subtable format */
- return;
- coverage = getushort (ttf);
- if (format == 1)
- {
- delta = getushort (ttf);
- }
- else
- {
- cnt = getushort (ttf);
- glyph2s = xmalloc (cnt * sizeof (uint16_t));
- for (i = 0; i < cnt; ++i)
- glyph2s[i] = getushort (ttf);
- /* in range check comes later */
- }
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- free (glyph2s);
- LogError (_("Bad simple substitution table, ignored\n"));
- return;
- }
- if (justinuse == git_findnames)
- {
- FeatureScriptLangList *fl;
- fl = l->otlookup->features;
- /* Unnamed glyphs get a name built of the base name and the feature tag */
- /* assuming this lookup is tagged with a feature... */
- if (fl != NULL)
- for (i = 0; glyphs[i] != 0xffff; ++i)
- if (glyphs[i] < info->glyph_cnt)
- {
- if (info->chars[glyphs[i]]->name != NULL)
- {
- which =
- format == 1 ? (uint16_t) (glyphs[i] + delta) : glyph2s[i];
- if (which < info->glyph_cnt && which >= 0
- && info->chars[which] != NULL
- && info->chars[which]->name == NULL)
- {
- char *basename = info->chars[glyphs[i]]->name;
- char *str;
- char tag[5], *pt = tag;
- for (j = 0;
- tagstr[j].tag != 0
- && tagstr[j].tag != fl->featuretag; ++j);
- if (tagstr[j].tag != 0)
- pt = tagstr[j].str;
- else
- {
- tag[0] = fl->featuretag >> 24;
- if ((tag[1] = (fl->featuretag >> 16) & 0xff) == ' ')
- tag[1] = '\0';
- if ((tag[2] = (fl->featuretag >> 8) & 0xff) == ' ')
- tag[2] = '\0';
- if ((tag[3] = (fl->featuretag) & 0xff) == ' ')
- tag[3] = '\0';
- tag[4] = '\0';
- pt = tag;
- }
- str = xmalloc (strlen (basename) + strlen (pt) + 2);
- sprintf (str, "%s.%s", basename, pt);
- if (!glyphNameExists (info, str))
- info->chars[which]->name = str;
- }
- }
- }
- }
- else if (justinuse == git_justinuse)
- {
- for (i = 0; glyphs[i] != 0xffff; ++i)
- if (glyphs[i] < info->glyph_cnt)
- {
- info->inuse[glyphs[i]] = true;
- which = format == 1 ? (uint16_t) (glyphs[i] + delta) : glyph2s[i];
- info->inuse[which] = true;
- }
- }
- else if (justinuse == git_normal)
- {
- for (i = 0; glyphs[i] != 0xffff; ++i)
- if (glyphs[i] < info->glyph_cnt && info->chars[glyphs[i]] != NULL)
- {
- which = format == 1 ? (uint16_t) (glyphs[i] + delta) : glyph2s[i];
- if (which >= info->glyph_cnt)
- {
- LogError (_("Bad substitution table. "
- "Glyph %d out of range [0, %d)"),
- which, info->glyph_cnt);
- info->bad_ot = true;
- which = 0;
- }
- if (info->chars[which] != NULL && info->chars[glyphs[i]] != NULL)
- {
- /* Might be in a ttc file */
- PST *pos = xzalloc (sizeof (PST));
- pos->type = pst_substitution;
- pos->subtable = subtable;
- pos->next = info->chars[glyphs[i]]->possub;
- info->chars[glyphs[i]]->possub = pos;
- pos->u.subs.variant =
- xstrdup_or_null (info->chars[which]->name);
- }
- }
- }
- subtable->per_glyph_pst_or_kern = true;
- free (glyph2s);
- free (glyphs);
- }
- /* Multiple and alternate substitution lookups have the same format */
- static void
- gsubMultipleSubTable (FILE *ttf, int stoffset, struct ttfinfo *info,
- struct lookup *l, struct lookup_subtable *subtable,
- int justinuse)
- {
- int coverage, cnt, i, j, len, max;
- uint16_t format;
- uint16_t *offsets;
- uint16_t *glyphs, *glyph2s;
- char *pt;
- int bad;
- int badcnt = 0;
- if (justinuse == git_findnames)
- return;
- format = getushort (ttf);
- if (format != 1) /* Unknown subtable format */
- return;
- coverage = getushort (ttf);
- cnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Unexpected end of file in GSUB sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- offsets = xmalloc (cnt * sizeof (uint16_t));
- for (i = 0; i < cnt; ++i)
- offsets[i] = getushort (ttf);
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- free (offsets);
- LogError (_("Bad multiple substitution table, ignored\n"));
- return;
- }
- for (i = 0; glyphs[i] != 0xffff; ++i);
- if (i != cnt)
- {
- LogError (_
- ("Coverage table specifies a different number of glyphs than the sub-table expects.\n"));
- info->bad_ot = true;
- if (cnt < i)
- glyphs[cnt] = 0xffff;
- else
- cnt = i;
- }
- max = 20;
- glyph2s = xmalloc (max * sizeof (uint16_t));
- for (i = 0; glyphs[i] != 0xffff; ++i)
- {
- PST *alt;
- fseek (ttf, stoffset + offsets[i], SEEK_SET);
- cnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Unexpected end of file in GSUB sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- if (cnt > max)
- {
- max = cnt + 30;
- glyph2s = xrealloc (glyph2s, max * sizeof (uint16_t));
- }
- len = 0;
- bad = false;
- for (j = 0; j < cnt; ++j)
- {
- glyph2s[j] = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Unexpected end of file in GSUB sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- if (glyph2s[j] >= info->glyph_cnt)
- {
- if (!justinuse)
- LogError (_("Bad Multiple/Alternate substitution glyph. "
- "Glyph %d out of range [0, %d)"),
- glyph2s[j], info->glyph_cnt);
- info->bad_ot = true;
- if (++badcnt > 20)
- return;
- glyph2s[j] = 0;
- }
- if (justinuse == git_justinuse)
- /* Do Nothing */ ;
- else if (info->chars[glyph2s[j]] == NULL)
- bad = true;
- else
- len += strlen (info->chars[glyph2s[j]]->name) + 1;
- }
- if (justinuse == git_justinuse)
- {
- info->inuse[glyphs[i]] = 1;
- for (j = 0; j < cnt; ++j)
- info->inuse[glyph2s[j]] = 1;
- }
- else if (info->chars[glyphs[i]] != NULL && !bad)
- {
- alt = xzalloc (sizeof (PST));
- alt->type =
- l->otlookup->lookup_type ==
- gsub_multiple ? pst_multiple : pst_alternate;
- alt->subtable = subtable;
- alt->next = info->chars[glyphs[i]]->possub;
- info->chars[glyphs[i]]->possub = alt;
- pt = alt->u.subs.variant = xmalloc (len + 1);
- *pt = '\0';
- for (j = 0; j < cnt; ++j)
- {
- strcat (pt, info->chars[glyph2s[j]]->name);
- strcat (pt, " ");
- }
- if (*pt != '\0' && pt[strlen (pt) - 1] == ' ')
- pt[strlen (pt) - 1] = '\0';
- }
- }
- subtable->per_glyph_pst_or_kern = true;
- free (glyphs);
- free (glyph2s);
- free (offsets);
- }
- static void
- gsubLigatureSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse)
- {
- int coverage, cnt, i, j, k, lig_cnt, cc, len;
- uint16_t *ls_offsets, *lig_offsets;
- uint16_t *glyphs, *lig_glyphs, lig;
- char *pt;
- PST *liga;
- /* Format = */ getushort (ttf);
- coverage = getushort (ttf);
- cnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Unexpected end of file in GSUB ligature sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- ls_offsets = xmalloc (cnt * sizeof (uint16_t));
- for (i = 0; i < cnt; ++i)
- ls_offsets[i] = getushort (ttf);
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- if (glyphs == NULL)
- {
- LogError (_("Bad ligature table, ignored\n"));
- return;
- }
- for (i = 0; i < cnt; ++i)
- {
- fseek (ttf, stoffset + ls_offsets[i], SEEK_SET);
- lig_cnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Unexpected end of file in GSUB ligature sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- lig_offsets = xmalloc (lig_cnt * sizeof (uint16_t));
- for (j = 0; j < lig_cnt; ++j)
- lig_offsets[j] = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Unexpected end of file in GSUB ligature sub-table.\n"));
- info->bad_ot = true;
- return;
- }
- for (j = 0; j < lig_cnt; ++j)
- {
- fseek (ttf, stoffset + ls_offsets[i] + lig_offsets[j], SEEK_SET);
- lig = getushort (ttf);
- if (lig >= info->glyph_cnt)
- {
- LogError (_("Bad ligature glyph. Glyph %d out of range [0, %d)"),
- lig, info->glyph_cnt);
- info->bad_ot = true;
- lig = 0;
- }
- cc = getushort (ttf);
- if (cc < 0 || cc > 100)
- {
- LogError (_("Unlikely count of ligature components (%d), "
- "I suspect this ligature sub-\n"
- "table is garbage, I'm giving up on it."),
- cc);
- info->bad_ot = true;
- free (glyphs);
- free (lig_offsets);
- return;
- }
- lig_glyphs = xmalloc (cc * sizeof (uint16_t));
- lig_glyphs[0] = glyphs[i];
- for (k = 1; k < cc; ++k)
- {
- lig_glyphs[k] = getushort (ttf);
- if (lig_glyphs[k] >= info->glyph_cnt)
- {
- if (justinuse == git_normal)
- LogError (_("Bad ligature component glyph. "
- "Glyph %d out of range [0, %d) "
- "(in ligature %d)"),
- lig_glyphs[k], info->glyph_cnt, lig);
- info->bad_ot = true;
- lig_glyphs[k] = 0;
- }
- }
- if (justinuse == git_justinuse)
- {
- info->inuse[lig] = 1;
- for (k = 0; k < cc; ++k)
- info->inuse[lig_glyphs[k]] = 1;
- }
- else if (justinuse == git_findnames)
- {
- FeatureScriptLangList *fl = l->otlookup->features;
- /* If our ligature glyph has no name (and its components do) */
- /* give it a name by concatenating components with underscores */
- /* between them, and appending the tag */
- if (fl != NULL && info->chars[lig] != NULL
- && info->chars[lig]->name == NULL)
- {
- int len = 0;
- for (k = 0; k < cc; ++k)
- {
- if (info->chars[lig_glyphs[k]] == NULL
- || info->chars[lig_glyphs[k]]->name == NULL)
- break;
- len += strlen (info->chars[lig_glyphs[k]]->name) + 1;
- }
- if (k == cc)
- {
- char *str = xmalloc (len + 6), *pt;
- char tag[5];
- tag[0] = fl->featuretag >> 24;
- if ((tag[1] = (fl->featuretag >> 16) & 0xff) == ' ')
- tag[1] = '\0';
- if ((tag[2] = (fl->featuretag >> 8) & 0xff) == ' ')
- tag[2] = '\0';
- if ((tag[3] = (fl->featuretag) & 0xff) == ' ')
- tag[3] = '\0';
- tag[4] = '\0';
- *str = '\0';
- for (k = 0; k < cc; ++k)
- {
- strcat (str, info->chars[lig_glyphs[k]]->name);
- strcat (str, "_");
- }
- pt = str + strlen (str);
- pt[-1] = '.';
- strcpy (pt, tag);
- if (!glyphNameExists (info, str))
- info->chars[lig]->name = str;
- }
- }
- }
- else if (info->chars[lig] != NULL)
- {
- int err = false;
- for (k = len = 0; k < cc; ++k)
- if (lig_glyphs[k] < info->glyph_cnt &&
- info->chars[lig_glyphs[k]] != NULL)
- len += strlen (info->chars[lig_glyphs[k]]->name) + 1;
- else
- err = true;
- if (!err)
- {
- liga = xzalloc (sizeof (PST));
- liga->type = pst_ligature;
- liga->subtable = subtable;
- liga->next = info->chars[lig]->possub;
- info->chars[lig]->possub = liga;
- liga->u.lig.lig = info->chars[lig];
- liga->u.lig.components = pt = xmalloc (len);
- for (k = 0; k < cc; ++k)
- {
- if (lig_glyphs[k] < info->glyph_cnt &&
- info->chars[lig_glyphs[k]] != NULL)
- {
- strcpy (pt, info->chars[lig_glyphs[k]]->name);
- pt += strlen (pt);
- *pt++ = ' ';
- }
- }
- pt[-1] = '\0';
- }
- }
- free (lig_glyphs);
- }
- free (lig_offsets);
- }
- subtable->per_glyph_pst_or_kern = true;
- free (ls_offsets);
- free (glyphs);
- }
- static void
- gsubContextSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks)
- {
- if (justinuse == git_findnames)
- return; /* Don't give names to these guys, they might not be unique */
- /* ie. because these are context based there is not a one to one */
- /* mapping between input glyphs and output glyphs. One input glyph */
- /* may go to several output glyphs (depending on context) and so */
- /* <input-glyph-name>"."<tag-name> would be used for several glyphs */
- switch (getushort (ttf))
- {
- case 1:
- g___ContextSubTable1 (ttf, stoffset, info, l, subtable, justinuse,
- alllooks, false);
- break;
- case 2:
- g___ContextSubTable2 (ttf, stoffset, info, l, subtable, justinuse,
- alllooks, false);
- break;
- case 3:
- g___ContextSubTable3 (ttf, stoffset, info, l, subtable, justinuse,
- alllooks, false);
- break;
- }
- }
- static void
- gsubChainingSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks)
- {
- if (justinuse == git_findnames)
- return; /* Don't give names to these guys, the names might not be unique */
- switch (getushort (ttf))
- {
- case 1:
- g___ChainingSubTable1 (ttf, stoffset, info, l, subtable, justinuse,
- alllooks, false);
- break;
- case 2:
- g___ChainingSubTable2 (ttf, stoffset, info, l, subtable, justinuse,
- alllooks, false);
- break;
- case 3:
- g___ChainingSubTable3 (ttf, stoffset, info, l, subtable, justinuse,
- alllooks, false);
- break;
- }
- }
- static void
- gsubReverseChainSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse)
- {
- int scnt, bcnt, fcnt, i;
- uint16_t coverage, *bcoverage, *fcoverage, *sglyphs, *glyphs;
- FPST *fpst;
- struct fpst_rule *rule;
- if (justinuse == git_findnames)
- return; /* Don't give names to these guys, they might not be unique */
- if (getushort (ttf) != 1)
- return; /* Don't understand this format type */
- coverage = getushort (ttf);
- bcnt = getushort (ttf);
- bcoverage = xmalloc (bcnt * sizeof (uint16_t));
- for (i = 0; i < bcnt; ++i)
- bcoverage[i] = getushort (ttf);
- fcnt = getushort (ttf);
- fcoverage = xmalloc (fcnt * sizeof (uint16_t));
- for (i = 0; i < fcnt; ++i)
- fcoverage[i] = getushort (ttf);
- scnt = getushort (ttf);
- sglyphs = xmalloc ((scnt + 1) * sizeof (uint16_t));
- for (i = 0; i < scnt; ++i)
- if ((sglyphs[i] = getushort (ttf)) >= info->glyph_cnt)
- {
- LogError (_("Bad reverse contextual chaining substitution table. "
- "Glyph %d out of range [0, %d)"),
- sglyphs[i], info->glyph_cnt);
- info->bad_ot = true;
- sglyphs[i] = 0;
- }
- sglyphs[i] = 0xffff;
- if (justinuse == git_justinuse)
- {
- for (i = 0; i < scnt; ++i)
- info->inuse[sglyphs[i]] = 1;
- }
- else
- {
- fpst = xzalloc (sizeof (FPST));
- fpst->type = pst_reversesub;
- fpst->format = pst_reversecoverage;
- fpst->subtable = subtable;
- fpst->next = info->possub;
- info->possub = fpst;
- subtable->fpst = fpst;
- fpst->rules = rule = xcalloc (1, sizeof (struct fpst_rule));
- fpst->rule_cnt = 1;
- rule->u.rcoverage.always1 = 1;
- rule->u.rcoverage.bcnt = bcnt;
- rule->u.rcoverage.fcnt = fcnt;
- rule->u.rcoverage.ncovers = xmalloc (sizeof (char *));
- rule->u.rcoverage.bcovers = xmalloc (bcnt * sizeof (char *));
- rule->u.rcoverage.fcovers = xmalloc (fcnt * sizeof (char *));
- rule->u.rcoverage.replacements = GlyphsToNames (info, sglyphs, false);
- glyphs = getCoverageTable (ttf, stoffset + coverage, info);
- rule->u.rcoverage.ncovers[0] = GlyphsToNames (info, glyphs, false);
- free (glyphs);
- for (i = 0; i < bcnt; ++i)
- {
- glyphs = getCoverageTable (ttf, stoffset + bcoverage[i], info);
- rule->u.rcoverage.bcovers[i] = GlyphsToNames (info, glyphs, true);
- free (glyphs);
- }
- for (i = 0; i < fcnt; ++i)
- {
- glyphs = getCoverageTable (ttf, stoffset + fcoverage[i], info);
- rule->u.rcoverage.fcovers[i] = GlyphsToNames (info, glyphs, true);
- free (glyphs);
- }
- rule->lookup_cnt = 0; /* substitution lookups needed for reverse chaining */
- }
- free (sglyphs);
- free (fcoverage);
- free (bcoverage);
- }
- static void
- readttfsizeparameters (FILE *ttf, int32_t broken_pos, int32_t correct_pos,
- struct ttfinfo *info)
- {
- int32_t here;
- /* Both of the two fonts I've seen that contain a 'size' feature */
- /* have multiple features all of which point to the same parameter */
- /* area. Odd. */
- /* When Adobe first released fonts containing the 'size' feature */
- /* they did not follow the spec, and the offset to the size parameters */
- /* was relative to the wrong location. They claim (Aug 2006) that */
- /* this has been fixed. Be prepared to read either style of 'size' */
- /* following the heuristics Adobe provides */
- int32_t test[2];
- int i, nid;
- if (info->last_size_pos == broken_pos || info->last_size_pos == correct_pos)
- return;
- if (info->last_size_pos != 0)
- {
- LogError (_
- ("This font, %s, has multiple GPOS 'size' features. I'm not sure how to interpret that. I shall pick one arbitrarily.\n"),
- info->fontname == NULL ? _("<Untitled>") : info->fontname);
- info->bad_ot = true;
- return;
- }
- test[0] = correct_pos;
- test[1] = broken_pos;
- here = ftell (ttf);
- for (i = 0; i < 2; ++i)
- {
- fseek (ttf, test[i], SEEK_SET);
- info->last_size_pos = test[i];
- info->design_size = getushort (ttf);
- if (info->design_size == 0)
- continue;
- info->fontstyle_id = getushort (ttf);
- nid = getushort (ttf);
- info->design_range_bottom = getushort (ttf);
- info->design_range_top = getushort (ttf);
- if (info->fontstyle_id == 0 && nid == 0 && info->design_size != 0 &&
- info->design_range_bottom == 0 && info->design_range_top == 0)
- {
- /* Reasonable spec, only design size provided */
- info->fontstyle_name = NULL;
- break;
- }
- if (info->design_size == 0 ||
- info->design_size < info->design_range_bottom ||
- info->design_size > info->design_range_top ||
- info->design_range_bottom > info->design_range_top)
- continue;
- if (info->fontstyle_id == 0 && nid == 0)
- {
- /* Not really allowed, but we'll accept it anyway */
- /* If a range is provided than a style name is expected */
- LogError (_
- ("This font contains a 'size' feature with a design size and design range but no stylename. That is technically an error, but we'll let it pass"));
- info->fontstyle_name = NULL;
- break;
- }
- if (nid < 256 || nid > 32767)
- continue;
- info->fontstyle_name = FindAllLangEntries (ttf, info, nid);
- if (info->fontstyle_name == NULL)
- continue;
- else
- break;
- }
- if (i == 2)
- {
- LogError (_
- ("The 'size' feature does not seem to follow the standard,\nnor does it conform to Adobe's early misinterpretation of\nthe standard. I cannot parse it.\n"));
- info->bad_ot = true;
- info->design_size = info->design_range_bottom = info->design_range_top =
- info->fontstyle_id = 0;
- info->fontstyle_name = NULL;
- }
- else if (i == 1)
- {
- LogError (_
- ("The 'size' feature of this font conforms to Adobe's early misinterpretation of the otf standard.\n"));
- }
- fseek (ttf, here, SEEK_SET);
- #if 0
- printf ("pos=%d size=%g, range=(%g,%g] id=%d name=%d\n", pos,
- info->design_size / 10.0, info->design_range_bottom / 10.0,
- info->design_range_top / 10.0, info->fontstyle_id,
- info->fontstyle_name);
- #endif
- }
- static void
- readttffeatnameparameters (FILE *ttf, int32_t pos, uint32_t tag,
- struct ttfinfo *info)
- {
- int version, nid;
- struct otffeatname *fn;
- uint32_t here;
- here = ftell (ttf);
- fseek (ttf, pos, SEEK_SET);
- version = getushort (ttf); /* Minor version #, currently (2009) 0 */
- nid = getushort (ttf);
- fseek (ttf, here, SEEK_SET);
- if (version >= 10 || nid < 256 || nid > 32767)
- {
- if (nid < 256 || nid > 32767)
- LogError (_
- ("The name parameter of the '%c%c%c%c' feature does not contain a valid name id.\n"),
- tag >> 24, tag >> 16, tag >> 8, tag);
- else
- LogError (_
- ("The name parameter of the '%c%c%c%c' feature has an unlikely version number %d.\n"),
- tag >> 24, tag >> 16, tag >> 8, tag, version);
- info->bad_ot = true;
- return;
- }
- for (fn = info->feat_names; fn != NULL && fn->tag != tag; fn = fn->next);
- if (fn != NULL)
- {
- if (fn->nid == nid)
- return;
- LogError (_
- ("There are multiple name ids naming the '%c%c%c%c' feature\n this is technically legitimate, but fontforge can't handle it.\n"),
- tag >> 24, tag >> 16, tag >> 8, tag);
- return;
- }
- fn = xzalloc (sizeof (*fn));
- fn->tag = tag;
- fn->nid = nid;
- fn->next = info->feat_names;
- info->feat_names = fn;
- fn->names = FindAllLangEntries (ttf, info, nid);
- }
- static struct scripts *
- readttfscripts (FILE *ttf, int32_t pos, struct ttfinfo *info, int isgpos)
- {
- int i, j, k, cnt;
- int deflang, lcnt;
- struct scripts *scripts;
- if (pos >= info->g_bounds)
- {
- LogError (_("Attempt to read script data beyond end of %s table"),
- isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, pos, SEEK_SET);
- cnt = getushort (ttf);
- if (cnt <= 0)
- return NULL;
- else if (cnt > 1000)
- {
- LogError (_("Too many scripts %d\n"), cnt);
- info->bad_ot = true;
- return NULL;
- }
- scripts = xcalloc (cnt + 1, sizeof (struct scripts));
- for (i = 0; i < cnt; ++i)
- {
- scripts[i].tag = getlong (ttf);
- scripts[i].offset = getushort (ttf);
- }
- for (i = 0; i < cnt; ++i)
- {
- fseek (ttf, pos + scripts[i].offset, SEEK_SET);
- deflang = getushort (ttf);
- lcnt = getushort (ttf);
- lcnt += (deflang != 0);
- scripts[i].langcnt = lcnt;
- scripts[i].languages = xcalloc (lcnt + 1, sizeof (struct language));
- j = 0;
- if (deflang != 0)
- {
- scripts[i].languages[0].tag = CHR ('d', 'f', 'l', 't');
- scripts[i].languages[0].offset = deflang + scripts[i].offset;
- ++j;
- }
- for (; j < lcnt; ++j)
- {
- scripts[i].languages[j].tag = getlong (ttf);
- scripts[i].languages[j].offset = scripts[i].offset + getushort (ttf);
- }
- for (j = 0; j < lcnt; ++j)
- {
- if (pos + scripts[i].languages[j].offset >= info->g_bounds)
- {
- LogError (_("Attempt to read script data beyond end of %s table"),
- isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, pos + scripts[i].languages[j].offset, SEEK_SET);
- (void) getushort (ttf); /* lookup ordering table undefined */
- scripts[i].languages[j].req = getushort (ttf);
- scripts[i].languages[j].fcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file when reading scripts in %s table"),
- isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- scripts[i].languages[j].features =
- xmalloc (scripts[i].languages[j].fcnt * sizeof (uint16_t));
- for (k = 0; k < scripts[i].languages[j].fcnt; ++k)
- scripts[i].languages[j].features[k] = getushort (ttf);
- }
- }
- if (feof (ttf))
- {
- LogError (_("End of file in %s table"), isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- return scripts;
- }
- static struct feature *
- readttffeatures (FILE *ttf, int32_t pos, int isgpos, struct ttfinfo *info)
- {
- /* read the features table returning an array containing all interesting */
- /* features */
- int cnt;
- int i, j;
- struct feature *features;
- int parameters;
- if (pos >= info->g_bounds)
- {
- LogError (_("Attempt to read feature data beyond end of %s table"),
- isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, pos, SEEK_SET);
- info->feature_cnt = cnt = getushort (ttf);
- if (cnt <= 0)
- return NULL;
- else if (cnt > 1000)
- {
- LogError (_("Too many features %d\n"), cnt);
- info->bad_ot = true;
- return NULL;
- }
- features = xcalloc (cnt + 1, sizeof (struct feature));
- for (i = 0; i < cnt; ++i)
- {
- features[i].tag = getlong (ttf);
- features[i].offset = getushort (ttf);
- }
- for (i = 0; i < cnt; ++i)
- {
- if (pos + features[i].offset >= info->g_bounds)
- {
- LogError (_("Attempt to read feature data beyond end of %s table"),
- isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, pos + features[i].offset, SEEK_SET);
- parameters = getushort (ttf);
- if (features[i].tag == CHR ('s', 'i', 'z', 'e') && parameters != 0
- && !feof (ttf))
- {
- readttfsizeparameters (ttf, pos + parameters,
- pos + parameters + features[i].offset, info);
- }
- else if (features[i].tag >= CHR ('s', 's', '0', '1')
- && features[i].tag <= CHR ('s', 's', '2', '0') && parameters != 0
- && !feof (ttf))
- {
- readttffeatnameparameters (ttf, pos + parameters + features[i].offset,
- features[i].tag, info);
- }
- features[i].lcnt = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("End of file when reading features in %s table"),
- isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- features[i].lookups = xmalloc (features[i].lcnt * sizeof (uint16_t));
- for (j = 0; j < features[i].lcnt; ++j)
- features[i].lookups[j] = getushort (ttf);
- }
- return features;
- }
- static struct lookup *
- readttflookups (FILE *ttf, int32_t pos, struct ttfinfo *info, int isgpos)
- {
- int cnt, i, j;
- struct lookup *lookups;
- OTLookup *otlookup, *last = NULL;
- struct lookup_subtable *st;
- if (pos >= info->g_bounds)
- {
- LogError (_("Attempt to read lookup data beyond end of %s table"),
- isgpos == 2 ? "JSTF" : isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, pos, SEEK_SET);
- info->lookup_cnt = cnt = getushort (ttf);
- info->cur_lookups = NULL;
- if (cnt <= 0)
- return NULL;
- else if (cnt > 1000)
- {
- LogError (_("Too many lookups %d\n"), cnt);
- info->bad_ot = true;
- return NULL;
- }
- lookups = xcalloc (cnt + 1, sizeof (struct lookup));
- for (i = 0; i < cnt; ++i)
- lookups[i].offset = getushort (ttf);
- for (i = 0; i < cnt; ++i)
- {
- if (pos + lookups[i].offset >= info->g_bounds)
- {
- LogError (_("Attempt to read lookup data beyond end of %s table"),
- isgpos == 2 ? "JSTF" : isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, pos + lookups[i].offset, SEEK_SET);
- lookups[i].type = getushort (ttf);
- lookups[i].flags = getushort (ttf);
- lookups[i].subtabcnt = getushort (ttf);
- lookups[i].subtab_offsets =
- xmalloc (lookups[i].subtabcnt * sizeof (int32_t));
- for (j = 0; j < lookups[i].subtabcnt; ++j)
- lookups[i].subtab_offsets[j] =
- pos + lookups[i].offset + getushort (ttf);
- if (lookups[i].flags & pst_usemarkfilteringset)
- lookups[i].flags |= (getushort (ttf) << 16);
- lookups[i].otlookup = otlookup = xzalloc (sizeof (OTLookup));
- otlookup->lookup_index = i;
- if (last == NULL)
- info->cur_lookups = otlookup;
- else
- last->next = otlookup;
- last = otlookup;
- otlookup->lookup_type = ((isgpos > 0) << 8) | lookups[i].type;
- otlookup->lookup_flags = lookups[i].flags;
- otlookup->lookup_index = i;
- if (feof (ttf))
- {
- LogError (_("End of file when reading lookups in %s table"),
- isgpos ? "GPOS" : "GSUB");
- info->bad_ot = true;
- return NULL;
- }
- for (j = 0; j < lookups[i].subtabcnt; ++j)
- {
- st =
- (struct lookup_subtable *)
- xzalloc (sizeof (struct lookup_subtable));
- st->next = otlookup->subtables;
- st->lookup = otlookup;
- otlookup->subtables = st;
- }
- }
- if (isgpos == 2)
- {
- OTLookup *end;
- /* Add any JSTF lookups to the end of the GPOS list. they have the */
- /* same format, we'll treat them as GPOS internally, and separate */
- /* them out when we generate the new font */
- if (info->gpos_lookups == NULL)
- info->gpos_lookups = info->cur_lookups;
- else
- {
- for (end = info->gpos_lookups; end->next != NULL; end = end->next);
- end->next = info->cur_lookups;
- }
- }
- else if (isgpos)
- info->gpos_lookups = info->cur_lookups;
- else
- info->gsub_lookups = info->cur_lookups;
- return lookups;
- }
- static void
- tagLookupsWithFeature (uint32_t script_tag, uint32_t lang_tag,
- int required_feature, struct feature *feature,
- struct lookup *lookups, struct ttfinfo *info)
- {
- uint32_t feature_tag = required_feature ? REQUIRED_FEATURE : feature->tag;
- int i;
- OTLookup *otlookup;
- FeatureScriptLangList *fl;
- /* The otf docs are ambiguous as to the capitalization of the default */
- /* script. The capitalized version is correct (uncapitalized is used for languages) */
- if (script_tag == DEFAULT_LANG)
- script_tag = DEFAULT_SCRIPT;
- for (i = 0; i < feature->lcnt; ++i)
- {
- if (feature->lookups[i] >= info->lookup_cnt)
- {
- LogError (_("Lookup out of bounds in feature table.\n"));
- info->bad_ot = true;
- }
- else
- {
- otlookup = lookups[feature->lookups[i]].otlookup;
- for (fl = otlookup->features;
- fl != NULL && fl->featuretag != feature_tag; fl = fl->next);
- if (fl == NULL)
- {
- fl =
- (FeatureScriptLangList *)
- xzalloc (sizeof (FeatureScriptLangList));
- fl->featuretag = feature_tag;
- fl->next = otlookup->features;
- otlookup->features = fl;
- }
- FListAppendScriptLang (fl, script_tag, lang_tag);
- }
- }
- }
- static void
- tagLookupsWithScript (struct scripts *scripts,
- struct feature *features, struct lookup *lookups,
- struct ttfinfo *info)
- {
- int i, j;
- struct scripts *s;
- struct language *lang;
- struct lookup *l;
- if (scripts == NULL || features == NULL)
- return; /* Legal, I'd guess, but not very interesting. Perhaps all lookups are controlled by the JSTF table or something */
- /* First tag every lookup with all script, lang, feature combinations that */
- /* invoke it */
- for (s = scripts; s->tag != 0; ++s)
- {
- for (lang = s->languages, i = 0; i < s->langcnt; ++i, ++lang)
- {
- if (lang->req == 0xffff)
- /* Do Nothing */ ;
- else if (lang->req >= info->feature_cnt)
- {
- LogError (_("Required feature out of bounds in script table.\n"));
- info->bad_ot = true;
- }
- else
- tagLookupsWithFeature (s->tag, lang->tag, true,
- &features[lang->req], lookups, info);
- for (j = 0; j < lang->fcnt; ++j)
- {
- if (lang->features[j] >= info->feature_cnt)
- {
- LogError (_("Feature out of bounds in script table.\n"));
- info->bad_ot = true;
- }
- else
- tagLookupsWithFeature (s->tag, lang->tag, false,
- &features[lang->features[j]], lookups,
- info);
- }
- }
- }
- /* The scripts got added backwards so reverse to put them in */
- /* alphabetic order again */
- for (l = lookups, i = 0; l->offset != 0; ++l, ++i)
- {
- OTLookup *otl = l->otlookup;
- FeatureScriptLangList *fl;
- struct scriptlanglist *sl, *next, *prev;
- for (fl = otl->features; fl != NULL; fl = fl->next)
- {
- prev = NULL;
- for (sl = fl->scripts; sl != NULL; sl = next)
- {
- next = sl->next;
- sl->next = prev;
- prev = sl;
- }
- fl->scripts = prev;
- }
- }
- }
- static void
- gposExtensionSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable,
- struct lookup *alllooks)
- {
- uint32_t base = ftell (ttf), st, offset;
- int lu_type;
- /* Format = */ getushort (ttf);
- lu_type = getushort (ttf);
- offset = getlong (ttf);
- l->otlookup->lookup_type = 0x100 | lu_type;
- fseek (ttf, st = base + offset, SEEK_SET);
- switch (lu_type)
- {
- case 1:
- gposSimplePos (ttf, st, info, l, subtable);
- break;
- case 2:
- gposKernSubTable (ttf, st, info, l, subtable);
- break;
- case 3:
- gposCursiveSubTable (ttf, st, info, l, subtable);
- break;
- case 4:
- case 5:
- case 6:
- gposMarkSubTable (ttf, st, info, l, subtable);
- break;
- case 7:
- gposContextSubTable (ttf, st, info, l, subtable, alllooks);
- break;
- case 8:
- gposChainingSubTable (ttf, st, info, l, subtable, alllooks);
- break;
- case 9:
- LogError (_
- ("This font is erroneous: it has a GPOS extension subtable that points to\nanother extension sub-table.\n"));
- info->bad_ot = true;
- break;
- /* Any cases added here also need to go in the gposLookupSwitch */
- default:
- LogError (_("Unknown GPOS sub-table type: %d\n"), lu_type);
- info->bad_ot = true;
- break;
- }
- if (ftell (ttf) > info->g_bounds)
- {
- LogError (_("Subtable extends beyond end of GPOS table\n"));
- info->bad_ot = true;
- }
- }
- static void
- gsubExtensionSubTable (FILE *ttf, int stoffset,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks)
- {
- uint32_t base = ftell (ttf), st, offset;
- int lu_type;
- /* Format = */ getushort (ttf);
- lu_type = getushort (ttf);
- offset = getlong (ttf);
- l->otlookup->lookup_type = lu_type;
- fseek (ttf, st = base + offset, SEEK_SET);
- switch (lu_type)
- {
- case 1:
- gsubSimpleSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- case 2:
- case 3: /* Multiple and alternate have same format, different semantics */
- gsubMultipleSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- case 4:
- gsubLigatureSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- case 5:
- gsubContextSubTable (ttf, st, info, l, subtable, justinuse, alllooks);
- break;
- case 6:
- gsubChainingSubTable (ttf, st, info, l, subtable, justinuse, alllooks);
- break;
- case 7:
- LogError (_
- ("This font is erroneous: it has a GSUB extension subtable that points to\nanother extension sub-table.\n"));
- info->bad_ot = true;
- break;
- case 8:
- gsubReverseChainSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- /* Any cases added here also need to go in the gsubLookupSwitch */
- default:
- LogError (_("Unknown GSUB sub-table type: %d\n"), lu_type);
- info->bad_ot = true;
- break;
- }
- if (ftell (ttf) > info->gsub_start + info->gsub_length)
- {
- LogError (_("Subtable extends beyond end of GSUB table\n"));
- info->bad_ot = true;
- }
- }
- static void
- gposLookupSwitch (FILE *ttf, int st,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, struct lookup *alllooks)
- {
- switch (l->type | 0x100)
- {
- case gpos_single:
- gposSimplePos (ttf, st, info, l, subtable);
- break;
- case gpos_pair:
- gposKernSubTable (ttf, st, info, l, subtable);
- break;
- case gpos_cursive:
- gposCursiveSubTable (ttf, st, info, l, subtable);
- break;
- case gpos_mark2base:
- case gpos_mark2ligature:
- case gpos_mark2mark:
- gposMarkSubTable (ttf, st, info, l, subtable);
- break;
- case gpos_context:
- gposContextSubTable (ttf, st, info, l, subtable, alllooks);
- break;
- case gpos_contextchain:
- gposChainingSubTable (ttf, st, info, l, subtable, alllooks);
- break;
- case 0x109:
- gposExtensionSubTable (ttf, st, info, l, subtable, alllooks);
- break;
- /* Any cases added here also need to go in the gposExtensionSubTable */
- default:
- LogError (_("Unknown GPOS sub-table type: %d\n"),
- l->otlookup->lookup_type);
- info->bad_ot = true;
- break;
- }
- if (ftell (ttf) > info->g_bounds)
- {
- LogError (_("Subtable extends beyond end of GPOS table\n"));
- info->bad_ot = true;
- }
- }
- static void
- gsubLookupSwitch (FILE *ttf, int st,
- struct ttfinfo *info, struct lookup *l,
- struct lookup_subtable *subtable, int justinuse,
- struct lookup *alllooks)
- {
- switch (l->type)
- {
- case gsub_single:
- gsubSimpleSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- case gsub_multiple:
- case gsub_alternate: /* Multiple and alternate have same format, different semantics */
- gsubMultipleSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- case gsub_ligature:
- gsubLigatureSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- case gsub_context:
- gsubContextSubTable (ttf, st, info, l, subtable, justinuse, alllooks);
- break;
- case gsub_contextchain:
- gsubChainingSubTable (ttf, st, info, l, subtable, justinuse, alllooks);
- break;
- case 7:
- gsubExtensionSubTable (ttf, st, info, l, subtable, justinuse, alllooks);
- break;
- case gsub_reversecchain:
- gsubReverseChainSubTable (ttf, st, info, l, subtable, justinuse);
- break;
- /* Any cases added here also need to go in the gsubExtensionSubTable */
- default:
- LogError (_("Unknown GSUB sub-table type: %d\n"),
- l->otlookup->lookup_type);
- info->bad_ot = true;
- break;
- }
- if (ftell (ttf) > info->g_bounds)
- {
- LogError (_("Subtable extends beyond end of GSUB table\n"));
- info->bad_ot = true;
- }
- }
- static void
- ScriptsFree (struct scripts *scripts)
- {
- int i, j;
- if (scripts == NULL)
- return;
- for (i = 0; scripts[i].offset != 0; ++i)
- {
- for (j = 0; j < scripts[i].langcnt; ++j)
- free (scripts[i].languages[j].features);
- free (scripts[i].languages);
- }
- free (scripts);
- }
- static void
- FeaturesFree (struct feature *features)
- {
- int i;
- if (features == NULL)
- return;
- for (i = 0; features[i].offset != 0; ++i)
- free (features[i].lookups);
- free (features);
- }
- static void
- LookupsFree (struct lookup *lookups)
- {
- int i;
- for (i = 0; lookups[i].offset != 0; ++i)
- {
- free (lookups[i].subtab_offsets);
- }
- free (lookups);
- }
- static void
- ProcessGPOSGSUB (FILE *ttf, struct ttfinfo *info, int gpos, int inusetype)
- {
- int k;
- int32_t base, lookup_start, st;
- int32_t script_off, feature_off;
- struct scripts *scripts;
- struct feature *features;
- struct lookup *lookups, *l;
- struct lookup_subtable *subtable;
- if (gpos)
- {
- base = info->gpos_start;
- info->g_bounds = base + info->gpos_length;
- }
- else
- {
- base = info->gsub_start;
- info->g_bounds = base + info->gsub_length;
- }
- fseek (ttf, base, SEEK_SET);
- /* version = */ getlong (ttf);
- script_off = getushort (ttf);
- feature_off = getushort (ttf);
- lookup_start = base + getushort (ttf);
- scripts = readttfscripts (ttf, base + script_off, info, gpos);
- features = readttffeatures (ttf, base + feature_off, gpos, info);
- /* It is legal to have lookups with no features or scripts */
- /* For example if all the lookups were controlled by the JSTF table */
- lookups = readttflookups (ttf, lookup_start, info, gpos);
- if (lookups == NULL)
- {
- ScriptsFree (scripts);
- FeaturesFree (features);
- return;
- }
- tagLookupsWithScript (scripts, features, lookups, info);
- ScriptsFree (scripts);
- scripts = NULL;
- FeaturesFree (features);
- features = NULL;
- for (l = lookups; l->offset != 0; ++l)
- {
- for (k = 0, subtable = l->otlookup->subtables; k < l->subtabcnt;
- ++k, subtable = subtable->next)
- {
- st = l->subtab_offsets[k];
- fseek (ttf, st, SEEK_SET);
- if (gpos)
- {
- gposLookupSwitch (ttf, st, info, l, subtable, lookups);
- }
- else
- {
- gsubLookupSwitch (ttf, st, info, l, subtable, inusetype, lookups);
- }
- }
- }
- /* Then generate some user-friendly names for the all the lookups */
- if (inusetype == git_normal)
- for (l = lookups; l->offset != 0; ++l)
- NameOTLookup (l->otlookup, NULL);
- LookupsFree (lookups);
- if (inusetype != git_normal && !gpos)
- {
- OTLookupListFree (info->gsub_lookups);
- info->gsub_lookups = info->cur_lookups = NULL;
- }
- }
- void
- readttfgsubUsed (FILE *ttf, struct ttfinfo *info)
- {
- ProcessGPOSGSUB (ttf, info, false, git_justinuse);
- info->g_bounds = 0;
- }
- void
- GuessNamesFromGSUB (FILE *ttf, struct ttfinfo *info)
- {
- ProcessGPOSGSUB (ttf, info, false, git_findnames);
- info->g_bounds = 0;
- }
- void
- readttfgpossub (FILE *ttf, struct ttfinfo *info, int gpos)
- {
- ProcessGPOSGSUB (ttf, info, gpos, git_normal);
- info->g_bounds = 0;
- }
- void
- readttfgdef (FILE *ttf, struct ttfinfo *info)
- {
- int lclo, gclass, mac, mas = 0;
- int coverage, cnt, i, j, format;
- int version;
- uint16_t *glyphs, *lc_offsets, *offsets;
- uint32_t caret_base;
- PST *pst;
- SplineChar *sc;
- fseek (ttf, info->gdef_start, SEEK_SET);
- version = getlong (ttf);
- if (version != 0x00010000 && version != 0x00010002)
- return;
- info->g_bounds = info->gdef_start + info->gdef_length;
- gclass = getushort (ttf);
- /* attach list = */ getushort (ttf);
- lclo = getushort (ttf); /* ligature caret list */
- mac = getushort (ttf); /* mark attach class */
- if (version == 0x00010002)
- mas = getushort (ttf);
- if (gclass != 0)
- {
- uint16_t *gclasses =
- getClassDefTable (ttf, info->gdef_start + gclass, info);
- for (i = 0; i < info->glyph_cnt; ++i)
- if (info->chars[i] != NULL && gclasses[i] != 0)
- info->chars[i]->glyph_class = gclasses[i] + 1;
- free (gclasses);
- }
- if (mac != 0)
- {
- uint16_t *mclasses = getClassDefTable (ttf, info->gdef_start + mac, info);
- const char *format_spec = _("MarkClass-%d");
- info->mark_class_cnt = ClassFindCnt (mclasses, info->glyph_cnt);
- info->mark_classes =
- ClassToNames (info, info->mark_class_cnt, mclasses, info->glyph_cnt);
- info->mark_class_names = xmalloc (info->mark_class_cnt * sizeof (char *));
- info->mark_class_names[0] = NULL;
- for (i = 1; i < info->mark_class_cnt; ++i)
- {
- info->mark_class_names[i] = xmalloc ((strlen (format_spec) + 10));
- sprintf (info->mark_class_names[i], format_spec, i);
- }
- free (mclasses);
- }
- if (mas != 0)
- {
- const char *format_spec = _("MarkSet-%d");
- fseek (ttf, info->gdef_start + mas, SEEK_SET);
- if (getushort (ttf) == 1)
- { /* Version number of Mark GLyph Sets Table */
- uint32_t *offsets;
- uint16_t *glyphs;
- info->mark_set_cnt = getushort (ttf);
- offsets = xmalloc (info->mark_set_cnt * sizeof (uint32_t));
- for (i = 0; i < info->mark_set_cnt; ++i)
- offsets[i] = getlong (ttf);
- info->mark_sets = xmalloc (info->mark_set_cnt * sizeof (char *));
- info->mark_set_names = xmalloc (info->mark_set_cnt * sizeof (char *));
- info->mark_set_names[0] = NULL;
- for (i = 0; i < info->mark_set_cnt; ++i)
- {
- info->mark_set_names[i] = xmalloc ((strlen (format_spec) + 10));
- sprintf (info->mark_set_names[i], format_spec, i);
- if (offsets[i] != 0)
- {
- glyphs =
- getCoverageTable (ttf, info->gdef_start + mas + offsets[i],
- info);
- info->mark_sets[i] = GlyphsToNames (info, glyphs, true);
- free (glyphs);
- }
- else
- info->mark_sets[i] = NULL; /* Should not happen */
- }
- free (offsets);
- }
- }
- if (lclo != 0)
- {
- lclo += info->gdef_start;
- fseek (ttf, lclo, SEEK_SET);
- coverage = getushort (ttf);
- cnt = getushort (ttf);
- if (cnt == 0)
- return;
- lc_offsets = xmalloc (cnt * sizeof (uint16_t));
- for (i = 0; i < cnt; ++i)
- lc_offsets[i] = getushort (ttf);
- glyphs = getCoverageTable (ttf, lclo + coverage, info);
- if (glyphs == NULL)
- return;
- for (i = 0; i < cnt; ++i)
- if (glyphs[i] < info->glyph_cnt
- && (sc = info->chars[glyphs[i]]) != NULL)
- {
- fseek (ttf, lclo + lc_offsets[i], SEEK_SET);
- for (pst = sc->possub; pst != NULL && pst->type != pst_lcaret;
- pst = pst->next);
- if (pst == NULL)
- {
- pst = xzalloc (sizeof (PST));
- pst->next = sc->possub;
- sc->possub = pst;
- pst->type = pst_lcaret;
- pst->subtable = NULL;
- sc->lig_caret_cnt_fixed = true;
- }
- caret_base = ftell (ttf);
- pst->u.lcaret.cnt = getushort (ttf);
- if (pst->u.lcaret.carets != NULL)
- free (pst->u.lcaret.carets);
- offsets = xmalloc (pst->u.lcaret.cnt * sizeof (uint16_t));
- for (j = 0; j < pst->u.lcaret.cnt; ++j)
- offsets[j] = getushort (ttf);
- pst->u.lcaret.carets =
- xmalloc (pst->u.lcaret.cnt * sizeof (int16_t));
- for (j = 0; j < pst->u.lcaret.cnt; ++j)
- {
- fseek (ttf, caret_base + offsets[j], SEEK_SET);
- format = getushort (ttf);
- if (format == 1)
- {
- pst->u.lcaret.carets[j] = getushort (ttf);
- }
- else if (format == 2)
- {
- pst->u.lcaret.carets[j] = 0;
- /* point = */ getushort (ttf);
- }
- else if (format == 3)
- {
- pst->u.lcaret.carets[j] = getushort (ttf);
- /* in device table = */ getushort (ttf);
- }
- else
- {
- LogError (_("!!!! Unknown caret format %d !!!!\n"), format);
- info->bad_ot = true;
- }
- }
- free (offsets);
- }
- free (lc_offsets);
- free (glyphs);
- }
- info->g_bounds = 0;
- }
- static void
- OTLAppend (struct ttfinfo *info, OTLookup *otl, int gpos)
- {
- OTLookup *prev;
- int pos = 0;
- if (gpos && info->gpos_lookups == NULL)
- info->gpos_lookups = otl;
- else if (!gpos && info->gsub_lookups == NULL)
- info->gsub_lookups = otl;
- else
- {
- prev = gpos ? info->gpos_lookups : info->gsub_lookups;
- pos = 1;
- while (prev->next != NULL)
- {
- prev = prev->next;
- ++pos;
- }
- prev->next = otl;
- }
- otl->lookup_index = pos;
- }
- static void
- OTLRemove (struct ttfinfo *info, OTLookup *otl, int gpos)
- {
- /* Remove the most recent lookup. We got bad data and can't use it */
- OTLookup *prev, **base;
- base = gpos ? &info->gpos_lookups : &info->gsub_lookups;
- if (*base == otl)
- *base = NULL;
- else if (*base != NULL)
- {
- for (prev = *base; prev->next != NULL && prev->next != otl;
- prev = prev->next);
- prev->next = NULL;
- }
- OTLookupFree (otl);
- }
- static void
- InfoNameOTLookup (OTLookup *otl, struct ttfinfo *info)
- {
- SplineFont sf;
- memset (&sf, 0, sizeof (sf));
- NameOTLookup (otl, &sf);
- }
- int32_t
- memlong (uint8_t *data, int len, int offset)
- {
- if (offset >= 0 && offset + 3 < len)
- {
- int ch1 = data[offset], ch2 = data[offset + 1], ch3 =
- data[offset + 2], ch4 = data[offset + 3];
- return (ch1 << 24) | (ch2 << 16) | (ch3 << 8) | ch4;
- }
- else
- {
- LogError (_("Bad font, offset out of bounds.\n"));
- return 0;
- }
- }
- int
- memushort (uint8_t *data, int len, int offset)
- {
- if (offset >= 0 && offset + 1 < len)
- {
- int ch1 = data[offset], ch2 = data[offset + 1];
- return (ch1 << 8) | ch2;
- }
- else
- {
- LogError (_("Bad font, offset out of bounds.\n"));
- return 0;
- }
- }
- void
- memputshort (uint8_t *data, int offset, uint16_t val)
- {
- data[offset] = (val >> 8);
- data[offset + 1] = val & 0xff;
- }
- /* Apple's docs imply that kerning info is always provided left to right, even*/
- /* for right to left scripts. My guess is that their docs are wrong, as they */
- /* often are, but if that be so then we need code in here to reverse */
- /* the order of the characters for right to left since pfaedit's convention */
- /* is to follow writing order rather than to go left to right */
- void
- readttfkerns (FILE *ttf, struct ttfinfo *info)
- {
- int tabcnt, len, coverage, i, j, npairs, version, format, flags_good, tab;
- int left, right, offset, array, rowWidth;
- int header_size;
- KernPair *kp;
- KernClass *kc;
- uint32_t begin_table;
- uint16_t *class1, *class2;
- int isv;
- OTLookup *otl;
- fseek (ttf, info->kern_start, SEEK_SET);
- version = getushort (ttf);
- tabcnt = getushort (ttf);
- if (version != 0)
- {
- LogError (_("Invalid or unsupported version (0x%x) for 'kern' table"),
- version);
- info->bad_gx = true;
- return;
- }
- if (tabcnt < 0 || tabcnt > 0x1000)
- LogError (_("Warning: Unlikely number of subtables (%d) for 'kern' table"),
- tabcnt);
- for (tab = 0; tab < tabcnt; ++tab)
- {
- begin_table = ftell (ttf);
- /* version = */ getushort (ttf);
- len = getushort (ttf);
- coverage = getushort (ttf);
- format = coverage >> 8;
- flags_good = ((coverage & 7) <= 1);
- isv = !(coverage & 1);
- header_size = 6;
- otl = NULL;
- if (flags_good)
- {
- otl = xzalloc (sizeof (OTLookup));
- otl->lookup_type = gpos_pair;
- otl->subtables =
- (struct lookup_subtable *)
- xzalloc (sizeof (struct lookup_subtable));
- otl->subtables->lookup = otl;
- otl->subtables->per_glyph_pst_or_kern = true;
- otl->subtables->vertical_kerning = isv;
- otl->features =
- xzalloc (sizeof (FeatureScriptLangList));
- if (isv)
- otl->features->featuretag = CHR ('v', 'k', 'r', 'n');
- else
- otl->features->featuretag = CHR ('k', 'e', 'r', 'n');
- OTLAppend (info, otl, true);
- }
- if (flags_good && format == 0)
- {
- /* format 0, horizontal kerning data (as pairs) not perpendicular */
- npairs = getushort (ttf);
- if (len - 14 != 6 * npairs || npairs > 10920)
- {
- LogError (_
- ("In the 'kern' table, a subtable's length does not match the number of kerning pairs."));
- info->bad_gx = true;
- }
- /* searchRange = */ getushort (ttf);
- /* entrySelector = */ getushort (ttf);
- /* rangeShift = */ getushort (ttf);
- otl->subtables[0].per_glyph_pst_or_kern = true;
- for (j = 0; j < npairs; ++j)
- {
- left = getushort (ttf);
- right = getushort (ttf);
- offset = (short) getushort (ttf);
- if (left < 0 || right < 0)
- {
- /* We've seen such buggy fonts... */
- LogError (_
- ("Bad kern pair: glyphs %d & %d mustn't be negative\n"),
- left, right);
- info->bad_gx = true;
- }
- else if (left >= info->glyph_cnt || right >= info->glyph_cnt)
- {
- /* Holes happen when reading ttc files. They are probably ok */
- LogError (_
- ("Bad kern pair: glyphs %d & %d must be less than %d\n"),
- left, right, info->glyph_cnt);
- info->bad_gx = true;
- }
- else if (info->chars[left] == NULL || info->chars[right] == NULL)
- {
- /* Shouldn't happen. */
- LogError (_("Bad kern pair: glyphs at %d & %d are null\n"),
- left, right);
- info->bad_gx = true;
- }
- else
- {
- kp = xzalloc (sizeof (KernPair));
- kp->sc = info->chars[right];
- kp->off = offset;
- kp->subtable = otl->subtables;
- FListsAppendScriptLang (otl->features,
- SCScriptFromUnicode (info->
- chars[left]),
- DEFAULT_LANG);
- if (isv)
- {
- kp->next = info->chars[left]->vkerns;
- info->chars[left]->vkerns = kp;
- }
- else
- {
- kp->next = info->chars[left]->kerns;
- info->chars[left]->kerns = kp;
- }
- }
- }
- InfoNameOTLookup (otl, info);
- }
- else if (flags_good && (format == 2 || format == 3))
- {
- /* two class based formats */
- KernClass **khead, **klast;
- if (isv)
- {
- khead = &info->vkhead;
- klast = &info->vklast;
- }
- else
- {
- khead = &info->khead;
- klast = &info->klast;
- }
- if (*khead == NULL)
- *khead = kc = xzalloc (sizeof (KernClass));
- else
- kc = xzalloc (sizeof (KernClass));
- *klast = kc;
- if (format == 2)
- {
- rowWidth = getushort (ttf);
- left = getushort (ttf);
- right = getushort (ttf);
- array = getushort (ttf);
- kc->second_cnt = rowWidth / sizeof (uint16_t);
- class1 =
- getAppleClassTable (ttf, begin_table + left, info->glyph_cnt,
- array, rowWidth, info);
- class2 =
- getAppleClassTable (ttf, begin_table + right, info->glyph_cnt,
- 0, sizeof (uint16_t), info);
- for (i = 0; i < info->glyph_cnt; ++i)
- if (class1[i] > kc->first_cnt)
- kc->first_cnt = class1[i];
- ++kc->first_cnt;
- kc->offsets =
- xmalloc (kc->first_cnt * kc->second_cnt * sizeof (int16_t));
- kc->adjusts =
- xcalloc (kc->first_cnt * kc->second_cnt, sizeof (DeviceTable));
- fseek (ttf, begin_table + array, SEEK_SET);
- for (i = 0; i < kc->first_cnt * kc->second_cnt; ++i)
- kc->offsets[i] = getushort (ttf);
- }
- else
- {
- /* format 3, horizontal kerning data (as classes limited to 256 entries) */
- /* OpenType's spec doesn't document this */
- int gc, kv, flags;
- int16_t *kvs;
- gc = getushort (ttf);
- kv = getc (ttf);
- kc->first_cnt = getc (ttf);
- kc->second_cnt = getc (ttf);
- flags = getc (ttf);
- if (gc > info->glyph_cnt)
- {
- LogError (_
- ("Kerning subtable 3 says the glyph count is %d, but maxp says %d\n"),
- gc, info->glyph_cnt);
- info->bad_gx = true;
- }
- class1 =
- xcalloc (gc > info->glyph_cnt ? gc : info->glyph_cnt,
- sizeof (uint16_t));
- class2 =
- xcalloc (gc > info->glyph_cnt ? gc : info->glyph_cnt,
- sizeof (uint16_t));
- kvs = xmalloc (kv * sizeof (int16_t));
- kc->offsets =
- xmalloc (kc->first_cnt * kc->second_cnt * sizeof (int16_t));
- kc->adjusts =
- xcalloc (kc->first_cnt * kc->second_cnt, sizeof (DeviceTable));
- for (i = 0; i < kv; ++i)
- kvs[i] = (int16_t) getushort (ttf);
- for (i = 0; i < gc; ++i)
- class1[i] = getc (ttf);
- for (i = 0; i < gc; ++i)
- class2[i] = getc (ttf);
- for (i = 0; i < kc->first_cnt * kc->second_cnt; ++i)
- kc->offsets[i] = kvs[getc (ttf)];
- free (kvs);
- }
- kc->firsts =
- ClassToNames (info, kc->first_cnt, class1, info->glyph_cnt);
- kc->seconds =
- ClassToNames (info, kc->second_cnt, class2, info->glyph_cnt);
- for (i = 0; i < info->glyph_cnt; ++i)
- {
- if (class1[i] >= 4 && info->chars[i] != NULL)
- FListsAppendScriptLang (otl->features,
- SCScriptFromUnicode (info->chars[i]),
- DEFAULT_LANG);
- }
- free (class1);
- free (class2);
- fseek (ttf, begin_table + len, SEEK_SET);
- otl->subtables[0].kc = kc;
- kc->subtable = otl->subtables;
- InfoNameOTLookup (otl, info);
- }
- else
- {
- LogError (_
- ("Invalid or unsupported format (%d) for subtable of 'kern' table"),
- format);
- info->bad_gx = true;
- fseek (ttf, len - header_size, SEEK_CUR);
- if (otl != NULL)
- OTLRemove (info, otl, true);
- return; /* Give up */
- }
- }
- }
- /******************************************************************************/
- /* ******************************* MATH Table ******************************* */
- /* ********************** (Not strictly OpenType yet) *********************** */
- /******************************************************************************/
- /* ******************************** Read MATH ******************************* */
- static void
- ttf_math_read_constants (FILE *ttf, struct ttfinfo *info, uint32_t start)
- {
- struct MATH *math;
- int i;
- uint16_t off;
- fseek (ttf, start, SEEK_SET);
- info->math = math = xcalloc (1, sizeof (struct MATH));
- for (i = 0; math_constants_descriptor[i].script_name != NULL; ++i)
- {
- int16_t *pos =
- (int16_t *) (((char *) (math)) + math_constants_descriptor[i].offset);
- if (pos == (int16_t *) &math->MinConnectorOverlap)
- continue; /* Actually lives in the Variant table, not here */
- *pos = getushort (ttf);
- if (math_constants_descriptor[i].devtab_offset >= 0)
- {
- DeviceTable **devtab =
- (DeviceTable **) (((char *) (math)) +
- math_constants_descriptor[i].devtab_offset);
- off = getushort (ttf);
- if (off != 0)
- {
- *devtab = xzalloc (sizeof (DeviceTable));
- ReadDeviceTable (ttf, *devtab, start + off, info);
- }
- }
- }
- }
- static void
- ttf_math_read_icta (FILE *ttf, struct ttfinfo *info, uint32_t start, int is_ic)
- {
- /* The italic correction and top accent sub-tables have the same format */
- int coverage, cnt, i, val, offset;
- uint16_t *glyphs;
- fseek (ttf, start, SEEK_SET);
- coverage = getushort (ttf);
- cnt = getushort (ttf);
- glyphs = getCoverageTable (ttf, start + coverage, info);
- if (glyphs == NULL)
- return;
- fseek (ttf, start + 4, SEEK_SET);
- for (i = 0; i < cnt; ++i)
- {
- val = (int16_t) getushort (ttf);
- offset = getushort (ttf);
- if (glyphs[i] < info->glyph_cnt && info->chars[glyphs[i]] != NULL)
- {
- if (is_ic)
- info->chars[glyphs[i]]->italic_correction = val;
- else
- info->chars[glyphs[i]]->top_accent_horiz = val;
- if (offset != 0)
- {
- DeviceTable *dv = xzalloc (sizeof (DeviceTable));
- ReadDeviceTable (ttf, dv, start + offset, info);
- if (is_ic)
- info->chars[glyphs[i]]->italic_adjusts = dv;
- else
- info->chars[glyphs[i]]->top_accent_adjusts = dv;
- }
- }
- }
- free (glyphs);
- }
- static void
- ttf_math_read_extended (FILE *ttf, struct ttfinfo *info, uint32_t start)
- {
- int i;
- uint16_t *glyphs;
- glyphs = getCoverageTable (ttf, start, info);
- if (glyphs == NULL)
- return;
- for (i = 0; glyphs[i] != 0xffff; ++i)
- if (glyphs[i] < info->glyph_cnt && info->chars[glyphs[i]] != NULL)
- info->chars[glyphs[i]]->is_extended_shape = true;
- free (glyphs);
- }
- static void
- ttf_math_read_mathkernv (FILE *ttf, uint32_t start, struct mathkernvertex *mkv,
- SplineChar *sc, int istop, struct ttfinfo *info)
- {
- int cnt, i;
- fseek (ttf, start, SEEK_SET);
- /* There is one more width than height. I store the width count */
- /* and guess a dummy height later */
- mkv->cnt = cnt = getushort (ttf) + 1;
- mkv->mkd = xcalloc (cnt, sizeof (struct mathkerndata));
- for (i = 0; i < cnt - 1; ++i)
- {
- mkv->mkd[i].height = getushort (ttf);
- mkv->mkd[i].height_adjusts = (void *) (intptr_t) getushort (ttf);
- }
- for (i = 0; i < cnt; ++i)
- {
- mkv->mkd[i].kern = getushort (ttf);
- mkv->mkd[i].kern_adjusts = (void *) (intptr_t) getushort (ttf);
- }
- for (i = 0; i < cnt; ++i)
- {
- DeviceTable *dv;
- uint32_t offset;
- if (mkv->mkd[i].height_adjusts != NULL)
- {
- offset = start + (intptr_t) mkv->mkd[i].height_adjusts;
- mkv->mkd[i].height_adjusts = dv =
- xzalloc (sizeof (DeviceTable));
- ReadDeviceTable (ttf, dv, offset, info);
- }
- if (mkv->mkd[i].kern_adjusts != NULL)
- {
- offset = start + (intptr_t) mkv->mkd[i].kern_adjusts;
- mkv->mkd[i].kern_adjusts = dv =
- xzalloc (sizeof (DeviceTable));
- ReadDeviceTable (ttf, dv, offset, info);
- }
- }
- if (cnt >= 3)
- mkv->mkd[cnt - 1].height =
- 2 * mkv->mkd[cnt - 2].height - mkv->mkd[cnt - 3].height;
- else if (cnt >= 2)
- mkv->mkd[cnt - 1].height = mkv->mkd[cnt - 2].height + 100;
- else if (cnt == 1)
- {
- if (istop)
- {
- DBounds b;
- SplineCharQuickBounds (sc, &b);
- mkv->mkd[cnt - 1].height = b.maxy;
- }
- else
- mkv->mkd[cnt - 1].height = 0;
- }
- }
- static void
- ttf_math_read_mathkern (FILE *ttf, struct ttfinfo *info, uint32_t start)
- {
- int coverage, cnt, i;
- uint16_t *glyphs;
- struct koff
- {
- uint16_t tr, tl, br, bl;
- } *koff;
- fseek (ttf, start, SEEK_SET);
- coverage = getushort (ttf);
- cnt = getushort (ttf);
- koff = xmalloc (cnt * sizeof (struct koff));
- for (i = 0; i < cnt; ++i)
- {
- koff[i].tr = getushort (ttf);
- koff[i].tl = getushort (ttf);
- koff[i].br = getushort (ttf);
- koff[i].bl = getushort (ttf);
- }
- glyphs = getCoverageTable (ttf, start + coverage, info);
- if (glyphs == NULL)
- {
- free (koff);
- return;
- }
- for (i = 0; i < cnt; ++i)
- if (glyphs[i] < info->glyph_cnt && info->chars[glyphs[i]] != NULL)
- {
- SplineChar *sc = info->chars[glyphs[i]];
- sc->mathkern = xzalloc (sizeof (struct mathkern));
- if (koff[i].tr != 0)
- ttf_math_read_mathkernv (ttf, start + koff[i].tr,
- &sc->mathkern->top_right, sc, true, info);
- if (koff[i].tl != 0)
- ttf_math_read_mathkernv (ttf, start + koff[i].tl,
- &sc->mathkern->top_left, sc, true, info);
- if (koff[i].br != 0)
- ttf_math_read_mathkernv (ttf, start + koff[i].br,
- &sc->mathkern->bottom_right, sc, false,
- info);
- if (koff[i].bl != 0)
- ttf_math_read_mathkernv (ttf, start + koff[i].bl,
- &sc->mathkern->bottom_left, sc, false, info);
- }
- free (koff);
- free (glyphs);
- }
- static void
- ttf_math_read_glyphinfo (FILE *ttf, struct ttfinfo *info, uint32_t start)
- {
- int icoff, taoff, esoff, kioff;
- fseek (ttf, start, SEEK_SET);
- icoff = getushort (ttf);
- taoff = getushort (ttf);
- esoff = getushort (ttf);
- kioff = getushort (ttf);
- if (icoff != 0)
- ttf_math_read_icta (ttf, info, start + icoff, true);
- if (taoff != 0)
- ttf_math_read_icta (ttf, info, start + taoff, false);
- if (esoff != 0)
- ttf_math_read_extended (ttf, info, start + esoff);
- if (kioff != 0)
- ttf_math_read_mathkern (ttf, info, start + kioff);
- }
- static struct glyphvariants *
- ttf_math_read_gvtable (FILE *ttf, struct ttfinfo *info, uint32_t start,
- enum gsub_inusetype justinuse, SplineChar *basesc,
- int isv)
- {
- struct glyphvariants *gv =
- xzalloc (sizeof (struct glyphvariants));
- int ga_offset;
- int vcnt;
- uint16_t *glyphs;
- int i, j, len;
- char *pt;
- int ic_offset, pcnt;
- SplineChar *sc;
- char ebuf[10], buffer[50], *ext;
- fseek (ttf, start, SEEK_SET);
- ga_offset = getushort (ttf);
- vcnt = getushort (ttf);
- if (vcnt != 0)
- {
- if (justinuse == git_justinuse)
- {
- for (i = 0; i < vcnt; ++i)
- {
- int gid = getushort (ttf);
- /* sizes[i] = */ getushort (ttf);
- if (gid >= 0 && gid < info->glyph_cnt)
- info->inuse[gid] = true;
- }
- }
- else if (justinuse == git_findnames)
- {
- for (i = 0; i < vcnt; ++i)
- {
- int gid = getushort (ttf);
- /* sizes[i] = */ getushort (ttf);
- if (basesc != NULL && basesc->name != NULL &&
- gid >= 0 && gid < info->glyph_cnt &&
- (sc = info->chars[gid]) != NULL && sc->name == NULL)
- {
- snprintf (buffer, sizeof (buffer), "%.30s.%csize%d",
- basesc->name, isv ? 'v' : 'h', i);
- if (!glyphNameExists (info, buffer))
- sc->name = xstrdup_or_null (buffer);
- }
- }
- }
- else
- {
- glyphs = xmalloc (vcnt * sizeof (uint16_t));
- len = 0;
- for (i = 0; i < vcnt; ++i)
- {
- glyphs[i] = getushort (ttf);
- /* sizes[i] = */ getushort (ttf);
- if (glyphs[i] < info->glyph_cnt
- && (sc = info->chars[glyphs[i]]) != NULL)
- len += strlen (sc->name) + 1;
- }
- if (len != 0)
- {
- gv->variants = pt = xmalloc (len);
- for (i = len = 0; i < vcnt; ++i)
- {
- if (glyphs[i] < info->glyph_cnt
- && (sc = info->chars[glyphs[i]]) != NULL)
- {
- strcpy (pt + len, sc->name);
- len += strlen (sc->name);
- pt[len++] = ' ';
- }
- }
- pt[len - 1] = '\0';
- }
- free (glyphs);
- }
- }
- if (ga_offset != 0)
- {
- start += ga_offset;
- fseek (ttf, start, SEEK_SET);
- gv->italic_correction = getushort (ttf);
- ic_offset = getushort (ttf);
- gv->part_cnt = pcnt = getushort (ttf);
- if (justinuse == git_normal)
- gv->parts = xcalloc (pcnt, sizeof (struct gv_part));
- for (i = j = 0; i < pcnt; ++i)
- {
- int gid, start, end, full, flags;
- gid = getushort (ttf);
- start = getushort (ttf);
- end = getushort (ttf);
- full = getushort (ttf);
- flags = getushort (ttf);
- if (feof (ttf))
- {
- LogError (_("Bad glyph variant subtable of MATH table.\n"));
- info->bad_ot = true;
- free (gv);
- return NULL;
- }
- if (justinuse == git_justinuse)
- {
- if (gid < info->glyph_cnt)
- info->inuse[gid] = true;
- }
- else if (justinuse == git_findnames)
- {
- if (basesc != NULL && basesc->name != NULL &&
- gid >= 0 && gid < info->glyph_cnt &&
- (sc = info->chars[gid]) != NULL && sc->name == NULL)
- {
- if (pcnt == 1)
- ext = "repeat";
- if (i == 0)
- ext = isv ? "bot" : "left";
- else if (i == pcnt - 1)
- ext = isv ? "top" : "right";
- else if (i == 1 && pcnt == 3)
- ext = "mid";
- else
- {
- sprintf (ebuf, "%cpart%d", isv ? 'v' : 'h', i);
- ext = ebuf;
- }
- snprintf (buffer, sizeof (buffer), "%.30s.%s",
- basesc->name, ext);
- if (!glyphNameExists (info, buffer))
- sc->name = xstrdup_or_null (buffer);
- }
- }
- else
- {
- if (gid < info->glyph_cnt && (sc = info->chars[gid]) != NULL)
- {
- gv->parts[j].component = xstrdup_or_null (sc->name);
- gv->parts[j].startConnectorLength = start;
- gv->parts[j].endConnectorLength = end;
- gv->parts[j].fullAdvance = full;
- gv->parts[j++].is_extender = flags & 1;
- }
- }
- }
- gv->part_cnt = j;
- if (ic_offset != 0 && justinuse == git_normal)
- {
- gv->italic_adjusts = xzalloc (sizeof (DeviceTable));
- ReadDeviceTable (ttf, gv->italic_adjusts, start + ic_offset, info);
- }
- }
- if (justinuse == git_justinuse)
- {
- free (gv);
- return NULL;
- }
- return gv;
- }
- static void
- ttf_math_read_variants (FILE *ttf, struct ttfinfo *info, uint32_t start,
- enum gsub_inusetype justinuse)
- {
- int vcoverage, hcoverage, vcnt, hcnt;
- int *hoffs, *voffs;
- uint16_t *hglyphs, *vglyphs;
- int i;
- fseek (ttf, start, SEEK_SET);
- if (info->math == NULL)
- info->math = xcalloc (1, sizeof (struct MATH));
- info->math->MinConnectorOverlap = getushort (ttf);
- vcoverage = getushort (ttf);
- hcoverage = getushort (ttf);
- vcnt = getushort (ttf);
- hcnt = getushort (ttf);
- hoffs = xmalloc (hcnt * sizeof (int));
- voffs = xmalloc (vcnt * sizeof (int));
- for (i = 0; i < vcnt; ++i)
- voffs[i] = getushort (ttf);
- for (i = 0; i < hcnt; ++i)
- hoffs[i] = getushort (ttf);
- vglyphs = hglyphs = NULL;
- if (vcoverage != 0)
- vglyphs = getCoverageTable (ttf, start + vcoverage, info);
- if (hcoverage != 0)
- hglyphs = getCoverageTable (ttf, start + hcoverage, info);
- if (vglyphs != NULL)
- {
- for (i = 0; i < vcnt; ++i)
- if (vglyphs[i] < info->glyph_cnt && voffs[i] != 0)
- {
- if (justinuse == git_normal || justinuse == git_findnames)
- {
- SplineChar *sc = info->chars[vglyphs[i]];
- if (sc != NULL)
- sc->vert_variants =
- ttf_math_read_gvtable (ttf, info, start + voffs[i],
- justinuse, sc, true);
- }
- else if (info->inuse[vglyphs[i]])
- ttf_math_read_gvtable (ttf, info, start + voffs[i], justinuse,
- NULL, true);
- }
- }
- if (hglyphs != NULL)
- {
- for (i = 0; i < hcnt; ++i)
- if (hglyphs[i] < info->glyph_cnt && hoffs[i] != 0)
- {
- if (justinuse == git_normal || justinuse == git_findnames)
- {
- SplineChar *sc = info->chars[hglyphs[i]];
- if (sc != NULL)
- sc->horiz_variants =
- ttf_math_read_gvtable (ttf, info, start + hoffs[i],
- justinuse, sc, false);
- }
- else if (info->inuse[hglyphs[i]])
- ttf_math_read_gvtable (ttf, info, start + hoffs[i], justinuse,
- NULL, false);
- }
- }
- free (vglyphs);
- free (voffs);
- free (hglyphs);
- free (hoffs);
- }
- static void
- _otf_read_math (FILE *ttf, struct ttfinfo *info, enum gsub_inusetype justinuse)
- {
- int constants, glyphinfo, variants;
- if (info->math_start == 0)
- return;
- fseek (ttf, info->math_start, SEEK_SET);
- info->g_bounds = info->math_start + info->math_length;
- if (getlong (ttf) != 0x00010000)
- return;
- constants = getushort (ttf);
- glyphinfo = getushort (ttf);
- variants = getushort (ttf);
- if (justinuse == git_normal)
- {
- if (constants != 0)
- ttf_math_read_constants (ttf, info, info->math_start + constants);
- if (glyphinfo != 0)
- ttf_math_read_glyphinfo (ttf, info, info->math_start + glyphinfo);
- }
- if (variants != 0)
- ttf_math_read_variants (ttf, info, info->math_start + variants, justinuse);
- if (ftell (ttf) > info->g_bounds)
- {
- LogError (_("MATH table extends beyond table bounds"));
- info->bad_ot = true;
- }
- info->g_bounds = 0;
- }
- void
- otf_read_math (FILE *ttf, struct ttfinfo *info)
- {
- _otf_read_math (ttf, info, git_normal);
- }
- void
- otf_read_math_used (FILE *ttf, struct ttfinfo *info)
- {
- _otf_read_math (ttf, info, git_justinuse);
- }
- void
- GuessNamesFromMATH (FILE *ttf, struct ttfinfo *info)
- {
- _otf_read_math (ttf, info, git_findnames);
- }
- static struct baselangextent *
- readttfbaseminmax (FILE *ttf, uint32_t offset, struct ttfinfo *info,
- uint32_t script_tag, uint32_t lang_tag)
- {
- int j, feat_cnt;
- struct baselangextent *lang, *cur, *last;
- fseek (ttf, offset, SEEK_SET);
- lang = xzalloc (sizeof (struct baselangextent));
- lang->lang = lang_tag;
- lang->descent = (short) getushort (ttf);
- lang->ascent = (short) getushort (ttf);
- feat_cnt = getushort (ttf);
- last = NULL;
- for (j = 0; j < feat_cnt; ++j)
- {
- cur = xzalloc (sizeof (struct baselangextent));
- if (last == NULL)
- lang->features = cur;
- else
- last->next = cur;
- last = cur;
- cur->lang = getlong (ttf); /* Actually feature tag here */
- cur->descent = (short) getushort (ttf);
- cur->ascent = (short) getushort (ttf);
- }
- return lang;
- }
- void
- readttfbase (FILE *ttf, struct ttfinfo *info)
- {
- int version;
- uint32_t axes[2];
- uint32_t basetags, basescripts;
- int basescriptcnt;
- struct tagoff
- {
- uint32_t tag;
- uint32_t offset;
- } *bs;
- int axis, i, j, tot;
- struct Base *curBase;
- struct basescript *curScript, *last;
- struct baselangextent *cur, *lastLang;
- if (info->base_start == 0)
- return;
- fseek (ttf, info->base_start, SEEK_SET);
- version = getlong (ttf);
- if (version != 0x00010000)
- return;
- axes[0] = getushort (ttf); /* Horizontal */
- axes[1] = getushort (ttf); /* Vertical */
- for (axis = 0; axis < 2; ++axis)
- {
- if (axes[axis] == 0)
- continue;
- fseek (ttf, info->base_start + axes[axis], SEEK_SET);
- curBase = xzalloc (sizeof (struct Base));
- if (axis == 0)
- info->horiz_base = curBase;
- else
- info->vert_base = curBase;
- basetags = getushort (ttf);
- basescripts = getushort (ttf);
- if (basetags == 0)
- {
- curBase->baseline_cnt = 0;
- curBase->baseline_tags = NULL;
- }
- else
- {
- fseek (ttf, info->base_start + axes[axis] + basetags, SEEK_SET);
- curBase->baseline_cnt = getushort (ttf);
- curBase->baseline_tags =
- xcalloc (curBase->baseline_cnt, sizeof (uint32_t));
- for (i = 0; i < curBase->baseline_cnt; ++i)
- curBase->baseline_tags[i] = getlong (ttf);
- }
- if (basescripts != 0)
- {
- fseek (ttf, info->base_start + axes[axis] + basescripts, SEEK_SET);
- basescriptcnt = getushort (ttf);
- bs = xcalloc (basescriptcnt, sizeof (struct tagoff));
- for (i = 0; i < basescriptcnt; ++i)
- {
- bs[i].tag = getlong (ttf);
- bs[i].offset = getushort (ttf);
- if (bs[i].offset != 0)
- bs[i].offset += info->base_start + axes[axis] + basescripts;
- }
- last = NULL;
- for (i = 0; i < basescriptcnt; ++i)
- if (bs[i].offset != 0)
- {
- int basevalues, defminmax;
- int langsyscnt;
- struct tagoff *ls;
- fseek (ttf, bs[i].offset, SEEK_SET);
- basevalues = getushort (ttf);
- defminmax = getushort (ttf);
- langsyscnt = getushort (ttf);
- ls = xcalloc (langsyscnt, sizeof (struct tagoff));
- for (j = 0; j < langsyscnt; ++j)
- {
- ls[j].tag = getlong (ttf);
- ls[j].offset = getushort (ttf);
- }
- curScript =
- xzalloc (sizeof (struct basescript));
- if (last == NULL)
- curBase->scripts = curScript;
- else
- last->next = curScript;
- last = curScript;
- curScript->script = bs[i].tag;
- if (basevalues != 0)
- {
- int coordcnt;
- int *coords;
- fseek (ttf, bs[i].offset + basevalues, SEEK_SET);
- curScript->def_baseline = getushort (ttf);
- tot = coordcnt = getushort (ttf);
- if (coordcnt != curBase->baseline_cnt)
- {
- info->bad_ot = true;
- LogError (_
- ("!!!!! Coord count (%d) for '%c%c%c%c' script does not match base tag count (%d) in 'BASE' table\n"),
- coordcnt, bs[i].tag >> 24, bs[i].tag >> 16,
- bs[i].tag >> 8, bs[i].tag,
- curBase->baseline_cnt);
- if (tot < curBase->baseline_cnt)
- tot = curBase->baseline_cnt;
- }
- coords = xcalloc (coordcnt, sizeof (int));
- curScript->baseline_pos = xcalloc (tot, sizeof (int16_t));
- for (j = 0; j < coordcnt; ++j)
- coords[j] = getushort (ttf);
- for (j = 0; j < coordcnt; ++j)
- if (coords[j] != 0)
- {
- int format;
- fseek (ttf, bs[i].offset + basevalues + coords[j],
- SEEK_SET);
- format = getushort (ttf);
- curScript->baseline_pos[j] = (short) getushort (ttf);
- if (format != 1 && format != 2 && format != 3)
- {
- info->bad_ot = true;
- LogError (_
- ("!!!!! Bad Base Coord format (%d) for '%c%c%c%c' in '%c%c%c%c' script in 'BASE' table\n"),
- format, curBase->baseline_tags[j] >> 24,
- curBase->baseline_tags[j] >> 16,
- curBase->baseline_tags[j] >> 8,
- curBase->baseline_tags[j],
- bs[i].tag >> 24, bs[i].tag >> 16,
- bs[i].tag >> 8, bs[i].tag);
- }
- }
- free (coords);
- }
- else
- {
- curScript->baseline_pos =
- xcalloc (curBase->baseline_cnt, sizeof (int16_t));
- }
- lastLang = NULL;
- if (defminmax != 0)
- curScript->langs = lastLang =
- readttfbaseminmax (ttf, bs[i].offset + defminmax, info,
- bs[i].tag, DEFAULT_LANG);
- if (langsyscnt != 0)
- {
- for (j = 0; j < langsyscnt; ++j)
- if (ls[j].offset != 0)
- {
- cur =
- readttfbaseminmax (ttf, bs[i].offset + ls[j].offset,
- info, bs[i].tag, ls[j].tag);
- if (lastLang == NULL)
- curScript->langs = cur;
- else
- lastLang->next = cur;
- lastLang = cur;
- }
- }
- free (ls);
- }
- }
- free (bs);
- }
- }
- static char *
- jstf_read_extenders (FILE *ttf, uint32_t spos, int extendOff,
- struct ttfinfo *info)
- {
- uint16_t *glyphs;
- int cnt, i;
- char *ret;
- if (extendOff == 0)
- return NULL;
- if (spos + extendOff + 2 > info->g_bounds)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, spos + extendOff, SEEK_SET);
- cnt = getushort (ttf);
- if (spos + extendOff + 2 + 2 * cnt > info->g_bounds || cnt < 0)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- if (cnt == 0)
- return NULL;
- glyphs = xmalloc ((cnt + 1) * sizeof (uint16_t));
- for (i = 0; i < cnt; ++i)
- {
- glyphs[i] = getushort (ttf);
- if (glyphs[i] >= info->glyph_cnt)
- {
- LogError (_("Bad GID in JSTF extenser table.\n"));
- glyphs[i] = 0;
- info->bad_ot = true;
- }
- }
- glyphs[i] = 0xffff;
- ret = GlyphsToNames (info, glyphs, false);
- free (glyphs);
- return ret;
- }
- static OTLookup *
- findLookupByIndex (OTLookup *lookups, int index)
- {
- while (index > 0)
- {
- if (lookups == NULL)
- return NULL;
- lookups = lookups->next;
- --index;
- }
- return lookups;
- }
- static OTLookup **
- jstf_subpos (FILE *ttf, uint32_t base, int Sub, int Pos, struct ttfinfo *info)
- {
- int scnt = 0, pcnt = 0;
- OTLookup **ret;
- int i;
- if (Sub > 0)
- {
- fseek (ttf, base + Sub, SEEK_SET);
- scnt = getushort (ttf);
- if (base + Sub + 2 + scnt * sizeof (int16_t) > info->g_bounds || scnt < 0)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- }
- if (Pos > 0)
- {
- fseek (ttf, base + Pos, SEEK_SET);
- pcnt = getushort (ttf);
- if (base + Pos + 2 + pcnt * sizeof (int16_t) > info->g_bounds || pcnt < 0)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- }
- if (scnt == 0 && pcnt == 0)
- return NULL;
- ret = xmalloc ((scnt + pcnt + 1) * sizeof (OTLookup *));
- if (Sub > 0)
- {
- fseek (ttf, base + Sub + 2, SEEK_SET);
- for (i = 0; i < scnt; ++i)
- {
- int index = getushort (ttf);
- if (index < 0)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- ret[i] = findLookupByIndex (info->gsub_lookups, index);
- if (ret[i] == NULL)
- {
- LogError (_
- ("Lookup index (%d) out of bounds in GSUB from JSTF table.\n"),
- index);
- info->bad_ot = true;
- return NULL;
- }
- }
- ret[i] = NULL;
- }
- if (Pos > 0)
- {
- fseek (ttf, base + Pos + 2, SEEK_SET);
- for (i = 0; i < pcnt; ++i)
- {
- int index = getushort (ttf);
- if (index < 0)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- ret[i + scnt] = findLookupByIndex (info->gpos_lookups, index);
- if (ret[i + scnt] == NULL)
- {
- LogError (_
- ("Lookup index (%d) out of bounds in GPOS from JSTF table.\n"),
- index);
- info->bad_ot = true;
- return NULL;
- }
- }
- ret[i + scnt] = NULL;
- }
- return ret;
- }
- static void
- NameOTJSTFLookup (OTLookup *otl, struct ttfinfo *info)
- {
- char buffer[300], *format;
- struct lookup_subtable *subtable;
- int cnt;
- if (info->jstf_isShrink)
- /* TRANSLATORS: This string is used to generate a name for an OpenType lookup. */
- /* the %c%c... is the language followed by the script (OT tags) */
- snprintf (buffer, sizeof (buffer),
- _
- ("JSTF shrinkage max at priority %d #%d for %c%c%c%c in %c%c%c%c"),
- info->jstf_prio, info->jstf_lcnt++, info->jstf_lang >> 24,
- info->jstf_lang >> 16, info->jstf_lang >> 8, info->jstf_lang,
- info->jstf_script >> 24, info->jstf_script >> 16,
- info->jstf_script >> 8, info->jstf_script);
- else
- snprintf (buffer, sizeof (buffer),
- _
- ("JSTF extension max at priority %d #%d for %c%c%c%c in %c%c%c%c"),
- info->jstf_prio, info->jstf_lcnt++, info->jstf_lang >> 24,
- info->jstf_lang >> 16, info->jstf_lang >> 8, info->jstf_lang,
- info->jstf_script >> 24, info->jstf_script >> 16,
- info->jstf_script >> 8, info->jstf_script);
- otl->lookup_name = xstrdup_or_null (buffer);
- cnt = 0;
- for (subtable = otl->subtables; subtable != NULL;
- subtable = subtable->next, ++cnt)
- {
- if (subtable->subtable_name == NULL)
- {
- if (subtable == otl->subtables && subtable->next == NULL)
- format = _("%s subtable");
- else
- format = _("%s subtable %d");
- snprintf (buffer, sizeof (buffer), format, otl->lookup_name, cnt);
- subtable->subtable_name = xstrdup_or_null (buffer);
- }
- }
- }
- static OTLookup **
- jstf_processlookups (FILE *ttf, uint32_t base, int lookup_off,
- struct ttfinfo *info)
- {
- OTLookup **ret;
- struct lookup *lookups, *l;
- struct lookup_subtable *subtable;
- int cnt, k;
- int32_t st;
- if (lookup_off == 0)
- return NULL;
- lookups = readttflookups (ttf, base + lookup_off, info, 2);
- if (lookups == NULL)
- return NULL;
- for (l = lookups, cnt = 0; l->offset != 0; ++l, ++cnt)
- {
- for (k = 0, subtable = l->otlookup->subtables; k < l->subtabcnt;
- ++k, subtable = subtable->next)
- {
- st = l->subtab_offsets[k];
- fseek (ttf, st, SEEK_SET);
- gposLookupSwitch (ttf, st, info, l, subtable, lookups);
- }
- }
- ret = xmalloc ((cnt + 1) * sizeof (OTLookup *));
- for (l = lookups, cnt = 0; l->offset != 0; ++l, ++cnt)
- {
- NameOTJSTFLookup (l->otlookup, info);
- ret[cnt] = l->otlookup;
- }
- ret[cnt] = NULL;
- LookupsFree (lookups);
- return ret;
- }
- static struct jstf_lang *
- jstf_lang (FILE *ttf, uint32_t base,
- int off, uint32_t tag, struct ttfinfo *info)
- {
- int cnt, i;
- struct jstf_lang *ret;
- if (off <= 0)
- return NULL;
- if (base + off + 2 > info->g_bounds)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- fseek (ttf, base + off, SEEK_SET);
- cnt = getushort (ttf);
- if (base + off + 2 + 2 * cnt > info->g_bounds || cnt < 0)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return NULL;
- }
- if (cnt == 0)
- return NULL;
- ret = xzalloc (sizeof (struct jstf_lang));
- ret->lang = info->jstf_lang = tag;
- ret->cnt = cnt;
- ret->prios = xcalloc (cnt, sizeof (struct jstf_prio));
- for (i = 0; i < cnt; ++i)
- ret->prios[i].maxExtend = (void *) (intptr_t) getushort (ttf);
- for (i = 0; i < cnt; ++i)
- {
- int enSub, disSub, enPos, disPos, maxShrink, maxExtend;
- int enSub2, disSub2, enPos2, disPos2;
- uint32_t pbase = base + off + (intptr_t) ret->prios[i].maxExtend;
- fseek (ttf, pbase, SEEK_SET);
- info->jstf_prio = i;
- enSub = getushort (ttf);
- disSub = getushort (ttf);
- enPos = getushort (ttf);
- disPos = getushort (ttf);
- maxShrink = getushort (ttf);
- enSub2 = getushort (ttf);
- disSub2 = getushort (ttf);
- enPos2 = getushort (ttf);
- disPos2 = getushort (ttf);
- maxExtend = getushort (ttf);
- ret->prios[i].enableShrink = jstf_subpos (ttf, pbase, enSub, enPos, info);
- ret->prios[i].disableShrink =
- jstf_subpos (ttf, pbase, disSub, disPos, info);
- ret->prios[i].enableExtend =
- jstf_subpos (ttf, pbase, enSub2, enPos2, info);
- ret->prios[i].disableExtend =
- jstf_subpos (ttf, pbase, disSub2, disPos2, info);
- info->jstf_isShrink = true;
- ret->prios[i].maxShrink =
- jstf_processlookups (ttf, pbase, maxShrink, info);
- info->jstf_isShrink = false;
- ret->prios[i].maxExtend =
- jstf_processlookups (ttf, pbase, maxExtend, info);
- }
- return ret;
- }
- void
- readttfjstf (FILE *ttf, struct ttfinfo *info)
- {
- int version;
- int scnt, lcnt, lmax;
- int i, j;
- struct tagoff
- {
- uint32_t tag;
- int offset;
- } *soff, *loff;
- Justify *last = NULL, *cur;
- struct jstf_lang *llast, *lcur;
- int extendOff, defOff;
- if (info->jstf_start == 0)
- return;
- fseek (ttf, info->jstf_start, SEEK_SET);
- info->g_bounds = info->jstf_start + info->jstf_length;
- version = getlong (ttf);
- if (version != 0x00010000)
- return;
- scnt = getushort (ttf);
- if (scnt < 0 || scnt > 1000)
- {
- LogError (_
- ("Unlikely script count (%d), I suspect the JSTF-\n table is garbage, I'm giving up on it.\n"),
- scnt);
- info->bad_ot = true;
- return;
- }
- soff = xmalloc (scnt * sizeof (struct tagoff));
- for (i = 0; i < scnt; ++i)
- {
- soff[i].tag = getlong (ttf);
- soff[i].offset = getushort (ttf);
- if (soff[i].offset < 0)
- {
- LogError (_("End of file found in JSTF table.\n"));
- info->bad_ot = true;
- return;
- }
- }
- if (ftell (ttf) > info->g_bounds)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return;
- }
- lmax = 0;
- loff = NULL;
- for (i = 0; i < scnt; ++i)
- {
- fseek (ttf, info->jstf_start + soff[i].offset, SEEK_SET);
- extendOff = getushort (ttf);
- defOff = getushort (ttf);
- lcnt = getushort (ttf);
- if (info->jstf_start + soff[i].offset > info->g_bounds - 6 - 6 * lcnt
- || lcnt < 0)
- {
- LogError (_("JSTF table is too long.\n"));
- info->bad_ot = true;
- return;
- }
- if (lcnt > lmax)
- loff = xrealloc (loff, (lmax = lcnt) * sizeof (struct tagoff));
- for (j = 0; j < lcnt; ++j)
- {
- loff[j].tag = getlong (ttf);
- loff[j].offset = getushort (ttf);
- if (loff[j].offset < 0)
- {
- LogError (_("End of file found in JSTF table.\n"));
- info->bad_ot = true;
- return;
- }
- }
- cur = xzalloc (sizeof (Justify));
- cur->script = info->jstf_script = soff[i].tag;
- if (last == NULL)
- info->justify = cur;
- else
- last->next = cur;
- last = cur;
- cur->extenders =
- jstf_read_extenders (ttf, info->jstf_start + soff[i].offset, extendOff,
- info);
- llast = NULL;
- if (defOff != 0)
- llast = cur->langs =
- jstf_lang (ttf, info->jstf_start + soff[i].offset, defOff,
- DEFAULT_LANG, info);
- for (j = 0; j < lcnt; ++j)
- {
- lcur = jstf_lang (ttf, info->jstf_start + soff[i].offset,
- loff[j].offset, loff[j].tag, info);
- if (lcur != NULL)
- {
- if (llast == NULL)
- cur->langs = lcur;
- else
- llast->next = lcur;
- llast = lcur;
- }
- }
- }
- free (loff);
- free (soff);
- }