summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc979
1 files changed, 0 insertions, 979 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc
deleted file mode 100644
index 6a30b9d17fd..00000000000
--- a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc
+++ /dev/null
@@ -1,979 +0,0 @@
-/* dvipsencoding.{cc,hh} -- store a DVIPS encoding
- *
- * Copyright (c) 2003-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 "dvipsencoding.hh"
-#include "metrics.hh"
-#include "secondary.hh"
-#include <lcdf/error.hh>
-#include <lcdf/straccum.hh>
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <algorithm>
-#include "util.hh"
-
-enum { GLYPHLIST_ALTERNATIVE = 0x40000000,
- GLYPHLIST_USEMAP = GLYPHLIST_ALTERNATIVE,
- U_EMPTYSLOT = 0xD801,
- U_ALTSELECTOR = 0xD802 };
-static HashMap<String, uint32_t> glyphlist((uint32_t) -1);
-static Vector<uint32_t> glyphmap;
-static PermString::Initializer perm_initializer;
-PermString DvipsEncoding::dot_notdef(".notdef");
-
-#define NEXT_GLYPH_NAME(gn) ("/" + (gn))
-
-void
-DvipsEncoding::add_glyphlist(String text)
-{
- const char *s = text.begin(), *end = text.end();
- while (s != end) {
- // move to first nonblank
- while (s != end && isspace((unsigned char) *s))
- ++s;
- // ignore comments
- if (s != end && *s == '#') {
- skip_to_end_of_line:
- while (s != end && *s != '\n' && *s != '\r')
- ++s;
- continue;
- }
- // parse glyph name
- const char *name_start = s;
- while (s != end && !isspace((unsigned char) *s) && *s != ';')
- ++s;
- if (s == name_start)
- goto skip_to_end_of_line;
- String glyph_name = text.substring(name_start, s).compact();
- int map_pos = glyphmap.size();
- // parse Unicodes
- while (1) {
- while (s != end && (*s == ' ' || *s == '\t'))
- ++s;
- if (s == end || *s == '\n' || *s == '\r' || *s == '#'
- || (map_pos == glyphmap.size() && *s != ';' && *s != ','))
- break;
- if (*s == ';' || *s == ',') {
- ++s;
- while (s != end && (*s == ' ' || *s == '\t'))
- ++s;
- if (s == end || !isxdigit((unsigned char) *s))
- goto skip_to_end_of_line;
- if (map_pos != glyphmap.size())
- glyphmap.push_back(GLYPHLIST_ALTERNATIVE);
- }
- uint32_t u = 0;
- while (s != end && isxdigit((unsigned char) *s)) {
- if (*s >= '0' && *s <= '9')
- u = (u << 4) + *s - '0';
- else if (*s >= 'A' && *s <= 'F')
- u = (u << 4) + *s - 'A' + 10;
- else
- u = (u << 4) + *s - 'a' + 10;
- ++s;
- }
- if (u == 0 || u > 0x10FFFF)
- goto skip_to_end_of_line;
- glyphmap.push_back(u);
- if (s != end && !isspace((unsigned char) *s) && *s != ',' && *s != ';')
- break;
- }
- // store result
- if (map_pos == glyphmap.size() - 1) {
- glyphlist.insert(glyph_name, glyphmap.back());
- glyphmap.pop_back();
- } else {
- glyphlist.insert(glyph_name, map_pos | GLYPHLIST_USEMAP);
- glyphmap.push_back(0);
- }
- goto skip_to_end_of_line;
- }
-}
-
-static void
-unicode_add_suffix(Vector<uint32_t> &prefix,
- int prefix_starting_from,
- const Vector<uint32_t> &suffix)
-{
- int prefix_size = prefix.size();
- for (Vector<uint32_t>::const_iterator it = suffix.begin();
- it != suffix.end() && *it != 0;
- ++it)
- if (*it == GLYPHLIST_ALTERNATIVE) {
- prefix.push_back(*it);
- for (int i = prefix_starting_from; i < prefix_size; ++i)
- prefix.push_back(prefix[i]);
- } else
- prefix.push_back(*it);
-}
-
-bool
-DvipsEncoding::glyphname_unicode(String gn, Vector<uint32_t> &unis)
-{
- int unis_first_size = unis.size();
-
- // drop all characters to the right of the first dot
- String::iterator dot = std::find(gn.begin(), gn.end(), '.');
- if (dot > gn.begin() && dot < gn.end())
- gn = gn.substring(gn.begin(), dot);
-
- // map the first component, handle later components recursively
- String::iterator underscore = std::find(gn.begin(), gn.end(), '_');
- String component = gn.substring(gn.begin(), underscore);
- int prefix_start = 0;
- Vector<uint32_t> suffix;
- if (String gn_suffix = gn.substring(underscore + 1, gn.end())) {
- if (!glyphname_unicode(gn_suffix, suffix))
- return false;
- }
-
- // check glyphlist
- int value = glyphlist[component];
- uint32_t uval;
- if (value >= 0 && !(value & GLYPHLIST_USEMAP))
- unis.push_back(value);
- else if (value >= 0) {
- for (int i = (value & ~GLYPHLIST_USEMAP);
- glyphmap[i];
- ++i)
- if (glyphmap[i] == GLYPHLIST_ALTERNATIVE) {
- unicode_add_suffix(unis, prefix_start, suffix);
- unis.push_back(GLYPHLIST_ALTERNATIVE);
- prefix_start = unis.size();
- } else
- unis.push_back(glyphmap[i]);
- } else if (component.length() >= 7
- && (component.length() % 4) == 3
- && (memcmp(component.data(), "uni", 3) == 0
- // 16.Aug.2008: Some texnansx.enc have incorrect "Uni"
- // prefix, but we might as well understand it.
- || memcmp(component.data(), "Uni", 3) == 0)) {
- for (const char *s = component.begin() + 3;
- s < component.end();
- s += 4)
- if (parse_unicode_number(s, s + 4, -1, uval))
- unis.push_back(uval);
- else {
- unis.resize(unis_first_size);
- return false;
- }
- } else if (component.length() >= 5
- && component.length() <= 7
- && component[0] == 'u'
- && parse_unicode_number(component.begin() + 1, component.end(), -1, uval))
- unis.push_back(uval);
- else
- return false;
-
- unicode_add_suffix(unis, prefix_start, suffix);
- return true;
-}
-
-
-DvipsEncoding::DvipsEncoding()
- : _boundary_char(-1), _altselector_char(-1), _unicoding_map(-1),
- _warn_missing(false)
-{
-}
-
-void
-DvipsEncoding::encode(int e, PermString what)
-{
- if (e >= _e.size())
- _e.resize(e + 1, dot_notdef);
- _e[e] = what;
-}
-
-int
-DvipsEncoding::encoding_of(PermString what, bool encoding_required)
-{
- int slot = -1;
- for (int i = 0; i < _e.size(); i++)
- if (_e[i] == what) {
- slot = i;
- goto use_slot;
- } else if (!_e[i] || _e[i] == dot_notdef)
- slot = i;
- if (what == "||")
- return _boundary_char;
- else if (!encoding_required || slot < 0)
- return -1;
- use_slot:
- if (encoding_required) {
- if (slot >= _encoding_required.size())
- _encoding_required.resize(slot + 1, false);
- _encoding_required[slot] = true;
- this->encode(slot, what);
- }
- return slot;
-}
-
-static String
-tokenize(const String &s, int &pos_in, int &line)
-{
- const char *data = s.data();
- int len = s.length();
- int pos = pos_in;
- while (1) {
- // skip whitespace
- while (pos < len && isspace((unsigned char) data[pos])) {
- if (data[pos] == '\n')
- line++;
- else if (data[pos] == '\r' && (pos + 1 == len || data[pos+1] != '\n'))
- line++;
- pos++;
- }
-
- if (pos >= len) {
- pos_in = len;
- return String();
- } else if (data[pos] == '%') {
- for (pos++; pos < len && data[pos] != '\n' && data[pos] != '\r'; pos++)
- /* nada */;
- } else if (data[pos] == '[' || data[pos] == ']' || data[pos] == '{' || data[pos] == '}') {
- pos_in = pos + 1;
- return s.substring(pos, 1);
- } else if (data[pos] == '(') {
- int first = pos, nest = 0;
- for (pos++; pos < len && (data[pos] != ')' || nest); pos++)
- switch (data[pos]) {
- case '(': nest++; break;
- case ')': nest--; break;
- case '\\':
- if (pos + 1 < len)
- pos++;
- break;
- case '\n': line++; break;
- case '\r':
- if (pos + 1 == len || data[pos+1] != '\n')
- line++;
- break;
- }
- pos_in = (pos < len ? pos + 1 : len);
- return s.substring(first, pos_in - first);
- } else {
- int first = pos;
- while (pos < len && data[pos] == '/')
- pos++;
- while (pos < len && data[pos] != '/' && !isspace((unsigned char) data[pos]) && data[pos] != '[' && data[pos] != ']' && data[pos] != '%' && data[pos] != '(' && data[pos] != '{' && data[pos] != '}')
- pos++;
- pos_in = pos;
- return s.substring(first, pos - first);
- }
- }
-}
-
-
-static String
-comment_tokenize(const String &s, int &pos_in, int &line)
-{
- const char *data = s.data();
- int len = s.length();
- int pos = pos_in;
- while (1) {
- while (pos < len && data[pos] != '%' && data[pos] != '(') {
- if (data[pos] == '\n')
- line++;
- else if (data[pos] == '\r' && (pos + 1 == len || data[pos+1] != '\n'))
- line++;
- pos++;
- }
-
- if (pos >= len) {
- pos_in = len;
- return String();
- } else if (data[pos] == '%') {
- for (pos++; pos < len && (data[pos] == ' ' || data[pos] == '\t'); pos++)
- /* nada */;
- int first = pos;
- for (; pos < len && data[pos] != '\n' && data[pos] != '\r'; pos++)
- /* nada */;
- pos_in = pos;
- if (pos > first)
- return s.substring(first, pos - first);
- } else {
- int nest = 0;
- for (pos++; pos < len && (data[pos] != ')' || nest); pos++)
- switch (data[pos]) {
- case '(': nest++; break;
- case ')': nest--; break;
- case '\\':
- if (pos + 1 < len)
- pos++;
- break;
- case '\n': line++; break;
- case '\r':
- if (pos + 1 == len || data[pos+1] != '\n')
- line++;
- break;
- }
- }
- }
-}
-
-static bool
-retokenize_isword(char c)
-{
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
- || (c >= '0' && c <= '9') || c == '.' || c == '_';
-}
-
-
-static struct { const char *s; int v; } ligkern_ops[] = {
- { "=:", DvipsEncoding::JL_LIG }, { "|=:", DvipsEncoding::JL_CLIG },
- { "|=:>", DvipsEncoding::JL_CLIG_S }, { "=:|", DvipsEncoding::JL_LIGC },
- { "=:|>", DvipsEncoding::JL_LIGC_S }, { "|=:|", DvipsEncoding::JL_CLIGC },
- { "|=:>", DvipsEncoding::JL_CLIGC_S }, { "|=:|>>", DvipsEncoding::JL_CLIGC_SS },
- { "{}", DvipsEncoding::JT_KERN }, { "{K}", DvipsEncoding::JT_KERN },
- { "{L}", DvipsEncoding::JT_LIG }, { "{LK}", DvipsEncoding::JT_NOLIGKERN },
- { "{KL}", DvipsEncoding::JT_NOLIGKERN }, { "{k}", DvipsEncoding::JT_KERN },
- { "{l}", DvipsEncoding::JT_LIG }, { "{lk}", DvipsEncoding::JT_NOLIGKERN },
- { "{kl}", DvipsEncoding::JT_NOLIGKERN },
- // some encodings have @{@} instead of {}
- { "@{@}", DvipsEncoding::JT_KERN },
- { 0, 0 }
-};
-
-static int
-find_ligkern_op(const String &s)
-{
- for (int i = 0; ligkern_ops[i].s; i++)
- if (ligkern_ops[i].s == s)
- return ligkern_ops[i].v;
- return 0;
-}
-
-inline bool
-operator==(const DvipsEncoding::Ligature& l1, const DvipsEncoding::Ligature& l2)
-{
- return l1.c1 == l2.c1 && l1.c2 == l2.c2;
-}
-
-void
-DvipsEncoding::add_ligkern(const Ligature &l, int override)
-{
- Ligature *old = std::find(_lig.begin(), _lig.end(), l);
- if (old == _lig.end())
- _lig.push_back(l);
- else {
- if ((l.join & JT_KERN) && (override > 0 || !(old->join & JT_KERN))) {
- old->join |= JT_KERN;
- old->k = l.k;
- }
- if ((l.join & JT_LIG) && (override > 0 || !(old->join & JT_LIG))) {
- old->join = (old->join & JT_KERN) | (l.join & JT_LIGALL);
- old->d = l.d;
- }
- }
-}
-
-int
-DvipsEncoding::parse_ligkern_words(Vector<String> &v, int override, ErrorHandler *errh)
-{
- _file_had_ligkern = true;
- int op;
- long l;
- char *endptr;
- if (v.size() == 3) {
- // empty string fails
- if (!v[0])
- return -1;
- // boundary char setting
- if (v[0] == "||" && v[1] == "=") {
- char *endptr;
- if (override > 0 || _boundary_char < 0)
- _boundary_char = strtol(v[2].c_str(), &endptr, 10);
- if (*endptr == 0 && _boundary_char < _e.size())
- return 0;
- else
- return errh->error("parse error in boundary character assignment");
- }
- // altselector char setting
- if (v[0] == "^^" && v[1] == "=") {
- char *endptr;
- if (override > 0 || _altselector_char < 0)
- _altselector_char = strtol(v[2].c_str(), &endptr, 10);
- if (*endptr == 0 && _altselector_char < _e.size())
- return 0;
- else
- return errh->error("parse error in altselector character assignment");
- }
- // encoding
- l = strtol(v[0].c_str(), &endptr, 0);
- if (endptr == v[0].end() && v[1] == "=") {
- if (l >= 0 && l < 256) {
- if (override > 0 || !_e[l])
- encode(l, v[2]);
- return 0;
- } else
- return errh->error("encoding value %<%d%> out of range", l);
- }
-
- // kern operation
- if (v[1].length() >= 3 && v[1][0] == '{' && v[1].back() == '}') {
- String middle = v[1].substring(1, v[1].length() - 2);
- l = strtol(middle.c_str(), &endptr, 0);
- if (endptr == middle.end()) {
- op = JT_KERN;
- goto found_kernop;
- }
- }
- op = find_ligkern_op(v[1]);
- if (!op || (op & JT_ADDLIG))
- return -1;
- found_kernop:
- int av = (v[0] == "*" ? J_ALL : encoding_of(v[0]));
- if (av < 0)
- return errh->warning("bad %<%s%> (%<%s%> has no encoding)", v[1].c_str(), v[0].c_str());
- int bv = (v[2] == "*" ? J_ALL : encoding_of(v[2]));
- if (bv < 0)
- return errh->warning("bad %<%s%> (%<%s%> has no encoding)", v[1].c_str(), v[2].c_str());
- if ((op & JT_KERN) && l && (av == J_ALL || bv == J_ALL))
- return errh->warning("%<%s %s %s%> illegal, only {0} works with *", v[0].c_str(), v[1].c_str(), v[2].c_str());
- Ligature lig = { av, bv, op, static_cast<int>(l), 0 };
- add_ligkern(lig, override);
- return 0;
-
- } else if (v.size() == 4 && ((op = find_ligkern_op(v[2])) & JT_ADDLIG)) {
- int av = encoding_of(v[0], override > 0);
- if (av < 0)
- return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[0].c_str()) : -1);
- int bv = encoding_of(v[1], override > 0);
- if (bv < 0)
- return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[1].c_str()) : -1);
- int cv = encoding_of(v[3], override > 0);
- if (cv < 0)
- return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[3].c_str()) : -1);
- Ligature lig = { av, bv, op, 0, cv };
- add_ligkern(lig, override);
- return 0;
-
- } else
- return -EPARSE;
-}
-
-int
-DvipsEncoding::parse_position_words(Vector<String> &v, int override, ErrorHandler *errh)
-{
- if (v.size() != 4)
- return -EPARSE;
-
- int c = encoding_of(v[0]);
- if (c < 0)
- return (override > 0 ? errh->warning("bad positioning (%<%s%> has no encoding)", v[0].c_str()) : -1);
-
- char *endptr;
- int pdx, pdy, adx;
- if (!v[1] || !v[2] || !v[3]
- || (pdx = strtol(v[1].c_str(), &endptr, 10), *endptr)
- || (pdy = strtol(v[2].c_str(), &endptr, 10), *endptr)
- || (adx = strtol(v[3].c_str(), &endptr, 10), *endptr))
- return errh->error("parse error in POSITION");
-
- Ligature l = { c, pdx, pdy, adx, 0 };
- Ligature *old = std::find(_pos.begin(), _pos.end(), l);
- if (old == _pos.end())
- _pos.push_back(l);
- else if (override > 0)
- *old = l;
- return 0;
-}
-
-int
-DvipsEncoding::parse_unicoding_words(Vector<String> &v, int override, ErrorHandler *errh)
-{
- int av;
- if (v.size() < 2 || (v[1] != "=" && v[1] != "=:" && v[1] != ":="))
- return -EPARSE;
- else if (v[0] == "||" || (av = encoding_of(v[0])) < 0)
- return errh->warning("bad UNICODING (%<%s%> has no encoding)", v[0].c_str());
-
- int original_size = _unicoding.size();
-
- if (v.size() == 2 || (v.size() == 3 && v[2] == dot_notdef))
- /* no warnings to delete a glyph */;
- else {
- for (int i = 2; i < v.size(); i++) {
- if (_unicoding.size() != original_size)
- _unicoding.push_back(GLYPHLIST_ALTERNATIVE);
- if (!glyphname_unicode(v[i], _unicoding)) {
- errh->warning("can%,t map %<%s%> to Unicode", v[i].c_str());
- if (i == v.size() - 1 && _unicoding.size() == original_size)
- errh->warning("target %<%s%> will be deleted from encoding", v[0].c_str());
- else if (_unicoding.size() != original_size)
- _unicoding.pop_back();
- }
- }
- }
-
- _unicoding.push_back(0);
- if (override > 0 || _unicoding_map[v[0]] < 0)
- _unicoding_map.insert(v[0], original_size);
- return 0;
-}
-
-const DvipsEncoding::WordType DvipsEncoding::word_types[] = {
- { "LIGKERN", &DvipsEncoding::parse_ligkern_words },
- { "POSITION", &DvipsEncoding::parse_position_words },
- { "UNICODING", &DvipsEncoding::parse_unicoding_words }
-};
-
-void
-DvipsEncoding::parse_word_group(Vector<String> &words, int override, int wt, ErrorHandler *errh)
-{
- if (words.size() > 0) {
- int (DvipsEncoding::*method)(Vector<String> &, int, ErrorHandler *) = word_types[wt].parsefunc;
- if ((this->*method)(words, override, errh) == -EPARSE) {
- Vector<String> rewords;
- for (String *sp = words.begin(); sp != words.end(); sp++) {
- const char *s = sp->begin(), *ends = sp->end();
- while (s != ends) {
- const char *word = s;
- if (*s == '{') {
- for (s++; s != ends && *s != '}'; s++)
- /* nada */;
- if (s != ends)
- s++;
- } else {
- bool x = retokenize_isword(*s);
- for (s++; s != ends && x == retokenize_isword(*s); s++)
- /* nada */;
- }
- rewords.push_back(sp->substring(word, s));
- }
- }
- if ((this->*method)(rewords, override, errh) == -EPARSE)
- errh->error("parse error in %s", word_types[wt].name);
-
- }
- words.clear();
- }
-}
-
-int
-DvipsEncoding::parse_words(const String &s, int override, int wt, ErrorHandler *errh)
-{
- Vector<String> words;
- const char *data = s.data();
- const char *end = s.end();
- while (data < end) {
- while (data < end && isspace((unsigned char) *data))
- data++;
- const char *first = data;
- while (data < end && !isspace((unsigned char) *data) && *data != ';')
- data++;
- if (data == first) {
- data++; // step past semicolon (or harmlessly past EOS)
- parse_word_group(words, override, wt, errh);
- } else
- words.push_back(s.substring(first, data));
- }
- parse_word_group(words, override, wt, errh);
- return 0;
-}
-
-String
-DvipsEncoding::landmark(int line) const
-{
- StringAccum sa;
- sa << _printable_filename << ':' << line;
- return sa.take_string();
-}
-
-static String
-trim_space(const String &s, int pos)
-{
- while (pos < s.length() && isspace((unsigned char) s[pos]))
- pos++;
- int epos = s.length();
- for (int x = 0; x < 2; x++) {
- while (epos > pos && isspace((unsigned char) s[epos - 1]))
- epos--;
- if (epos == pos || s[epos - 1] != ';')
- break;
- epos--;
- }
- return s.substring(pos, epos - pos);
-}
-
-int
-DvipsEncoding::parse(String filename, bool ignore_ligkern, bool ignore_other, ErrorHandler *errh)
-{
- int before = errh->nerrors();
- String s = read_file(filename, errh);
- if (errh->nerrors() != before)
- return -1;
- _filename = filename;
- _printable_filename = printable_filename(filename);
- _file_had_ligkern = false;
- int pos = 0, line = 1;
-
- // parse text
- String token = tokenize(s, pos, line);
- if (!token || token[0] != '/')
- return errh->lerror(landmark(line), "parse error, expected name");
- _name = token.substring(1);
- _initial_comment = s.substring(0, pos - token.length());
-
- if (tokenize(s, pos, line) != "[")
- return errh->lerror(landmark(line), "parse error, expected [");
-
- while ((token = tokenize(s, pos, line)) && token[0] == '/')
- _e.push_back(token.substring(1));
-
- _final_text = token + s.substring(pos);
-
- // now parse comments
- pos = 0, line = 1;
- Vector<String> words;
- LandmarkErrorHandler lerrh(errh, "");
- while ((token = comment_tokenize(s, pos, line)))
- if (token.length() >= 8
- && memcmp(token.data(), "LIGKERN", 7) == 0
- && isspace((unsigned char) token[7])
- && !ignore_ligkern) {
- lerrh.set_landmark(landmark(line));
- parse_words(token.substring(8), 1, WT_LIGKERN, &lerrh);
-
- } else if (token.length() >= 9
- && memcmp(token.data(), "LIGKERNX", 8) == 0
- && isspace((unsigned char) token[8])
- && !ignore_ligkern) {
- lerrh.set_landmark(landmark(line));
- parse_words(token.substring(9), 1, WT_LIGKERN, &lerrh);
-
- } else if (token.length() >= 10
- && memcmp(token.data(), "UNICODING", 9) == 0
- && isspace((unsigned char) token[9])
- && !ignore_other) {
- lerrh.set_landmark(landmark(line));
- parse_words(token.substring(10), 1, WT_UNICODING, &lerrh);
-
- } else if (token.length() >= 9
- && memcmp(token.data(), "POSITION", 8) == 0
- && isspace((unsigned char) token[8])
- && !ignore_other) {
- lerrh.set_landmark(landmark(line));
- parse_words(token.substring(9), 1, WT_POSITION, &lerrh);
-
- } else if (token.length() >= 13
- && memcmp(token.data(), "CODINGSCHEME", 12) == 0
- && isspace((unsigned char) token[12])
- && !ignore_other) {
- _coding_scheme = trim_space(token, 13);
- if (_coding_scheme.length() > 39)
- lerrh.lwarning(landmark(line), "only first 39 chars of CODINGSCHEME are significant");
- if (std::find(_coding_scheme.begin(), _coding_scheme.end(), '(') < _coding_scheme.end()
- || std::find(_coding_scheme.begin(), _coding_scheme.end(), ')') < _coding_scheme.end()) {
- lerrh.lerror(landmark(line), "CODINGSCHEME cannot contain parentheses");
- _coding_scheme = String();
- }
-
- } else if (token.length() >= 11
- && memcmp(token.data(), "WARNMISSING", 11) == 0
- && (token.length() == 11 || isspace((unsigned char) token[11]))
- && !ignore_other) {
- String value = trim_space(token, 11);
- if (value == "1" || value == "yes" || value == "true" || !value)
- _warn_missing = true;
- else if (value == "0" || value == "no" || value == "false")
- _warn_missing = false;
- else
- lerrh.lerror(landmark(line), "WARNMISSING command not understood");
- }
-
- return 0;
-}
-
-int
-DvipsEncoding::parse_ligkern(const String &ligkern_text, int override, ErrorHandler *errh)
-{
- return parse_words(ligkern_text, override, WT_LIGKERN, errh);
-}
-
-int
-DvipsEncoding::parse_position(const String &position_text, int override, ErrorHandler *errh)
-{
- return parse_words(position_text, override, WT_POSITION, errh);
-}
-
-int
-DvipsEncoding::parse_unicoding(const String &unicoding_text, int override, ErrorHandler *errh)
-{
- return parse_words(unicoding_text, override, WT_UNICODING, errh);
-}
-
-void
-DvipsEncoding::bad_codepoint(int code, Metrics &metrics, HashMap<PermString, int> &unencoded)
-{
- for (int i = 0; i < _lig.size(); i++) {
- Ligature &l = _lig[i];
- if (l.c1 == code || l.c2 == code)
- l.join = 0;
- else if ((l.join & JT_ADDLIG) && l.d == code)
- l.join &= ~JT_LIGALL;
- }
-
- if (_warn_missing) {
- Vector<uint32_t> garbage;
- bool unicodes_explicit = x_unicodes(_e[code], garbage);
- if (!unicodes_explicit || garbage.size() > 0) {
- Vector<Setting> v;
- v.push_back(Setting(Setting::RULE, 500, 500));
- v.push_back(Setting(Setting::SPECIAL, String("Warning: missing glyph '") + _e[code] + "'"));
- metrics.encode_virtual(code, _e[code], 0, v, true);
- unencoded.insert(_e[code], 1);
- }
- }
-}
-
-static inline Efont::OpenType::Glyph
-map_uni(uint32_t uni, const Efont::OpenType::Cmap &cmap, const Metrics &m)
-{
- if (uni == U_EMPTYSLOT)
- return m.emptyslot_glyph();
- else
- return cmap.map_uni(uni);
-}
-
-bool
-DvipsEncoding::x_unicodes(PermString chname, Vector<uint32_t> &unicodes) const
-{
- int i = _unicoding_map[chname];
- if (i >= 0) {
- for (; _unicoding[i] > 0; i++)
- unicodes.push_back(_unicoding[i]);
- return true;
- } else {
- glyphname_unicode(chname, unicodes);
- return false;
- }
-}
-
-
-void
-DvipsEncoding::make_metrics(Metrics &metrics, const FontInfo &finfo, Secondary *secondary, bool literal, ErrorHandler *errh)
-{
- // first pass: without secondaries
- for (int code = 0; code < _e.size(); code++) {
- PermString chname = _e[code];
-
- // common case: skip .notdef
- if (chname == dot_notdef)
- continue;
-
- // find first single Unicode glyph supported by the font
- Efont::OpenType::Glyph glyph = 0;
- uint32_t glyph_uni = 0;
- {
- Vector<uint32_t> unicodes;
- (void) x_unicodes(chname, unicodes);
- Vector<uint32_t>::iterator u = unicodes.begin();
- while (u != unicodes.end() && glyph <= 0) {
- uint32_t this_uni = u[0];
- ++u;
- if (u != unicodes.end()) {
- if (*u != GLYPHLIST_ALTERNATIVE)
- break;
- ++u;
- }
-
- glyph = map_uni(this_uni, *finfo.cmap, metrics);
- if (glyph_uni == 0 || glyph > 0)
- glyph_uni = this_uni;
- }
- }
-
- // find named glyph, if any
- Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
-#if 0
- // 2.May.2008: ff, fi, fl, ffi, and ffl might map to f_f, f_i, f_l,
- // f_f_i, and f_f_l
- if (!named_glyph && chname.length() > 0 && chname.length() <= 3
- && chname[0] == 'f') {
- if (chname.equals("ff", 2))
- named_glyph = finfo.glyphid("f_f");
- else if (chname.equals("fi", 2))
- named_glyph = finfo.glyphid("f_i");
- else if (chname.equals("fl", 2))
- named_glyph = finfo.glyphid("f_l");
- else if (chname.equals("ffi", 2))
- named_glyph = finfo.glyphid("f_f_i");
- else if (chname.equals("ffl", 2))
- named_glyph = finfo.glyphid("f_f_l");
- }
-#endif
- // do not use a Unicode-mapped glyph if literal
- if (literal)
- glyph = named_glyph;
-
- // If we found a glyph, maybe use its named_glyph variant.
- if (glyph > 0 && named_glyph > 0
- && std::find(chname.begin(), chname.end(), '.') < chname.end())
- glyph = named_glyph;
-
- // assign slot
- if (glyph > 0)
- metrics.encode(code, glyph_uni, glyph);
- }
-
- // second pass: with secondaries
- for (int code = 0; code < _e.size(); code++) {
- // skip already-encoded characters and .notdef
- if (literal || metrics.glyph(code) > 0 || _e[code] == dot_notdef)
- continue;
-
- PermString chname = _e[code];
-
- // find all Unicodes
- Vector<uint32_t> unicodes;
- bool unicodes_explicit = x_unicodes(chname, unicodes);
-
- // find named glyph, if any
- Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
-
- // 1. We were not able to find the glyph using Unicode.
- // 2. There might be a named_glyph.
- // May need to try secondaries later. Store this slot.
- // Try secondaries, if there's explicit unicoding or no named_glyph.
- if (unicodes_explicit || named_glyph <= 0)
- for (uint32_t *u = unicodes.begin(); u != unicodes.end(); ) {
- uint32_t *endu = u + 1;
- while (endu != unicodes.end() && *endu != GLYPHLIST_ALTERNATIVE)
- ++endu;
- if (secondary->encode_uni(code, chname, u, endu, metrics, errh))
- goto encoded;
- u = (endu == unicodes.end() ? endu : endu + 1);
- }
-
- // 1. We were not able to find the glyph using Unicode or secondaries.
- // 2. There might be a named_glyph.
- // Use named glyph, if any. Special case for "UNICODING foo =: ;",
- // which should turn off the character (even if a named_glyph exists),
- // UNLESS the glyph was explicitly requested.
- if (named_glyph > 0
- && (!unicodes_explicit
- || unicodes.size() > 0
- || (_encoding_required.size() > code && _encoding_required[code]))) {
- uint32_t uni = 0;
- if (unicodes.size() == 1 || (unicodes.size() > 0 && unicodes[1] == GLYPHLIST_ALTERNATIVE))
- uni = unicodes[0];
- metrics.encode(code, uni, named_glyph);
- }
-
- encoded:
- /* all set */;
- }
-
- // add altselector
- if (_altselector_char >= 0 && _altselector_char < _e.size()) {
- metrics.add_altselector_code(_altselector_char, 0);
- if (metrics.glyph(_altselector_char) <= 0 && !literal)
- (void) secondary->encode_uni(_altselector_char, "<altselector>", U_ALTSELECTOR, metrics, errh);
- }
-
- // final pass: complain
- HashMap<PermString, int> unencoded_map;
- for (int code = 0; code < _e.size(); code++)
- if (_e[code] != dot_notdef && metrics.glyph(code) <= 0)
- bad_codepoint(code, metrics, unencoded_map);
- Vector<String> unencoded;
- for (HashMap<PermString, int>::iterator it = unencoded_map.begin(); it; ++it)
- unencoded.push_back(it.key());
-
- if (unencoded.size() == 1) {
- errh->warning("%<%s%> glyph not found in font", unencoded[0].c_str());
- errh->message("(This glyph will appear as a blot and cause warnings if used.)");
- } else if (unencoded.size() > 1) {
- std::sort(unencoded.begin(), unencoded.end());
- StringAccum sa;
- for (const String* a = unencoded.begin(); a < unencoded.end(); a++)
- sa << *a << ' ';
- sa.pop_back();
- sa.append_break_lines(sa.take_string(), 68, " ");
- sa.pop_back();
- errh->warning("%d glyphs not found in font:", unencoded.size());
- errh->message("%s\n(These glyphs will appear as blots and cause warnings if used.)", sa.c_str());
- }
-
- metrics.set_coding_scheme(_coding_scheme);
-}
-
-void
-DvipsEncoding::make_base_mappings(Vector<int> &mappings, const FontInfo &finfo)
-{
- mappings.clear();
- for (int code = 0; code < _e.size(); code++) {
- PermString chname = _e[code];
-
- // common case: skip .notdef
- if (chname == dot_notdef)
- continue;
-
- // find named glyph
- Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
- if (named_glyph > 0) {
- if (mappings.size() <= named_glyph)
- mappings.resize(named_glyph + 1, -1);
- mappings[named_glyph] = code;
- }
- }
-}
-
-
-void
-DvipsEncoding::apply_ligkern_lig(Metrics &metrics, ErrorHandler *errh) const
-{
- assert((int)J_ALL == (int)Metrics::CODE_ALL);
- for (const Ligature *l = _lig.begin(); l < _lig.end(); l++) {
- if (l->c1 < 0 || l->c2 < 0 || l->join < 0 || !(l->join & JT_LIG))
- continue;
- metrics.remove_ligatures(l->c1, l->c2);
- if (!(l->join & JT_ADDLIG))
- /* nada */;
- else if ((l->join & JT_LIGALL) == JL_LIG)
- metrics.add_ligature(l->c1, l->c2, l->d);
- else if ((l->join & JT_LIGALL) == JL_LIGC)
- metrics.add_ligature(l->c1, l->c2, metrics.pair_code(l->d, l->c2));
- else if ((l->join & JT_LIGALL) == JL_CLIG)
- metrics.add_ligature(l->c1, l->c2, metrics.pair_code(l->c1, l->d));
- else {
- static int complex_join_warning = 0;
- if (!complex_join_warning) {
- errh->warning("complex LIGKERN ligature removed (I only support %<=:%>, %<=:|%>, and %<|=:%>)");
- complex_join_warning = 1;
- }
- }
- }
-}
-
-void
-DvipsEncoding::apply_ligkern_kern(Metrics &metrics, ErrorHandler *) const
-{
- assert((int)J_ALL == (int)Metrics::CODE_ALL);
- for (const Ligature *l = _lig.begin(); l < _lig.end(); l++)
- if (l->c1 >= 0 && l->c2 >= 0 && (l->join & JT_KERN))
- metrics.set_kern(l->c1, l->c2, l->k);
-}
-
-void
-DvipsEncoding::apply_position(Metrics &metrics, ErrorHandler *) const
-{
- for (const Ligature *l = _pos.begin(); l < _pos.end(); l++)
- if (l->c1 >= 0)
- metrics.add_single_positioning(l->c1, l->c2, l->join, l->k);
-}