/fontforge/tottfgpos.c
C | 5571 lines | 4941 code | 397 blank | 233 comment | 1955 complexity | fb79f565cec60f1267722303855b2deb MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- #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 "fontforgevw.h"
- #include <utype.h>
- #include <ustring.h>
- VISIBLE int coverageformatsallowed = 3;
- VISIBLE int use_second_indic_scripts = false;
- #include "ttf.h"
- /* This file contains routines to create the otf gpos and gsub tables and their */
- /* attendant subtables */
- /* Undocumented fact: ATM (which does kerning for otf fonts in Word) can't handle features with multiple lookups */
- /* Undocumented fact: Only one feature with a given tag allowed per script/lang */
- /* So if we have multiple lookups with the same tag they must be merged into */
- /* one feature with many lookups */
- /* scripts (for opentype) that I understand */
- /* see also list in lookups.c mapping script tags to friendly names */
- static uint32_t scripts[][15] = {
- /* Arabic */ {CHR ('a', 'r', 'a', 'b'), 0x0600, 0x06ff, 0xfb50, 0xfdff,
- 0xfe70, 0xfefe},
- /* Aramaic */ {CHR ('a', 'r', 'a', 'm'), 0x820, 0x83f},
- /* Armenian */ {CHR ('a', 'r', 'm', 'n'), 0x0530, 0x058f, 0xfb13, 0xfb17},
- /* Balinese */ {CHR ('b', 'a', 'l', 'i'), 0x1b00, 0x1b7f},
- /* Bengali */ {CHR ('b', 'e', 'n', 'g'), 0x0980, 0x09ff},
- /* Bliss symb */ {CHR ('b', 'l', 'i', 's'), 0x12200, 0x124ff},
- /* Bopomofo */ {CHR ('b', 'o', 'p', 'o'), 0x3100, 0x312f, 0x31a0, 0x31bf},
- /* Braille */ {CHR ('b', 'r', 'a', 'i'), 0x2800, 0x28ff},
- /* Buginese */ {CHR ('b', 'u', 'g', 'i'), 0x1a00, 0x1a1f},
- /* Buhid */ {CHR ('b', 'u', 'h', 'd'), 0x1740, 0x1753},
- /* Byzantine M*/ {CHR ('b', 'y', 'z', 'm'), 0x1d000, 0x1d0ff},
- /* Canadian Syl*/ {CHR ('c', 'a', 'n', 's'), 0x1400, 0x167f},
- /* Carian */ {CHR ('c', 'a', 'r', 'i'), 0x0, 0x0},
- /* Cham */ {CHR ('c', 'h', 'a', 'm'), 0x0, 0x0},
- /* Cherokee */ {CHR ('c', 'h', 'e', 'r'), 0x13a0, 0x13ff},
- /* Cirth */ {CHR ('c', 'i', 'r', 't'), 0x12080, 0x120ff},
- /* CJKIdeogra */ {CHR ('h', 'a', 'n', 'i'), 0x3300, 0x9fff, 0xf900, 0xfaff,
- 0x020000, 0x02ffff},
- /* Coptic */ {CHR ('c', 'o', 'p', 't'), 0x2c80, 0x2cff},
- /* Cypriot */ {CHR ('c', 'p', 'm', 'n'), 0x10800, 0x1083f},
- /* Cyrillic */ {CHR ('c', 'y', 'r', 'l'), 0x0400, 0x052f, 0x1d2b, 0x1d2b,
- 0x1d78, 0x1d78,
- 0x2de0, 0x2dff, 0xa640, 0xa6ff},
- /* Deseret */ {CHR ('d', 's', 'r', 't'), 0x10400, 0x1044f},
- /* Devanagari */ {CHR ('d', 'e', 'v', 'a'), 0x0900, 0x097f},
- /* Ethiopic */ {CHR ('e', 't', 'h', 'i'), 0x1200, 0x139f},
- /* Georgian */ {CHR ('g', 'e', 'o', 'r'), 0x1080, 0x10ff},
- /* Glagolitic */ {CHR ('g', 'l', 'a', 'g'), 0x1080, 0x10ff},
- /* Gothic */ {CHR ('g', 'o', 't', 'h'), 0x10330, 0x1034a},
- /* Greek */ {CHR ('g', 'r', 'e', 'k'), 0x0370, 0x03ff, 0x1f00, 0x1fff},
- /* Gujarati */ {CHR ('g', 'u', 'j', 'r'), 0x0a80, 0x0aff},
- /* Gurmukhi */ {CHR ('g', 'u', 'r', 'u'), 0x0a00, 0x0a7f},
- /* Hangul */ {CHR ('h', 'a', 'n', 'g'), 0xac00, 0xd7af, 0x3130, 0x319f,
- 0xffa0, 0xff9f},
- /* Hanunoo */ {CHR ('h', 'a', 'n', 'o'), 0x1720, 0x1734},
- /* I'm not sure what the difference is between the 'hang' tag and the 'jamo' */
- /* tag. 'Jamo' is said to be the precomposed forms, but what's 'hang'? */
- /* Hebrew */ {CHR ('h', 'e', 'b', 'r'), 0x0590, 0x05ff, 0xfb1e, 0xfb4f},
- #if 0 /* Hiragana used to have its own tag, but has since been merged with katakana */
- /* Hiragana */ {CHR ('h', 'i', 'r', 'a'), 0x3040, 0x309f},
- #endif
- /* Hangul Jamo*/ {CHR ('j', 'a', 'm', 'o'), 0x1100, 0x11ff, 0x3130, 0x319f,
- 0xffa0, 0xffdf},
- /* Javanese */ {CHR ('j', 'a', 'v', 'a'), 0},
- /* MS has a tag, but there is no unicode range */
- /* Katakana */ {CHR ('k', 'a', 'n', 'a'), 0x3040, 0x30ff, 0xff60, 0xff9f},
- /* Kayah Li */ {CHR ('k', 'a', 'l', 'i'), 0},
- /* Kannada */ {CHR ('k', 'n', 'd', 'a'), 0x0c80, 0x0cff},
- /* Kharosthi */ {CHR ('k', 'h', 'a', 'r'), 0x10a00, 0x10a5f},
- /* Khmer */ {CHR ('k', 'h', 'm', 'r'), 0x1780, 0x17ff},
- /* Latin */ {CHR ('l', 'a', 't', 'n'), 0x0041, 0x005a, 0x0061, 0x007a,
- 0x00c0, 0x02af, 0x1d00, 0x1eff, 0xfb00, 0xfb0f, 0xff00, 0xff5f,
- 0xa770, 0xa7ff},
- /* Lao */ {CHR ('l', 'a', 'o', ' '), 0x0e80, 0x0eff},
- /* Lepcha */ {CHR ('l', 'e', 'p', 'c'), 0},
- /* Limbu */ {CHR ('l', 'i', 'm', 'b'), 0x1900, 0x194f},
- /* Linear A *//*{ CHR('l','i','n','a'), 0x10180, 0x102cf }, *//* What happened to linear A? */
- /* Linear B */ {CHR ('l', 'i', 'n', 'b'), 0x10000, 0x100fa},
- /* Lycian */ {CHR ('l', 'y', 'c', 'i'), 0},
- /* Lydian */ {CHR ('l', 'y', 'd', 'i'), 0},
- /* Malayalam */ {CHR ('m', 'l', 'y', 'm'), 0x0d00, 0x0d7f},
- /* Mathematical Alphanumeric Symbols */
- {CHR ('m', 'a', 't', 'h'), 0x1d400, 0x1d7ff},
- /* Mongolian */ {CHR ('m', 'o', 'n', 'g'), 0x1800, 0x18af},
- /* Musical */ {CHR ('m', 'u', 's', 'c'), 0x1d100, 0x1d1ff},
- /* Myanmar */ {CHR ('m', 'y', 'm', 'r'), 0x1000, 0x107f},
- /* New Tai Lue*/ {CHR ('t', 'a', 'l', 'u'), 0},
- /* N'Ko */ {CHR ('n', 'k', 'o', ' '), 0x07c0, 0x07fa},
- /* Ogham */ {CHR ('o', 'g', 'a', 'm'), 0x1680, 0x169f},
- /* Ol Chiki */ {CHR ('o', 'l', 'c', 'k'), 0},
- /* Old Italic */ {CHR ('i', 't', 'a', 'l'), 0x10300, 0x1031e},
- /* Old Permic */ {CHR ('p', 'e', 'r', 'm'), 0x10350, 0x1037f},
- /* Old Persian cuneiform */
- {CHR ('x', 'p', 'e', 'o'), 0x103a0, 0x103df},
- /* Oriya */ {CHR ('o', 'r', 'y', 'a'), 0x0b00, 0x0b7f},
- /* Osmanya */ {CHR ('o', 's', 'm', 'a'), 0x10480, 0x104a9},
- /* Phags-pa */ {CHR ('p', 'h', 'a', 'g'), 0xa840, 0xa87f},
- /* Phoenician */ {CHR ('p', 'h', 'n', 'x'), 0x10900, 0x1091f},
- /* Pollard */ {CHR ('p', 'l', 'r', 'd'), 0x104b0, 0x104d9},
- /* Rejang */ {CHR ('r', 'j', 'n', 'g'), 0},
- /* Rongorongo */ {CHR ('r', 'o', 'r', 'o'), 0},
- /* Runic */ {CHR ('r', 'u', 'n', 'r'), 0x16a0, 0x16ff},
- /* Saurashtra*/ {CHR ('s', 'a', 'u', 'r'), 0},
- /* Shavian */ {CHR ('s', 'h', 'a', 'w'), 0x10450, 0x1047f},
- /* Sinhala */ {CHR ('s', 'i', 'n', 'h'), 0x0d80, 0x0dff},
- /* Sumero-Akkadian Cuneiform */
- {CHR ('x', 's', 'u', 'x'), 0x12000, 0x1236e},
- /* Sundanese */ {CHR ('s', 'u', 'n', 'd'), 0},
- /* Syloti Nagri */
- {CHR ('s', 'y', 'l', 'o'), 0xa800, 0xa82f},
- /* Syriac */ {CHR ('s', 'y', 'r', 'c'), 0x0700, 0x074f},
- /* Tagalog */ {CHR ('t', 'a', 'g', 'l'), 0x1700, 0x1714},
- /* Tagbanwa */ {CHR ('t', 'a', 'g', 'b'), 0x1760, 0x1773},
- /* Tai Le */ {CHR ('t', 'a', 'l', 'e'), 0x1950, 0x1974},
- /* Tai Lu */ {CHR ('t', 'a', 'l', 'u'), 0x1980, 0x19df},
- /* Tamil */ {CHR ('t', 'a', 'm', 'l'), 0x0b80, 0x0bff},
- /* Telugu */ {CHR ('t', 'e', 'l', 'u'), 0x0c00, 0x0c7f},
- /* Tengwar */ {CHR ('t', 'e', 'n', 'g'), 0x12000, 0x1207f},
- /* Thaana */ {CHR ('t', 'h', 'a', 'a'), 0x0780, 0x07bf},
- /* Thai */ {CHR ('t', 'h', 'a', 'i'), 0x0e00, 0x0e7f},
- /* Tibetan */ {CHR ('t', 'i', 'b', 't'), 0x0f00, 0x0fff},
- /* Tifinagh */ {CHR ('t', 'f', 'n', 'g'), 0x2d30, 0x2d7f},
- /* Ugaritic */ {CHR ('u', 'g', 'a', 'r'), 0x10380, 0x1039d},
- /* Yi */ {CHR ('y', 'i', ' ', ' '), 0xa000, 0xa4c6},
- {0}
- };
- void
- ScriptMainRange (uint32_t script, int *start, int *end)
- {
- int i;
- for (i = 0; scripts[i][0] != 0; ++i)
- {
- if (scripts[i][0] == script)
- {
- *start = scripts[i][1];
- *end = scripts[i][2];
- return;
- }
- }
- *start = *end = -1;
- }
- int
- ScriptIsRightToLeft (uint32_t script)
- {
- if (script == CHR ('a', 'r', 'a', 'b') || script == CHR ('h', 'e', 'b', 'r')
- || script == CHR ('c', 'p', 'm', 'n')
- || script == CHR ('k', 'h', 'a', 'r')
- || script == CHR ('s', 'y', 'r', 'c')
- || script == CHR ('t', 'h', 'a', 'a')
- || script == CHR ('n', 'k', 'o', ' '))
- return true;
- return false;
- }
- uint32_t
- ScriptFromUnicode (int u, SplineFont *sf)
- {
- int s, k;
- if (u != -1)
- {
- for (s = 0; scripts[s][0] != 0; ++s)
- {
- for (k = 1; scripts[s][k + 1] != 0; k += 2)
- if (u >= scripts[s][k] && u <= scripts[s][k + 1])
- break;
- if (scripts[s][k + 1] != 0)
- break;
- }
- if (scripts[s][0] != 0)
- {
- uint32_t script = scripts[s][0];
- if (use_second_indic_scripts)
- {
- /* MS has a parallel set of script tags for their new */
- /* Indic font shaper */
- if (script == CHR ('b', 'e', 'n', 'g'))
- script = CHR ('b', 'n', 'g', '2');
- else if (script == CHR ('d', 'e', 'v', 'a'))
- script = CHR ('d', 'e', 'v', '2');
- else if (script == CHR ('g', 'u', 'j', 'r'))
- script = CHR ('g', 'j', 'r', '2');
- else if (script == CHR ('g', 'u', 'r', 'u'))
- script = CHR ('g', 'u', 'r', '2');
- else if (script == CHR ('k', 'n', 'd', 'a'))
- script = CHR ('k', 'n', 'd', '2');
- else if (script == CHR ('m', 'l', 'y', 'm'))
- script = CHR ('m', 'l', 'm', '2');
- else if (script == CHR ('o', 'r', 'y', 'a'))
- script = CHR ('o', 'r', 'y', '2');
- else if (script == CHR ('t', 'a', 'm', 'l'))
- script = CHR ('t', 'm', 'l', '2');
- else if (script == CHR ('t', 'e', 'l', 'u'))
- script = CHR ('t', 'e', 'l', '2');
- }
- return script;
- }
- }
- else if (sf != NULL)
- {
- if (sf->cidmaster != NULL || sf->subfontcnt != 0)
- {
- if (sf->cidmaster != NULL)
- sf = sf->cidmaster;
- if (strcasecmp (sf->ordering, "Identity") == 0)
- return DEFAULT_SCRIPT;
- else if (strcasecmp (sf->ordering, "Korean") == 0)
- return CHR ('h', 'a', 'n', 'g');
- else
- return CHR ('h', 'a', 'n', 'i');
- }
- }
- return DEFAULT_SCRIPT;
- }
- uint32_t
- SCScriptFromUnicode (SplineChar *sc)
- {
- char *pt;
- PST *pst;
- SplineFont *sf;
- int i;
- unsigned uni;
- FeatureScriptLangList *features;
- if (sc == NULL)
- return DEFAULT_SCRIPT;
- sf = sc->parent;
- if (sc->unicodeenc != -1 &&
- !(sc->unicodeenc >= 0xe000 && sc->unicodeenc < 0xf8ff) &&
- !(sc->unicodeenc >= 0xf0000 && sc->unicodeenc < 0x10ffff))
- return ScriptFromUnicode (sc->unicodeenc, sf);
- pt = sc->name;
- if (*pt)
- for (++pt; *pt != '\0' && *pt != '_' && *pt != '.'; ++pt)
- ;
- if (*pt != '\0')
- {
- char *str = xstrndup (sc->name, pt - sc->name);
- int uni = sf == NULL
- || sf->fv == NULL ? UniFromName (str, ui_none,
- &custom) : UniFromName (str,
- sf->uni_interp,
- sf->fv->map->
- enc);
- free (str);
- if (uni != -1)
- return ScriptFromUnicode (uni, sf);
- }
- /* Adobe ligature uniXXXXXXXX */
- if (strncmp (sc->name, "uni", 3) == 0
- && sscanf (sc->name + 3, "%4x", &uni) == 1)
- return ScriptFromUnicode (uni, sf);
- if (sf == NULL)
- return DEFAULT_SCRIPT;
- if (sf->cidmaster)
- sf = sf->cidmaster;
- else if (sf->mm != NULL)
- sf = sf->mm->normal;
- for (i = 0; i < 2; ++i)
- {
- for (pst = sc->possub; pst != NULL; pst = pst->next)
- {
- if (pst->type == pst_lcaret)
- continue;
- for (features = pst->subtable->lookup->features; features != NULL;
- features = features->next)
- {
- if (features->scripts != NULL)
- return features->scripts->script;
- }
- }
- }
- return ScriptFromUnicode (sc->unicodeenc, sf);
- }
- int
- SCRightToLeft (SplineChar *sc)
- {
- if (sc->unicodeenc >= 0x10800 && sc->unicodeenc <= 0x10fff)
- return true; /* Supplemental Multilingual Plane, RTL scripts */
- if (sc->unicodeenc != -1 && sc->unicodeenc < 0x10000)
- return isrighttoleft (sc->unicodeenc);
- return ScriptIsRightToLeft (SCScriptFromUnicode (sc));
- }
- static void
- GlyphMapFree (SplineChar ***map)
- {
- int i;
- if (map == NULL)
- return;
- for (i = 0; map[i] != NULL; ++i)
- free (map[i]);
- free (map);
- }
- static SplineChar **
- FindSubs (SplineChar *sc, struct lookup_subtable *sub)
- {
- SplineChar *spc[30], **space = spc;
- int max = sizeof (spc) / sizeof (spc[0]);
- int cnt = 0;
- char *pt, *start;
- SplineChar *subssc, **ret;
- PST *pst;
- for (pst = sc->possub; pst != NULL; pst = pst->next)
- {
- if (pst->subtable == sub)
- {
- pt = pst->u.subs.variant;
- while (1)
- {
- while (*pt == ' ')
- ++pt;
- start = pt;
- pt = strchr (start, ' ');
- if (pt != NULL)
- *pt = '\0';
- subssc = SFGetChar (sc->parent, -1, start);
- if (subssc != NULL && subssc->ttf_glyph != -1)
- {
- if (cnt >= max)
- {
- if (spc == space)
- {
- space = xmalloc ((max += 30) * sizeof (SplineChar *));
- memcpy (space, spc,
- (max - 30) * sizeof (SplineChar *));
- }
- else
- space =
- xrealloc (space, (max += 30) * sizeof (SplineChar *));
- }
- space[cnt++] = subssc;
- }
- if (pt == NULL)
- break;
- *pt = ' ';
- }
- }
- }
- if (cnt == 0) /* Might happen if the substitution names weren't in the font */
- return NULL;
- ret = xmalloc ((cnt + 1) * sizeof (SplineChar *));
- memcpy (ret, space, cnt * sizeof (SplineChar *));
- ret[cnt] = NULL;
- if (space != spc)
- free (space);
- return ret;
- }
- static SplineChar ***
- generateMapList (SplineChar **glyphs, struct lookup_subtable *sub)
- {
- int cnt;
- SplineChar *sc;
- int i;
- SplineChar ***maps = NULL;
- for (cnt = 0; glyphs[cnt] != NULL; ++cnt);
- maps = xmalloc ((cnt + 1) * sizeof (SplineChar **));
- for (i = 0; i < cnt; ++i)
- {
- sc = glyphs[i];
- maps[i] = FindSubs (sc, sub);
- }
- maps[cnt] = NULL;
- return maps;
- }
- void
- AnchorClassDecompose (SplineFont *sf, AnchorClass * _ac, int classcnt,
- int *subcnts, SplineChar ***marks, SplineChar ***base,
- SplineChar ***lig, SplineChar ***mkmk,
- struct glyphinfo *gi)
- {
- /* Run through the font finding all characters with this anchor class */
- /* (and the cnt-1 classes after it) */
- /* and distributing in the four possible anchor types */
- int i, j, k, gid, gmax;
- struct sclist
- {
- int cnt;
- SplineChar **glyphs;
- } heads[at_max];
- AnchorPoint *test;
- AnchorClass *ac;
- memset (heads, 0, sizeof (heads));
- memset (subcnts, 0, classcnt * sizeof (int));
- memset (marks, 0, classcnt * sizeof (SplineChar **));
- gmax = gi == NULL ? sf->glyphcnt : gi->gcnt;
- for (j = 0; j < 2; ++j)
- {
- for (i = 0; i < gmax; ++i)
- if ((gid = gi == NULL ? i : gi->bygid[i]) != -1
- && sf->glyphs[gid] != NULL)
- {
- for (ac = _ac, k = 0; k < classcnt; ac = ac->next)
- if (ac->matches)
- {
- for (test = sf->glyphs[gid]->anchor; test != NULL;
- test = test->next)
- {
- if (test->anchor == ac)
- {
- if (test->type == at_mark)
- {
- if (j)
- marks[k][subcnts[k]] = sf->glyphs[gid];
- ++subcnts[k];
- if (AnchorClass_lookup_type (ac) != gpos_mark2mark)
- break;
- }
- else if (test->type != at_centry
- && test->type != at_cexit)
- {
- if (heads[test->type].glyphs != NULL)
- {
- /* If we have multiple mark classes, we may use the same base glyph */
- /* with more than one mark class. But it should only appear once in */
- /* the output */
- if (heads[test->type].cnt == 0 ||
- heads[test->type].
- glyphs[heads[test->type].cnt - 1] !=
- sf->glyphs[gid])
- {
- heads[test->type].
- glyphs[heads[test->type].cnt] =
- sf->glyphs[gid];
- ++heads[test->type].cnt;
- }
- }
- else
- ++heads[test->type].cnt;
- if (AnchorClass_lookup_type (ac) != gpos_mark2mark)
- break;
- }
- }
- }
- ++k;
- }
- }
- if (j == 1)
- break;
- for (i = 0; i < 4; ++i)
- if (heads[i].cnt != 0)
- {
- heads[i].glyphs =
- xmalloc ((heads[i].cnt + 1) * sizeof (SplineChar *));
- /* I used to set glyphs[cnt] to NULL here. But it turns out */
- /* cnt may be an overestimate on the first pass. So we can */
- /* only set it at the end of the second pass */
- heads[i].cnt = 0;
- }
- for (k = 0; k < classcnt; ++k)
- if (subcnts[k] != 0)
- {
- marks[k] = xmalloc ((subcnts[k] + 1) * sizeof (SplineChar *));
- marks[k][subcnts[k]] = NULL;
- subcnts[k] = 0;
- }
- }
- for (i = 0; i < 4; ++i)
- if (heads[i].glyphs != NULL)
- heads[i].glyphs[heads[i].cnt] = NULL;
- *base = heads[at_basechar].glyphs;
- *lig = heads[at_baselig].glyphs;
- *mkmk = heads[at_basemark].glyphs;
- }
- SplineChar **
- EntryExitDecompose (SplineFont *sf, AnchorClass * ac, struct glyphinfo *gi)
- {
- /* Run through the font finding all characters with this anchor class */
- int i, j, cnt, gmax, gid;
- SplineChar **array;
- AnchorPoint *test;
- array = NULL;
- gmax = gi == NULL ? sf->glyphcnt : gi->gcnt;
- for (j = 0; j < 2; ++j)
- {
- cnt = 0;
- for (i = 0; i < gmax; ++i)
- if ((gid = gi == NULL ? i : gi->bygid[i]) != -1
- && sf->glyphs[gid] != NULL)
- {
- for (test = sf->glyphs[gid]->anchor;
- test != NULL && test->anchor != ac; test = test->next);
- if (test != NULL
- && (test->type == at_centry || test->type == at_cexit))
- {
- if (array != NULL)
- array[cnt] = sf->glyphs[gid];
- ++cnt;
- }
- }
- if (cnt == 0)
- return NULL;
- if (j == 1)
- break;
- array = xmalloc ((cnt + 1) * sizeof (SplineChar *));
- array[cnt] = NULL;
- }
- return array;
- }
- static void
- AnchorGuessContext (SplineFont *sf, struct alltabs *at)
- {
- int i;
- int maxbase = 0, maxmark = 0, basec, markc;
- AnchorPoint *ap;
- int hascursive = 0;
- /* the order in which we examine the glyphs does not matter here, so */
- /* we needn't add the complexity running though in gid order */
- for (i = 0; i < sf->glyphcnt; ++i)
- if (sf->glyphs[i])
- {
- basec = markc = 0;
- for (ap = sf->glyphs[i]->anchor; ap != NULL; ap = ap->next)
- if (ap->type == at_basemark)
- ++markc;
- else if (ap->type == at_basechar || ap->type == at_baselig)
- ++basec;
- else if (ap->type == at_centry)
- hascursive = true;
- if (basec > maxbase)
- maxbase = basec;
- if (markc > maxmark)
- maxmark = markc;
- }
- if (maxbase * (maxmark + 1) > at->os2.maxContext)
- at->os2.maxContext = maxbase * (maxmark + 1);
- if (hascursive && at->os2.maxContext < 2)
- at->os2.maxContext = 2;
- }
- static void
- dumpcoveragetable (FILE *gpos, SplineChar **glyphs)
- {
- int i, last = -2, range_cnt = 0, start, r;
- /* the glyph list should already be sorted */
- /* figure out whether it is better (smaller) to use an array of glyph ids */
- /* or a set of glyph id ranges */
- for (i = 0; glyphs[i] != NULL; ++i)
- {
- if (glyphs[i]->ttf_glyph <= last)
- IError ("Glyphs must be ordered when creating coverage table");
- if (glyphs[i]->ttf_glyph != last + 1)
- ++range_cnt;
- last = glyphs[i]->ttf_glyph;
- }
- /* I think Windows will only accept format 2 coverage tables? */
- if (!(coverageformatsallowed & 2)
- || ((coverageformatsallowed & 1) && i <= 3 * range_cnt))
- {
- /* We use less space with a list of glyphs than with a set of ranges */
- putshort (gpos, 1); /* Coverage format=1 => glyph list */
- putshort (gpos, i); /* count of glyphs */
- for (i = 0; glyphs[i] != NULL; ++i)
- putshort (gpos, glyphs[i]->ttf_glyph); /* array of glyph IDs */
- }
- else
- {
- putshort (gpos, 2); /* Coverage format=2 => range list */
- putshort (gpos, range_cnt); /* count of ranges */
- last = -2;
- start = -2; /* start is a index in our glyph array, last is ttf_glyph */
- r = 0;
- for (i = 0; glyphs[i] != NULL; ++i)
- {
- if (glyphs[i]->ttf_glyph != last + 1)
- {
- if (last != -2)
- {
- putshort (gpos, glyphs[start]->ttf_glyph); /* start glyph ID */
- putshort (gpos, last); /* end glyph ID */
- putshort (gpos, start); /* coverage index of start glyph */
- ++r;
- }
- start = i;
- }
- last = glyphs[i]->ttf_glyph;
- }
- if (last != -2)
- {
- putshort (gpos, glyphs[start]->ttf_glyph); /* start glyph ID */
- putshort (gpos, last); /* end glyph ID */
- putshort (gpos, start); /* coverage index of start glyph */
- ++r;
- }
- if (r != range_cnt)
- IError ("Miscounted ranges in format 2 coverage table output");
- }
- }
- static int
- sc_ttf_order (const void *_sc1, const void *_sc2)
- {
- const SplineChar *sc1 = *(const SplineChar **) _sc1, *sc2 =
- *(const SplineChar **) _sc2;
- return sc1->ttf_glyph - sc2->ttf_glyph;
- }
- static SplineChar **
- SFOrderedGlyphsWithPSTinSubtable (SplineFont *sf, struct lookup_subtable *sub)
- {
- SplineChar **glyphs = SFGlyphsWithPSTinSubtable (sf, sub);
- int cnt, i, k;
- if (glyphs == NULL)
- return NULL;
- for (cnt = 0; glyphs[cnt] != NULL; ++cnt);
- qsort (glyphs, cnt, sizeof (SplineChar *), sc_ttf_order);
- if (glyphs[0]->ttf_glyph == -1)
- {
- /* Not sure if this can happen, but it's easy to fix */
- for (k = 0; k < cnt && glyphs[k]->ttf_glyph == -1; ++k);
- for (i = 0; i <= cnt - k; ++i)
- glyphs[i] = glyphs[i + k];
- }
- return glyphs;
- }
- SplineChar **
- SFGlyphsFromNames (SplineFont *sf, char *names)
- {
- int cnt, ch;
- char *pt, *end;
- SplineChar *sc, **glyphs;
- if (names == NULL)
- return xcalloc (1, sizeof (SplineChar *));
- cnt = 0;
- for (pt = names; *pt; pt = end + 1)
- {
- ++cnt;
- end = strchr (pt, ' ');
- if (end == NULL)
- break;
- }
- glyphs = xmalloc ((cnt + 1) * sizeof (SplineChar *));
- cnt = 0;
- for (pt = names; *pt; pt = end + 1)
- {
- end = strchr (pt, ' ');
- if (end == NULL)
- end = pt + strlen (pt);
- ch = *end;
- *end = '\0';
- sc = SFGetChar (sf, -1, pt);
- if (sc != NULL && sc->ttf_glyph != -1)
- glyphs[cnt++] = sc;
- *end = ch;
- if (ch == '\0')
- break;
- }
- glyphs[cnt] = NULL;
- return glyphs;
- }
- static SplineChar **
- OrderedGlyphsFromNames (SplineFont *sf, char *names)
- {
- SplineChar **glyphs = SFGlyphsFromNames (sf, names);
- int i, j;
- if (glyphs == NULL || glyphs[0] == NULL)
- return glyphs;
- for (i = 0; glyphs[i + 1] != NULL; ++i)
- for (j = i + 1; glyphs[j] != NULL; ++j)
- {
- if (glyphs[i]->ttf_glyph > glyphs[j]->ttf_glyph)
- {
- SplineChar *sc = glyphs[i];
- glyphs[i] = glyphs[j];
- glyphs[j] = sc;
- }
- }
- if (glyphs[0] != NULL)
- { /* Glyphs should not appear twice in the name list, just just in case they do... */
- for (i = 0; glyphs[i + 1] != NULL; ++i)
- {
- if (glyphs[i] == glyphs[i + 1])
- {
- for (j = i + 1; glyphs[j] != NULL; ++j)
- glyphs[j] = glyphs[j + 1];
- }
- }
- }
- return glyphs;
- }
- static void
- gposvrmaskeddump (FILE *gpos, int vf1, int mask, int offset)
- {
- if (vf1 & 1)
- putshort (gpos, mask & 1 ? offset : 0);
- if (vf1 & 2)
- putshort (gpos, mask & 2 ? offset : 0);
- if (vf1 & 4)
- putshort (gpos, mask & 4 ? offset : 0);
- if (vf1 & 8)
- putshort (gpos, mask & 8 ? offset : 0);
- }
- static int
- devtaboffsetsize (DeviceTable *dt)
- {
- int type = 1, i;
- for (i = dt->last_pixel_size - dt->first_pixel_size; i >= 0; --i)
- {
- if (dt->corrections[i] >= 8 || dt->corrections[i] < -8)
- return 3;
- else if (dt->corrections[i] >= 2 || dt->corrections[i] < -2)
- type = 2;
- }
- return type;
- }
- static void
- dumpgposdevicetable (FILE *gpos, DeviceTable *dt)
- {
- int type;
- int i, cnt, b;
- if (dt == NULL || dt->corrections == NULL)
- return;
- type = devtaboffsetsize (dt);
- putshort (gpos, dt->first_pixel_size);
- putshort (gpos, dt->last_pixel_size);
- putshort (gpos, type);
- cnt = dt->last_pixel_size - dt->first_pixel_size + 1;
- if (type == 3)
- {
- for (i = 0; i < cnt; ++i)
- putc (dt->corrections[i], gpos);
- if (cnt & 1)
- putc (0, gpos);
- }
- else if (type == 2)
- {
- for (i = 0; i < cnt; i += 4)
- {
- int val = 0;
- for (b = 0; b < 4 && i + b < cnt; ++b)
- val |= (dt->corrections[i + b] & 0x000f) << (12 - b * 4);
- putshort (gpos, val);
- }
- }
- else
- {
- for (i = 0; i < cnt; i += 8)
- {
- int val = 0;
- for (b = 0; b < 8 && i + b < cnt; ++b)
- val |= (dt->corrections[i + b] & 0x0003) << (14 - b * 2);
- putshort (gpos, val);
- }
- }
- }
- static int
- DevTabLen (DeviceTable *dt)
- {
- int type;
- int cnt;
- if (dt == NULL || dt->corrections == NULL)
- return 0;
- cnt = dt->last_pixel_size - dt->first_pixel_size + 1;
- type = devtaboffsetsize (dt);
- if (type == 3)
- cnt = (cnt + 1) / 2;
- else if (type == 2)
- cnt = (cnt + 3) / 4;
- else
- cnt = (cnt + 7) / 8;
- cnt += 3; /* first, last, type */
- return sizeof (uint16_t) * cnt;
- }
- static int
- ValDevTabLen (ValDevTab * vdt)
- {
- if (vdt == NULL)
- return 0;
- return (DevTabLen (&vdt->xadjust) + DevTabLen (&vdt->yadjust) +
- DevTabLen (&vdt->xadv) + DevTabLen (&vdt->yadv));
- }
- static int
- gposdumpvaldevtab (FILE *gpos, ValDevTab * vdt, int bits, int next_dev_tab)
- {
- if (bits & 0x10)
- {
- if (vdt == NULL || vdt->xadjust.corrections == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&vdt->xadjust);
- }
- }
- if (bits & 0x20)
- {
- if (vdt == NULL || vdt->yadjust.corrections == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&vdt->yadjust);
- }
- }
- if (bits & 0x40)
- {
- if (vdt == NULL || vdt->xadv.corrections == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&vdt->xadv);
- }
- }
- if (bits & 0x80)
- {
- if (vdt == NULL || vdt->yadv.corrections == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&vdt->yadv);
- }
- }
- return next_dev_tab;
- }
- static int
- gposmaskeddumpdevtab (FILE *gpos, DeviceTable *dt, int bits, int mask,
- int next_dev_tab)
- {
- if (bits & 0x10)
- {
- if (!(mask & 0x10) || dt == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (dt);
- }
- }
- if (bits & 0x20)
- {
- if (!(mask & 0x20) || dt == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (dt);
- }
- }
- if (bits & 0x40)
- {
- if (!(mask & 0x40) || dt == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (dt);
- }
- }
- if (bits & 0x80)
- {
- if (!(mask & 0x80) || dt == NULL)
- putshort (gpos, 0);
- else
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (dt);
- }
- }
- return next_dev_tab;
- }
- static int
- DevTabsSame (DeviceTable *dt1, DeviceTable *dt2)
- {
- DeviceTable _dt;
- int i;
- if (dt1 == NULL && dt2 == NULL)
- return true;
- if (dt1 == NULL)
- {
- memset (&_dt, 0, sizeof (_dt));
- dt1 = &_dt;
- }
- if (dt2 == NULL)
- {
- memset (&_dt, 0, sizeof (_dt));
- dt2 = &_dt;
- }
- if (dt1->corrections == NULL && dt2->corrections == NULL)
- return true;
- if (dt1->corrections == NULL || dt2->corrections == NULL)
- return false;
- if (dt1->first_pixel_size != dt2->first_pixel_size ||
- dt1->last_pixel_size != dt2->last_pixel_size)
- return false;
- for (i = dt2->last_pixel_size - dt1->first_pixel_size; i >= 0; --i)
- if (dt1->corrections[i] != dt2->corrections[i])
- return false;
- return true;
- }
- static int
- ValDevTabsSame (ValDevTab * vdt1, ValDevTab * vdt2)
- {
- ValDevTab _vdt;
- if (vdt1 == NULL && vdt2 == NULL)
- return true;
- if (vdt1 == NULL)
- {
- memset (&_vdt, 0, sizeof (_vdt));
- vdt1 = &_vdt;
- }
- if (vdt2 == NULL)
- {
- memset (&_vdt, 0, sizeof (_vdt));
- vdt2 = &_vdt;
- }
- return (DevTabsSame (&vdt1->xadjust, &vdt2->xadjust) &&
- DevTabsSame (&vdt1->yadjust, &vdt2->yadjust) &&
- DevTabsSame (&vdt1->xadv, &vdt2->xadv) &&
- DevTabsSame (&vdt1->yadv, &vdt2->yadv));
- }
- static void
- dumpGPOSsimplepos (FILE *gpos, SplineFont *sf, struct lookup_subtable *sub)
- {
- int cnt, cnt2;
- int32_t coverage_pos, end;
- PST *pst, *first = NULL;
- int bits = 0, same = true;
- SplineChar **glyphs;
- glyphs = SFOrderedGlyphsWithPSTinSubtable (sf, sub);
- for (cnt = cnt2 = 0; glyphs[cnt] != NULL; ++cnt)
- {
- for (pst = glyphs[cnt]->possub; pst != NULL; pst = pst->next)
- {
- if (pst->subtable == sub && pst->type == pst_position)
- {
- if (first == NULL)
- first = pst;
- else if (same)
- {
- if (first->u.pos.xoff != pst->u.pos.xoff ||
- first->u.pos.yoff != pst->u.pos.yoff ||
- first->u.pos.h_adv_off != pst->u.pos.h_adv_off ||
- first->u.pos.v_adv_off != pst->u.pos.v_adv_off)
- same = false;
- if (!ValDevTabsSame (pst->u.pos.adjust, first->u.pos.adjust))
- same = false;
- }
- if (pst->u.pos.xoff != 0)
- bits |= 1;
- if (pst->u.pos.yoff != 0)
- bits |= 2;
- if (pst->u.pos.h_adv_off != 0)
- bits |= 4;
- if (pst->u.pos.v_adv_off != 0)
- bits |= 8;
- if (pst->u.pos.adjust != NULL)
- {
- if (pst->u.pos.adjust->xadjust.corrections != NULL)
- bits |= 0x10;
- if (pst->u.pos.adjust->yadjust.corrections != NULL)
- bits |= 0x20;
- if (pst->u.pos.adjust->xadv.corrections != NULL)
- bits |= 0x40;
- if (pst->u.pos.adjust->yadv.corrections != NULL)
- bits |= 0x80;
- }
- ++cnt2;
- break;
- }
- }
- }
- if (bits == 0)
- bits = 1;
- if (cnt != cnt2)
- IError ("Count mismatch in dumpGPOSsimplepos#1 %d vs %d\n", cnt, cnt2);
- putshort (gpos, same ? 1 : 2); /* 1 means all value records same */
- coverage_pos = ftell (gpos);
- putshort (gpos, 0); /* offset to coverage table */
- putshort (gpos, bits);
- if (same)
- {
- if (bits & 1)
- putshort (gpos, first->u.pos.xoff);
- if (bits & 2)
- putshort (gpos, first->u.pos.yoff);
- if (bits & 4)
- putshort (gpos, first->u.pos.h_adv_off);
- if (bits & 8)
- putshort (gpos, first->u.pos.v_adv_off);
- if (bits & 0xf0)
- {
- int next_dev_tab = ftell (gpos) - coverage_pos + 2 +
- sizeof (int16_t) * ((bits & 0x10 ? 1 : 0) + (bits & 0x20 ? 1 : 0) +
- (bits & 0x40 ? 1 : 0) + (bits & 0x80 ? 1 : 0));
- if (bits & 0x10)
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&first->u.pos.adjust->xadjust);
- }
- if (bits & 0x20)
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&first->u.pos.adjust->yadjust);
- }
- if (bits & 0x40)
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&first->u.pos.adjust->xadv);
- }
- if (bits & 0x80)
- {
- putshort (gpos, next_dev_tab);
- next_dev_tab += DevTabLen (&first->u.pos.adjust->yadv);
- }
- if (bits & 0x10)
- dumpgposdevicetable (gpos, &first->u.pos.adjust->xadjust);
- if (bits & 0x20)
- dumpgposdevicetable (gpos, &first->u.pos.adjust->yadjust);
- if (bits & 0x40)
- dumpgposdevicetable (gpos, &first->u.pos.adjust->xadv);
- if (bits & 0x80)
- dumpgposdevicetable (gpos, &first->u.pos.adjust->yadv);
- if (next_dev_tab != ftell (gpos) - coverage_pos + 2)
- IError ("Device Table offsets wrong in simple positioning 2");
- }
- }
- else
- {
- int vr_size =
- sizeof (int16_t) * ((bits & 0x1 ? 1 : 0) + (bits & 0x2 ? 1 : 0) +
- (bits & 0x4 ? 1 : 0) + (bits & 0x8 ? 1 : 0) +
- (bits & 0x10 ? 1 : 0) + (bits & 0x20 ? 1 : 0) +
- (bits & 0x40 ? 1 : 0) + (bits & 0x80 ? 1 : 0));
- int next_dev_tab = ftell (gpos) - coverage_pos + 2 + 2 + vr_size * cnt;
- putshort (gpos, cnt);
- for (cnt2 = 0; glyphs[cnt2] != NULL; ++cnt2)
- {
- for (pst = glyphs[cnt2]->possub; pst != NULL; pst = pst->next)
- {
- if (pst->subtable == sub && pst->type == pst_position)
- {
- if (bits & 1)
- putshort (gpos, pst->u.pos.xoff);
- if (bits & 2)
- putshort (gpos, pst->u.pos.yoff);
- if (bits & 4)
- putshort (gpos, pst->u.pos.h_adv_off);
- if (bits & 8)
- putshort (gpos, pst->u.pos.v_adv_off);
- next_dev_tab =
- gposdumpvaldevtab (gpos, pst->u.pos.adjust, bits,
- next_dev_tab);
- break;
- }
- }
- }
- if (cnt != cnt2)
- IError ("Count mismatch in dumpGPOSsimplepos#3 %d vs %d\n", cnt, cnt2);
- if (bits & 0xf0)
- {
- for (cnt2 = 0; glyphs[cnt2] != NULL; ++cnt2)
- {
- for (pst = glyphs[cnt2]->possub; pst != NULL; pst = pst->next)
- {
- if (pst->subtable == sub && pst->type == pst_position)
- {
- if (bits & 0x10)
- dumpgposdevicetable (gpos,
- &first->u.pos.adjust->xadjust);
- if (bits & 0x20)
- dumpgposdevicetable (gpos,
- &first->u.pos.adjust->yadjust);
- if (bits & 0x40)
- dumpgposdevicetable (gpos, &first->u.pos.adjust->xadv);
- if (bits & 0x80)
- dumpgposdevicetable (gpos, &first->u.pos.adjust->yadv);
- }
- }
- }
- }
- if (next_dev_tab != ftell (gpos) - coverage_pos + 2)
- IError ("Device Table offsets wrong in simple positioning 2");
- }
- end = ftell (gpos);
- fseek (gpos, coverage_pos, SEEK_SET);
- putshort (gpos, end - coverage_pos + 2);
- fseek (gpos, end, SEEK_SET);
- dumpcoveragetable (gpos, glyphs);
- fseek (gpos, 0, SEEK_END);
- free (glyphs);
- }
- struct sckppst
- {
- uint16_t samewas;
- uint16_t devtablen;
- uint16_t tot;
- uint8_t isv;
- uint8_t subtable_too_big;
- /* The first few fields are only meaningful in the first structure in the array*/
- /* and provide information about the entire rest of the array */
- uint16_t other_gid;
- SplineChar *sc;
- KernPair *kp;
- PST *pst;
- };
- static int
- cmp_gid (const void *_s1, const void *_s2)
- {
- const struct sckppst *s1 = _s1, *s2 = _s2;
- return ((int) s1->other_gid) - ((int) s2->other_gid);
- }
- static void
- dumpGPOSpairpos (FILE *gpos, SplineFont *sf, struct lookup_subtable *sub)
- {
- int cnt;
- int32_t coverage_pos, offset_pos, end, start, pos;
- PST *pst;
- KernPair *kp;
- int vf1 = 0, vf2 = 0, i, j, k, tot, bit_cnt, v;
- int start_cnt, end_cnt;
- int chunk_cnt, chunk_max;
- SplineChar *sc, **glyphs, *gtemp;
- struct sckppst **seconds;
- int devtablen;
- int next_dev_tab;
- /* Figure out all the data we need. First the glyphs with kerning info */
- /* then the glyphs to which they kern, and by how much */
- glyphs = SFOrderedGlyphsWithPSTinSubtable (sf, sub);
- for (cnt = 0; glyphs[cnt] != NULL; ++cnt);
- seconds = xmalloc (cnt * sizeof (struct sckppst *));
- for (cnt = 0; glyphs[cnt] != NULL; ++cnt)
- {
- for (k = 0; k < 2; ++k)
- {
- devtablen = 0;
- tot = 0;
- for (pst = glyphs[cnt]->possub; pst != NULL; pst = pst->next)
- {
- if (pst->subtable == sub && pst->type == pst_pair &&
- (sc = SFGetChar (sf, -1, pst->u.pair.paired)) != NULL &&
- sc->ttf_glyph != -1)
- {
- if (k)
- {
- seconds[cnt][tot].sc = sc;
- seconds[cnt][tot].other_gid = sc->ttf_glyph;
- seconds[cnt][tot].pst = pst;
- devtablen += ValDevTabLen (pst->u.pair.vr[0].adjust) +
- ValDevTabLen (pst->u.pair.vr[1].adjust);
- }
- ++tot;
- }
- }
- for (v = 0; v < 2; ++v)
- {
- for (kp = v ? glyphs[cnt]->vkerns : glyphs[cnt]->kerns;
- kp != NULL; kp = kp->next)
- {
- if (kp->sc->ttf_glyph != -1)
- {
- if (k)
- {
- seconds[cnt][tot].other_gid = kp->sc->ttf_glyph;
- seconds[cnt][tot].sc = kp->sc;
- seconds[cnt][tot].kp = kp;
- seconds[cnt][tot].isv = v;
- devtablen += DevTabLen (kp->adjust);
- }
- ++tot;
- }
- }
- }
- if (k == 0)
- {
- seconds[cnt] = xcalloc (tot + 1, sizeof (struct sckppst));
- }
- else
- {
- qsort (seconds[cnt], tot, sizeof (struct sckppst), cmp_gid);
- seconds[cnt][0].tot = tot;
- /* Devtablen is 0 unless we are configured for device tables */
- seconds[cnt][0].devtablen = devtablen;
- seconds[cnt][0].samewas = 0xffff;
- }
- }
- }
- /* Some fonts do a primitive form of class based kerning, several glyphs */
- /* can share the same list of second glyphs & offsets */
- for (cnt = 0; glyphs[cnt] != NULL; ++cnt)
- {
- struct sckppst *test = seconds[cnt], *test2;
- for (i = cnt - 1; i >= 0; --i)
- {
- test2 = seconds[i];
- if (test[0].tot != test2[0].tot || test2[0].samewas != 0xffff)
- continue;
- for (j = test[0].tot - 1; j >= 0; --j)
- {
- if (test[j].other_gid != test2[j].other_gid)
- break;
- if (test[j].kp != NULL && test2[j].kp != NULL &&
- test[j].kp->off == test2[j].kp->off
- && DevTabsSame (test[j].kp->adjust, test2[j].kp->adjust))
- /* So far, so good */ ;
- else if (test[j].pst != NULL && test2[j].pst != NULL &&
- test[j].pst->u.pair.vr[0].xoff ==
- test2[j].pst->u.pair.vr[0].xoff
- && test[j].pst->u.pair.vr[0].yoff ==
- test2[j].pst->u.pair.vr[0].yoff
- && test[j].pst->u.pair.vr[0].h_adv_off ==
- test2[j].pst->u.pair.vr[0].h_adv_off
- && test[j].pst->u.pair.vr[0].v_adv_off ==
- test2[j].pst->u.pair.vr[0].v_adv_off
- && test[j].pst->u.pair.vr[1].xoff ==
- test2[j].pst->u.pair.vr[1].xoff
- && test[j].pst->u.pair.vr[1].yoff ==
- test2[j].pst->u.pair.vr[1].yoff
- && test[j].pst->u.pair.vr[1].h_adv_off ==
- test2[j].pst->u.pair.vr[1].h_adv_off
- && test[j].pst->u.pair.vr[1].v_adv_off ==
- test2[j].pst->u.pair.vr[1].v_adv_off
- && ValDevTabsSame (test[j].pst->u.pair.vr[0].adjust,
- test2[j].pst->u.pair.vr[0].adjust)
- && ValDevTabsSame (test[j].pst->u.pair.vr[1].adjust,
- test2[j].pst->u.pair.vr[1].adjust))
- /* That's ok too. */ ;
- else
- break;
- }
- if (j >= 0)
- continue;
- test[0].samewas = i;
- break;
- }
- }
- /* Ok, how many offsets must we output? Normal kerning will just use */
- /* one offset (with perhaps a device table), but the standard allows */
- /* us to adjust 8 different values (with 8 different device tables) */
- /* Find out which we need */
- for (cnt = 0; glyphs[cnt] != NULL; ++cnt)
- {
- for (tot = 0; tot < seconds[cnt][0].tot; ++tot)
- {
- if ((pst = seconds[cnt][tot].pst) != NULL)
- {
- if (pst->subtable == sub && pst->type == pst_pair)
- {
- if (pst->u.pair.vr[0].xoff != 0)
- vf1 |= 1;
- if (pst->u.pair.vr[0].yoff != 0)
- vf1 |= 2;
- if (pst->u.pair.vr[0].h_adv_off != 0)
- vf1 |= 4;
- if (pst->u.pair.vr[0].v_adv_off != 0)
- vf1 |= 8;
- if (pst->u.pair.vr[0].adjust != NULL)
- {
- if (pst->u.pair.vr[0].adjust->xadjust.corrections != NULL)
- vf1 |= 0x10;
- if (pst->u.pair.vr[0].adjust->yadjust.corrections != NULL)
- vf1 |= 0x20;
- if (pst->u.pair.vr[0].adjust->xadv.corrections != NULL)
- vf1 |= 0x40;
- if (pst->u.pair.vr[0].adjust->yadv.corrections != NULL)
- vf1 |= 0x80;
- }
- if (pst->u.pair.vr[1].xoff != 0)
- vf2 |= 1;
- if (pst->u.pair.vr[1].yoff != 0)
- vf2 |= 2;
- if (pst->u.pair.vr[1].h_adv_off != 0)
- vf2 |= 4;
- if (pst->u.pair.vr[1].v_adv_off != 0)
- vf2 |= 8;
- if (pst->u.pair.vr[1].adjust != NULL)
- {
- if (pst->u.pair.vr[1].adjust->xadjust.corrections != NULL)
- vf2 |= 0x10;
- if (pst->u.pair.vr[1].adjust->yadjust.corrections != NULL)
- vf2 |= 0x20;
- if (pst->u.pair.vr[1].adjust->xadv.corrections != NULL)
- vf2 |= 0x40;
- if (pst->u.pair.vr[1].adjust->yadv.corrections != NULL)
- vf2 |= 0x80;
- }
- }
- }
- if ((kp = seconds[cnt][tot].kp) != NULL)
- {
- int mask = 0, mask2 = 0;
- if (seconds[cnt][tot].isv)
- mask = 0x0008;
- else
- mask = 0x0004;
- if (kp->adjust != NULL)
- {
- mask |= mask << 4;
- mask2 |= mask2 << 4;
- }
- vf1 |= mask;
- vf2 |= mask2;
- }
- }
- }
- if (vf1 == 0 && vf2 == 0)
- vf1 = 1;
- bit_cnt = 0;
- for (i = 0; i < 8; ++i)
- {
- if (vf1 & (1 << i))
- ++bit_cnt;
- if (vf2 & (1 << i))
- ++bit_cnt;
- }
- chunk_max = chunk_cnt = 0;
- for (start_cnt = 0; start_cnt < cnt; start_cnt = end_cnt)
- {
- int len = 5 * 2; /* Subtable header */
- for (end_cnt = start_cnt; end_cnt < cnt; ++end_cnt)
- {
- int glyph_len = 2; /* For the glyph's offset */
- if (seconds[end_cnt][0].samewas == 0xffff
- || seconds[end_cnt][0].samewas < start_cnt)
- glyph_len += (bit_cnt * 2 + 2) * seconds[end_cnt][0].tot + seconds[end_cnt][0].devtablen + 2; /* Number of secondary glyphs */
- if (glyph_len > 65535 && end_cnt == start_cnt)
- {
- LogError (_
- ("Lookup subtable %s contains a glyph %s whose kerning information takes up more than 64k bytes\n"),
- sub->subtable_name, glyphs[start_cnt]->name);
- len += glyph_len;
- }
- else if (len + glyph_len > 65535)
- {
- if (start_cnt == 0)
- LogError (_
- ("Lookup subtable %s had to be split into several subtables\nbecause it was too big.\n"),
- sub->subtable_name);
- break;
- }
- else
- len += glyph_len;
- }
- if (start_cnt != 0 || end_cnt != cnt)
- {
- if (chunk_cnt >= chunk_max)
- sub->extra_subtables =
- xrealloc (sub->extra_subtables,
- ((chunk_max += 10) + 1) * sizeof (uint32_t));
- sub->extra_subtables[chunk_cnt++] = ftell (gpos);
- sub->extra_subtables[chunk_cnt] = -1;
- }
- start = ftell (gpos);
- putshort (gpos, 1); /* 1 means char pairs (ie. not classes) */
- coverage_pos = ftell (gpos);
- putshort (gpos, 0); /* offset to coverage table */
- putshort (gpos, vf1);
- putshort (gpos, vf2);
- putshort (gpos, end_cnt - start_cnt);
- offset_pos = ftell (gpos);
- for (i = start_cnt; i < end_cnt; ++i)
- putshort (gpos, 0); /* Fill in later */
- for (i = start_cnt; i < end_cnt; ++i)
- {
- if (seconds[i][0].samewas >= start_cnt
- && seconds[i][0].samewas != 0xffff)
- {
- /* It's the same as the glyph at samewas, so just copy t…
Large files files are truncated, but you can click here to view the full file