diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.103/t1dotlessj/t1dotlessj.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/lcdf-typetools-2.103/t1dotlessj/t1dotlessj.cc | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.103/t1dotlessj/t1dotlessj.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.103/t1dotlessj/t1dotlessj.cc new file mode 100644 index 00000000000..03f56452728 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.103/t1dotlessj/t1dotlessj.cc @@ -0,0 +1,425 @@ +/* t1dotlessj.cc -- driver for creating dotlessj characters from Type 1 fonts + * + * Copyright (c) 2003-2013 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/psres.hh> +#include <efont/t1rw.hh> +#include <efont/t1font.hh> +#include <efont/t1item.hh> +#include <efont/t1csgen.hh> +#include <efont/t1bounds.hh> +#include <efont/t1unparser.hh> +#include <lcdf/clp.h> +#include <lcdf/error.hh> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> +#include <errno.h> +#ifdef HAVE_CTIME +# include <time.h> +#endif +#if defined(_MSDOS) || defined(_WIN32) +# include <fcntl.h> +# include <io.h> +#endif + +// also see otftotfm/automatic.cc +enum { EXIT_NORMAL = 0, EXIT_DOTLESSJ_EXISTS = 1, EXIT_J_NODOT = 2, + EXIT_NO_J = 3, EXIT_ERROR = 4 }; + +using namespace Efont; + +#define VERSION_OPT 301 +#define HELP_OPT 302 +#define QUIET_OPT 303 +#define PFA_OPT 304 +#define PFB_OPT 305 +#define OUTPUT_OPT 306 +#define NAME_OPT 307 + +const Clp_Option options[] = { + { "help", 'h', HELP_OPT, 0, 0 }, + { "name", 'n', NAME_OPT, Clp_ValString, 0 }, + { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, + { "pfa", 'a', PFA_OPT, 0, 0 }, + { "pfb", 'b', PFB_OPT, 0, 0 }, + { "quiet", 'q', QUIET_OPT, 0, Clp_Negate }, + { "version", 0, VERSION_OPT, 0, 0 }, +}; + + +static const char *program_name; + + +void +usage_error(ErrorHandler *errh, const char *error_message, ...) +{ + va_list val; + va_start(val, error_message); + if (!error_message) + errh->message("Usage: %s [OPTIONS] [FONTFILE [OUTPUTFILE]]", program_name); + else + errh->vxmessage(ErrorHandler::e_error, error_message, val); + errh->message("Type %s --help for more information.", program_name); + exit(EXIT_ERROR); +} + +void +usage() +{ + FileErrorHandler uerrh(stdout); + uerrh.message("\ +%<T1dotlessj%> reads a PostScript Type 1 font, derives a new PostScript Type 1\n\ +font containing just a dotlessj character (by chopping the dot from the j),\n\ +and writes it to the standard output.\n\ +\n\ +Usage: %s [OPTIONS] [FONTFILE [OUTPUTFILE]]\n\ +\n\ +Options:\n\ + -a, --pfa Output PFA font.\n\ + -b, --pfb Output PFB font. This is the default.\n\ + -o, --output=FILE Write output to FILE instead of standard output.\n\ + -n, --name=NAME Set output font%,s PostScript name.\n\ + -h, --help Print this message and exit.\n\ + -q, --quiet Do not report errors to standard error.\n\ + --version Print version number and exit.\n\ +\n\ +Report bugs to <ekohler@gmail.com>.\n", program_name); +} + + +// Sectioner + +class Sectioner : public Type1CharstringGenInterp { public: + + Sectioner(int precision); + + void act_line(int, const Point &, const Point &); + void act_curve(int, const Point &, const Point &, const Point &, const Point &); + void act_closepath(int); + void act_flex(int, const Point &, const Point &, const Point &, const Point &, const Point &, const Point &, const Point &, double); + + void run(const CharstringContext &g); + void undot(PermString, ErrorHandler *); + Type1Charstring gen(Type1Font *); + + private: + + CharstringBounds _boundser; + + Vector<String> _sections; + Vector<int> _bounds; + + void append_bounds(); + +}; + +Sectioner::Sectioner(int precision) + : Type1CharstringGenInterp(precision) +{ + set_direct_hint_replacement(true); +} + +void +Sectioner::act_line(int cmd, const Point &p0, const Point &p1) +{ + Type1CharstringGenInterp::act_line(cmd, p0, p1); + _boundser.act_line(cmd, p0, p1); +} + +void +Sectioner::act_curve(int cmd, const Point &p0, const Point &p1, const Point &p2, const Point &p3) +{ + Type1CharstringGenInterp::act_curve(cmd, p0, p1, p2, p3); + _boundser.act_curve(cmd, p0, p1, p2, p3); +} + +void +Sectioner::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) +{ + Type1CharstringGenInterp::act_flex(cmd, p0, p1, p2, p3_4, p5, p6, p7, flex_depth); + _boundser.act_flex(cmd, p0, p1, p2, p3_4, p5, p6, p7, flex_depth); +} + +void Sectioner::append_bounds() { + double bb[5]; + _boundser.output(bb, bb[4]); + _bounds.push_back((int) floor(bb[0])); + _bounds.push_back((int) floor(bb[1])); + _bounds.push_back((int) ceil(bb[2])); + _bounds.push_back((int) ceil(bb[3])); +} + +void +Sectioner::act_closepath(int cmd) +{ + Type1CharstringGenInterp::act_closepath(cmd); + Type1Charstring result; + Type1CharstringGenInterp::intermediate_output(result); + _sections.push_back(result.data_string()); + append_bounds(); + _boundser.clear(); +} + +void +Sectioner::run(const CharstringContext &g) +{ + _boundser.clear(); + Type1Charstring last_section; + Type1CharstringGenInterp::run(g, last_section); + _sections.push_back(last_section.data_string()); + append_bounds(); +} + +void +Sectioner::undot(PermString font_name, ErrorHandler *errh) +{ + //for (String *s = _sections.begin(); s < _sections.end(); s++) + // fprintf(stderr, "%d %s\n", s - _sections.begin(), CharstringUnparser::unparse(Type1Charstring(*s)).c_str()); + + if (_sections.size() < 3) + errh->fatal("<%d>%s: %<j%> is already dotless", -EXIT_J_NODOT, font_name.c_str()); + + int topmost = -1; + for (int i = 0; i < _sections.size() - 1; i++) + if (topmost < 0 || _bounds[i*4 + 1] > _bounds[topmost*4 + 1]) + topmost = i; + + // check if any sections are below this + for (int i = 0; i < _sections.size() - 1; i++) + if (_bounds[i*4 + 1] < _bounds[topmost*4 + 1]) + goto found_below; + errh->fatal("<%d>%s: %<j%> is already dotless", -EXIT_J_NODOT, font_name.c_str()); + + found_below: + _sections[topmost] = String(); +} + +Type1Charstring +Sectioner::gen(Type1Font *font) +{ + StringAccum sa; + for (String *s = _sections.begin(); s < _sections.end(); s++) + sa << *s; + Type1Charstring in(sa.take_string()), out; + Type1CharstringGenInterp gen(precision()); + gen.set_hint_replacement_storage(font); + gen.run(CharstringContext(program(), &in), out); + return out; +} + + +// MAIN + +static Type1Font * +do_file(const char *filename, PsresDatabase *psres, ErrorHandler *errh) +{ + FILE *f; + if (!filename || strcmp(filename, "-") == 0) { + f = stdin; + filename = "<stdin>"; +#if defined(_MSDOS) || defined(_WIN32) + _setmode(_fileno(f), _O_BINARY); +#endif + } else + f = fopen(filename, "rb"); + + if (!f) { + // check for PostScript name + Filename fn = psres->filename_value("FontOutline", filename); + f = fn.open_read(); + } + + if (!f) + errh->fatal("<%d>%s: %s", -EXIT_ERROR, filename, strerror(errno)); + + Type1Reader *reader; + int c = getc(f); + ungetc(c, f); + if (c == EOF) + errh->fatal("<%d>%s: empty file", -EXIT_ERROR, filename); + if (c == 128) + reader = new Type1PFBReader(f); + else + reader = new Type1PFAReader(f); + + Type1Font *font = new Type1Font(*reader); + if (!font->ok()) + errh->fatal("<%d>%s: no glyphs in font", -EXIT_ERROR, filename); + + delete reader; + return font; +} + +int +main(int argc, char *argv[]) +{ + PsresDatabase *psres = new PsresDatabase; + psres->add_psres_path(getenv("PSRESOURCEPATH"), 0, false); + + Clp_Parser *clp = + Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); + program_name = Clp_ProgramName(clp); + + ErrorHandler *errh = ErrorHandler::static_initialize(new FileErrorHandler(stderr)); + const char *input_file = 0; + FILE *outputf = 0; + const char *private_use_dotlessj = "uniF6BE"; + bool binary = true; + const char *font_name = 0; + + while (1) { + int opt = Clp_Next(clp); + switch (opt) { + + case QUIET_OPT: + if (clp->negated) + errh = ErrorHandler::default_handler(); + else + errh = new SilentErrorHandler; + break; + + case NAME_OPT: + font_name = clp->vstr; + break; + + case PFA_OPT: + binary = false; + break; + + case PFB_OPT: + binary = true; + break; + + case OUTPUT_OPT: + output_file: + if (outputf) + usage_error(errh, "output file specified twice"); + if (strcmp(clp->vstr, "-") == 0) + outputf = stdout; + else if (!(outputf = fopen(clp->vstr, "wb"))) + errh->fatal("<%d>%s: %s", -EXIT_ERROR, clp->vstr, strerror(errno)); + break; + + case VERSION_OPT: + printf("t1dotlessj (LCDF typetools) %s\n", VERSION); + printf("Copyright (C) 2003-2013 Eddie Kohler\n\ +This is free software; see the source for copying conditions.\n\ +There is NO warranty, not even for merchantability or fitness for a\n\ +particular purpose.\n"); + exit(0); + break; + + case HELP_OPT: + usage(); + exit(0); + break; + + case Clp_NotOption: + if (input_file && outputf) + usage_error(errh, "too many arguments"); + else if (input_file) + goto output_file; + else + input_file = clp->vstr; + break; + + case Clp_Done: + goto done; + + case Clp_BadOption: + usage_error(errh, 0); + break; + + default: + break; + + } + } + + done: + Type1Font *font = do_file(input_file, psres, errh); + if (!input_file || strcmp(input_file, "-") == 0) + input_file = "<stdin>"; + + // check for existing dotlessj + if (font->glyph("dotlessj")) + errh->fatal("<%d>%s: already has a %<dotlessj%> glyph", -EXIT_DOTLESSJ_EXISTS, font->font_name().c_str()); + else if (font->glyph("uni0237")) + errh->fatal("<%d>%s: already has a dotlessj glyph at %<uni0237%>", -EXIT_DOTLESSJ_EXISTS, font->font_name().c_str()); + else if (font->glyph("u0237")) + errh->fatal("<%d>%s: already has a dotlessj glyph at %<u0237%>", -EXIT_DOTLESSJ_EXISTS, font->font_name().c_str()); + else if (private_use_dotlessj && font->glyph(private_use_dotlessj)) + errh->fatal("<%d>%s: already has a dotlessj glyph at %<%s%>", -EXIT_DOTLESSJ_EXISTS, font->font_name().c_str(), private_use_dotlessj); + + // check for j + Type1Charstring *j_cs = font->glyph("j"); + if (!j_cs) + j_cs = font->glyph("uni006A"); + if (!j_cs) + j_cs = font->glyph("u006A"); + if (!j_cs) + errh->fatal("<%d>%s: has no %<j%> glyph to make dotless", -EXIT_NO_J, font->font_name().c_str()); + + // make new font + String actual_font_name = (font_name ? String(font_name) : font->font_name() + String("LCDFJ")); + if (actual_font_name.length() > 29 && !font_name) { + errh->warning("derived font name %<%s%> longer than 29 characters", actual_font_name.c_str()); + errh->message("(Use the %<--name%> option to supply your own name.)"); + } + + Vector<double> xuid_extension; + xuid_extension.push_back(0x00237237); + Type1Font *dotless_font = Type1Font::skeleton_make_copy(font, actual_font_name, &xuid_extension); + dotless_font->skeleton_common_subrs(); + + // copy space and .notdef + if (Type1Charstring *notdef = font->glyph(".notdef")) + dotless_font->add_glyph(Type1Subr::make_glyph(".notdef", *notdef, " |-")); + if (Type1Charstring *space = font->glyph("space")) { + dotless_font->add_glyph(Type1Subr::make_glyph("space", *space, " |-")); + dotless_font->type1_encoding()->put(' ', "space"); + } + + // create dotless j + Sectioner sec(5); + sec.run(CharstringContext(font, j_cs)); + sec.undot(font->font_name(), errh); + Type1Subr *dotlessj = Type1Subr::make_glyph("uni0237", sec.gen(dotless_font), " |-"); + dotless_font->add_glyph(dotlessj); + //fprintf(stderr, "! %s\n", CharstringUnparser::unparse(dotlessj->t1cs()).c_str()); + + // encode dotless j + dotless_font->type1_encoding()->clear(); + dotless_font->type1_encoding()->put('j', "uni0237"); + + // write it to output + if (!outputf) + outputf = stdout; +#if defined(_MSDOS) || defined(_WIN32) + _setmode(_fileno(outputf), _O_BINARY); +#endif + if (binary) { + Type1PFBWriter w(outputf); + dotless_font->write(w); + } else { + Type1PFAWriter w(outputf); + dotless_font->write(w); + } + + return (errh->nerrors() == 0 ? EXIT_NORMAL : EXIT_ERROR); +} |