summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc1573
1 files changed, 0 insertions, 1573 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc
deleted file mode 100644
index 84259ad69c6..00000000000
--- a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc
+++ /dev/null
@@ -1,1573 +0,0 @@
-/* metrics.{cc,hh} -- an encoding during and after OpenType features
- *
- * 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 "metrics.hh"
-#include "dvipsencoding.hh"
-#include "util.hh"
-#include "glyphfilter.hh"
-#include <string.h>
-#include <stdio.h>
-#include <algorithm>
-#include <lcdf/straccum.hh>
-
-Metrics::Metrics(const Efont::CharstringProgram *font, int nglyphs)
- : _boundary_glyph(nglyphs), _emptyslot_glyph(nglyphs + 1),
- _design_units(1000), _units_per_em(font->units_per_em()),
- _liveness_marked(false)
-{
- _encoding.assign(256, Char());
- add_mapped_font(font, String());
-}
-
-Metrics::~Metrics()
-{
- for (Char *c = _encoding.begin(); c != _encoding.end(); c++)
- delete c->virtual_char;
-}
-
-int
-Metrics::add_mapped_font(const Efont::CharstringProgram *font, const String &name)
-{
- _mapped_fonts.push_back(font);
- _mapped_font_names.push_back(name);
- return _mapped_fonts.size() - 1;
-}
-
-void
-Metrics::check() const
-{
- // check invariants
- // 1. all 'ligatures' entries refer to valid characters
- // 2. all 'ligatures' entries with 'in1 == c' are in '_encoding[c].ligs'
- // 3. 'virtual_char' SHOW operations point to valid non-virtual chars
- for (int code = 0; code < _encoding.size(); code++) {
- const Char *ch = &_encoding[code];
- assert((ch->virtual_char != 0) == (ch->glyph == VIRTUAL_GLYPH));
- for (const Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
- assert(valid_code(l->in2) && valid_code(l->out));
- for (const Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
- assert(valid_code(k->in2));
- if (const VirtualChar *vc = ch->virtual_char) {
- assert(vc->name);
- int font_number = 0;
- for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++) {
- assert(s->valid_op());
- if (s->op == Setting::SHOW && font_number == 0)
- assert(nonvirtual_code(s->x));
- else if (s->op == Setting::FONT)
- font_number = s->x;
- }
- }
- assert(ch->built_in1 < 0 || valid_code(ch->built_in1));
- assert(ch->built_in2 < 0 || valid_code(ch->built_in2));
- assert((ch->built_in1 >= 0) == (ch->built_in2 >= 0));
- assert(ch->base_code < 0 || valid_code(ch->base_code));
- if (valid_code(ch->base_code)) {
- const Char *ch2 = &_encoding[ch->base_code];
- assert((!ch->virtual_char && ch->glyph)
- || (!ch2->virtual_char && ch2->glyph));
- }
- if (ch->flag(Char::CONTEXT_ONLY))
- assert(ch->virtual_char && ch->built_in1 >= 0 && ch->built_in2 >= 0);
- if (ch->flag(Char::CONTEXT_ONLY))
- assert(ch->flag(Char::LIVE));
- }
-}
-
-PermString
-Metrics::code_name(Code code) const
-{
- if (code < 0 || code >= _encoding.size())
- return permprintf("<badcode%d>", code);
- else {
- const Char &ch = _encoding[code];
- if (ch.virtual_char)
- return ch.virtual_char->name;
- else if (ch.glyph == _boundary_glyph)
- return "<boundary>";
- else if (ch.glyph == _emptyslot_glyph)
- return "<emptyslot>";
- else if (ch.glyph >= 0 && ch.glyph < _mapped_fonts[0]->nglyphs())
- return _mapped_fonts[0]->glyph_name(ch.glyph);
- else
- return permprintf("<glyph%d>", ch.glyph);
- }
-}
-
-
-/*****************************************************************************/
-/* encoding */
-
-Metrics::Code
-Metrics::unicode_encoding(uint32_t uni) const
-{
- for (const Char *ch = _encoding.begin(); ch < _encoding.end(); ch++)
- if (ch->unicode == uni)
- return ch - _encoding.begin();
- return -1;
-}
-
-Metrics::Code
-Metrics::hard_encoding(Glyph g, Code after) const
-{
- if (g < 0)
- return -1;
- int answer = -1, n = 0;
- for (int i = _encoding.size() - 1; i >= after; i--)
- if (_encoding[i].glyph == g)
- answer = i, n++;
- if (n < 2 && after == 0) {
- if (g >= _emap.size())
- _emap.resize(g + 1, -2);
- _emap[g] = answer;
- }
- return answer;
-}
-
-Metrics::Code
-Metrics::force_encoding(Glyph g, int lookup_source)
-{
- assert(g >= 0);
- int e = encoding(g, 0);
- if (e >= 0)
- return e;
- else {
- Char ch;
- ch.glyph = g;
- ch.base_code = _encoding.size();
- ch.lookup_source = lookup_source;
- _encoding.push_back(ch);
- assign_emap(g, ch.base_code);
- return ch.base_code;
- }
-}
-
-void
-Metrics::encode(Code code, uint32_t uni, Glyph g)
-{
- assert(code >= 0 && g >= 0 && g != VIRTUAL_GLYPH);
- if (code >= _encoding.size())
- _encoding.resize(code + 1, Char());
- _encoding[code].unicode = uni;
- _encoding[code].glyph = g;
- if (g > 0)
- _encoding[code].base_code = code;
- assert(!_encoding[code].virtual_char);
- assign_emap(g, code);
-}
-
-void
-Metrics::encode_virtual(Code code, PermString name, uint32_t uni, const Vector<Setting> &v, bool base_char)
-{
- assert(code >= 0 && v.size() > 0);
- if (code >= _encoding.size())
- _encoding.resize(code + 1, Char());
- _encoding[code].unicode = uni;
- _encoding[code].glyph = VIRTUAL_GLYPH;
- if (base_char)
- _encoding[code].flags |= Char::BASE_REP;
- assert(!_encoding[code].virtual_char);
- VirtualChar *vc = _encoding[code].virtual_char = new VirtualChar;
- vc->name = name;
- vc->setting = v;
- int font_number = 0;
- for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++) {
- assert(s->valid_op() && (s->op != Setting::SHOW || font_number != 0 || nonvirtual_code(s->x)));
- if (s->op == Setting::FONT)
- font_number = s->x;
- }
-}
-
-void
-Metrics::apply_base_encoding(const String &font_name, const DvipsEncoding &dvipsenc, const Vector<int> &mapping)
-{
- int font_number = -1;
- for (Char *c = _encoding.begin(); c != _encoding.end(); c++)
- if (c->glyph > 0 && !c->virtual_char && c->glyph < mapping.size()
- && mapping[c->glyph] >= 0) {
- if (font_number < 0)
- font_number = add_mapped_font(mapped_font(0), font_name);
- VirtualChar *vc = c->virtual_char = new VirtualChar;
- vc->name = dvipsenc.encoding(mapping[c->glyph]);
- vc->setting.push_back(Setting(Setting::FONT, font_number));
- vc->setting.push_back(Setting(Setting::SHOW, mapping[c->glyph], c->glyph));
- c->glyph = VIRTUAL_GLYPH;
- c->base_code = -1;
- c->flags = (c->flags & ~Char::BASE_LIVE) | Char::BASE_REP;
- }
-}
-
-void
-Metrics::add_altselector_code(Code code, int altselector_type)
-{
- for (Kern *k = _altselectors.begin(); k != _altselectors.end(); k++)
- if (k->in2 == code) {
- k->kern = altselector_type;
- return;
- }
- _altselectors.push_back(Kern(code, altselector_type));
-}
-
-bool
-Metrics::base_glyphs(Vector<Glyph> &v, int size) const
-{
- bool any = false;
- v.assign(_encoding.size(), 0);
- for (const Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
- if (ch->base_code >= 0 && ch->base_code < size) {
- v[ch->base_code] = ch->glyph;
- any = true;
- }
- return any;
-}
-
-
-/*****************************************************************************/
-/* Char methods */
-
-void
-Metrics::Char::clear()
-{
- glyph = 0;
- base_code = -1;
- unicode = 0;
- ligatures.clear();
- kerns.clear();
- delete virtual_char;
- virtual_char = 0;
- pdx = pdy = adx = 0;
- built_in1 = built_in2 = -1;
- lookup_source = -1;
- flags = 0;
-}
-
-void
-Metrics::Char::swap(Char &c)
-{
- std::swap(glyph, c.glyph);
- // NB: only a partial switch of base_code!!
- if (base_code < 0)
- base_code = c.base_code;
- c.base_code = -1;
- std::swap(unicode, c.unicode);
- ligatures.swap(c.ligatures);
- kerns.swap(c.kerns);
- std::swap(virtual_char, c.virtual_char);
- std::swap(pdx, c.pdx);
- std::swap(pdy, c.pdy);
- std::swap(adx, c.adx);
- std::swap(built_in1, c.built_in1);
- std::swap(built_in2, c.built_in2);
- std::swap(lookup_source, c.lookup_source);
- std::swap(flags, c.flags);
-}
-
-
-/*****************************************************************************/
-/* manipulating ligature lists */
-
-Metrics::Ligature *
-Metrics::ligature_obj(Code code1, Code code2)
-{
- assert(valid_code(code1) && valid_code(code2));
- Char &ch = _encoding[code1];
- for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
- if (l->in2 == code2)
- return l;
- return 0;
-}
-
-inline void
-Metrics::new_ligature(Code in1, Code in2, Code out)
-{
- assert(valid_code(in1) && valid_code(in2) && valid_code(out));
- _encoding[in1].ligatures.push_back(Ligature(in2, out));
-}
-
-inline void
-Metrics::repoint_ligature(Code, Ligature *l, Code out)
-{
- l->out = out;
-}
-
-void
-Metrics::add_ligature(Code in1, Code in2, Code out)
-{
- if (Ligature *l = ligature_obj(in1, in2)) {
- Char &ch = _encoding[l->out];
- if (ch.flags & Char::BUILT) {
- // move old ligatures to point to the true ligature
- for (Ligature *ll = ch.ligatures.begin(); ll != ch.ligatures.end(); ll++)
- add_ligature(out, ll->in2, ll->out);
- repoint_ligature(in1, l, out);
- }
- } else
- new_ligature(in1, in2, out);
-}
-
-Metrics::Code
-Metrics::pair_code(Code in1, Code in2, int lookup_source)
-{
- if (const Ligature *l = ligature_obj(in1, in2)) {
- if (lookup_source < 0)
- _encoding[l->out].flags &= ~Char::INTERMEDIATE;
- return l->out;
- } else {
- Char ch;
- ch.glyph = VIRTUAL_GLYPH;
- ch.flags = Char::BUILT | (lookup_source >= 0 ? Char::INTERMEDIATE : 0);
- VirtualChar *vc = ch.virtual_char = new VirtualChar;
- vc->name = permprintf("%s__%s", code_str(in1), code_str(in2));
- setting(in1, vc->setting, SET_INTERMEDIATE);
- vc->setting.push_back(Setting(Setting::KERN));
- setting(in2, vc->setting, SET_INTERMEDIATE);
- ch.built_in1 = in1;
- ch.built_in2 = in2;
- ch.lookup_source = lookup_source;
- _encoding.push_back(ch);
- new_ligature(in1, in2, _encoding.size() - 1);
- return _encoding.size() - 1;
- }
-}
-
-void
-Metrics::remove_ligatures(Code in1, Code in2)
-{
- if (in1 == CODE_ALL) {
- for (in1 = 0; in1 < _encoding.size(); in1++)
- remove_ligatures(in1, in2);
- } else {
- Char &ch = _encoding[in1];
- if (in2 == CODE_ALL)
- ch.ligatures.clear();
- else if (Ligature *l = ligature_obj(in1, in2)) {
- *l = ch.ligatures.back();
- ch.ligatures.pop_back();
- }
- }
-}
-
-
-/*****************************************************************************/
-/* manipulating kern lists */
-
-Metrics::Kern *
-Metrics::kern_obj(Code in1, Code in2)
-{
- assert(valid_code(in1) && valid_code(in2));
- Char &ch = _encoding[in1];
- for (Kern *k = ch.kerns.begin(); k != ch.kerns.end(); k++)
- if (k->in2 == in2)
- return k;
- return 0;
-}
-
-int
-Metrics::kern(Code in1, Code in2) const
-{
- assert(valid_code(in1) && valid_code(in2));
- const Char &ch = _encoding[in1];
- for (const Kern *k = ch.kerns.begin(); k != ch.kerns.end(); k++)
- if (k->in2 == in2)
- return k->kern;
- return 0;
-}
-
-void
-Metrics::add_kern(Code in1, Code in2, int kern)
-{
- if (Kern *k = kern_obj(in1, in2))
- k->kern += kern;
- else
- _encoding[in1].kerns.push_back(Kern(in2, kern));
-}
-
-void
-Metrics::set_kern(Code in1, Code in2, int kern)
-{
- if (in1 == CODE_ALL) {
- for (in1 = 0; in1 < _encoding.size(); in1++)
- set_kern(in1, in2, kern);
- } else {
- Char &ch = _encoding[in1];
- if (in2 == CODE_ALL) {
- assert(kern == 0);
- ch.kerns.clear();
- } else if (Kern *k = kern_obj(in1, in2)) {
- if (kern == 0) {
- *k = ch.kerns.back();
- ch.kerns.pop_back();
- } else
- k->kern = kern;
- } else if (kern != 0)
- ch.kerns.push_back(Kern(in2, kern));
- }
-}
-
-int
-Metrics::reencode_right_ligkern(Code old_in2, Code new_in2)
-{
- int nchanges = 0;
- for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++) {
- for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
- if (l->in2 == old_in2) {
- if (new_in2 >= 0)
- l->in2 = new_in2;
- else {
- *l = ch->ligatures.back();
- ch->ligatures.pop_back();
- l--;
- }
- nchanges++;
- }
- for (Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
- if (k->in2 == old_in2) {
- if (new_in2 >= 0)
- k->in2 = new_in2;
- else {
- *k = ch->kerns.back();
- ch->kerns.pop_back();
- k--;
- }
- nchanges++;
- }
- // XXX?
- if (ch->context_setting(-1, old_in2) && new_in2 >= 0 && ch->built_in1 >= 0)
- ch->built_in2 = new_in2;
- }
- return nchanges;
-}
-
-
-/*****************************************************************************/
-/* positioning */
-
-void
-Metrics::add_single_positioning(Code c, int pdx, int pdy, int adx)
-{
- assert(valid_code(c));
- Char &ch = _encoding[c];
- ch.pdx += pdx;
- ch.pdy += pdy;
- ch.adx += adx;
-}
-
-
-/*****************************************************************************/
-/* changed_context structure */
-
-class Metrics::ChangedContext { public:
- ChangedContext(int ncodes);
- ~ChangedContext();
- typedef Metrics::Code Code;
-
- enum Context { CH_NONE = 0, CH_SOME = 1, CH_ALL = 2 };
- bool allowed(Code, bool left_context) const;
- bool pair_allowed(Code, Code) const;
- bool virgin(Code) const;
- void disallow(Code);
- void disallow_pair(Code, Code);
- private:
- Vector<Vector<uint32_t> *> _v;
- int _initial_ncodes;
- mutable Vector<uint32_t> _all_sentinel;
- ChangedContext(const ChangedContext &);
- ChangedContext &operator=(const ChangedContext &);
- static inline bool bit(const Vector<uint32_t> &, Code);
- inline void ensure_all(Code) const;
-};
-
-Metrics::ChangedContext::ChangedContext(int ncodes)
- : _v(ncodes, 0), _initial_ncodes(ncodes), _all_sentinel(((ncodes - 1) >> 5) + 1, 0xFFFFFFFFU)
-{
-}
-
-Metrics::ChangedContext::~ChangedContext()
-{
- for (Vector<uint32_t> **v = _v.begin(); v != _v.end(); v++)
- if (*v != &_all_sentinel)
- delete *v;
-}
-
-inline void
-Metrics::ChangedContext::ensure_all(Code c) const
-{
- if (c >= 0 && (c >> 5) >= _all_sentinel.size())
- _all_sentinel.resize((c >> 5) + 1, 0xFFFFFFFFU);
-}
-
-inline bool
-Metrics::ChangedContext::bit(const Vector<uint32_t> &v, Code c)
-{
- if (c < 0 || (c >> 5) >= v.size())
- return false;
- else
- return (v[c >> 5] & (1 << (c & 0x1F))) != 0;
-}
-
-bool
-Metrics::ChangedContext::allowed(Code c, bool left_context) const
-{
- if (c < 0)
- return false;
- else if (c >= _v.size())
- return left_context;
- else
- return (_v[c] != &_all_sentinel);
-}
-
-bool
-Metrics::ChangedContext::pair_allowed(Code c1, Code c2) const
-{
- ensure_all(c2);
- if (c1 < 0 || c2 < 0)
- return false;
- else if (c1 >= _v.size() || c2 >= _v.size() || !_v[c1])
- return true;
- else
- return !bit(*_v[c1], c2);
-}
-
-bool
-Metrics::ChangedContext::virgin(Code c) const
-{
- return (c >= 0 && (c >= _v.size() || _v[c] == 0));
-}
-
-void
-Metrics::ChangedContext::disallow(Code c)
-{
- assert(c >= 0);
- if (c >= _v.size())
- _v.resize(c + 1, 0);
- if (_v[c] != &_all_sentinel) {
- delete _v[c];
- _v[c] = &_all_sentinel;
- }
-}
-
-void
-Metrics::ChangedContext::disallow_pair(Code c1, Code c2)
-{
- assert(c1 >= 0 && c2 >= 0);
- if (c1 >= _v.size())
- _v.resize(c1 + 1, 0);
- if (!_v[c1])
- _v[c1] = new Vector<uint32_t>;
- if (_v[c1] != &_all_sentinel) {
- if ((c2 >> 5) >= _v[c1]->size())
- _v[c1]->resize((c2 >> 5) + 1, 0);
- (*_v[c1])[c2 >> 5] |= 1 << (c2 & 0x1F);
- }
-}
-
-
-/*****************************************************************************/
-/* applying GSUB substitutions */
-
-void
-Metrics::apply_single(Code cin, const Substitution *s, int lookup,
- ChangedContext &ctx, const GlyphFilter &glyph_filter,
- const Vector<PermString> &glyph_names)
-{
- // check if encoded
- if (!ctx.allowed(cin, false))
- /* not encoded before this substitution began, or completely changed;
- ingore */
- return;
-
- // check if substitution of this code allowed
- if (!glyph_filter.allow_substitution(s->in_glyph(), glyph_names, unicode(cin)))
- return;
-
- // look for an allowed alternate
- Glyph out = -1;
- for (int i = 0; out < 0 && i < s->out_nglyphs(); i++)
- if (glyph_filter.allow_alternate(s->out_glyph(i), glyph_names, unicode(cin)))
- out = s->out_glyph(i);
- if (out < 0) // no allowed alternate
- return;
-
- // apply substitution
- if (ctx.virgin(cin)) {
- // no one has changed this glyph yet, change it unilaterally
- assign_emap(s->in_glyph(), -2);
- assign_emap(out, cin);
- assert(!_encoding[cin].virtual_char);
- _encoding[cin].glyph = out;
- } else {
- // some contextual substitutions have changed this glyph, add
- // contextual substitutions for the remaining possibilities
- Code cout = force_encoding(out, lookup);
- for (Code right = 0; right < _encoding.size(); right++)
- if (_encoding[right].visible() && !_encoding[right].flag(Char::BUILT) && ctx.pair_allowed(cin, right)) {
- Code pair = pair_code(cout, right, lookup);
- _encoding[cout].flags &= ~Char::INTERMEDIATE;
- add_ligature(cin, right, pair);
- }
- }
-
- // no more substitutions for cin
- ctx.disallow(cin);
-}
-
-void
-Metrics::apply_ligature(const Vector<Code> &in, const Substitution *s, int lookup)
-{
- // build up the character pair
- int cin1 = in[0];
- for (const Code *inp = in.begin() + 1; inp < in.end() - 1; inp++)
- cin1 = pair_code(cin1, *inp, lookup);
- int cin2 = in.back();
-
- // build up the output character
- Vector<Code> out;
- s->all_out_glyphs(out);
- int cout = -1;
- for (Glyph *outp = out.begin(); outp < out.end(); outp++) {
- *outp = force_encoding(*outp, lookup);
- cout = (cout < 0 ? *outp : pair_code(cout, *outp, lookup));
- }
- _encoding[cout].flags &= ~Char::INTERMEDIATE;
-
- // check for replacing a fake ligature
- int old_out = -1;
- if (Ligature *l = ligature_obj(cin1, cin2)) {
- if (l->out == cout) // already created this same ligature
- return;
- if (_encoding[l->out].flags & Char::BUILT)
- old_out = l->out;
- }
-
- // make the final ligature
- add_ligature(cin1, cin2, cout);
-
- //fprintf(stderr, "%s : %d/%s %d/%s => %d/%s [was %d/%s]\n", s->unparse().c_str(), cin1, code_str(cin1), cin2, code_str(cin2), cout, code_str(cout), old_out, code_str(old_out));
-
- // if appropriate, swap old ligatures to point to the new result
- if (old_out >= 0)
- for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
- for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
- if (l->out == old_out)
- repoint_ligature(ch - _encoding.begin(), l, cout);
-}
-
-void
-Metrics::apply_simple_context_ligature(const Vector<Code> &codes,
- const Substitution *s, int lookup, ChangedContext &ctx,
- const GlyphFilter &glyph_filter,
- const Vector<PermString>& glyph_names)
-{
- int nleft = s->left_nglyphs(), nin = s->in_nglyphs();
- assert(codes.size() >= 2);
-
- // check if context allows substitutions
- for (int i = 0; i < codes.size(); ++i) {
- if (!ctx.allowed(codes[i], i < nleft)
- || !glyph_filter.allow_substitution(s->in_glyph(i), glyph_names, unicode(codes[i])))
- return;
- }
-
- // check if any part of the combination has already changed
- int ncheck = nleft + (nin > 2 ? 2 : nin);
- if (ncheck == codes.size())
- --ncheck;
- for (const Code *inp = codes.begin(); inp < codes.begin() + ncheck; ++inp)
- if (!ctx.pair_allowed(inp[0], inp[1]))
- return;
-
- // mark this combination as changed if appropriate
- if (codes.size() == 2 && nin == 1)
- ctx.disallow_pair(codes[0], codes[1]);
-
- // actually apply ligature
- apply_ligature(codes, s, lookup);
-}
-
-bool
-Metrics::next_encoding(Vector<Code> &codes, const Vector<Glyph> &glyphs) const
-{
- if (!codes.size()) {
- codes.assign(glyphs.size(), 0);
- for (int i = 0; i < glyphs.size(); ++i)
- if ((codes[i] = encoding(glyphs[i], 0)) < 0)
- return false;
- return true;
- } else {
- for (int i = 0; i < glyphs.size(); ++i)
- if ((codes[i] = encoding(glyphs[i], codes[i] + 1)) >= 0)
- return true;
- else
- codes[i] = encoding(glyphs[i], 0);
- return false;
- }
-}
-
-int
-Metrics::apply(const Vector<Substitution>& sv, bool allow_single, int lookup, const GlyphFilter& glyph_filter, const Vector<PermString>& glyph_names)
-{
- Vector<Glyph> glyphs;
- Vector<Code> codes;
-
- // keep track of what substitutions we have performed
- ChangedContext ctx(_encoding.size());
-
- // loop over substitutions
- int failures = 0;
- for (const Substitution *s = sv.begin(); s != sv.end(); s++) {
- bool is_single = s->is_single() || s->is_alternate();
- bool is_apply_single = is_single && allow_single;
- bool is_apply_simple_context_ligature = !is_single && !s->is_multiple() && s->is_simple_context();
-
- if (is_apply_single || is_apply_simple_context_ligature) {
- s->all_in_glyphs(glyphs);
- for (codes.clear(); next_encoding(codes, glyphs); ) {
- if (is_apply_single)
- apply_single(codes[0], s, lookup, ctx, glyph_filter, glyph_names);
- else
- apply_simple_context_ligature(codes, s, lookup, ctx, glyph_filter, glyph_names);
- }
- } else
- failures++;
- }
-
- return sv.size() - failures;
-}
-
-void
-Metrics::apply_alternates_single(Code cin, const Substitution *s, int lookup,
- const GlyphFilter &glyph_filter,
- const Vector<PermString> &glyph_names)
-{
- for (const Kern *as = _altselectors.begin(); as != _altselectors.end(); as++)
- if (as->kern == 0) {
- Code last = cin;
- uint32_t u = unicode(cin);
- for (int i = 0; i < s->out_nglyphs(); i++)
- if (glyph_filter.allow_alternate(s->out_glyph(i), glyph_names, u)) {
- Code out = force_encoding(s->out_glyph(i), lookup);
- add_ligature(last, as->in2, out);
- last = out;
- }
- } else if (as->kern <= s->out_nglyphs()) {
- Code out = force_encoding(s->out_glyph(as->kern - 1), lookup);
- add_ligature(cin, as->in2, out);
- }
-}
-
-void
-Metrics::apply_alternates_ligature(const Vector<Code> &codes,
- const Substitution *s, int lookup,
- const GlyphFilter &glyph_filter,
- const Vector<PermString> &glyph_names)
-{
- // check whether the output character is allowed
- if (!glyph_filter.allow_alternate(s->out_glyph(), glyph_names, 0))
- return;
-
- // find alternate selector and apply ligature if appropriate
- for (const Kern *as = _altselectors.begin(); as != _altselectors.end(); as++)
- if (as->kern == 0) {
- Vector<Code> lig(codes);
- lig.insert(lig.begin() + 1, as->in2);
- apply_ligature(lig, s, lookup);
- }
-}
-
-void
-Metrics::apply_alternates(const Vector<Substitution>& sv, int lookup, const GlyphFilter& glyph_filter, const Vector<PermString>& glyph_names)
-{
- Vector<Glyph> glyphs;
- Vector<Code> codes;
-
- for (const Substitution *s = sv.begin(); s != sv.end(); s++) {
- bool is_single = s->is_single() || s->is_alternate();
- if (is_single || s->is_ligature()) {
- s->all_in_glyphs(glyphs);
- for (codes.clear(); next_encoding(codes, glyphs); ) {
- if (is_single)
- apply_alternates_single(codes[0], s, lookup, glyph_filter, glyph_names);
- else
- apply_alternates_ligature(codes, s, lookup, glyph_filter, glyph_names);
- }
- }
- }
-}
-
-
-/*****************************************************************************/
-/* applying GPOS positionings */
-
-static bool // returns old value
-assign_bitvec(int*& bitvec, int e, int n)
-{
- if (e >= 0 && e < n) {
- if (!bitvec) {
- bitvec = new int[((n - 1) >> 5) + 1];
- memset(bitvec, 0, sizeof(int) * (((n - 1) >> 5) + 1));
- }
- bool result = (bitvec[e >> 5] & (1 << (e & 0x1F))) != 0;
- bitvec[e >> 5] |= (1 << (e & 0x1F));
- return result;
- } else
- return false;
-}
-
-int
-Metrics::apply(const Vector<Positioning>& pv)
-{
- // keep track of what substitutions we have performed
- int *single_changed = 0;
- Vector<int *> pair_changed(_encoding.size(), 0);
- Vector<Glyph> glyphs;
- Vector<Code> codes;
-
- // loop over substitutions
- int success = 0;
- for (const Positioning *p = pv.begin(); p != pv.end(); p++) {
- bool is_single = p->is_single();
- if (is_single || p->is_pairkern()) {
- p->all_in_glyphs(glyphs);
- for (codes.clear(); next_encoding(codes, glyphs); )
- if (is_single) {
- if (!assign_bitvec(single_changed, codes[0], _encoding.size())) {
- _encoding[codes[0]].pdx += p->left().pdx;
- _encoding[codes[0]].pdy += p->left().pdy;
- _encoding[codes[0]].adx += p->left().adx;
- }
- } else {
- if (!assign_bitvec(pair_changed[codes[0]], codes[1], _encoding.size()))
- add_kern(codes[0], codes[1], p->left().adx);
- }
- success++;
- }
- }
-
- delete[] single_changed;
- for (int i = 0; i < pair_changed.size(); i++)
- delete[] pair_changed[i];
- return success;
-}
-
-
-/*****************************************************************************/
-/* liveness marking, Ligature3s */
-
-String Metrics::Ligature3::unparse(const Metrics& m) const {
- StringAccum sa;
- sa << '[' << m.code_name(in1) << ' ' << m.code_name(in2)
- << " -> " << m.code_name(out) << ']';
- return sa.take_string();
-}
-
-inline bool
-operator<(const Metrics::Ligature3 &l1, const Metrics::Ligature3 &l2)
-{
- // topological < : is l1's output one of l2's inputs?
- if (l1.out == l2.in1 || l1.out == l2.in2)
- return true;
- else
- return l1.in1 < l2.in1
- || (l1.in1 == l2.in1 && (l1.in2 < l2.in2
- || (l1.in2 == l2.in2 && l1.out < l2.out)));
-}
-
-void
-Metrics::all_ligatures(Vector<Ligature3> &all_ligs) const
-{
- /* Develop a topologically-sorted ligature list. */
- all_ligs.clear();
- for (Code code = 0; code < _encoding.size(); code++)
- for (const Ligature *l = _encoding[code].ligatures.begin(); l != _encoding[code].ligatures.end(); l++)
- all_ligs.push_back(Ligature3(code, l->in2, l->out));
- std::sort(all_ligs.begin(), all_ligs.end());
-}
-
-void
-Metrics::mark_liveness(int size, const Vector<Ligature3> *all_ligs)
-{
- _liveness_marked = true;
- bool changed;
-
- // make sure we have ligatures
- Vector<Ligature3> my_ligs;
- if (!all_ligs) {
- all_ligatures(my_ligs);
- all_ligs = &my_ligs;
- }
-
- /* Characters below 'size' are in both virtual and base encodings. */
- for (Char *ch = _encoding.begin(); ch < _encoding.begin() + size; ch++)
- if (ch->visible())
- ch->flags |= Char::LIVE | (ch->virtual_char ? 0 : Char::BASE_LIVE);
-
- /* Characters reachable from live chars by live ligatures are live. */
- redo_live_reachable:
- for (const Ligature3 *l = all_ligs->begin(); l != all_ligs->end(); l++)
- if (_encoding[l->in1].flag(Char::LIVE) && _encoding[l->in2].flag(Char::LIVE)) {
- Char &ch = _encoding[l->out];
- if (!ch.flag(Char::LIVE))
- ch.flags |= Char::LIVE | Char::CONTEXT_ONLY | (ch.virtual_char ? 0 : Char::BASE_LIVE);
- if (ch.flag(Char::CONTEXT_ONLY) && !ch.context_setting(l->in1, l->in2))
- ch.flags &= ~Char::CONTEXT_ONLY;
- }
-
- /* Characters reachable from context-only ligatures are live. */
- changed = false;
- for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
- if (ch->flag(Char::CONTEXT_ONLY)) {
- Char &ch1 = _encoding[ch->built_in1];
- Char &ch2 = _encoding[ch->built_in2];
- if (!ch1.flag(Char::LIVE) || !ch2.flag(Char::LIVE)) {
- ch1.flags |= Char::LIVE;
- ch2.flags |= Char::LIVE;
- changed = true;
- }
- }
- if (changed)
- goto redo_live_reachable;
-
- /* Characters reachable from live settings are base-live. */
- for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
- if (ch->flag(Char::LIVE))
- if (VirtualChar *vc = ch->virtual_char) {
- int font_number = 0;
- for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
- if (s->op == Setting::SHOW && font_number == 0
- && _encoding[s->x].base_code >= 0)
- _encoding[s->x].flags |= Char::BASE_LIVE;
- else if (s->op == Setting::FONT)
- font_number = s->x;
- }
-}
-
-void
-Metrics::reencode(const Vector<Code> &reencoding)
-{
- for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++) {
- for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++) {
- l->in2 = reencoding[l->in2];
- l->out = reencoding[l->out];
- }
- for (Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
- k->in2 = reencoding[k->in2];
- if (VirtualChar *vc = ch->virtual_char) {
- int font_number = 0;
- for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
- if (s->op == Setting::SHOW && font_number == 0)
- s->x = reencoding[s->x];
- else if (s->op == Setting::FONT)
- font_number = s->x;
- }
- if (ch->built_in1 >= 0) {
- ch->built_in1 = reencoding[ch->built_in1];
- ch->built_in2 = reencoding[ch->built_in2];
- }
- if (ch->base_code >= 0)
- ch->base_code = reencoding[ch->base_code];
- }
- _emap.clear();
-}
-
-
-/*****************************************************************************/
-/* shrinking the encoding */
-
-bool
-Metrics::Char::context_setting(Code in1, Code in2) const
-{
- // return true iff this character could represent the context setting of
- // 'in1' and 'in2'
- if (!virtual_char || ligatures.size())
- return false;
- else
- return (in1 == built_in1 || in2 == built_in2);
-}
-
-void
-Metrics::cut_encoding(int size)
-{
- /* Function makes it so that characters below 'size' do not point to
- characters above 'size', except for context ligatures. */
-
- /* Change "emptyslot"s to ".notdef"s. */
- for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
- if (ch->glyph == emptyslot_glyph()) {
- ch->glyph = 0;
- ch->base_code = -1;
- // 21.Feb.2007: Character isn't live any more.
- ch->flags &= ~(Char::BASE_LIVE | Char::LIVE);
- }
-
- /* Maybe we don't need to do anything else. */
- if (_encoding.size() <= size) {
- _encoding.resize(size, Char());
- return;
- }
-
- /* Need liveness markings. */
- if (!_liveness_marked)
- mark_liveness(size);
-
- /* Characters below 'size' are 'good'.
- Characters above 'size' are not 'good'. */
- Vector<int> good(_encoding.size(), 1);
- for (Code c = size; c < _encoding.size(); c++)
- good[c] = 0;
-
- /* Characters encoded via base_code are 'good', though. */
- for (Char *ch = _encoding.begin(); ch < _encoding.begin() + size; ch++)
- if (ch->base_code >= size)
- good[ch->base_code] = 1;
-
- /* Some fake characters might point beyond 'size'; remove them too. No
- need for a multipass algorithm since virtual chars never point to
- virtual chars. */
- for (Code c = 0; c < _encoding.size(); c++) {
- if (VirtualChar *vc = _encoding[c].virtual_char) {
- int font_number = 0;
- for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
- if (s->op == Setting::SHOW && font_number == 0 && !good[s->x]) {
- _encoding[c].clear();
- goto bad_virtual_char;
- } else if (s->op == Setting::FONT)
- font_number = s->x;
- }
- if (c < size)
- good[c] = 1;
- bad_virtual_char: ;
- }
-
- /* Certainly none of the later ligatures or kerns will be meaningful. */
- for (Code c = size; c < _encoding.size(); c++) {
- _encoding[c].ligatures.clear();
- _encoding[c].kerns.clear();
- }
-
- /* Remove ligatures and kerns that point beyond 'size', except for valid
- context ligatures. Also remove ligatures that have non-live
- components. */
- /* 30.May.2005 -- Kerns might point involve a too-high character; kill
- them. */
- for (Code c = 0; c < size; c++) {
- Char &ch = _encoding[c];
- for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
- if (!good[l->in2] || l->in2 >= size
- || (!good[l->out] && !_encoding[l->out].context_setting(c, l->in2))) {
- *l = ch.ligatures.back();
- ch.ligatures.pop_back();
- l--;
- }
- for (Kern *k = ch.kerns.begin(); k != ch.kerns.end(); k++)
- if (!good[k->in2] || k->in2 >= size) {
- *k = ch.kerns.back();
- ch.kerns.pop_back();
- k--;
- }
- }
-
- /* We are done! */
-}
-
-namespace {
-// preference-sorting extra characters
-enum {
- CONVENTIONAL_F_LIGATURE_SCORE = 4,
- CONVENTIONAL_F_F_LIGATURE_SCORE = 5,
- BASIC_LATIN_LOWER_SCORE = 3,
- BASIC_LATIN_UPPER_SCORE = 4,
- BASIC_LATIN_OTHER_SCORE = 5,
- LATIN1_SUPPLEMENT_SCORE = 6,
- LOW_16_SCORE = 7,
- OTHER_SCORE = 8,
- NOCHAR_SCORE = 100000,
- CONTEXT_PENALTY = 4
-};
-
-static int
-unicode_score(uint32_t u)
-{
- if (u == 0)
- return NOCHAR_SCORE;
- else if (u >= 'a' && u <= 'z')
- return BASIC_LATIN_LOWER_SCORE;
- else if (u >= 'A' && u <= 'Z')
- return BASIC_LATIN_UPPER_SCORE;
- else if (u < 0x0080)
- return BASIC_LATIN_OTHER_SCORE;
- else if (u < 0x0100)
- return LATIN1_SUPPLEMENT_SCORE;
- else if (u < 0x8000)
- return LOW_16_SCORE;
- else
- return OTHER_SCORE;
-}
-
-struct Slot {
- Metrics::Code old_code;
- Metrics::Code new_code;
- Metrics::Glyph glyph;
- int score;
- int lookup_source;
-};
-
-inline bool
-operator<(const Slot &a, const Slot &b)
-{
- // note: will give real glyphs priority over virtual ones at a given
- // priority
- // 6.Jul.2014 -- Make sure you include an old_code comparison; this
- // is required to ensure that a ligature's inputs (which have smaller
- // old_codes) are included whenever its outputs are included.
- if (a.lookup_source != b.lookup_source)
- return a.lookup_source < b.lookup_source;
- if (a.score != b.score)
- return a.score < b.score;
- if (a.glyph != b.glyph)
- return a.glyph < b.glyph;
- return a.old_code < b.old_code;
-}
-}
-
-void
-Metrics::shrink_encoding(int size, const DvipsEncoding &dvipsenc, ErrorHandler *errh)
-{
- /* Move characters around. */
-
- /* Maybe we don't need to do anything. */
- if (_encoding.size() <= size) {
- cut_encoding(size);
- return;
- }
-
- /* Need a list of all ligatures.. */
- Vector<Ligature3> all_ligs;
- all_ligatures(all_ligs);
-
- /* Need liveness markings. */
- if (!_liveness_marked)
- mark_liveness(size, &all_ligs);
-
- /* Score characters by importance. Importance relates first to Unicode
- values, and then recursively to the importances of characters that form
- a ligature. */
-
- /* Create an initial set of scores, based on Unicode values. */
- Vector<int> scores(_encoding.size(), NOCHAR_SCORE);
- for (int i = 0; i < _encoding.size(); i++)
- if (_encoding[i].unicode)
- scores[i] = unicode_score(_encoding[i].unicode);
-
- /* Prefer conventional f-ligatures. */
- bool has_ff = false;
- for (Ligature3* l = all_ligs.begin(); l != all_ligs.end(); ++l)
- if (_encoding[l->in1].unicode == 'f'
- && (_encoding[l->in2].unicode == 'f'
- || _encoding[l->in2].unicode == 'i'
- || _encoding[l->in2].unicode == 'l')) {
- if (scores[l->out] > CONVENTIONAL_F_LIGATURE_SCORE)
- scores[l->out] = CONVENTIONAL_F_LIGATURE_SCORE;
- if (_encoding[l->in2].unicode == 'f') {
- _encoding[l->out].flags |= Char::IS_FF;
- has_ff = true;
- }
- }
- if (has_ff)
- for (Ligature3* l = all_ligs.begin(); l != all_ligs.end(); ++l)
- if (_encoding[l->in1].flag(Char::IS_FF)
- && (_encoding[l->in2].unicode == 'i'
- || _encoding[l->in2].unicode == 'l')
- && scores[l->out] > CONVENTIONAL_F_F_LIGATURE_SCORE)
- scores[l->out] = CONVENTIONAL_F_F_LIGATURE_SCORE;
-
- /* Repeat these steps until you reach a stable set of scores: Score
- ligatures (ligscore = SUM[char scores]), then score characters touched
- only by fakes. */
- bool changed = true;
- while (changed) {
- changed = false;
- for (Ligature3 *l = all_ligs.begin(); l != all_ligs.end(); l++) {
- int score = scores[l->in1] + scores[l->in2];
- if (scores[l->out] > score)
- scores[l->out] = score, changed = true;
- }
-
- for (Code c = 0; c < _encoding.size(); c++)
- if (VirtualChar *vc = _encoding[c].virtual_char) {
- /* Make sure that if this virtual character appears, its parts
- will also appear, by scoring the parts less */
- int score = scores[c] - 1, font_number = 0;
- for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
- if (s->op == Setting::SHOW && font_number == 0
- && score < scores[s->x])
- scores[s->x] = score, changed = true;
- else if (s->op == Setting::FONT)
- font_number = s->x;
- }
- }
-
- /* Rescore intermediates to not be better off than their endpoints. */
- /* XXX multiple layers of intermediate? */
- for (Code c = 0; c < _encoding.size(); c++) {
- Char &ch = _encoding[c];
- if (ch.flag(Char::INTERMEDIATE))
- for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
- if (scores[c] < scores[l->out] && !_encoding[l->out].context_setting(c, l->in2))
- scores[c] = scores[l->out];
- }
-
- /* Collect characters that want to be reassigned. */
- Vector<Slot> slots;
- for (Code c = size; c < _encoding.size(); c++)
- if (scores[c] < NOCHAR_SCORE
- && !(_encoding[c].flags & Char::CONTEXT_ONLY)
- && (_encoding[c].flags & (Char::LIVE | Char::BASE_LIVE))) {
- Slot slot = { c, -1, _encoding[c].glyph, scores[c], _encoding[c].lookup_source };
- slots.push_back(slot);
- }
- // Sort them by score, then by glyph.
- std::sort(slots.begin(), slots.end());
-
- /* Prefer their old slots, if available. */
- for (Slot *slot = slots.begin(); slot < slots.end(); slot++)
- if (PermString g = code_name(slot->old_code)) {
- int c = dvipsenc.encoding_of(g);
- if (c >= 0 && _encoding[c].glyph == 0) {
- _encoding[c].swap(_encoding[slot->old_code]);
- slot->new_code = c;
- }
- }
-
- /* List empty slots in two phases: Those not encoded by the input
- encoding, then those encoded by the input encoding (but that character
- wasn't available). */
- Vector<Code> empty_codes;
- for (int want_encoded = 0; want_encoded < 2; want_encoded++)
- for (Code c = 0; c < size; c++)
- if (_encoding[c].base_code < 0
- && dvipsenc.encoded(c) == (bool) want_encoded)
- empty_codes.push_back(c);
-
- /* Then, assign codes to the unencoded characters. */
- int nunencoded = 0;
-
- for (Slot *slot = slots.begin(); slot != slots.end(); slot++) {
- if (slot->new_code >= 0)
- continue;
-
- int needs = (_encoding[slot->old_code].visible_base() ? 1 : 0)
- + (_encoding[slot->old_code].flag(Char::LIVE) ? 2 : 0);
- assert(needs > 0);
-
- Code dest = -1;
- for (Code *h = empty_codes.begin(); h < empty_codes.end() && dest < 0; h++) {
- int haves = (_encoding[*h].base_code < 0 ? 1 : 0)
- + (!_encoding[*h].visible() ? 2 : 0);
- if ((needs & haves) == needs)
- dest = *h;
- }
-
- if (dest >= 0) {
- if (needs & 2) {
- assert(!_encoding[dest].visible());
- _encoding[dest].swap(_encoding[slot->old_code]);
- slot->new_code = dest;
- } else {
- _encoding[slot->old_code].base_code = dest;
- slot->new_code = slot->old_code;
- }
- if (needs & 1) {
- assert(_encoding[dest].base_code < 0 || _encoding[dest].base_code == slot->old_code);
- _encoding[dest].base_code = slot->old_code;
- }
- } else
- nunencoded++;
- }
-
- /* Complain if some characters can't fit. */
- if (nunencoded) {
- // collect names of unencoded glyphs
- Vector<String> unencoded;
- for (Slot *slot = slots.begin(); slot != slots.end(); slot++)
- if (slot->new_code < 0)
- unencoded.push_back(code_name(slot->old_code));
- std::sort(unencoded.begin(), unencoded.end());
- StringAccum sa;
- for (const String* a = unencoded.begin(); a < unencoded.end(); a++)
- sa << *a << ' ';
- sa.pop_back();
- sa.append_break_lines(sa.take_string(), 68, " ");
- sa.pop_back();
- errh->lwarning(" ", (unencoded.size() == 1 ? "not enough room in encoding, ignoring %d glyph" : "not enough room in encoding, ignoring %d glyphs"), unencoded.size());
- errh->lmessage(" ", "(\
-The font uses more glyphs than the encoding has available slots,\n\
-so these glyphs have been left out:\n%s\n\
-To select specific glyphs, add them to the input encoding.)", sa.c_str());
- }
-
- /* Reencode changed slots. */
- Vector<Code> reencoding;
- for (Code c = 0; c < _encoding.size(); c++)
- reencoding.push_back(c);
- for (Slot *s = slots.begin(); s != slots.end(); s++)
- if (s->new_code >= 0)
- reencoding[s->old_code] = s->new_code;
- reencode(reencoding);
-
- check();
-}
-
-void
-Metrics::make_base(int size)
-{
- Vector<Code> reencoding;
- for (Code c = 0; c < size && c < _encoding.size(); c++) {
- Char &ch = _encoding[c];
- if (ch.base_code >= 0 && ch.base_code != c) {
- if (!reencoding.size())
- for (Code cc = 0; cc < _encoding.size(); cc++)
- reencoding.push_back(cc);
- reencoding[ch.base_code] = c;
- reencoding[c] = ch.base_code;
- _encoding[c].swap(_encoding[ch.base_code]);
- }
- if (ch.virtual_char) // remove it
- ch.clear();
- }
- if (reencoding.size()) {
- reencode(reencoding);
- cut_encoding(size);
- }
- check();
-}
-
-
-/*****************************************************************************/
-/* output */
-
-bool
-Metrics::need_virtual(int size) const
-{
- if (size > _encoding.size())
- size = _encoding.size();
- for (const Char *ch = _encoding.begin(); ch < _encoding.begin() + size; ch++)
- if (ch->glyph /* actually encoded */
- && (ch->pdx || ch->pdy || ch->adx || ch->virtual_char))
- return true;
- return false;
-}
-
-bool
-Metrics::need_base()
-{
- if (!_liveness_marked)
- mark_liveness(_encoding.size());
- for (const Char *ch = _encoding.begin(); ch < _encoding.end(); ch++)
- if ((ch->flags & Char::BASE_LIVE) && ch->glyph != _boundary_glyph)
- return true;
- return false;
-}
-
-bool
-Metrics::setting(Code code, Vector<Setting> &v, SettingMode sm) const
-{
- extern int letterspace;
-
- if (!(sm & SET_KEEP))
- v.clear();
-
- if (!valid_code(code) || _encoding[code].glyph == 0)
- return false;
-
- const Char &ch = _encoding[code];
-
- if (const VirtualChar *vc = ch.virtual_char) {
- bool good = true;
- int font_number = 0;
-
- if (ch.pdx != 0 || ch.pdy != 0)
- v.push_back(Setting(Setting::MOVE, ch.pdx, ch.pdy));
-
- for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
- switch (s->op) {
- case Setting::MOVE:
- case Setting::RULE:
- case Setting::PUSH:
- case Setting::POP:
- case Setting::SPECIAL:
- v.push_back(*s);
- break;
- case Setting::FONT:
- v.push_back(*s);
- font_number = s->x;
- break;
- case Setting::SHOW:
- if (font_number == 0)
- good &= setting(s->x, v, (SettingMode)(sm | SET_KEEP));
- else
- v.push_back(*s);
- break;
- case Setting::KERN:
- case Setting::KERNX:
- if (sm & SET_INTERMEDIATE)
- v.push_back(*s);
- else if (font_number == 0 && s > vc->setting.begin()
- && s + 1 < vc->setting.end()
- && s[-1].op == Setting::SHOW
- && s[1].op == Setting::SHOW) {
- int k = kern(s[-1].x, s[1].x);
- if (s->op == Setting::KERNX)
- k -= letterspace;
- if (k)
- v.push_back(Setting(Setting::MOVE, k, 0));
- }
- break;
- }
-
- if (ch.pdy != 0 || ch.adx - ch.pdx != 0)
- v.push_back(Setting(Setting::MOVE, ch.adx - ch.pdx, -ch.pdy));
- return good;
-
- } else if (ch.base_code >= 0) {
- if (ch.pdx != 0 || ch.pdy != 0)
- v.push_back(Setting(Setting::MOVE, ch.pdx, ch.pdy));
-
- v.push_back(Setting(Setting::SHOW, ch.base_code, ch.glyph));
-
- if (ch.pdy != 0 || ch.adx - ch.pdx != 0)
- v.push_back(Setting(Setting::MOVE, ch.adx - ch.pdx, -ch.pdy));
- return true;
-
- } else
- return false;
-}
-
-int
-Metrics::ligatures(Code in1, Vector<Code> &in2, Vector<Code> &out, Vector<int> &context) const
-{
- in2.clear();
- out.clear();
- context.clear();
-
- const Char &in1ch = _encoding[in1];
- for (const Ligature *l = in1ch.ligatures.begin(); l != in1ch.ligatures.end(); l++) {
- in2.push_back(l->in2);
- const Char &outch = _encoding[l->out];
- if (outch.context_setting(in1, l->in2)) {
- if (in1 == outch.built_in1 && l->in2 == outch.built_in2)
- in2.pop_back();
- else if (in1 == outch.built_in1) {
- out.push_back(outch.built_in2);
- context.push_back(-1);
- } else {
- out.push_back(outch.built_in1);
- context.push_back(1);
- }
- } else {
- out.push_back(l->out);
- context.push_back(0);
- }
- }
-
- return in2.size();
-}
-
-int
-Metrics::kerns(Code in1, Vector<Code> &in2, Vector<int> &kern) const
-{
- in2.clear();
- kern.clear();
-
- const Char &in1ch = _encoding[in1];
- for (const Kern *k = in1ch.kerns.begin(); k != in1ch.kerns.end(); k++)
- if (k->kern != 0) {
- in2.push_back(k->in2);
- kern.push_back(k->kern);
- }
-
- return in2.size();
-}
-
-
-/*****************************************************************************/
-/* debugging */
-
-void
-Metrics::unparse(const Char *ch) const
-{
- Code c;
- if (ch >= _encoding.begin() && ch < _encoding.end())
- c = ch - _encoding.begin();
- else
- c = -1;
- fprintf(stderr, "%4d/%s%s%s%s%s%s\n", c, code_str(c),
- (ch->flag(Char::LIVE) ? " [L]" : ""),
- (ch->flag(Char::BASE_LIVE) ? " [B]" : ""),
- (ch->flag(Char::CONTEXT_ONLY) ? " [C]" : ""),
- (ch->flag(Char::BUILT) ? " [!]" : ""),
- (ch->base_code >= 0 ? " <BC>" : ""));
- if (ch->base_code >= 0 && ch->base_code != c)
- fprintf(stderr, "\tBASE %d/%s\n", ch->base_code, code_str(ch->base_code));
- if (const VirtualChar *vc = ch->virtual_char) {
- fprintf(stderr, "\t*");
- int curfont = 0;
- for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
- switch (s->op) {
- case Setting::FONT:
- fprintf(stderr, " {F%d}", s->x);
- curfont = s->x;
- break;
- case Setting::SHOW:
- fprintf(stderr, " %d", s->x);
- if (curfont == 0)
- fprintf(stderr, "/%s", code_str(s->x));
- break;
- case Setting::KERN:
- fprintf(stderr, " <>");
- break;
- case Setting::MOVE:
- fprintf(stderr, " <%+d,%+d>", s->x, s->y);
- break;
- case Setting::RULE:
- fprintf(stderr, " [%d,%d]", s->x, s->y);
- break;
- case Setting::PUSH:
- fprintf(stderr, " (");
- break;
- case Setting::POP:
- fprintf(stderr, " )");
- break;
- case Setting::SPECIAL:
- fprintf(stderr, " S{%s}", s->s.c_str());
- break;
- }
- fprintf(stderr, " ((%d/%s, %d/%s))\n", ch->built_in1, code_str(ch->built_in1), ch->built_in2, code_str(ch->built_in2));
- }
- for (const Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
- fprintf(stderr, "\t[%d/%s => %d/%s]%s\n", l->in2, code_str(l->in2), l->out, code_str(l->out), (_encoding[l->out].context_setting(c, l->in2) ? " [C]" : ""));
-#if 0
- for (const Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
- fprintf(stderr, "\t{%d/%s %+d}\n", k->in2, code_str(k->in2), k->kern);
-#endif
-}
-
-void
-Metrics::unparse() const
-{
- for (const Char *ch = _encoding.begin(); ch < _encoding.end(); ch++)
- if (ch->glyph)
- unparse(ch);
-}