diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc | 1398 |
1 files changed, 0 insertions, 1398 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc deleted file mode 100644 index 8527d04b5aa..00000000000 --- a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc +++ /dev/null @@ -1,1398 +0,0 @@ -// -*- related-file-name: "../include/efont/otfgsub.hh" -*- - -/* otfgsub.{cc,hh} -- OpenType GSUB table - * - * Copyright (c) 2003-2019 Eddie Kohler - * - * This program 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 2 of the License, or (at your option) - * any later version. This program 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. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <efont/otfgsub.hh> -#include <efont/otfname.hh> -#include <lcdf/error.hh> -#include <lcdf/straccum.hh> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <algorithm> - -namespace Efont { namespace OpenType { - -void -Substitution::clear(Substitute &s, uint8_t &t) -{ - switch (t) { - case T_GLYPHS: - delete[] s.gids; - break; - case T_COVERAGE: - delete s.coverage; - break; - } - t = T_NONE; -} - -void -Substitution::assign_space(Substitute &s, uint8_t &t, int n) -{ - clear(s, t); - if (n == 1) - t = T_GLYPH; - else if (n > 1) { - s.gids = new Glyph[n + 1]; - s.gids[0] = n; - t = T_GLYPHS; - } -} - -void -Substitution::assign(Substitute &s, uint8_t &t, Glyph gid) -{ - clear(s, t); - s.gid = gid; - t = T_GLYPH; -} - -void -Substitution::assign(Substitute &s, uint8_t &t, int ngids, const Glyph *gids) -{ - clear(s, t); - assert(ngids > 0); - if (ngids == 1) { - s.gid = gids[0]; - t = T_GLYPH; - } else { - s.gids = new Glyph[ngids + 1]; - s.gids[0] = ngids; - memcpy(s.gids + 1, gids, ngids * sizeof(Glyph)); - t = T_GLYPHS; - } -} - -void -Substitution::assign(Substitute &s, uint8_t &t, const Coverage &coverage) -{ - clear(s, t); - s.coverage = new Coverage(coverage); - t = T_COVERAGE; -} - -void -Substitution::assign(Substitute &s, uint8_t &t, const Substitute &os, uint8_t ot) -{ - if (&s == &os) - return; - switch (ot) { - case T_NONE: - clear(s, t); - break; - case T_GLYPH: - assign(s, t, os.gid); - break; - case T_GLYPHS: - assign(s, t, os.gids[0], os.gids + 1); - break; - case T_COVERAGE: - assign(s, t, *os.coverage); - break; - default: - assert(0); - } -} - -Substitution::Substitution(const Substitution &o) - : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_NONE), _right_is(T_NONE), - _alternate(o._alternate) -{ - assign(_left, _left_is, o._left, o._left_is); - assign(_in, _in_is, o._in, o._in_is); - assign(_out, _out_is, o._out, o._out_is); - assign(_right, _right_is, o._right, o._right_is); -} - -Substitution::Substitution(Glyph in, Glyph out) - : _left_is(T_NONE), _in_is(T_GLYPH), _out_is(T_GLYPH), _right_is(T_NONE) -{ - _in.gid = in; - _out.gid = out; -} - -Substitution::Substitution(Glyph in, const Vector<Glyph> &out, bool is_alternate) - : _left_is(T_NONE), _in_is(T_GLYPH), _out_is(T_NONE), _right_is(T_NONE), - _alternate(is_alternate) -{ - assert(out.size() > 0); - _in.gid = in; - assign(_out, _out_is, out.size(), &out[0]); -} - -Substitution::Substitution(Glyph in1, Glyph in2, Glyph out) - : _left_is(T_NONE), _in_is(T_GLYPHS), _out_is(T_GLYPH), _right_is(T_NONE) -{ - _in.gids = new Glyph[3]; - _in.gids[0] = 2; - _in.gids[1] = in1; - _in.gids[2] = in2; - _out.gid = out; -} - -Substitution::Substitution(const Vector<Glyph> &in, Glyph out) - : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_GLYPH), _right_is(T_NONE) -{ - assert(in.size() > 0); - assign(_in, _in_is, in.size(), &in[0]); - _out.gid = out; -} - -Substitution::Substitution(int nin, const Glyph *in, Glyph out) - : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_GLYPH), _right_is(T_NONE) -{ - assert(nin > 0); - assign(_in, _in_is, nin, in); - _out.gid = out; -} - -Substitution::Substitution(int nleft, int nin, int nout, int nright) - : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_NONE), _right_is(T_NONE) -{ - if (nleft) - assign_space(_left, _left_is, nleft); - if (nin) - assign_space(_in, _in_is, nin); - if (nout) - assign_space(_out, _out_is, nout); - if (nright) - assign_space(_right, _right_is, nright); -} - -Substitution::~Substitution() -{ - clear(_left, _left_is); - clear(_in, _in_is); - clear(_out, _out_is); - clear(_right, _right_is); -} - -Substitution & -Substitution::operator=(const Substitution &o) -{ - assign(_left, _left_is, o._left, o._left_is); - assign(_in, _in_is, o._in, o._in_is); - assign(_out, _out_is, o._out, o._out_is); - assign(_right, _right_is, o._right, o._right_is); - _alternate = o._alternate; - return *this; -} - -bool -Substitution::substitute_in(const Substitute &s, uint8_t t, const Coverage &c) -{ - switch (t) { - case T_NONE: - return true; - case T_GLYPH: - return c.covers(s.gid); - case T_GLYPHS: - for (int i = 1; i <= s.gids[0]; i++) - if (!c.covers(s.gids[i])) - return false; - return true; - case T_COVERAGE: - return *s.coverage <= c; - default: - assert(0); - return false; - } -} - -bool -Substitution::substitute_in(const Substitute &s, uint8_t t, const GlyphSet &gs) -{ - switch (t) { - case T_NONE: - return true; - case T_GLYPH: - return gs.covers(s.gid); - case T_GLYPHS: - for (int i = 1; i <= s.gids[0]; i++) - if (!gs.covers(s.gids[i])) - return false; - return true; - case T_COVERAGE: - for (Coverage::iterator i = s.coverage->begin(); i; i++) - if (!gs.covers(*i)) - return false; - return true; - default: - assert(0); - return false; - } -} - -bool -Substitution::context_in(const Coverage &c) const -{ - return substitute_in(_left, _left_is, c) - && substitute_in(_in, _in_is, c) - && substitute_in(_right, _right_is, c); -} - -bool -Substitution::context_in(const GlyphSet &gs) const -{ - return substitute_in(_left, _left_is, gs) - && substitute_in(_in, _in_is, gs) - && substitute_in(_right, _right_is, gs); -} - -Glyph -Substitution::extract_glyph(const Substitute &s, uint8_t t) noexcept -{ - return (t == T_GLYPH ? s.gid : 0); -} - -Glyph -Substitution::extract_glyph(const Substitute &s, int which, uint8_t t) noexcept -{ - switch (t) { - case T_GLYPH: - return (which == 0 ? s.gid : 0); - case T_GLYPHS: - return (s.gids[0] > which ? s.gids[which + 1] : 0); - case T_COVERAGE: - for (Coverage::iterator ci = s.coverage->begin(); ci; ci++, which--) - if (which == 0) - return *ci; - return 0; - default: - return 0; - } -} - -bool -Substitution::extract_glyphs(const Substitute &s, uint8_t t, Vector<Glyph> &v, bool coverage_ok) noexcept -{ - switch (t) { - case T_GLYPH: - v.push_back(s.gid); - return true; - case T_GLYPHS: - for (int i = 1; i <= s.gids[0]; i++) - v.push_back(s.gids[i]); - return true; - case T_COVERAGE: - if (coverage_ok) { - for (Coverage::iterator i = s.coverage->begin(); i; i++) - v.push_back(*i); - return true; - } else - return false; - default: - return false; - } -} - -Glyph * -Substitution::extract_glyphptr(const Substitute &s, uint8_t t) noexcept -{ - switch (t) { - case T_GLYPH: - return const_cast<Glyph *>(&s.gid); - case T_GLYPHS: - return &s.gids[1]; - default: - return 0; - } -} - -int -Substitution::extract_nglyphs(const Substitute &s, uint8_t t, bool coverage_ok) noexcept -{ - switch (t) { - case T_GLYPH: - return 1; - case T_GLYPHS: - return s.gids[0]; - case T_COVERAGE: - return (coverage_ok ? 1 : 0); - default: - return 0; - } -} - -bool -Substitution::matches(const Substitute &s, uint8_t t, int pos, Glyph g) noexcept -{ - switch (t) { - case T_GLYPH: - return (pos == 0 && s.gid == g); - case T_GLYPHS: - return (pos >= 0 && pos < s.gids[0] && s.gids[1 + pos] == g); - case T_COVERAGE: - return (pos == 0 && s.coverage->covers(g)); - default: - return false; - } -} - -bool -Substitution::is_noop() const -{ - return (_in_is == T_GLYPH && _out_is == T_GLYPH && _in.gid == _out.gid) - || (_in_is == T_GLYPHS && _out_is == T_GLYPHS - && _in.gids[0] == _out.gids[0] - && memcmp(_in.gids, _out.gids, (_in.gids[0] + 1) * sizeof(Glyph)) == 0); -} - -bool -Substitution::all_in_glyphs(Vector<Glyph> &gs) const -{ - bool ok = true; - gs.clear(); - if (_left_is != T_NONE) - ok &= extract_glyphs(_left, _left_is, gs, false); - ok &= extract_glyphs(_in, _in_is, gs, false); - if (_right_is != T_NONE) - ok &= extract_glyphs(_right, _right_is, gs, false); - return ok; -} - -bool -Substitution::all_out_glyphs(Vector<Glyph> &v) const -{ - bool ok = true; - if (_left_is != T_NONE) - ok &= extract_glyphs(_left, _left_is, v, false); - ok &= extract_glyphs(_out, _out_is, v, false); - if (_right_is != T_NONE) - ok &= extract_glyphs(_right, _right_is, v, false); - return ok; -} - -void -Substitution::assign_append(Substitute &s, uint8_t &t, const Substitute &ls, uint8_t lt, const Substitute &rs, uint8_t rt) -{ - if (lt == T_NONE) - assign(s, t, rs, rt); - else if (rt == T_NONE) - assign(s, t, ls, lt); - else if (lt != T_COVERAGE && rt != T_COVERAGE) { - int nl = extract_nglyphs(ls, lt, false); - int nr = extract_nglyphs(rs, rt, false); - Glyph *gids = new Glyph[nl + nr + 1]; - gids[0] = nl + nr; - memcpy(&gids[1], extract_glyphptr(ls, lt), nl * sizeof(Glyph)); - memcpy(&gids[1 + nl], extract_glyphptr(rs, rt), nr * sizeof(Glyph)); - clear(s, t); - s.gids = gids; - t = T_GLYPHS; - } else - throw Error(); -} - -void -Substitution::assign_append(Substitute &s, uint8_t &t, const Substitute &ls, uint8_t lt, Glyph rg) -{ - Substitute rs; - rs.gid = rg; - assign_append(s, t, ls, lt, rs, T_GLYPH); -} - -Substitution -Substitution::in_out_append_glyph(Glyph g) const -{ - Substitution s; - assign(s._left, s._left_is, _left, _left_is); - assign(s._right, s._right_is, _right, _right_is); - assign_append(s._in, s._in_is, _in, _in_is, g); - assign_append(s._out, s._out_is, _out, _out_is, g); - return s; -} - -void -Substitution::add_outer_left(Glyph g) -{ - Substitute ls; - ls.gid = g; - assign_append(_left, _left_is, ls, T_GLYPH, _left, _left_is); -} - -void -Substitution::remove_outer_left() -{ - if (_left_is == T_GLYPH) - _left_is = T_NONE; - else if (_left_is == T_GLYPHS) { - if (_left.gids[0] == 2) - assign(_left, _left_is, _left.gids[2]); - else { - _left.gids[0]--; - memmove(_left.gids + 1, _left.gids + 2, _left.gids[0] * sizeof(Glyph)); - } - } -} - -void -Substitution::add_outer_right(Glyph g) -{ - assign_append(_right, _right_is, _right, _right_is, g); -} - -void -Substitution::remove_outer_right() -{ - if (_right_is == T_GLYPH) - _right_is = T_NONE; - else if (_right_is == T_GLYPHS) { - if (_right.gids[0] == 2) - assign(_right, _right_is, _right.gids[1]); - else - _right.gids[0]--; - } -} - -bool -Substitution::out_alter(const Substitution &o, int pos) noexcept -{ - const Glyph *g = out_glyphptr(); - int ng = out_nglyphs(); - const Glyph *out_g = o.out_glyphptr(); - int out_ng = o.out_nglyphs(); - int in_ng = o.in_nglyphs(); - if (pos + in_ng > ng || out_ng == 0) - return false; - - // check that input substitution actually matches us - for (int i = 0; i < in_ng; i++) - if (!o.in_matches(i, g[pos+i])) - return false; - - // actually change output - Vector<Glyph> new_g; - for (int i = 0; i < pos; i++) - new_g.push_back(g[i]); - for (int i = 0; i < out_ng; i++) - new_g.push_back(out_g[i]); - for (int i = pos + in_ng; i < ng; i++) - new_g.push_back(g[i]); - assign(_out, _out_is, new_g.size(), &new_g[0]); - - return true; -} - -static void -unparse_glyphid(StringAccum &sa, Glyph gid, const Vector<PermString> *gns) noexcept -{ - if (gid > 0 && gns && gns->size() > gid && (*gns)[gid]) - sa << (*gns)[gid]; - else - sa << "g" << gid; -} - -void -Substitution::unparse_glyphids(StringAccum &sa, const Substitute &s, uint8_t t, const Vector<PermString> *gns) noexcept -{ - if (t == T_GLYPH) - unparse_glyphid(sa, s.gid, gns); - else if (t == T_GLYPHS) { - for (int i = 1; i <= s.gids[0]; i++) { - if (i != 1) - sa << ' '; - unparse_glyphid(sa, s.gids[i], gns); - } - } else if (t == T_COVERAGE) - sa << "<coverage>"; - else - sa << "-"; -} - -void -Substitution::unparse(StringAccum &sa, const Vector<PermString> *gns) const -{ - if (!*this) - sa << "NULL[]"; - else { - if (is_single()) - sa << "SINGLE["; - else if (is_ligature()) - sa << "LIGATURE["; - else if (is_multiple()) - sa << "MULTIPLE["; - else if (is_alternate()) - sa << "ALTERNATE["; - else if (is_simple_context()) - sa << "SIMPLECONTEXT["; - else - sa << "UNKNOWN["; - - if (_left_is != T_NONE) { - unparse_glyphids(sa, _left, _left_is, gns); - sa << " | "; - } - unparse_glyphids(sa, _in, _in_is, gns); - sa << " => "; - unparse_glyphids(sa, _out, _out_is, gns); - if (_right_is != T_NONE) { - sa << " | "; - unparse_glyphids(sa, _right, _right_is, gns); - } - - sa << ']'; - } -} - -String -Substitution::unparse(const Vector<PermString> *gns) const -{ - StringAccum sa; - unparse(sa, gns); - return sa.take_string(); -} - - - -/************************** - * Gsub * - * * - **************************/ - -Gsub::Gsub(const Data &d, const Font *otf, ErrorHandler *errh) - : _chaincontext_reverse_backtrack(false) -{ - // Fixed Version - // Offset ScriptList - // Offset FeatureList - // Offset LookupList - if (d.length() == 0) - throw BlankTable("GSUB"); - if (d.u16(0) != 1) - throw Format("GSUB"); - if (_script_list.assign(d.offset_subtable(4), errh) < 0) - throw Format("GSUB script list"); - if (_feature_list.assign(d.offset_subtable(6), errh) < 0) - throw Format("GSUB feature list"); - _lookup_list = d.offset_subtable(8); - - if (!otf) - return; - - // Check for "correct" chaining context rules, as suggested by Adobe's - // OpenType FDK - try { - Name nametable(otf->table("name"), ErrorHandler::silent_handler()); - _chaincontext_reverse_backtrack = nametable.version_chaincontext_reverse_backtrack(); - } catch (Error) { - } -} - -int -Gsub::nlookups() const -{ - return _lookup_list.u16(0); -} - -GsubLookup -Gsub::lookup(unsigned i) const -{ - if (i >= _lookup_list.u16(0)) - throw Error("GSUB lookup out of range"); - else - return GsubLookup(_lookup_list.offset_subtable(2 + i*2)); -} - - -/************************** - * GsubLookup * - * * - **************************/ - -GsubLookup::GsubLookup(const Data &d) - : _d(d) -{ - if (_d.length() < 6) - throw Format("GSUB Lookup table"); - _type = _d.u16(0); - if (_type == L_EXTENSION && _d.u16(4) != 0) { - Data first_subtable = _d.offset_subtable(HEADERSIZE); - if (first_subtable.length() < 8 || first_subtable.u16(0) != 1) - throw Format("GSUB Extension Lookup table"); - _type = first_subtable.u16(2); - } -} - -Data -GsubLookup::subtable(int i) const -{ - Data subd = _d.offset_subtable(HEADERSIZE + i*RECSIZE); - if (_d.u16(0) != L_EXTENSION) - return subd; - else if (subd.length() >= 8 && subd.u16(0) == 1 && subd.u16(2) == _type) - return subd.subtable(subd.u32(4)); - else - return Data(); -} - -void -GsubLookup::mark_out_glyphs(const Gsub &gsub, Vector<bool> &gmap) const -{ - int nlookup = _d.u16(4); - switch (_type) { - case L_SINGLE: - for (int i = 0; i < nlookup; i++) { - GsubSingle x(subtable(i)); // this pattern makes gcc-3.3.4 happier - x.mark_out_glyphs(gmap); - } - return; - case L_MULTIPLE: - for (int i = 0; i < nlookup; i++) { - GsubMultiple x(subtable(i)); - x.mark_out_glyphs(gmap); - } - return; - case L_ALTERNATE: - for (int i = 0; i < nlookup; i++) { - GsubMultiple x(subtable(i)); - x.mark_out_glyphs(gmap); - } - return; - case L_LIGATURE: - for (int i = 0; i < nlookup; i++) { - GsubLigature x(subtable(i)); - x.mark_out_glyphs(gmap); - } - return; - case L_CONTEXT: - for (int i = 0; i < nlookup; i++) { - GsubContext x(subtable(i)); - x.mark_out_glyphs(gsub, gmap); - } - return; - case L_CHAIN: - for (int i = 0; i < nlookup; i++) { - GsubChainContext x(subtable(i)); - x.mark_out_glyphs(gsub, gmap); - } - return; - } -} - -bool -GsubLookup::unparse_automatics(const Gsub &gsub, Vector<Substitution> &v, const Coverage &limit) const -{ - int nlookup = _d.u16(4); - switch (_type) { - case L_SINGLE: - for (int i = 0; i < nlookup; i++) { - GsubSingle x(subtable(i)); // this pattern makes gcc-3.3.4 happier - x.unparse(v, limit); - } - return true; - case L_MULTIPLE: - for (int i = 0; i < nlookup; i++) { - GsubMultiple x(subtable(i)); - x.unparse(v); - } - return true; - case L_ALTERNATE: - for (int i = 0; i < nlookup; i++) { - GsubMultiple x(subtable(i)); - x.unparse(v, true); - } - return true; - case L_LIGATURE: - for (int i = 0; i < nlookup; i++) { - GsubLigature x(subtable(i)); - x.unparse(v); - } - return true; - case L_CONTEXT: { - bool understood = true; - for (int i = 0; i < nlookup; i++) { - GsubContext x(subtable(i)); - understood &= x.unparse(gsub, v, limit); - } - return understood; - } - case L_CHAIN: { - bool understood = true; - for (int i = 0; i < nlookup; i++) { - GsubChainContext x(subtable(i)); - understood &= x.unparse(gsub, v, limit); - } - return understood; - } - default: - return false; - } -} - -bool -GsubLookup::apply(const Glyph *g, int pos, int n, Substitution &s) const -{ - int nlookup = _d.u16(4); - switch (_type) { - case L_SINGLE: - for (int i = 0; i < nlookup; i++) { - GsubSingle x(subtable(i)); - if (x.apply(g, pos, n, s)) - return true; - } - return false; - case L_MULTIPLE: - for (int i = 0; i < nlookup; i++) { - GsubMultiple x(subtable(i)); - if (x.apply(g, pos, n, s)) - return true; - } - return false; - case L_ALTERNATE: - for (int i = 0; i < nlookup; i++) { - GsubMultiple x(subtable(i)); - if (x.apply(g, pos, n, s, true)) - return true; - } - return false; - case L_LIGATURE: - for (int i = 0; i < nlookup; i++) { - GsubLigature x(subtable(i)); - if (x.apply(g, pos, n, s)) - return true; - } - return false; - default: // XXX - return false; - } -} - - -/************************** - * GsubSingle * - * * - **************************/ - -GsubSingle::GsubSingle(const Data &d) - : _d(d) -{ - if (_d[0] != 0 - || (_d[1] != 1 && _d[1] != 2)) - throw Format("GSUB Single Substitution"); - Coverage coverage(_d.offset_subtable(2)); - if (!coverage.ok() - || (_d[1] == 2 && coverage.size() > _d.u16(4))) - throw Format("GSUB Single Substitution coverage"); -} - -Coverage -GsubSingle::coverage() const noexcept -{ - return Coverage(_d.offset_subtable(2), 0, false); -} - -Glyph -GsubSingle::map(Glyph g) const -{ - int ci = coverage().coverage_index(g); - if (ci < 0) - return g; - else if (_d[1] == 1) - return g + _d.s16(4); - else - return _d.u16(HEADERSIZE + FORMAT2_RECSIZE*ci); -} - -void -GsubSingle::mark_out_glyphs(Vector<bool> &gmap) const -{ - if (_d[1] == 1) { - int delta = _d.s16(4); - for (Coverage::iterator i = coverage().begin(); i; i++) - gmap[*i + delta] = true; - } else { - for (Coverage::iterator i = coverage().begin(); i; i++) - gmap[_d.u16(HEADERSIZE + i.coverage_index()*FORMAT2_RECSIZE)] = true; - } -} - -void -GsubSingle::unparse(Vector<Substitution> &v, const Coverage &limit) const -{ - if (_d[1] == 1) { - int delta = _d.s16(4); - for (Coverage::iterator it = coverage().begin(); it; ++it) - if (limit.covers(*it)) - v.push_back(Substitution(*it, *it + delta)); - } else { - for (Coverage::iterator it = coverage().begin(); it; ++it) - if (limit.covers(*it)) - v.push_back(Substitution(*it, _d.u16(HEADERSIZE + it.coverage_index()*FORMAT2_RECSIZE))); - } -} - -bool -GsubSingle::apply(const Glyph *g, int pos, int n, Substitution &s) const -{ - int ci; - if (pos < n && (ci = coverage().coverage_index(g[pos])) >= 0) { - if (_d[1] == 1) - s = Substitution(g[pos], g[pos] + _d.s16(4)); - else - s = Substitution(g[pos], _d.u16(HEADERSIZE + ci*FORMAT2_RECSIZE)); - return true; - } else - return false; -} - - -/************************** - * GsubMultiple * - * * - **************************/ - -GsubMultiple::GsubMultiple(const Data &d) - : _d(d) -{ - if (_d[0] != 0 || _d[1] != 1) - throw Format("GSUB Multiple Substitution"); - Coverage coverage(_d.offset_subtable(2)); - if (!coverage.ok() - || coverage.size() > _d.u16(4)) - throw Format("GSUB Multiple Substitution coverage"); -} - -Coverage -GsubMultiple::coverage() const noexcept -{ - return Coverage(_d.offset_subtable(2), 0, false); -} - -bool -GsubMultiple::map(Glyph g, Vector<Glyph> &v) const -{ - v.clear(); - int ci = coverage().coverage_index(g); - if (ci < 0) { - v.push_back(g); - return false; - } else { - Data seq = _d.offset_subtable(HEADERSIZE + ci*RECSIZE); - for (int i = 0; i < seq.u16(0); i++) - v.push_back(seq.u16(SEQ_HEADERSIZE + i*SEQ_RECSIZE)); - return true; - } -} - -void -GsubMultiple::mark_out_glyphs(Vector<bool> &gmap) const -{ - for (Coverage::iterator i = coverage().begin(); i; ++i) { - Data seq = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE); - for (int j = 0; j < seq.u16(0); ++j) - gmap[seq.u16(SEQ_HEADERSIZE + j*SEQ_RECSIZE)] = true; - } -} - -void -GsubMultiple::unparse(Vector<Substitution> &v, bool is_alternate) const -{ - Vector<Glyph> result; - for (Coverage::iterator i = coverage().begin(); i; i++) { - Data seq = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE); - result.clear(); - for (int j = 0; j < seq.u16(0); j++) - result.push_back(seq.u16(SEQ_HEADERSIZE + j*SEQ_RECSIZE)); - v.push_back(Substitution(*i, result, is_alternate)); - } -} - -bool -GsubMultiple::apply(const Glyph *g, int pos, int n, Substitution &s, bool is_alternate) const -{ - int ci; - if (pos < n && (ci = coverage().coverage_index(g[pos])) >= 0) { - Vector<Glyph> result; - Data seq = _d.offset_subtable(HEADERSIZE + ci*RECSIZE); - for (int j = 0; j < seq.u16(0); j++) - result.push_back(seq.u16(SEQ_HEADERSIZE + j*SEQ_RECSIZE)); - s = Substitution(g[pos], result, is_alternate); - return true; - } else - return false; -} - - -/************************** - * GsubLigature * - * * - **************************/ - -GsubLigature::GsubLigature(const Data &d) - : _d(d) -{ - if (_d[0] != 0 - || _d[1] != 1) - throw Format("GSUB Ligature Substitution"); - Coverage coverage(_d.offset_subtable(2)); - if (!coverage.ok() - || coverage.size() > _d.u16(4)) - throw Format("GSUB Ligature Substitution coverage"); -} - -Coverage -GsubLigature::coverage() const noexcept -{ - return Coverage(_d.offset_subtable(2), 0, false); -} - -bool -GsubLigature::map(const Vector<Glyph> &gs, Glyph &result, int &consumed) const -{ - assert(gs.size() > 0); - result = gs[0]; - consumed = 1; - int ci = coverage().coverage_index(gs[0]); - if (ci < 0) - return false; - Data ligset = _d.offset_subtable(HEADERSIZE + ci*RECSIZE); - int nligset = ligset.u16(0); - for (int i = 0; i < nligset; i++) { - Data lig = ligset.offset_subtable(SET_HEADERSIZE + i*SET_RECSIZE); - int nlig = lig.u16(2); - if (nlig > gs.size() - 1) - goto bad; - for (int j = 0; j < nlig - 1; j++) - if (lig.u16(LIG_HEADERSIZE + j*LIG_RECSIZE) != gs[j + 1]) - goto bad; - result = lig.u16(0); - consumed = nlig + 1; - return true; - bad: ; - } - return false; -} - -void -GsubLigature::mark_out_glyphs(Vector<bool> &gmap) const -{ - for (Coverage::iterator i = coverage().begin(); i; i++) { - Data ligset = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE); - int nligset = ligset.u16(0); - Vector<Glyph> components(1, *i); - for (int j = 0; j < nligset; j++) { - Data lig = ligset.offset_subtable(SET_HEADERSIZE + j*SET_RECSIZE); - gmap[lig.u16(0)] = true; - } - } -} - -void -GsubLigature::unparse(Vector<Substitution> &v) const -{ - for (Coverage::iterator i = coverage().begin(); i; i++) { - Data ligset = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE); - int nligset = ligset.u16(0); - Vector<Glyph> components(1, *i); - for (int j = 0; j < nligset; j++) { - Data lig = ligset.offset_subtable(SET_HEADERSIZE + j*SET_RECSIZE); - int nlig = lig.u16(2); - components.resize(1); - for (int k = 0; k < nlig - 1; k++) - components.push_back(lig.u16(LIG_HEADERSIZE + k*LIG_RECSIZE)); - v.push_back(Substitution(components, lig.u16(0))); - } - } -} - -bool -GsubLigature::apply(const Glyph *g, int pos, int n, Substitution &s) const -{ - int ci; - if (pos < n && (ci = coverage().coverage_index(g[pos])) >= 0) { - Data ligset = _d.offset_subtable(HEADERSIZE + ci*RECSIZE); - int nligset = ligset.u16(0); - for (int j = 0; j < nligset; j++) { - Data lig = ligset.offset_subtable(SET_HEADERSIZE + j*SET_RECSIZE); - int nlig = lig.u16(2); - if (pos + nlig <= n) { - for (int k = 0; k < nlig - 1; k++) - if (lig.u16(LIG_HEADERSIZE + k*LIG_RECSIZE) != g[pos + k + 1]) - goto ligature_failed; - s = Substitution(nlig, &g[pos], lig.u16(0)); - return true; - } - ligature_failed: ; - } - } - return false; -} - - -/************************** - * GsubContext * - * * - **************************/ - -GsubContext::GsubContext(const Data &d) - : _d(d) -{ - switch (_d.u16(0)) { - case 1: - case 2: - break; - case 3: { - int ninput = _d.u16(2); - if (ninput < 1) - throw Format("GSUB Context Substitution input sequence"); - Coverage coverage(_d.offset_subtable(F3_HSIZE)); - if (!coverage.ok()) - throw Format("GSUB Context Substitution coverage"); - break; - } - default: - throw Format("GSUB Context Substitution"); - } -} - -Coverage -GsubContext::coverage() const noexcept -{ - if (_d[1] == 3) - return Coverage(_d.offset_subtable(F3_HSIZE), 0, false); - else - return Coverage(); -} - -void -GsubContext::subruleset_mark_out_glyphs(const Data &data, int nsub, - int subtab_offset, const Gsub &gsub, - Vector<bool> &gmap) -{ - for (int j = 0; j < nsub; ++j) { - int lookup_index = data.u16(subtab_offset + SUBRECSIZE*j + 2); - gsub.lookup(lookup_index).mark_out_glyphs(gsub, gmap); - } -} - -void -GsubContext::mark_out_glyphs(const Gsub &gsub, Vector<bool> &gmap) const -{ - if (_d.u16(0) != 3) // XXX - return; - int nglyph = _d.u16(2); - int nsubst = _d.u16(4); - subruleset_mark_out_glyphs(_d, nsubst, F3_HSIZE + nglyph*2, gsub, gmap); -} - -bool -GsubContext::f1_unparse(const Data& data, - int nsub, int subtab_offset, - const Gsub& gsub, Vector<Substitution>& outsubs, - Substitution s) { - Substitution subtab_sub; - int napplied = 0; - for (int j = 0; j < nsub; j++) { - int seq_index = data.u16(subtab_offset + SUBRECSIZE*j); - int lookup_index = data.u16(subtab_offset + SUBRECSIZE*j + 2); - // XXX check seq_index against size of output glyphs? - if (gsub.lookup(lookup_index).apply(s.out_glyphptr(), seq_index, s.out_nglyphs(), subtab_sub)) { - napplied++; - s.out_alter(subtab_sub, seq_index); - } - } - outsubs.push_back(s); - return true; -} - -bool -GsubContext::f3_unparse(const Data &data, - int nglyph, int glyphtab_offset, const Coverage &limit, - int nsub, int subtab_offset, - const Gsub &gsub, Vector<Substitution> &outsubs, - const Substitution &prototype_sub) -{ - Vector<Substitution> subs; - subs.push_back(prototype_sub); - Vector<Substitution> work_subs; - - // get array of possible substitutions including contexts - for (int i = 0; i < nglyph; i++) { - assert(!work_subs.size()); - Coverage c(data.offset_subtable(glyphtab_offset + i*2)); - for (Coverage::iterator ci = (c & limit).begin(); ci; ci++) - for (int j = 0; j < subs.size(); j++) - work_subs.push_back(subs[j].in_out_append_glyph(*ci)); - subs.clear(); - subs.swap(work_subs); - } - - // now, apply referred lookups to the resulting substitution array - Substitution subtab_sub; - for (int i = 0; i < subs.size(); i++) { - Substitution &s = subs[i]; - int napplied = 0; - for (int j = 0; j < nsub; j++) { - int seq_index = data.u16(subtab_offset + SUBRECSIZE*j); - int lookup_index = data.u16(subtab_offset + SUBRECSIZE*j + 2); - // XXX check seq_index against size of output glyphs? - if (gsub.lookup(lookup_index).apply(s.out_glyphptr(), seq_index, s.out_nglyphs(), subtab_sub)) { - napplied++; - s.out_alter(subtab_sub, seq_index); - } - } - // 26.Jun.2003 -- always push substitution back, since the no-op might - // override a following substitution - outsubs.push_back(s); - } - - return true; // XXX -} - -bool -GsubContext::unparse(const Gsub &gsub, Vector<Substitution> &v, const Coverage &limit) const -{ - if (_d.u16(0) != 3) // XXX - return false; - int nglyph = _d.u16(2); - int nsubst = _d.u16(4); - return f3_unparse(_d, nglyph, F3_HSIZE, limit, nsubst, F3_HSIZE + nglyph*2, gsub, v, Substitution()); -} - - -/************************** - * GsubChainContext * - * * - **************************/ - -GsubChainContext::GsubChainContext(const Data &d) - : _d(d) -{ - switch (_d.u16(0)) { - case 1: { - Coverage coverage(_d.offset_subtable(2)); - if (!coverage.ok() - || coverage.size() != _d.u16(4)) - throw Format("ChainContext Substitution coverage"); - break; - } - case 2: - break; - case 3: { - int nbacktrack = _d.u16(2); - int input_offset = F3_HSIZE + nbacktrack*2; - int ninput = _d.u16(input_offset); - if (ninput < 1) - throw Format("GSUB ChainContext Substitution input sequence"); - Coverage coverage(_d.offset_subtable(input_offset + F3_INPUT_HSIZE)); - if (!coverage.ok()) - throw Format("GSUB ChainContext Substitution coverage"); - break; - } - default: - throw Format("GSUB ChainContext Substitution"); - } -} - -Coverage -GsubChainContext::coverage() const noexcept -{ - switch (_d.u16(0)) { - case 1: - return Coverage(_d.offset_subtable(2), 0, false); - case 3: { - int nbacktrack = _d.u16(2); - int input_offset = F3_HSIZE + nbacktrack*2; - return Coverage(_d.offset_subtable(input_offset + F3_INPUT_HSIZE), 0, false); - } - default: - return Coverage(); - } -} - -void -GsubChainContext::mark_out_glyphs(const Gsub &gsub, Vector<bool> &gmap) const -{ - switch (_d.u16(0)) { - case 1: { - int nsubruleset = _d.u16(4); - for (int i = 0; i != nsubruleset; ++i) { - int srs_offset = _d.u16(6 + i*2); - int nsubrule = _d.u16(srs_offset); - for (int j = 0; j != nsubrule; ++j) { - int subrule_offset = srs_offset + _d.u16(srs_offset + 2 + j*2); - int nbacktrack = _d.u16(subrule_offset); - int input_offset = subrule_offset + 2 + nbacktrack*2; - int ninput = _d.u16(input_offset); - int lookahead_offset = input_offset + 2 + (ninput-1)*2; - int nlookahead = _d.u16(lookahead_offset); - int subst_offset = lookahead_offset + 2 + nlookahead*2; - int nsubst = _d.u16(subst_offset); - - GsubContext::subruleset_mark_out_glyphs(_d, nsubst, subst_offset + 2, gsub, gmap); - } - } - break; - } - case 3: { - int nbacktrack = _d.u16(2); - int input_offset = F3_HSIZE + nbacktrack*2; - int ninput = _d.u16(input_offset); - int lookahead_offset = input_offset + F3_INPUT_HSIZE + ninput*2; - int nlookahead = _d.u16(lookahead_offset); - int subst_offset = lookahead_offset + F3_LOOKAHEAD_HSIZE + nlookahead*2; - int nsubst = _d.u16(subst_offset); - - GsubContext::subruleset_mark_out_glyphs(_d, nsubst, subst_offset + F3_SUBST_HSIZE, gsub, gmap); - break; - } - default: - return; - } -} - -bool -GsubChainContext::f1_unparse(const Gsub &gsub, Vector<Substitution> &v, const Coverage &limit) const -{ - Coverage input0_coverage(_d.offset_subtable(2), 0, false); - Coverage::iterator i0iter = input0_coverage.begin(); - - for (int i0index = 0; i0index != input0_coverage.size(); - ++i0index, ++i0iter) { - int srs_offset = _d.u16(6 + i0index*2); - int nsubrule = _d.u16(srs_offset); - for (int srindex = 0; srindex != nsubrule; ++srindex) { - int sr_offset = srs_offset + _d.u16(srs_offset + 2 + srindex*2); - int nbacktrack = _d.u16(sr_offset); - int input_offset = sr_offset + 2 + nbacktrack*2; - int ninput = _d.u16(input_offset); - int lookahead_offset = input_offset + 2 + (ninput-1)*2; - int nlookahead = _d.u16(lookahead_offset); - int subst_offset = lookahead_offset + 2 + nlookahead*2; - int nsubst = _d.u16(subst_offset); - int subtab_offset = subst_offset + 2; - - Substitution s(nbacktrack, ninput, ninput, nlookahead); - if (gsub.chaincontext_reverse_backtrack()) { - for (int i = 0; i != nbacktrack; ++i) - s.left_glyphptr()[i] = _d.u16(sr_offset + 2 + i*2); - } else { - for (int i = nbacktrack - 1; i != -1; --i) - s.left_glyphptr()[nbacktrack - 1 - i] = _d.u16(sr_offset + 2 + i*2); - } - Glyph* in_begin = s.in_glyphptr(); - Glyph* out_begin = s.out_glyphptr(); - in_begin[0] = out_begin[0] = *i0iter; - for (int i = 1; i != ninput; ++i) - in_begin[i] = out_begin[i] = _d.u16(input_offset + 2 + (i-1)*2); - for (int i = 0; i != ninput; ++i) - if (!limit.covers(in_begin[i])) - goto skip; - for (int i = 0; i != nlookahead; ++i) - s.right_glyphptr()[i] = _d.u16(lookahead_offset + 2 + i*2); - - // now, apply referred lookups to the resulting substitution array - GsubContext::f1_unparse(_d, nsubst, subtab_offset, gsub, v, s); - skip: ; - } - } - - return true; -} - -bool -GsubChainContext::f3_unparse(const Gsub &gsub, Vector<Substitution> &v, const Coverage &limit) const -{ - int nbacktrack = _d.u16(2); - int input_offset = F3_HSIZE + nbacktrack*2; - int ninput = _d.u16(input_offset); - int lookahead_offset = input_offset + F3_INPUT_HSIZE + ninput*2; - int nlookahead = _d.u16(lookahead_offset); - int subst_offset = lookahead_offset + F3_LOOKAHEAD_HSIZE + nlookahead*2; - int nsubst = _d.u16(subst_offset); - - Vector<Coverage> backtrackc; - Vector<Coverage> lookaheadc; - if (gsub.chaincontext_reverse_backtrack()) { - for (int i = 0; i < nbacktrack; i++) - backtrackc.push_back(Coverage(_d.offset_subtable(F3_HSIZE + i*2)) & limit); - } else { - for (int i = nbacktrack - 1; i >= 0; i--) - backtrackc.push_back(Coverage(_d.offset_subtable(F3_HSIZE + i*2)) & limit); - } - for (int i = 0; i < nlookahead; i++) - lookaheadc.push_back(Coverage(_d.offset_subtable(lookahead_offset + F3_LOOKAHEAD_HSIZE + i*2)) & limit); - - // give up if would generate too many substitutions - double n = 1; - for (int i = 0; i < nbacktrack; ++i) - n *= backtrackc[i].size(); - for (int i = 0; i < nlookahead; ++i) - n *= lookaheadc[i].size(); - for (int i = 0; i < ninput; ++i) - n *= (Coverage(_d.offset_subtable(input_offset + F3_INPUT_HSIZE + i*2)) & limit).size(); - if (n > 1000000) // arbitrary cutoff - return false; - - Vector<Coverage::iterator> backtracki; - Vector<Coverage::iterator> lookaheadi; - for (int i = 0; i < nbacktrack; i++) - backtracki.push_back(backtrackc[i].begin()); - for (int i = 0; i < nlookahead; i++) - lookaheadi.push_back(lookaheadc[i].begin()); - - bool any = false; - - while (1) { - - // run GsubContext - Substitution s(nbacktrack, 0, 0, nlookahead); - Glyph *left_begin = s.left_glyphptr(); - for (int i = 0; i < nbacktrack; i++) - left_begin[i] = *backtracki[i]; - Glyph *right_begin = s.right_glyphptr(); - for (int i = 0; i < nlookahead; i++) - right_begin[i] = *lookaheadi[i]; - - any |= GsubContext::f3_unparse(_d, ninput, input_offset + F3_INPUT_HSIZE, limit, nsubst, subst_offset + F3_SUBST_HSIZE, gsub, v, s); - - // step iterators - for (int i = nlookahead - 1; i >= 0; i--) { - lookaheadi[i]++; - if (lookaheadi[i]) - goto next; - lookaheadi[i] = lookaheadc[i].begin(); - } - for (int i = nbacktrack - 1; i >= 0; i--) { - backtracki[i]++; - if (backtracki[i]) - goto next; - backtracki[i] = backtrackc[i].begin(); - } - break; - - next: ; - } - - return any; -} - -bool -GsubChainContext::unparse(const Gsub &gsub, Vector<Substitution> &v, const Coverage &limit) const -{ - if (_d.u16(0) == 1) - return f1_unparse(gsub, v, limit); - else if (_d.u16(0) == 3) - return f3_unparse(gsub, v, limit); - else - return false; -} - - -}} |