diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc | 850 |
1 files changed, 0 insertions, 850 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc deleted file mode 100644 index 0ee4f66e6b0..00000000000 --- a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc +++ /dev/null @@ -1,850 +0,0 @@ -// -*- related-file-name: "../include/efont/amfm.hh" -*- - -/* amfm.{cc,hh} -- Adobe Multiple-Master Font Metrics - * - * Copyright (c) 1998-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/amfm.hh> -#include <efont/afm.hh> -#include <efont/afmparse.hh> -#include <lcdf/error.hh> -#include <efont/findmet.hh> -#include <efont/t1cs.hh> -#include <lcdf/straccum.hh> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <assert.h> -#include <string.h> -namespace Efont { - -AmfmMetrics::AmfmMetrics(MetricsFinder *finder) - : _finder(finder), - _fdv(fdLast, UNKDOUBLE), - _nmasters(-1), _naxes(-1), _masters(0), _mmspace(0), - _primary_fonts(0), _sanity_afm(0), _uses(0) -{ -} - -AmfmMetrics::~AmfmMetrics() -{ - assert(_uses == 0); - for (int m = 0; m < _nmasters; m++) - if (_masters[m].afm) - _masters[m].afm->unuse(); - delete[] _masters; - delete _mmspace; - while (_primary_fonts) { - AmfmPrimaryFont *pf = _primary_fonts; - _primary_fonts = _primary_fonts->next; - delete pf; - } -} - - -bool -AmfmMetrics::sanity(ErrorHandler *errh) const -{ - if (!_mmspace) { - errh->error("AMFM sanity: no multiple master interpolation information"); - return false; - } - - bool ok = true; - for (int m = 0; m < _nmasters; m++) - if (!_masters[m].font_name - || _masters[m].weight_vector.size() != _nmasters) { - errh->error("AMFM sanity: no information for master %d", m); - ok = false; - } - - if (!_mmspace->check(errh)) - ok = false; - - return ok; -} - - -int -AmfmMetrics::primary_label_value(int ax, PermString label) const -{ - assert(ax >= 0 && ax < _naxes); - for (AmfmPrimaryFont *pf = _primary_fonts; pf; pf = pf->next) { - if (pf->labels[ax] == label) - return pf->design_vector[ax]; - } - return -1; -} - - -inline static bool -strcompat(PermString a, PermString b) -{ - return !a || !b || a == b; -} - -Metrics * -AmfmMetrics::master(int m, ErrorHandler *errh) -{ - AmfmMaster &master = _masters[m]; - - if (!master.loaded) { - master.loaded = true; - DirectoryMetricsFinder directory_finder(_directory); - _finder->add_finder(&directory_finder); - Metrics *afm = _finder->find_metrics(master.font_name); - - if (!afm) { - if (errh) - errh->error("%s: can't find AFM file for master `%s'", - _font_name.c_str(), master.font_name.c_str()); - - } else if (!strcompat(afm->font_name(), master.font_name) - || !strcompat(afm->family(), master.family) - || !strcompat(afm->full_name(), master.full_name) - || !strcompat(afm->version(), master.version)) { - if (errh) - errh->error("%s: AFM for master `%s' doesn't match AMFM", - _font_name.c_str(), master.font_name.c_str()); - - } else if (!_sanity_afm) { - master.afm = afm; - _sanity_afm = afm; - afm->use(); - - } else { - PairProgram *sanity_pairp = _sanity_afm->pair_program(); - PairProgram *pairp = afm->pair_program(); - char buf[1024]; - buf[0] = 0; - - if (afm->nglyphs() != _sanity_afm->nglyphs()) - sprintf(buf, "glyph count (%d vs. %d)", afm->nglyphs(), _sanity_afm->nglyphs()); - if (afm->nfd() != _sanity_afm->nfd()) - sprintf(buf, "fd count (%d vs. %d)", afm->nfd(), _sanity_afm->nfd()); - if (afm->nkv() != _sanity_afm->nkv()) - sprintf(buf, "kv count (%d vs. %d)", afm->nkv(), _sanity_afm->nkv()); - if (pairp->op_count() != sanity_pairp->op_count()) - sprintf(buf, "pair op count (%d vs. %d)", pairp->op_count(), sanity_pairp->op_count()); - - if (!buf[0]) { - master.afm = afm; - afm->use(); - } else if (errh) - errh->error("%s: AFM for master `%s' failed sanity checks (%s)", _font_name.c_str(), master.font_name.c_str(), buf); - } - } - - return master.afm; -} - - -AmfmPrimaryFont * -AmfmMetrics::find_primary_font(const Vector<double> &design_vector) const -{ - assert(design_vector.size() == _naxes); - for (AmfmPrimaryFont *pf = _primary_fonts; pf; pf = pf->next) { - - for (int a = 0; a < _naxes; a++) - if ((int)design_vector[a] != pf->design_vector[a]) - goto loser; - return pf; - - loser: ; - } - return 0; -} - - -Metrics * -AmfmMetrics::interpolate(const Vector<double> &design_vector, - const Vector<double> &weight_vector, - ErrorHandler *errh) -{ - assert(design_vector.size() == _naxes); - assert(weight_vector.size() == _nmasters); - - // FIXME: check masters for correspondence. - - /* 0. - * Make sure all necessary AFMs have been loaded. */ - int m; - for (m = 0; m < _nmasters; m++) - if (weight_vector[m]) - if (!master(m, errh)) - return 0; - - /* 1. - * Use the design vector to generate new FontName and FullName. */ - - AmfmPrimaryFont *pf = find_primary_font(design_vector); - // The primary font is useless to us if it doesn't have axis labels. - if (pf && !pf->labels.size()) - pf = 0; - - StringAccum font_name_sa, full_name_sa; - font_name_sa << _font_name; - full_name_sa << _full_name; - for (int a = 0; a < _naxes; a++) { - double dv = design_vector[a]; - font_name_sa << '_' << dv; - full_name_sa << (a == 0 ? '_' : ' ') << dv; - - PermString label; - if (pf) - label = pf->labels[a]; - if (!label) - label = _mmspace->axis_abbreviation(a); - if (label) - full_name_sa << ' ' << label; - } - // Multiple master fonts require an underscore AFTER the font name too - font_name_sa << '_'; - - /* 2. - * Set up the new AFM with the special constructor. */ - - // Find the first master with a non-zero component. - for (m = 0; m < _nmasters && weight_vector[m] == 0; m++) - ; - Metrics *afm = new Metrics(font_name_sa.c_str(), full_name_sa.c_str(), *_masters[m].afm); - if (MetricsXt *xt = _masters[m].afm->find_xt("AFM")) { - AfmMetricsXt *new_xt = new AfmMetricsXt((AfmMetricsXt &)*xt); - afm->add_xt(new_xt); - } - - /* 2. - * Interpolate the old AFM data into the new. */ - - afm->interpolate_dimens(*_masters[m].afm, weight_vector[m], false); - - for (m++; m < _nmasters; m++) - if (weight_vector[m]) - afm->interpolate_dimens(*_masters[m].afm, weight_vector[m], true); - - return afm; -} - - -/***** - * AmfmReader - **/ - -AmfmReader::AmfmReader(AfmParser &afmp, AmfmMetrics *amfm, ErrorHandler *errh) - : _amfm(amfm), _finder(amfm->_finder), _l(afmp), - _mmspace(amfm->_mmspace) -{ - _errh = errh ? errh : ErrorHandler::silent_handler(); -} - -AmfmMetrics * -AmfmReader::read(Slurper &slurper, MetricsFinder *finder, ErrorHandler *errh) -{ - AfmParser parser(slurper); - if (!parser.ok()) return 0; - AmfmMetrics *amfm = new AmfmMetrics(finder); - AmfmReader reader(parser, amfm, errh); - if (!reader.read()) { - delete amfm; - return 0; - } else - return amfm; -} - -AmfmMetrics * -AmfmReader::read(const Filename &fn, MetricsFinder *finder, ErrorHandler *errh) -{ - Slurper slurper(fn); - return read(slurper, finder, errh); -} - -void -AmfmReader::add_amcp_file(Slurper &slurper, AmfmMetrics *amfm, ErrorHandler *errh) -{ - AfmParser parser(slurper); - if (!parser.ok()) return; - AmfmReader reader(parser, amfm, errh); - reader.read_amcp_file(); -} - - -void -AmfmReader::lwarning(const char *format, ...) const -{ - va_list val; - va_start(val, format); - _errh->xmessage(_l.landmark(), ErrorHandler::e_warning, format, val); - va_end(val); -} - -void -AmfmReader::lerror(const char *format, ...) const -{ - va_list val; - va_start(val, format); - _errh->xmessage(_l.landmark(), ErrorHandler::e_error, format, val); - va_end(val); -} - -void -AmfmReader::no_match_warning(const char *context) const -{ - // keyword() will fail (and a warning won't get printed) only if the string - // is all whitespace, which the spec allows - PermString keyword = _l.keyword(); - if (!keyword) return; - if (_l.key_matched()) { - lwarning(context ? "bad `%s' command in %s:" - : "bad `%s' command:", keyword.c_str(), context); - lwarning("field %d %s", _l.fail_field(), _l.message().c_str()); - } else - lwarning(context ? "unknown command `%s' in %s" - : "unknown command `%s'", keyword.c_str(), context); - _l.clear_message(); -} - - -void -AmfmReader::check_mmspace() -{ - if (!_mmspace && _amfm->_naxes >= 0 && _amfm->_nmasters >= 0 - && _amfm->_font_name) { - _mmspace = _amfm->_mmspace = - new MultipleMasterSpace(_amfm->_font_name, _amfm->_naxes, _amfm->_nmasters); - } -} - - -bool -AmfmReader::read() -{ - assert(_amfm != 0); - _mmspace = _amfm->_mmspace; - - AfmParser &l = _l; - _amfm->_directory = l.filename().directory(); - - // First, read all opening comments into an array so we can print them out - // later. - PermString comment; - while (l.next_line()) { - if (l.isall("Comment %+s", &comment)) - _amfm->_opening_comments.push_back(comment); - else if (l.isall("StartMasterFontMetrics %g", (double *)0)) - ; - else { - l.save_line(); - break; - } - } - - int master = 0, axis = 0; - - while (l.next_line()) - switch (l[0]) { - - case 'A': - if (l.isall("Ascender %g", &fd( fdAscender ))) - break; - if (l.isall("Axes %d", &_amfm->_naxes)) { - check_mmspace(); - break; - } - goto invalid; - - case 'B': - if (l.is("BlendDesignPositions")) { - read_positions(); - break; - } - if (l.is("BlendDesignMap")) { - read_normalize(); - break; - } - if (l.is("BlendAxisTypes")) { - read_axis_types(); - break; - } - goto invalid; - - case 'C': - if (l.isall("CapHeight %g", &fd( fdCapHeight ))) - break; - if (l.is("Comment")) - break; - goto invalid; - - case 'D': - if (l.isall("Descender %g", &fd( fdDescender ))) - break; - goto invalid; - - case 'E': - if (l.isall("EncodingScheme %+s", &_amfm->_encoding_scheme)) - break; - if (l.isall("EndMasterFontMetrics")) - goto done; - goto invalid; - - case 'F': - if (l.isall("FontName %+s", &_amfm->_font_name)) { - check_mmspace(); - break; - } - if (l.isall("FullName %+s", &_amfm->_full_name)) - break; - if (l.isall("FamilyName %+s", &_amfm->_family)) - break; - if (l.isall("FontBBox %g %g %g %g", - &fd( fdFontBBllx ), &fd( fdFontBBlly ), - &fd( fdFontBBurx ), &fd( fdFontBBury ))) - break; - goto invalid; - - case 'I': - if (l.isall("IsFixedPitch %b", (bool *)0)) - break; - if (l.isall("ItalicAngle %g", &fd( fdItalicAngle ))) - break; - goto invalid; - - case 'M': - if (l.isall("Masters %d", &_amfm->_nmasters)) { - check_mmspace(); - break; - } - goto invalid; - - case 'N': - if (l.isall("Notice %+s", &_amfm->_notice)) - break; - goto invalid; - - case 'S': - if (l.isall("StartAxis")) { - read_axis(axis++); - break; - } - if (l.isall("StartMaster")) { - read_master(master++); - break; - } - if (l.isall("StartPrimaryFonts %d", (int *)0)) { - read_primary_fonts(); - break; - } - if (l.isall("StartConversionPrograms %d %d", (int *)0, (int *)0)) { - read_conversion_programs(); - break; - } - if (l.isall("StartMasterFontMetrics %g", (double *)0)) - break; - goto invalid; - - case 'U': - if (l.isall("UnderlinePosition %g", &fd( fdUnderlinePosition ))) - break; - else if (l.isall("UnderlineThickness %g", &fd( fdUnderlineThickness ))) - break; - goto invalid; - - case 'V': - if (l.isall("Version %+s", &_amfm->_version)) - break; - goto invalid; - - case 'W': - if (l.isall("Weight %+s", &_amfm->_weight)) - break; - if (l.is("WeightVector")) { - Vector<double> wv; - if (!read_simple_array(wv) || !_mmspace) - lerror("bad WeightVector"); - else - _mmspace->set_weight_vector(wv); - break; - } - goto invalid; - - case 'X': - if (l.isall("XHeight %g", &fd( fdXHeight ))) - break; - goto invalid; - - default: - invalid: - no_match_warning(); - - } - - done: - if (!_mmspace) { - _errh->error("`%s' is not an AMFM file", String(_l.landmark().file()).c_str()); - return false; - } - - LandmarkErrorHandler pin_errh(_errh, _l.landmark()); - if (!_amfm->sanity(&pin_errh)) { - _errh->lerror(_l.landmark().whole_file(), - "bad AMFM file (missing or inconsistent information)"); - return false; - } - - if (!_mmspace->check_intermediate() && _l.filename().directory()) { - String name = l.filename().base() + ".amcp"; - Slurper slurp(_l.filename().from_directory(name)); - add_amcp_file(slurp, _amfm, _errh); - } - - return true; -} - - -void -AmfmReader::read_amcp_file() -{ - int lines_read = 0; - - while (_l.next_line()) { - lines_read++; - switch (_l[0]) { - - case 'C': - if (_l.is("Comment")) - break; - goto invalid; - - case 'S': - if (_l.isall("StartConversionPrograms %d %d", (int *)0, (int *)0)) { - read_conversion_programs(); - break; - } - goto invalid; - - default: - invalid: - no_match_warning("AMCP file"); - - } - } - - if (_mmspace && !_mmspace->ndv() && !_mmspace->cdv() && lines_read) - lwarning("no conversion programs in .amcp file"); -} - - -bool -AmfmReader::read_simple_array(Vector<double> &vec) const -{ - if (!_l.is("[")) return false; - - vec.clear(); - double d; - while (_l.is("%g", &d)) - vec.push_back(d); - - return _l.is("]"); -} - - -void -AmfmReader::read_positions() const -{ - if (nmasters() < 2 || naxes() < 1) return; - Vector<NumVector> positions; - if (!_l.is("[") || !_mmspace) goto error; - - for (int i = 0; i < nmasters(); i++) { - positions.push_back(NumVector()); - if (!read_simple_array(positions.back())) - goto error; - } - - if (!_l.is("]")) goto error; - _mmspace->set_master_positions(positions); - return; - - error: - lerror("bad BlendDesignPositions"); -} - - -void -AmfmReader::read_normalize() const -{ - if (naxes() < 1) return; - Vector<NumVector> normalize_in, normalize_out; - if (!_l.is("[") || !_mmspace) goto error; - - for (int a = 0; a < naxes(); a++) { - if (!_l.is("[")) goto error; - normalize_in.push_back(NumVector()); - normalize_out.push_back(NumVector()); - double v1, v2; - while (_l.is("[-%g %g-]", &v1, &v2)) { - normalize_in[a].push_back(v1); - normalize_out[a].push_back(v2); - } - if (!_l.is("]")) goto error; - } - - if (!_l.is("]")) goto error; - _mmspace->set_normalize(normalize_in, normalize_out); - return; - - error: - lerror("bad BlendDesignPositions"); -} - - -void -AmfmReader::read_axis_types() const -{ - PermString s; - int ax = 0; - Vector<PermString> types; - if (naxes() < 1) return; - if (!_l.is("[") || !_mmspace) goto error; - _mmspace->check(); - - while (_l.is("/%/s", &s)) - _mmspace->set_axis_type(ax++, s); - - if (!_l.is("]")) goto error; - return; - - error: - lerror("bad BlendAxisTypes"); -} - - -void -AmfmReader::read_axis(int ax) const -{ - bool ok = _mmspace && ax < naxes(); - if (!ok) - lerror("bad axis number %d", ax); - else - _mmspace->check(); - - PermString s; - while (_l.next_line()) - switch (_l[0]) { - - case 'A': - if (_l.is("AxisType %+s", &s)) { - if (ok) - _mmspace->set_axis_type(ax, s); - break; - } - if (_l.is("AxisLabel %+s", &s)) { - if (ok) - _mmspace->set_axis_label(ax, s); - break; - } - goto invalid; - - case 'C': - if (_l.is("Comment")) - break; - goto invalid; - - case 'E': - if (_l.isall("EndAxis")) - goto endaxis; - goto invalid; - - default: - invalid: - no_match_warning(); - - } - - endaxis: ; -} - - -void -AmfmReader::read_master(int m) const -{ - AmfmMaster *amfmm; - AmfmMaster dummy; - if (m >= nmasters()) { - lerror("too many masters"); - amfmm = &dummy; - } else { - if (!_amfm->_masters) - _amfm->_masters = new AmfmMaster[ nmasters() ]; - amfmm = &_amfm->_masters[m]; - } - - while (_l.next_line()) - // Grok the whole line. Are we on a character metric data line? - switch (_l[0]) { - - case 'C': - if (_l.is("Comment")) - break; - goto invalid; - - case 'E': - if (_l.isall("EndMaster")) - goto endmaster; - goto invalid; - - case 'F': - if (_l.isall("FontName %+s", &amfmm->font_name)) - break; - if (_l.isall("FullName %+s", &amfmm->full_name)) - break; - if (_l.isall("FamilyName %+s", &amfmm->family)) - break; - goto invalid; - - case 'V': - if (_l.isall("Version %+s", &amfmm->version)) - break; - goto invalid; - - case 'W': - if (_l.is("WeightVector")) { - if (!(read_simple_array(amfmm->weight_vector) && - amfmm->weight_vector.size() == nmasters())) { - lerror("bad WeightVector"); - amfmm->weight_vector.clear(); - } - break; - } - goto invalid; - - default: - invalid: - no_match_warning(); - - } - - endmaster: ; -} - - -void -AmfmReader::read_one_primary_font() const -{ - AmfmPrimaryFont *pf = new AmfmPrimaryFont; - pf->design_vector.resize(naxes()); - pf->labels.resize(naxes()); - - while (_l.left()) { - - if (_l.is("PC")) { - for (int a = 0; a < naxes(); a++) - if (!_l.is("%d", &pf->design_vector[a])) - goto error; - } else if (_l.is("PL")) { - for (int a = 0; a < naxes(); a++) - if (!_l.is("(-%/s-)", &pf->labels[a])) - goto error; - } else if (_l.is("PN %(", &pf->name)) - ; - else - no_match_warning("primary font"); - - _l.is(";"); // get rid of any possible semicolon - } - - pf->next = _amfm->_primary_fonts; - _amfm->_primary_fonts = pf; - return; - - error: - delete pf; -} - - -void -AmfmReader::read_primary_fonts() const -{ - while (_l.next_line()) - switch (_l[0]) { - - case 'C': - if (_l.is("Comment")) - break; - goto invalid; - - case 'E': - if (_l.isall("EndPrimaryFonts")) - goto end_primary_fonts; - goto invalid; - - case 'P': - if (_l[1] == 'C' && isspace(_l[2])) { - read_one_primary_font(); - break; - } - goto invalid; - - default: - invalid: - no_match_warning(); - - } - - end_primary_fonts: ; -} - - -void -AmfmReader::read_conversion_programs() const -{ - String ndv, cdv, s; - - while (_l.next_line()) - switch (_l[0]) { - - case 'C': - if (_l.isall("CDV %<", &s)) { - cdv += s; - break; - } - goto invalid; - - case 'E': - if (_l.isall("EndConversionPrograms")) - goto end_conversion_programs; - goto invalid; - - case 'N': - if (_l.isall("NDV %<", &s)) { - ndv += s; - break; - } - goto invalid; - - default: - invalid: - no_match_warning(); - break; - - } - - end_conversion_programs: - if (_mmspace) { - _mmspace->set_ndv(Type1Charstring(ndv)); - _mmspace->set_cdv(Type1Charstring(cdv)); - } -} - -} |