summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc924
1 files changed, 0 insertions, 924 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc
deleted file mode 100644
index c8a4f507f03..00000000000
--- a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc
+++ /dev/null
@@ -1,924 +0,0 @@
-/* t1rewrit.cc -- routines for multiple- to single-master charstring conversion
- *
- * Copyright (c) 1997-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 "t1rewrit.hh"
-#include <efont/t1item.hh>
-#include <efont/t1csgen.hh>
-#include <lcdf/error.hh>
-#include <lcdf/straccum.hh>
-#include <stdio.h>
-#include <math.h>
-
-using namespace Efont;
-
-static bool itc_complained = false;
-static ErrorHandler *itc_errh;
-
-void
-itc_complain()
-{
- //itc_errh->warning("strange %<callothersubr%>; is this an ITC font?");
- itc_complained = true;
-}
-
-
-/*****
- * HintReplacementDetector
- **/
-
-class HintReplacementDetector : public CharstringInterp { public:
-
- HintReplacementDetector(Type1Font *, int);
- HintReplacementDetector(Type1Font *, const Vector<double> &, int);
-
- bool is_hint_replacement(int i) const { return _hint_replacements[i] != 0; }
- int call_count(int i) const { return _call_counts[i]; }
-
- bool type1_command(int);
-
- bool run(Type1Font *, Type1Charstring &);
-
- private:
-
- Vector<int> _hint_replacements;
- Vector<int> _call_counts;
- int _subr_level;
- int _count_calls_below;
-
-};
-
-HintReplacementDetector::HintReplacementDetector(Type1Font *f, int b)
- : CharstringInterp(),
- _hint_replacements(f->nsubrs(), 0), _call_counts(f->nsubrs(), 0),
- _count_calls_below(b)
-{
-}
-
-HintReplacementDetector::HintReplacementDetector(Type1Font *f, const Vector<double> &wv, int b)
- : CharstringInterp(wv),
- _hint_replacements(f->nsubrs(), 0), _call_counts(f->nsubrs(), 0),
- _count_calls_below(b)
-{
-}
-
-bool
-HintReplacementDetector::type1_command(int cmd)
-{
- switch (cmd) {
-
- case Cs::cCallothersubr: {
- if (size() < 2)
- goto unknown;
- int command = (int)top(0);
- int n = (int)top(1);
- if (command == Cs::othcReplacehints && n == 1) {
- pop(2);
- _hint_replacements[(int)top()] = 1;
- ps_clear();
- ps_push(top());
- pop();
- break;
- } else if (command >= Cs::othcMM1 && command <= Cs::othcMM6) {
- pop(2);
- return mm_command(command, n);
- } else if (command >= Cs::othcITC_load && command <= Cs::othcITC_random) {
- pop(2);
- return itc_command(command, n);
- } else
- goto unknown;
- }
-
- case Cs::cCallsubr: {
- if (size() < 1)
- return error(errUnderflow, cmd);
- int which = (int)pop();
- if (!_count_calls_below || _subr_level < _count_calls_below)
- _call_counts[which]++;
-
- Charstring *subr_cs = get_subr(which);
- if (!subr_cs)
- return error(errSubr, which);
-
- _subr_level++;
- subr_cs->process(*this);
- _subr_level--;
-
- if (error() != errOK)
- return false;
- return !done();
- }
-
- case Cs::cEndchar:
- case Cs::cReturn:
- return CharstringInterp::type1_command(cmd);
-
- case Cs::cBlend:
- case Cs::cAbs:
- case Cs::cAdd:
- case Cs::cSub:
- case Cs::cDiv:
- case Cs::cNeg:
- case Cs::cRandom:
- case Cs::cMul:
- case Cs::cSqrt:
- case Cs::cDrop:
- case Cs::cExch:
- case Cs::cIndex:
- case Cs::cRoll:
- case Cs::cDup:
- case Cs::cAnd:
- case Cs::cOr:
- case Cs::cNot:
- case Cs::cEq:
- case Cs::cIfelse:
- return arith_command(cmd);
-
- case Cs::cPop:
- if (ps_size() >= 1)
- push(ps_pop());
- break;
-
- default:
- unknown:
- clear();
- break;
-
- }
- return true;
-}
-
-bool
-HintReplacementDetector::run(Type1Font *f, Type1Charstring &cs)
-{
- _subr_level = 0;
- CharstringInterp::interpret(f, &cs);
- return error() == errOK;
-}
-
-
-/*****
- * Type1OneMMRemover
- **/
-
-class Type1OneMMRemover: public CharstringInterp { public:
-
- Type1OneMMRemover(Type1MMRemover *);
-
- bool type1_command(int);
-
- inline bool run_fresh_subr(const Type1Charstring &, bool);
- inline bool run_fresh_glyph(const Type1Charstring &);
- inline bool rerun_subr(const Type1Charstring &);
-
- Type1Charstring *output_prefix();
- void output_main(Type1Charstring &);
-
- private:
-
- Type1MMRemover *_remover;
- Type1CharstringGen _prefix_gen;
- Type1CharstringGen _main_gen;
-
- int _subr_level;
- bool _in_subr;
- bool _in_prefix;
- bool _must_expand;
-
- inline void run_subr(Type1Charstring *);
- bool itc_command(int command, int on_stack);
-
- bool run(const Type1Charstring &, bool, bool, bool);
-
-};
-
-/* For version 1.1
- *
- * Problem: Sometimes a charstring will call one subroutine, which will call
- * another, etc., which finally does a multiple master CallOtherSubr! The
- * required arguments might build up only gradually over all the subrs. This
- * makes it hard to remove the eventual CallOtherSubr!
- *
- * Partial solution: Divide each subroutine into two parts: the initial
- * "prefix" contains the closure of any initial multiple-master commands
- * (including those from sub-subroutines), the following "main" part has all
- * the other commands. In a situation like this:
- *
- * subr-1 = 8 15 callothersubr pop pop pop return
- * subr-2 = 4 5 6 1 callsubr return
- * subr-3 = 1 2 3 2 callsubr return
- *
- * we'll divide it up like this: (prefix || main)
- *
- * subr-1 = 8 15 callothersubr pop pop pop || (nothing)
- * subr-2 = 4 5 6 8 15 callothersubr pop pop pop || (nothing)
- * subr-3 = 1 2 3 4 5 6 8 15 callothersubr pop pop pop || (nothing)
- *
- * Now, when we call a subroutine, we EXECUTE its prefix part. Then, if its
- * main part is nonempty, we output the original call to the subroutine to
- * take care of the main part. */
-
-
-Type1OneMMRemover::Type1OneMMRemover(Type1MMRemover *remover)
- : CharstringInterp(remover->weight_vector()),
- _remover(remover), _prefix_gen(remover->precision()),
- _main_gen(remover->precision())
-{
-}
-
-inline void
-Type1OneMMRemover::run_subr(Type1Charstring *cs)
-{
- _subr_level++;
- cs->process(*this);
- _subr_level--;
-}
-
-bool
-Type1OneMMRemover::itc_command(int command, int on_stack)
-{
- const Vector<double> &weight = weight_vector();
- assert(weight.size());
- Vector<double> *scratch = scratch_vector();
- Type1CharstringGen *gen =
- (_in_prefix ? &_prefix_gen : (_in_subr ? &_main_gen : 0));
-
- int base = size() - on_stack - 2;
- switch (command) {
-
- case Cs::othcITC_load: {
- if (on_stack != 1)
- return false;
- int offset = (int)at(base);
- for (int i = 0; i < weight.size(); i++)
- vec(scratch, offset+i) = weight.at_u(i);
- // save load command, so we expand its effects into the scratch
- // vector
- if (gen) {
- gen->gen_number(offset);
- gen->gen_number(1);
- gen->gen_number(Cs::othcITC_load);
- gen->gen_command(Cs::cCallothersubr);
- }
- break;
- }
-
- case Cs::othcITC_put: {
- if (on_stack != 2)
- return false;
- int offset = (int)at(base+1);
- vec(scratch, offset) = at(base);
- // save put command, so we expand its effects into the scratch
- // vector
- if (gen) {
- gen->gen_number(at(base));
- gen->gen_number(offset);
- gen->gen_number(2);
- gen->gen_number(Cs::othcITC_put);
- gen->gen_command(Cs::cCallothersubr);
- }
- break;
- }
-
- case Cs::othcITC_get: {
- if (on_stack != 1)
- return false;
- int offset = (int)at(base);
- double d = vec(scratch, offset);
- if (!KNOWN(d)) {
- _must_expand = true;
- return false;
- }
- ps_push(d);
- break;
- }
-
- case Cs::othcITC_add: {
- if (on_stack != 2)
- return false;
- ps_push(at(base) + at(base+1));
- break;
- }
-
- case Cs::othcITC_sub: {
- if (on_stack != 2)
- return false;
- ps_push(at(base) - at(base+1));
- break;
- }
-
- case Cs::othcITC_mul: {
- if (on_stack != 2)
- return false;
- ps_push(at(base) * at(base+1));
- break;
- }
-
- case Cs::othcITC_div: {
- if (on_stack != 2)
- return false;
- ps_push(at(base) / at(base+1));
- break;
- }
-
- case Cs::othcITC_ifelse: {
- if (on_stack != 4)
- return false;
- if (at(base+2) <= at(base+3))
- ps_push(at(base));
- else
- ps_push(at(base+1));
- break;
- }
-
- default:
- return false;
-
- }
-
- pop(on_stack + 2);
- return true;
-}
-
-bool
-Type1OneMMRemover::type1_command(int cmd)
-{
- switch (cmd) {
-
- case Cs::cCallothersubr: {
- // Expand known othersubr calls. If we cannot expand the othersubr
- // call completely, then write it to the expander.
- if (size() < 2)
- goto partial_othersubr;
- int command = (int)top(0);
- int n = (int)top(1);
- if (command >= Cs::othcITC_load && command <= Cs::othcITC_random) {
- if (!itc_complained)
- itc_complain();
- if (size() < 2 + n || !itc_command(command, n))
- goto partial_othersubr;
- } else if (command >= Cs::othcMM1 && command <= Cs::othcMM6) {
- if (size() < 2 + n)
- goto partial_othersubr;
- pop(2);
- mm_command(command, n);
- } else
- goto normal;
- break;
- }
-
- partial_othersubr: {
- if (!_in_prefix) {
- _must_expand = true;
- goto normal;
- }
- _prefix_gen.gen_stack(*this, 0);
- _prefix_gen.gen_command(Cs::cCallothersubr);
- break;
- }
-
- case Cs::cCallsubr: {
- // expand subroutines in line if necessary
- if (size() < 1)
- goto normal;
- int subrno = (int)pop();
- if (_subr_level < 1) { // otherwise, have already included prefix
- if (Type1Charstring *cs = _remover->subr_prefix(subrno))
- run_subr(cs);
- }
- if (Type1Charstring *cs = _remover->subr_expander(subrno))
- run_subr(cs);
- else {
- push(subrno);
- goto normal;
- }
- break;
- }
-
- case Cs::cPop:
- if (ps_size() >= 1)
- push(ps_pop());
- else if (_in_prefix && ps_size() == 0) {
- _prefix_gen.gen_stack(*this, 0);
- _prefix_gen.gen_command(Cs::cPop);
- } else
- goto normal;
- break;
-
- case Cs::cDiv:
- if (size() < 2)
- goto normal;
- top(1) /= top(0);
- pop();
- break;
-
- case Cs::cReturn:
- return false;
-
- normal:
- default:
- _main_gen.gen_stack(*this, cmd);
- _main_gen.gen_command(cmd);
- _in_prefix = 0;
- return (cmd != Cs::cEndchar);
-
- }
- return true;
-}
-
-
-bool
-Type1OneMMRemover::run(const Type1Charstring &cs,
- bool in_subr, bool do_prefix, bool fresh)
-{
- _prefix_gen.clear();
- _main_gen.clear();
- _in_subr = in_subr;
- _in_prefix = do_prefix;
- _subr_level = (fresh ? 0 : 1);
- _must_expand = false;
- Vector<double> *scratch = scratch_vector();
- scratch->assign(scratch->size(), UNKDOUBLE);
-
- CharstringInterp::interpret(_remover->program(), &cs);
-
- if (in_subr) {
- _main_gen.gen_stack(*this, Cs::cReturn);
- _main_gen.gen_command(Cs::cReturn);
- }
- if (_must_expand)
- return true;
- if (fresh && in_subr) {
- if (_main_gen.length() == 0
- || (_main_gen.length() == 1 && _main_gen.data()[0] == Cs::cReturn))
- return true;
- }
- return false;
-}
-
-inline bool
-Type1OneMMRemover::run_fresh_subr(const Type1Charstring &cs, bool do_prefix)
-{
- return run(cs, true, do_prefix, true);
-}
-
-inline bool
-Type1OneMMRemover::run_fresh_glyph(const Type1Charstring &cs)
-{
- return run(cs, false, false, true);
-}
-
-inline bool
-Type1OneMMRemover::rerun_subr(const Type1Charstring &cs)
-{
- return run(cs, true, false, false);
-}
-
-Type1Charstring *
-Type1OneMMRemover::output_prefix()
-{
- if (_prefix_gen.length() > 0) {
- _prefix_gen.gen_command(Cs::cReturn);
- return _prefix_gen.output();
- } else
- return 0;
-}
-
-void
-Type1OneMMRemover::output_main(Type1Charstring &cs)
-{
- _main_gen.output(cs);
-}
-
-
-/*****
- * Type1BadCallRemover
- **/
-
-class Type1BadCallRemover: public CharstringInterp { public:
-
- Type1BadCallRemover(Type1MMRemover *);
-
- bool type1_command(int);
-
- bool run(Type1Charstring &, bool is_subr);
-
- private:
-
- Type1CharstringGen _gen;
- Type1MMRemover *_remover;
- bool _is_subr;
-
-};
-
-Type1BadCallRemover::Type1BadCallRemover(Type1MMRemover *remover)
- : CharstringInterp(remover->weight_vector()),
- _gen(remover->precision()), _remover(remover)
-{
-}
-
-bool
-Type1BadCallRemover::type1_command(int cmd)
-{
- switch (cmd) {
-
- case Cs::cCallsubr: {
- if (size() < 1)
- goto normal;
- int subrno = (int)top();
- if (!get_subr(subrno)) {
- pop();
- return false;
- } else
- goto normal;
- }
-
- normal:
- default:
- _gen.gen_stack(*this, 0);
- _gen.gen_command(cmd);
- return (cmd != Cs::cEndchar || _is_subr) && cmd != Cs::cReturn;
-
- }
-}
-
-bool
-Type1BadCallRemover::run(Type1Charstring &cs, bool is_subr)
-{
- _is_subr = is_subr;
- _gen.clear();
- CharstringInterp::interpret(_remover->program(), &cs);
- _gen.output(cs);
- return error() == errOK;
-}
-
-
-/*****
- * Type1MMRemover
- **/
-
-Type1MMRemover::Type1MMRemover(Type1Font *font, const Vector<double> &wv,
- int precision, ErrorHandler *errh)
- : _font(font), _weight_vector(wv), _precision(precision),
- _nsubrs(font->nsubrs()),
- _subr_done(_nsubrs, 0),
- _subr_prefix(_nsubrs, (Type1Charstring *)0),
- _must_expand_subr(_nsubrs, 0),
- _hint_replacement_subr(_nsubrs, 0),
- _expand_all_subrs(false), _errh(errh)
-{
- itc_errh = _errh;
-
- // find subroutines needed for hint replacement
- HintReplacementDetector hr(font, wv, 0);
- for (int i = 0; i < _font->nglyphs(); i++)
- if (Type1Subr *g = _font->glyph_x(i))
- hr.run(font, g->t1cs());
- for (int i = 0; i < _nsubrs; i++)
- if (hr.is_hint_replacement(i))
- _hint_replacement_subr[i] = 1;
-
- // don't get rid of first 4 subrs
- for (int i = 0; i < _nsubrs && i < 4; i++)
- _subr_done[i] = 1;
-}
-
-Type1MMRemover::~Type1MMRemover()
-{
- for (int i = 0; i < _nsubrs; i++)
- if (_subr_prefix[i])
- delete _subr_prefix[i];
-}
-
-
-Type1Charstring *
-Type1MMRemover::subr_prefix(int subrno)
-{
- if (subrno < 0 || subrno >= _nsubrs)
- return 0;
-
- if (!_subr_done[subrno]) {
- _subr_done[subrno] = 1;
-
- Type1Charstring *subr = _font->subr(subrno);
- if (!subr)
- return 0;
-
- Type1OneMMRemover one(this);
- if (one.run_fresh_subr(*subr, !_hint_replacement_subr[subrno]))
- _must_expand_subr[subrno] = true;
- _subr_prefix[subrno] = one.output_prefix();
- one.output_main(*subr);
- }
-
- return _subr_prefix[subrno];
-}
-
-Type1Charstring *
-Type1MMRemover::subr_expander(int subrno)
-{
- if (subrno < 0 || subrno >= _nsubrs)
- return 0;
- if (!_subr_done[subrno])
- (void)subr_prefix(subrno);
- if (!_expand_all_subrs && !_must_expand_subr[subrno])
- return 0;
- return _font->subr(subrno);
-}
-
-extern "C" {
-static int CDECL
-sort_permstring_compare(const void *v1, const void *v2)
-{
- const PermString *s1 = (const PermString *)v1;
- const PermString *s2 = (const PermString *)v2;
- return strcmp(s1->c_str(), s2->c_str());
-}
-}
-
-void
-Type1MMRemover::run()
-{
- Type1OneMMRemover one(this);
-
- // check subroutines
- for (int subrno = 0; subrno < _nsubrs; subrno++)
- (void)subr_prefix(subrno);
-
- // expand glyphs
- Vector<PermString> bad_glyphs;
- for (int i = 0; i < _font->nglyphs(); i++) {
- Type1Subr *g = _font->glyph_x(i);
- if (g) {
- if (one.run_fresh_glyph(g->t1cs())) {
- // Every glyph should be fully expandable without encountering
- // a MM command. If we fail the first time, try again,
- // expanding ALL subroutines. This catches, for example, SUBR
- // 1 { 1 0 return }; GLYPH g { 1 callsubr 2 blend }; This will
- // fail the first time, because `1 callsubr' will be left as a
- // subroutine call, so `1 0' (required arguments to `blend')
- // won't be visible.
- _expand_all_subrs = true;
- if (one.run_fresh_glyph(g->t1cs()))
- bad_glyphs.push_back(g->name());
- _expand_all_subrs = false;
- }
- one.output_main(g->t1cs());
- }
- }
-
- // remove uncalled subroutines, expand hint replacement subroutines
- HintReplacementDetector hr(_font, _weight_vector, 0);
- for (int i = 0; i < _font->nglyphs(); i++)
- if (Type1Subr *g = _font->glyph_x(i))
- hr.run(_font, g->t1cs());
- // don't remove first four subroutines!
- for (int subrno = 4; subrno < _nsubrs; subrno++)
- if (hr.call_count(subrno) || _hint_replacement_subr[subrno]) {
- Type1Charstring *cs = _font->subr(subrno);
- if (one.rerun_subr(*cs)) {
- _expand_all_subrs = true;
- if (one.rerun_subr(*cs))
- bad_glyphs.push_back(permprintf("subr %d", subrno));
- _expand_all_subrs = false;
- }
- one.output_main(*cs);
- } else
- _font->remove_subr(subrno);
-
- // remove calls to removed subroutines
- Type1BadCallRemover bcr(this);
- for (int i = 0; i < _font->nglyphs(); i++)
- if (Type1Subr *g = _font->glyph_x(i))
- bcr.run(g->t1cs(), false);
- for (int subrno = 4; subrno < _nsubrs; subrno++)
- if (Type1Charstring *cs = _font->subr(subrno))
- bcr.run(*cs, true);
-
- // report warnings
- if (bad_glyphs.size()) {
- qsort(&bad_glyphs[0], bad_glyphs.size(), sizeof(PermString), sort_permstring_compare);
- _errh->error("could not fully interpolate the following glyphs:");
- StringAccum sa;
- for (int i = 0; i < bad_glyphs.size(); i++) {
- PermString n = bad_glyphs[i];
- bool comma = (i < bad_glyphs.size() - 1);
- if (sa.length() && sa.length() + 1 + n.length() + comma > 70) {
- _errh->message(" %s", sa.c_str());
- sa.clear();
- }
- sa << (sa.length() ? " " : "") << n << (comma ? "," : "");
- }
- _errh->message(" %s", sa.c_str());
- }
-}
-
-
-/*****
- * SubrExpander
- **/
-
-class SubrExpander : public CharstringInterp { public:
-
- SubrExpander();
-
- void set_renumbering(const Vector<int> *v) { _renumbering = v; }
-
- bool type1_command(int);
-
- bool run(Type1Font *, Type1Charstring &);
-
- private:
-
- Type1CharstringGen _gen;
- const Vector<int> *_renumbering;
- int _subr_level;
-
-};
-
-SubrExpander::SubrExpander()
- : CharstringInterp(), _gen(0), _renumbering(0)
-{
-}
-
-bool
-SubrExpander::type1_command(int cmd)
-{
- switch (cmd) {
-
- case Cs::cCallsubr: {
- if (size() < 1)
- goto unknown;
- int subrno = (int)top(0);
- int renumber_subrno = (subrno >= 0 && subrno < _renumbering->size() ? (*_renumbering)[subrno] : subrno);
- if (renumber_subrno >= 0) {
- top(0) = renumber_subrno;
- goto unknown;
- }
- pop();
- if (Charstring *subr_cs = get_subr(subrno)) {
- _subr_level++;
- subr_cs->process(*this);
- _subr_level--;
- }
- return !done();
- }
-
- case Cs::cEndchar:
- set_done();
- goto end_cs;
-
- case Cs::cReturn:
- if (_subr_level)
- return false;
- goto end_cs;
-
- end_cs:
- _gen.gen_stack(*this, cmd);
- _gen.gen_command(cmd);
- return false;
-
- default:
- unknown:
- _gen.gen_stack(*this, cmd);
- _gen.gen_command(cmd);
- break;
-
- }
- return true;
-}
-
-bool
-SubrExpander::run(Type1Font *font, Type1Charstring &cs)
-{
- _gen.clear();
- _subr_level = 0;
- CharstringInterp::interpret(font, &cs);
- _gen.output(cs);
- return error() == errOK;
-}
-
-
-/*****
- * Type1SubrRemover
- **/
-
-Type1SubrRemover::Type1SubrRemover(Type1Font *font, ErrorHandler *errh)
- : _font(font), _nsubrs(font->nsubrs()),
- _renumbering(_nsubrs, REMOVABLE), _cost(_nsubrs, 0),
- _save_count(0), _nonexist_count(0), _errh(errh)
-{
- // find subroutines needed for hint replacement
- HintReplacementDetector hr(font, 2);
- for (int i = 0; i < _font->nglyphs(); i++) {
- Type1Subr *g = _font->glyph_x(i);
- if (g)
- hr.run(_font, g->t1cs());
- }
-
- // save necessary subroutines
- for (int i = 0; i < 4; i++) {
- _renumbering[i] = i;
- _save_count++;
- }
- // save hint-replacement subroutines
- for (int i = 0; i < _nsubrs; i++) {
- Type1Subr *cs = _font->subr_x(i);
- if (!cs) {
- _renumbering[i] = DEAD;
- _nonexist_count++;
- } else if (hr.is_hint_replacement(i)) {
- _renumbering[i] = i;
- _save_count++;
- } else
- _cost[i] = hr.call_count(i) * (cs->t1cs().length() - (i <= 107 ? 2 : 3));
- }
-}
-
-Type1SubrRemover::~Type1SubrRemover()
-{
-}
-
-static Vector<int> *sort_keys;
-
-extern "C" {
-static int CDECL
-sort_permute_compare(const void *v1, const void *v2)
-{
- const int *i1 = (const int *)v1;
- const int *i2 = (const int *)v2;
- return (*sort_keys)[*i1] - (*sort_keys)[*i2];
-}
-}
-
-bool
-Type1SubrRemover::run(int lower_to)
-{
- if (lower_to < 0)
- lower_to = _nsubrs;
- if (lower_to < _save_count) {
- _errh->warning("reducing %s to minimum number of subroutines (%d)",
- _font->font_name().c_str(), _save_count - _nonexist_count);
- lower_to = _save_count;
- }
- int to_remove = _nsubrs - _nonexist_count - lower_to;
- if (to_remove < 0)
- to_remove = 0;
-
- // multiply by lost bytes per call
- Vector<int> permute;
- for (int i = 0; i < _nsubrs; i++)
- permute.push_back(i);
-
- // sort them by least frequent use -> most frequent use
- sort_keys = &_cost;
- qsort(&permute[0], _nsubrs, sizeof(int), sort_permute_compare);
-
- // mark first portion of `permute' to be removed
- int removed = 0;
- for (int i = 0; i < _nsubrs; i++) {
- int p = permute[i];
- if (_renumbering[p] == REMOVABLE && removed < to_remove) {
- _renumbering[p] = DEAD;
- removed++;
- }
- }
-
- // renumber the rest
- int renumber_pos = 0;
- for (int i = 0; i < _nsubrs; i++)
- if (_renumbering[i] == REMOVABLE) { // save it
- while (_renumbering[renumber_pos] >= 0)
- renumber_pos++;
- _renumbering[i] = renumber_pos++;
- }
- SubrExpander rem0;
- rem0.set_renumbering(&_renumbering);
-
- // go through and change them all
- for (int i = 0; i < _nsubrs; i++) {
- Type1Subr *s = _font->subr_x(i);
- if (s && _renumbering[i] >= 0)
- rem0.run(_font, s->t1cs());
- }
- for (int i = 0; i < _font->nglyphs(); i++)
- if (Type1Subr *g = _font->glyph_x(i))
- rem0.run(_font, g->t1cs());
-
- // actually remove subroutines
- _font->renumber_subrs(_renumbering);
-
- return true;
-}