summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-2.101/libefont/t1interp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.101/libefont/t1interp.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-2.101/libefont/t1interp.cc1377
1 files changed, 1377 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.101/libefont/t1interp.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.101/libefont/t1interp.cc
new file mode 100644
index 00000000000..53483f211f8
--- /dev/null
+++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.101/libefont/t1interp.cc
@@ -0,0 +1,1377 @@
+// -*- 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, msg) 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,
+ "errLastError defined incorrectly");
+ 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 */
+}
+
+}