diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/libefont/t1interp.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/libefont/t1interp.cc | 1376 |
1 files changed, 1376 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/libefont/t1interp.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/libefont/t1interp.cc new file mode 100644 index 00000000000..7b607bb407d --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/libefont/t1interp.cc @@ -0,0 +1,1376 @@ +// -*- related-file-name: "../include/efont/t1interp.hh" -*- + +/* t1interp.{cc,hh} -- Type 1/2 charstring interpretation + * + * Copyright (c) 1998-2012 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/t1interp.hh> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#ifdef WIN32 +# define random() rand() +#endif + +#define CHECK_STACK(numargs) do { if (size() < numargs) return error(errUnderflow, cmd); } while (0) +#define CHECK_STATE() do { if (_state < S_IPATH) return error(errOrdering, cmd); } while (0) +#define CHECK_PATH_START() do { _state = S_PATH; } while (0) +#define CHECK_PATH_END() do { if (_state == S_PATH) { act_closepath(cmd); } _state = S_IPATH; } while (0) + +#ifndef static_assert +# define static_assert(c) switch (c) case 0: case (c): +#endif + +namespace Efont { + +static const char * const error_formats[] = { + "charstring OK", // errOK + "charstring internal error in '%C'", // errInternal + "charstring commands past end", // errRunoff + "charstring command '%C' unimplemented", // errUnimplemented + "charstring stack overflow", // errOverflow + "charstring stack underflow in '%C'", // errUnderflow + "charstring bad vector operation in '%C'", // errVector + "charstring bad value in '%C'", // errValue + "charstring bad subroutine number %d", // errSubr + "charstring bad glyph number '%d'", // errGlyph + "charstring no current point in '%C'", // errCurrentPoint + "charstring flex error", // errFlex + "charstring multiple master error in '%C'", // errMultipleMaster + "charstring open stroke", // errOpenStroke + "charstring late sidebearing command '%C'", // errLateSidebearing + "charstring bad othersubr number %d", // errOthersubr + "charstring ordering constraints violated at '%C'", // errOrdering + "charstring inappropriate hintmask", // errHintmask + "charstring subrs nested too deep at '%d'" // errSubrDepth +}; + +double CharstringInterp::double_for_error; + + +CharstringInterp::CharstringInterp() + : _error(errOK), _careful(false), _sp(0), _ps_sp(0), + _scratch_vector(SCRATCH_SIZE, 0), _program(0) +{ +} + +CharstringInterp::CharstringInterp(const Vector<double> &weight_vector) + : _error(errOK), _careful(false), _sp(0), _ps_sp(0), + _weight_vector(weight_vector), + _scratch_vector(SCRATCH_SIZE, 0), _program(0) +{ +} + +void +CharstringInterp::initialize() +{ + clear(); + ps_clear(); + _lsb = _cp = _seac_origin = Point(0, 0); + _state = S_INITIAL; + _flex = false; + _t2nhints = 0; + _subr_depth = 0; + _done = false; + _error = errOK; +} + +bool +CharstringInterp::interpret(const CharstringProgram *program, const Charstring *cs) +{ + if (cs) { + initialize(); + _program = program; + cs->process(*this); + return _error == errOK; + } else + return error(errGlyph, 0); +} + +bool +CharstringInterp::error(int err, int error_data) +{ + _error = err; + _error_data = error_data; + return false; +} + +String +CharstringInterp::error_string(int error, int error_data) +{ + static_assert(-errLastError == (sizeof(error_formats) / sizeof(error_formats[0])) - 1); + if (error >= 0) + return error_formats[0]; + else if (error < errLastError) + return "charstring unknown error number " + String(error); + String format = error_formats[-error]; + int percent = format.find_left('%'); + if (percent >= 0 && format[percent + 1] == 'C') + return format.substring(0, percent) + Charstring::command_name(error_data) + format.substring(percent + 2); + else if (percent >= 0 && format[percent + 1] == 'd') + return format.substring(0, percent) + String(error_data) + format.substring(percent + 2); + else + return format; +} + +bool +CharstringInterp::number(double v) +{ + push(v); + return true; +} + +void +CharstringInterp::fetch_weight_vector() +{ + if (_program) + if (Vector<double> *wv = _program->mm_vector(CharstringProgram::VEC_WEIGHT, false)) + _weight_vector = *wv; +} + +bool +CharstringInterp::vector_command(int cmd) +{ + CharstringProgram::VectorType which_vector; + int vectoroff, offset, num, i; + Vector<double> *v = 0; + + switch (cmd) { + + case Cs::cPut: + CHECK_STACK(2); + offset = (int)top(0); + vec(&_scratch_vector, offset) = top(1); + pop(2); + break; + + case Cs::cGet: + CHECK_STACK(1); + offset = (int)top(); + top() = vec(&_scratch_vector, offset); + break; + + case Cs::cStore: + CHECK_STACK(4); + which_vector = (CharstringProgram::VectorType)((int)top(3)); + vectoroff = (int)top(2); + offset = (int)top(1); + num = (int)top(0); + pop(4); + + if (!_program) + return error(errVector, cmd); + v = _program->mm_vector(which_vector, true); + if (!v) + return error(errVector, cmd); + + for (i = 0; i < num; i++, offset++, vectoroff++) + vec(v, vectoroff) = vec(&_scratch_vector, offset); + // erase our weight vector if the global weight vector has changed + if (which_vector == CharstringProgram::VEC_WEIGHT) + _weight_vector.clear(); + break; + + case Cs::cLoad: + CHECK_STACK(3); + which_vector = (CharstringProgram::VectorType)((int)top(2)); + offset = (int)top(1); + num = (int)top(0); + pop(3); + + if (!_program) + return error(errVector, cmd); + v = _program->mm_vector(which_vector, false); + // use our weight vector if appropriate + if (!v && which_vector == CharstringProgram::VEC_WEIGHT && _weight_vector.size()) + v = &_weight_vector; + if (!v) + return error(errVector, cmd); + + for (i = 0; i < num; i++, offset++) + vec(&_scratch_vector, offset) = vec(v, i); + break; + + default: + return error(errUnimplemented, cmd); + + } + + return true; +} + +bool +CharstringInterp::blend_command() +{ + const int cmd = Cs::cBlend; + CHECK_STACK(1); + int nargs = (int)pop(); + + ensure_weight_vector(); + if (!_weight_vector.size()) + return error(errVector, cmd); + + int nmasters = _weight_vector.size(); + CHECK_STACK(nargs * nmasters); + + int base = _sp - nargs * nmasters; + int off = base + nargs; + for (int j = 0; j < nargs; j++) { + double &val = _s[base + j]; + for (int i = 1; i < nmasters; i++, off++) + val += _weight_vector.at_u(i) * _s[off]; + } + + pop(nargs * (nmasters - 1)); + return true; +} + +bool +CharstringInterp::roll_command() +{ + const int cmd = Cs::cRoll; + CHECK_STACK(2); + int amount = (int)pop(); + int n = (int)pop(); + if (n <= 0) + return error(errValue, cmd); + CHECK_STACK(n); + + int base = _sp - n; + while (amount < 0) + amount += n; + + int i; + double copy_stack[STACK_SIZE]; + for (i = 0; i < n; i++) + copy_stack[i] = _s[ base + (i+amount) % n ]; + for (i = 0; i < n; i++) + _s[base + i] = copy_stack[i]; + + return true; +} + +bool +CharstringInterp::arith_command(int cmd) +{ + int i; + double d; + + switch (cmd) { + + case Cs::cBlend: + return blend_command(); + + case Cs::cAbs: + CHECK_STACK(1); + if (top() < 0) + top() = -top(); + break; + + case Cs::cAdd: + CHECK_STACK(1); + d = pop(); + top() += d; + break; + + case Cs::cSub: + CHECK_STACK(1); + d = pop(); + top() -= d; + break; + + case Cs::cDiv: + CHECK_STACK(2); + d = pop(); + top() /= d; + break; + + case Cs::cNeg: + CHECK_STACK(1); + top() = -top(); + break; + + case Cs::cRandom: { + double d; + do { + d = random() / ((double)RAND_MAX); + } while (d == 0); + push(d); + break; + } + + case Cs::cMul: + CHECK_STACK(2); + d = pop(); + top() *= d; + break; + + case Cs::cSqrt: + CHECK_STACK(1); + if (top() < 0) + return error(errValue, cmd); + top() = sqrt(top()); + break; + + case Cs::cDrop: + CHECK_STACK(1); + pop(); + break; + + case Cs::cExch: + CHECK_STACK(2); + d = top(0); + top(0) = top(1); + top(1) = d; + break; + + case Cs::cIndex: + CHECK_STACK(1); + i = (int)top(); + if (i < 0) + return error(errValue, cmd); + CHECK_STACK(i + 2); + top() = top(i+1); + break; + + case Cs::cRoll: + return roll_command(); + + case Cs::cDup: + CHECK_STACK(1); + push(top()); + break; + + case Cs::cAnd: + CHECK_STACK(2); + d = pop(); + top() = (top() != 0) && (d != 0); + break; + + case Cs::cOr: + CHECK_STACK(2); + d = pop(); + top() = (top() != 0) || (d != 0); + break; + + case Cs::cNot: + CHECK_STACK(1); + top() = (top() == 0); + break; + + case Cs::cEq: + CHECK_STACK(2); + d = pop(); + top() = (top() == d); + break; + + case Cs::cIfelse: + CHECK_STACK(4); + if (top(1) > top(0)) + top(3) = top(2); + pop(3); + break; + + case Cs::cPop: + if (ps_size() < 1) + return error(errUnderflow, cmd); + push(ps_pop()); + break; + + case 15: + // this command is found with no explanation in JansonText-Roman + CHECK_STACK(2); + pop(2); + return true; + + default: + return error(errUnimplemented, cmd); + + } + + return true; +} + +bool +CharstringInterp::callsubr_command() +{ + const int cmd = Cs::cCallsubr; + CHECK_STACK(1); + int which = (int)pop(); + + Charstring *subr_cs = get_subr(which); + if (!subr_cs) + return error(errSubr, which); + + if (_subr_depth >= MAX_SUBR_DEPTH) + return error(errSubrDepth, which); + _subr_depth++; + + subr_cs->process(*this); + + _subr_depth--; + if (_error != errOK) + return false; + return !done(); +} + +bool +CharstringInterp::callgsubr_command() +{ + const int cmd = Cs::cCallgsubr; + CHECK_STACK(1); + int which = (int)pop(); + + Charstring *subr_cs = get_gsubr(which); + if (!subr_cs) + return error(errSubr, which); + + if (_subr_depth >= MAX_SUBR_DEPTH) + return error(errSubrDepth, which); + _subr_depth++; + + subr_cs->process(*this); + + _subr_depth--; + if (_error != errOK) + return false; + return !done(); +} + +bool +CharstringInterp::mm_command(int command, int on_stack) +{ + ensure_weight_vector(); + if (!_weight_vector.size()) + return error(errVector, command); + + int nargs; + switch (command) { + case Cs::othcMM1: nargs = 1; break; + case Cs::othcMM2: nargs = 2; break; + case Cs::othcMM3: nargs = 3; break; + case Cs::othcMM4: nargs = 4; break; + case Cs::othcMM6: nargs = 6; break; + default: return error(errInternal, command); + } + + int nmasters = _weight_vector.size(); + if (size() < nargs * nmasters + || on_stack != nargs * nmasters) + return error(errMultipleMaster, command); + + int base = size() - on_stack; + + int off = base + nargs; + for (int j = 0; j < nargs; j++) { + double &val = at(base + j); + for (int i = 1; i < nmasters; i++, off++) + val += _weight_vector.at_u(i) * at(off); + } + + for (int i = nargs - 1; i >= 0; i--) + ps_push(at(base + i)); + + pop(on_stack); + return true; +} + +bool +CharstringInterp::itc_command(int command, int on_stack) +{ + ensure_weight_vector(); + if (!_weight_vector.size()) + return error(errVector, command); + + int base = size() - on_stack; + switch (command) { + + case Cs::othcITC_load: { + if (on_stack != 1) + return error(errOthersubr, command); + int offset = (int)at(base); + for (int i = 0; i < _weight_vector.size(); i++) + vec(&_scratch_vector, offset+i) = _weight_vector.at_u(i); + break; + } + + case Cs::othcITC_put: { + if (on_stack != 2) + return error(errOthersubr, command); + int offset = (int)at(base+1); + vec(&_scratch_vector, offset) = at(base); + break; + } + + case Cs::othcITC_get: { + if (on_stack != 1) + return error(errOthersubr, command); + int offset = (int)at(base); + ps_push(vec(&_scratch_vector, offset)); + break; + } + + case Cs::othcITC_add: { + if (on_stack != 2) + return error(errOthersubr, command); + ps_push(at(base) + at(base+1)); + break; + } + + case Cs::othcITC_sub: { + if (on_stack != 2) + return error(errOthersubr, command); + ps_push(at(base) - at(base+1)); + break; + } + + case Cs::othcITC_mul: { + if (on_stack != 2) + return error(errOthersubr, command); + ps_push(at(base) * at(base+1)); + break; + } + + case Cs::othcITC_div: { + if (on_stack != 2) + return error(errOthersubr, command); + ps_push(at(base) / at(base+1)); + break; + } + + case Cs::othcITC_ifelse: { + if (on_stack != 4) + return error(errOthersubr, command); + if (at(base+2) <= at(base+3)) + ps_push(at(base)); + else + ps_push(at(base+1)); + break; + } + + default: + return error(errOthersubr, command); + + } + + pop(on_stack); + return true; +} + + +inline void +CharstringInterp::actp_rmoveto(int /*cmd*/, double dx, double dy) +{ + _cp.shift(dx, dy); +} + +inline void +CharstringInterp::actp_rlineto(int cmd, double dx, double dy) +{ + Point p0(_cp); + _cp.shift(dx, dy); + act_line(cmd, p0, _cp); +} + +void +CharstringInterp::actp_rrcurveto(int cmd, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3) +{ + Point p0(_cp); + Point p1(p0, dx1, dy1); + Point p2(p1, dx2, dy2); + _cp = p2.shifted(dx3, dy3); + act_curve(cmd, p0, p1, p2, _cp); +} + +void +CharstringInterp::actp_rrflex(int cmd, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3, double dx4, double dy4, double dx5, double dy5, double dx6, double dy6, double flex_depth) +{ + Point p0(_cp); + Point p1(p0, dx1, dy1); + Point p2(p1, dx2, dy2); + Point p3_4(p2, dx3, dy3); + Point p5(p3_4, dx4, dy4); + Point p6(p5, dx5, dy5); + _cp = p6.shifted(dx6, dy6); + act_flex(cmd, p0, p1, p2, p3_4, p5, p6, _cp, flex_depth); +} + + +bool +CharstringInterp::callothersubr_command(int othersubrnum, int n) +{ + switch (othersubrnum) { + + case Cs::othcFlexend: + if (n != 3) + goto unknown; + if (!_flex || ps_size() != 16) + return error(errFlex); + CHECK_PATH_START(); + act_flex(Cs::cCallothersubr, Point(ps_at(0), ps_at(1)), + Point(ps_at(4), ps_at(5)), Point(ps_at(6), ps_at(7)), + Point(ps_at(8), ps_at(9)), Point(ps_at(10), ps_at(11)), + Point(ps_at(12), ps_at(13)), Point(ps_at(14), ps_at(15)), + top(2)); + ps_clear(); + ps_push(top(0)); + ps_push(top(1)); + _flex = false; + _state = S_PATH; + break; + + case Cs::othcFlexbegin: + if (n != 0) + goto unknown; + if (_flex) + return error(errFlex); + ps_clear(); + ps_push(_cp.x); + ps_push(_cp.y); + _flex = true; + _state = S_IPATH; + break; + + case Cs::othcFlexmiddle: + if (n != 0) + goto unknown; + if (!_flex) + return error(errFlex); + ps_push(_cp.x); + ps_push(_cp.y); + break; + + case Cs::othcReplacehints: + if (n != 1) + goto unknown; + ps_clear(); + ps_push(top()); + break; + + case Cs::othcMM1: + case Cs::othcMM2: + case Cs::othcMM3: + case Cs::othcMM4: + case Cs::othcMM6: + return mm_command(othersubrnum, n); + + case Cs::othcITC_load: + case Cs::othcITC_add: + case Cs::othcITC_sub: + case Cs::othcITC_mul: + case Cs::othcITC_div: + case Cs::othcITC_put: + case Cs::othcITC_get: + case Cs::othcITC_unknown: + case Cs::othcITC_ifelse: + case Cs::othcITC_random: + return itc_command(othersubrnum, n); + + default: // unknown + unknown: + ps_clear(); + for (int i = 0; i < n; i++) + ps_push(top(i)); + break; + + } + + pop(n); + return true; +} + +bool +CharstringInterp::type1_command(int cmd) +{ + switch (cmd) { + + case Cs::cReturn: + return false; + + case Cs::cHsbw: + CHECK_STACK(2); + if (_state > S_SEAC && _careful) + return error(errOrdering, cmd); + else { + _lsb = _cp = _seac_origin.shifted(at(0), 0); + if (_state == S_INITIAL) { + act_sidebearing(cmd, _lsb); + act_width(cmd, Point(at(1), 0)); + } + if (_state <= S_SEAC) + _state = S_SBW; + } + break; + + case Cs::cSbw: + CHECK_STACK(4); + if (_state > S_SEAC && _careful) + return error(errOrdering, cmd); + else { + _lsb = _cp = _seac_origin.shifted(at(0), at(1)); + if (_state == S_INITIAL) { + act_sidebearing(cmd, _lsb); + act_width(cmd, Point(at(2), at(3))); + } + if (_state <= S_SEAC) + _state = S_SBW; + } + break; + + case Cs::cSeac: + CHECK_STACK(5); + if (_state > S_SBW) + return error(errOrdering, cmd); + act_seac(cmd, at(0), at(1), at(2), (int)at(3), (int)at(4)); + clear(); + return false; + + case Cs::cCallsubr: + return callsubr_command(); + + case Cs::cCallothersubr: { + CHECK_STACK(2); + int othersubrnum = (int)top(0); + int n = (int)top(1); + pop(2); + if (othersubrnum < 0 || size() < n) + return error(errOthersubr, cmd); + return callothersubr_command(othersubrnum, n); + } + + case Cs::cPut: + case Cs::cGet: + case Cs::cStore: + case Cs::cLoad: + return vector_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: + case Cs::cPop: + return arith_command(cmd); + + case Cs::cHlineto: + CHECK_STACK(1); + CHECK_PATH_START(); + actp_rlineto(cmd, at(0), 0); + break; + + case Cs::cHmoveto: + CHECK_STACK(1); + CHECK_PATH_END(); + actp_rmoveto(cmd, at(0), 0); + break; + + case Cs::cHvcurveto: + CHECK_STACK(4); + CHECK_PATH_START(); + actp_rrcurveto(cmd, at(0), 0, at(1), at(2), 0, at(3)); + break; + + case Cs::cRlineto: + CHECK_STACK(2); + CHECK_PATH_START(); + actp_rlineto(cmd, at(0), at(1)); + break; + + case Cs::cRmoveto: + CHECK_STACK(2); + CHECK_PATH_END(); + actp_rmoveto(cmd, at(0), at(1)); + break; + + case Cs::cRrcurveto: + CHECK_STACK(6); + CHECK_PATH_START(); + actp_rrcurveto(cmd, at(0), at(1), at(2), at(3), at(4), at(5)); + break; + + case Cs::cVhcurveto: + CHECK_STACK(4); + CHECK_PATH_START(); + actp_rrcurveto(cmd, 0, at(0), at(1), at(2), at(3), 0); + break; + + case Cs::cVlineto: + CHECK_STACK(1); + CHECK_PATH_START(); + actp_rlineto(cmd, 0, at(0)); + break; + + case Cs::cVmoveto: + CHECK_STACK(1); + CHECK_PATH_END(); + actp_rmoveto(cmd, 0, at(0)); + break; + + case Cs::cDotsection: + break; + + case Cs::cHstem: + CHECK_STACK(2); + act_hstem(cmd, _lsb.y + at(0), at(1)); + break; + + case Cs::cHstem3: + CHECK_STACK(6); + act_hstem3(cmd, _lsb.y + at(0), at(1), _lsb.y + at(2), at(3), _lsb.y + at(4), at(5)); + break; + + case Cs::cVstem: + CHECK_STACK(2); + act_vstem(cmd, _lsb.x + at(0), at(1)); + break; + + case Cs::cVstem3: + CHECK_STACK(6); + act_vstem3(cmd, _lsb.x + at(0), at(1), _lsb.x + at(2), at(3), _lsb.x + at(4), at(5)); + break; + + case Cs::cSetcurrentpoint: + CHECK_STACK(2); + _cp = Point(at(0), at(1)); + break; + + case Cs::cClosepath: + CHECK_PATH_END(); + break; + + case Cs::cEndchar: + CHECK_PATH_END(); + set_done(); + return false; + + case Cs::cError: + default: + return error(errUnimplemented, cmd); + + } + + clear(); + return error() >= 0; +} + + +#undef DEBUG_TYPE2 + +int +CharstringInterp::type2_handle_width(int cmd, bool have_width) +{ + _cp = _lsb = _seac_origin; + if (_state != S_INITIAL) + /* ignore width */; + else if (have_width) + act_nominal_width_delta(cmd, at(0)); + else + act_default_width(cmd); + return (have_width ? 1 : 0); +} + +bool +CharstringInterp::type2_command(int cmd, const uint8_t *data, int *left) +{ + int bottom = 0; + +#ifdef DEBUG_TYPE2 + fprintf(stderr, "%s [%d/%d]\n", Charstring::command_name(cmd).c_str(), _t2nhints, size()); +#endif + + switch (cmd) { + + case Cs::cHstem: + case Cs::cHstemhm: + CHECK_STACK(2); + if (_state <= S_SEAC) + bottom = type2_handle_width(cmd, (size() % 2) == 1); + if (_state > S_HSTEM) + return error(errOrdering, cmd); + _state = S_HSTEM; + for (double pos = 0; bottom + 1 < size(); bottom += 2) { + _t2nhints++; + act_hstem(cmd, pos + at(bottom), at(bottom + 1)); + pos += at(bottom) + at(bottom + 1); + } + break; + + case Cs::cVstem: + case Cs::cVstemhm: + CHECK_STACK(2); + if (_state <= S_SEAC) + bottom = type2_handle_width(cmd, (size() % 2) == 1); + if (_state > S_VSTEM) + return error(errOrdering, cmd); + _state = S_VSTEM; + for (double pos = 0; bottom + 1 < size(); bottom += 2) { + _t2nhints++; + act_vstem(cmd, pos + at(bottom), at(bottom + 1)); + pos += at(bottom) + at(bottom + 1); + } + break; + + case Cs::cHintmask: + case Cs::cCntrmask: + if (_state <= S_SEAC && size() >= 1) { + bottom = type2_handle_width(cmd, (size() % 2) == 1); + for (double pos = 0; bottom + 1 < size(); bottom += 2) { + _t2nhints++; + act_hstem(cmd, pos + at(bottom), at(bottom + 1)); + pos += at(bottom) + at(bottom + 1); + } + } + if ((_state == S_HSTEM || _state == S_VSTEM) && size() >= 2) + for (double pos = 0; bottom + 1 < size(); bottom += 2) { + _t2nhints++; + act_vstem(cmd, pos + at(bottom), at(bottom + 1)); + pos += at(bottom) + at(bottom + 1); + } + if (_state < S_HINTMASK) + _state = S_HINTMASK; + if (_t2nhints == 0) + return error(errHintmask, cmd); + if (!data || !left) + return error(errInternal, cmd); + if (((_t2nhints - 1) >> 3) + 1 > *left) + return error(errRunoff, cmd); + act_hintmask(cmd, data, _t2nhints); + *left -= ((_t2nhints - 1) >> 3) + 1; + break; + + case Cs::cRmoveto: + CHECK_STACK(2); + if (_state <= S_SEAC) + bottom = type2_handle_width(cmd, size() > 2); + CHECK_PATH_END(); + actp_rmoveto(cmd, at(bottom), at(bottom + 1)); +#if DEBUG_TYPE2 + bottom += 2; +#endif + break; + + case Cs::cHmoveto: + CHECK_STACK(1); + if (_state <= S_SEAC) + bottom = type2_handle_width(cmd, size() > 1); + CHECK_PATH_END(); + actp_rmoveto(cmd, at(bottom), 0); +#if DEBUG_TYPE2 + bottom++; +#endif + break; + + case Cs::cVmoveto: + CHECK_STACK(1); + if (_state <= S_SEAC) + bottom = type2_handle_width(cmd, size() > 1); + CHECK_PATH_END(); + actp_rmoveto(cmd, 0, at(bottom)); +#if DEBUG_TYPE2 + bottom++; +#endif + break; + + case Cs::cRlineto: + CHECK_STACK(2); + CHECK_STATE(); + CHECK_PATH_START(); + for (; bottom + 1 < size(); bottom += 2) + actp_rlineto(cmd, at(bottom), at(bottom + 1)); + break; + + case Cs::cHlineto: + CHECK_STACK(1); + CHECK_STATE(); + CHECK_PATH_START(); + while (bottom < size()) { + actp_rlineto(cmd, at(bottom++), 0); + if (bottom < size()) + actp_rlineto(cmd, 0, at(bottom++)); + } + break; + + case Cs::cVlineto: + CHECK_STACK(1); + CHECK_STATE(); + CHECK_PATH_START(); + while (bottom < size()) { + actp_rlineto(cmd, 0, at(bottom++)); + if (bottom < size()) + actp_rlineto(cmd, at(bottom++), 0); + } + break; + + case Cs::cRrcurveto: + CHECK_STACK(6); + CHECK_STATE(); + CHECK_PATH_START(); + for (; bottom + 5 < size(); bottom += 6) + actp_rrcurveto(cmd, at(bottom), at(bottom + 1), at(bottom + 2), at(bottom + 3), at(bottom + 4), at(bottom + 5)); + break; + + case Cs::cHhcurveto: + CHECK_STACK(4); + CHECK_STATE(); + CHECK_PATH_START(); + if (size() % 2 == 1) { + actp_rrcurveto(cmd, at(bottom + 1), at(bottom), at(bottom + 2), at(bottom + 3), at(bottom + 4), 0); + bottom += 5; + } + for (; bottom + 3 < size(); bottom += 4) + actp_rrcurveto(cmd, at(bottom), 0, at(bottom + 1), at(bottom + 2), at(bottom + 3), 0); + break; + + case Cs::cHvcurveto: + CHECK_STACK(4); + CHECK_STATE(); + CHECK_PATH_START(); + while (bottom + 3 < size()) { + double dx3 = (bottom + 5 == size() ? at(bottom + 4) : 0); + actp_rrcurveto(cmd, at(bottom), 0, at(bottom + 1), at(bottom + 2), dx3, at(bottom + 3)); + bottom += 4; + if (bottom + 3 < size()) { + double dy3 = (bottom + 5 == size() ? at(bottom + 4) : 0); + actp_rrcurveto(cmd, 0, at(bottom), at(bottom + 1), at(bottom + 2), at(bottom + 3), dy3); + bottom += 4; + } + } +#if DEBUG_TYPE2 + if (bottom + 1 == size()) + bottom++; +#endif + break; + + case Cs::cRcurveline: + CHECK_STACK(8); + CHECK_STATE(); + CHECK_PATH_START(); + for (; bottom + 7 < size(); bottom += 6) + actp_rrcurveto(cmd, at(bottom), at(bottom + 1), at(bottom + 2), at(bottom + 3), at(bottom + 4), at(bottom + 5)); + actp_rlineto(cmd, at(bottom), at(bottom + 1)); +#if DEBUG_TYPE2 + bottom += 2; +#endif + break; + + case Cs::cRlinecurve: + CHECK_STACK(8); + CHECK_STATE(); + CHECK_PATH_START(); + for (; bottom + 7 < size(); bottom += 2) + actp_rlineto(cmd, at(bottom), at(bottom + 1)); + actp_rrcurveto(cmd, at(bottom), at(bottom + 1), at(bottom + 2), at(bottom + 3), at(bottom + 4), at(bottom + 5)); +#if DEBUG_TYPE2 + bottom += 6; +#endif + break; + + case Cs::cVhcurveto: + CHECK_STACK(4); + CHECK_STATE(); + CHECK_PATH_START(); + while (bottom + 3 < size()) { + double dy3 = (bottom + 5 == size() ? at(bottom + 4) : 0); + actp_rrcurveto(cmd, 0, at(bottom), at(bottom + 1), at(bottom + 2), at(bottom + 3), dy3); + bottom += 4; + if (bottom + 3 < size()) { + double dx3 = (bottom + 5 == size() ? at(bottom + 4) : 0); + actp_rrcurveto(cmd, at(bottom), 0, at(bottom + 1), at(bottom + 2), dx3, at(bottom + 3)); + bottom += 4; + } + } +#if DEBUG_TYPE2 + if (bottom + 1 == size()) + bottom++; +#endif + break; + + case Cs::cVvcurveto: + CHECK_STACK(4); + CHECK_STATE(); + CHECK_PATH_START(); + if (size() % 2 == 1) { + actp_rrcurveto(cmd, at(bottom), at(bottom + 1), at(bottom + 2), at(bottom + 3), 0, at(bottom + 4)); + bottom += 5; + } + for (; bottom + 3 < size(); bottom += 4) + actp_rrcurveto(cmd, 0, at(bottom), at(bottom + 1), at(bottom + 2), 0, at(bottom + 3)); + break; + + case Cs::cFlex: + CHECK_STACK(13); + CHECK_STATE(); + CHECK_PATH_START(); + assert(bottom == 0); + actp_rrflex(cmd, + at(0), at(1), at(2), at(3), at(4), at(5), + at(6), at(7), at(8), at(9), at(10), at(11), + at(12)); +#if DEBUG_TYPE2 + bottom += 13; +#endif + break; + + case Cs::cHflex: + CHECK_STACK(7); + CHECK_STATE(); + CHECK_PATH_START(); + assert(bottom == 0); + actp_rrflex(cmd, + at(0), 0, at(1), at(2), at(3), 0, + at(4), 0, at(5), -at(2), at(6), 0, + 50); +#if DEBUG_TYPE2 + bottom += 7; +#endif + break; + + case Cs::cHflex1: + CHECK_STACK(9); + CHECK_STATE(); + CHECK_PATH_START(); + assert(bottom == 0); + actp_rrflex(cmd, + at(0), at(1), at(2), at(3), at(4), 0, + at(5), 0, at(6), at(7), at(8), -(at(1) + at(3) + at(7)), + 50); +#if DEBUG_TYPE2 + bottom += 9; +#endif + break; + + case Cs::cFlex1: { + CHECK_STACK(11); + CHECK_STATE(); + CHECK_PATH_START(); + assert(bottom == 0); + double dx = at(0) + at(2) + at(4) + at(6) + at(8); + double dy = at(1) + at(3) + at(5) + at(7) + at(9); + if (fabs(dx) > fabs(dy)) + actp_rrflex(cmd, + at(0), at(1), at(2), at(3), at(4), at(5), + at(6), at(7), at(8), at(9), at(10), -dy, + 50); + else + actp_rrflex(cmd, + at(0), at(1), at(2), at(3), at(4), at(5), + at(6), at(7), at(8), at(9), -dx, at(10), + 50); + break; +#if DEBUG_TYPE2 + bottom += 11; +#endif + } + + case Cs::cEndchar: + if (_state <= S_SEAC) + bottom = type2_handle_width(cmd, size() > 0 && size() != 4); + if (bottom + 3 < size() && _state == S_INITIAL) + act_seac(cmd, 0, at(bottom), at(bottom + 1), (int)at(bottom + 2), (int)at(bottom + 3)); + CHECK_PATH_END(); + set_done(); + clear(); + return false; + + case Cs::cReturn: + return false; + + case Cs::cCallsubr: + return callsubr_command(); + + case Cs::cCallgsubr: + return callgsubr_command(); + + case Cs::cPut: + case Cs::cGet: + case Cs::cStore: + case Cs::cLoad: + return vector_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: + case Cs::cPop: + return arith_command(cmd); + + case Cs::cDotsection: + break; + + case Cs::cError: + default: + return error(errUnimplemented, cmd); + + } + +#if DEBUG_TYPE2 + if (bottom != size()) + fprintf(stderr, "[left %d on stack] ", size() - bottom); +#endif + + clear(); + return error() >= 0; +} + + +void +CharstringInterp::act_sidebearing(int, const Point &) +{ + /* do nothing */ +} + +void +CharstringInterp::act_width(int, const Point &) +{ + /* do nothing */ +} + +void +CharstringInterp::act_default_width(int cmd) +{ + double d = (_program ? _program->global_width_x(false) : UNKDOUBLE); + if (KNOWN(d)) + act_width(cmd, Point(d, 0)); +} + +void +CharstringInterp::act_nominal_width_delta(int cmd, double delta) +{ + double d = (_program ? _program->global_width_x(true) : UNKDOUBLE); + if (KNOWN(d)) + act_width(cmd, Point(d + delta, 0)); +} + +void +CharstringInterp::act_seac(int cmd, double asb, double adx, double ady, int bchar, int achar) +{ + Charstring *acs = 0, *bcs = 0; + if (achar < 0 || achar >= 256 || bchar < 0 || bchar >= 256 + || !_program || _program->parent_program() + || !(acs = get_glyph(Charstring::standard_encoding[achar])) + || !(bcs = get_glyph(Charstring::standard_encoding[bchar]))) { + error(errGlyph, cmd); + return; + } + + Point apos = Point(adx + _lsb.x - asb, ady + _lsb.y); + Point save_lsb = _lsb; + Point save_seac_origin = _seac_origin; + + CharstringInterp::initialize(); + _seac_origin = apos; + _state = S_SEAC; + acs->process(*this); + if (error() == errOK) { + CharstringInterp::initialize(); + _seac_origin = save_seac_origin; + _state = S_SEAC; + bcs->process(*this); + } + + _lsb = save_lsb; +} + +void +CharstringInterp::act_line(int cmd, const Point &p0, const Point &p1) +{ + act_curve(cmd, p0, p0, p1, p1); +} + +void +CharstringInterp::act_curve(int cmd, const Point &, const Point &, const Point &, const Point &) +{ + error(errUnimplemented, cmd); +} + +void +CharstringInterp::act_flex(int cmd, const Point &p0, const Point &p1, const Point &p2, const Point &p3_4, const Point &p5, const Point &p6, const Point &p7, double flex_depth) +{ + (void) flex_depth; + act_curve(cmd, p0, p1, p2, p3_4); + act_curve(cmd, p3_4, p5, p6, p7); +} + +void +CharstringInterp::act_closepath(int) +{ + /* do nothing */ +} + +void +CharstringInterp::act_hstem(int, double, double) +{ + /* do nothing */ +} + +void +CharstringInterp::act_vstem(int, double, double) +{ + /* do nothing */ +} + +void +CharstringInterp::act_hstem3(int cmd, double y0, double dy0, double y1, double dy1, double y2, double dy2) +{ + act_hstem(cmd, y0, dy0); + act_hstem(cmd, y1, dy1); + act_hstem(cmd, y2, dy2); +} + +void +CharstringInterp::act_vstem3(int cmd, double x0, double dx0, double x1, double dx1, double x2, double dx2) +{ + act_vstem(cmd, x0, dx0); + act_vstem(cmd, x1, dx1); + act_vstem(cmd, x2, dx2); +} + +void +CharstringInterp::act_hintmask(int, const uint8_t *, int) +{ + /* do nothing */ +} + +} |