summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/otftotfm/glyphfilter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/otftotfm/glyphfilter.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/otftotfm/glyphfilter.cc236
1 files changed, 236 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/otftotfm/glyphfilter.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/otftotfm/glyphfilter.cc
new file mode 100644
index 00000000000..a4120660bfc
--- /dev/null
+++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/otftotfm/glyphfilter.cc
@@ -0,0 +1,236 @@
+/* glyphfilter.{cc,hh} -- define subsets of characters
+ *
+ * Copyright (c) 2004-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
+#ifdef WIN32
+# define _USE_MATH_DEFINES
+#endif
+#include "glyphfilter.hh"
+#include <lcdf/error.hh>
+#include <lcdf/straccum.hh>
+#include <ctype.h>
+#include <algorithm>
+#include "uniprop.hh"
+#include "util.hh"
+
+bool
+GlyphFilter::allow(Efont::OpenType::Glyph glyph, const Vector<PermString>& glyph_names, uint32_t unicode, int ptype) const
+{
+ // out-of-range glyphs never match
+ if (glyph < 0 || glyph >= glyph_names.size())
+ return false;
+
+ String glyph_name = glyph_names[glyph];
+ int uniprop = -1;
+ bool any_includes = false;
+ bool included = false;
+
+ // loop over patterns
+ for (const Pattern* p = _patterns.begin(); p < _patterns.end(); p++) {
+ // check pattern type
+ if ((p->type & ~T_TYPEMASK) != ptype)
+ continue;
+ // check include/exclude
+ if ((p->type & T_EXCLUDE) == 0) {
+ if (included)
+ continue;
+ any_includes = true;
+ }
+ // check if there's a match
+ bool match;
+ if (p->data == D_NAME)
+ match = glob_match(glyph_name, p->pattern);
+ else if (p->data == D_UNIPROP) {
+ if (uniprop < 0)
+ uniprop = UnicodeProperty::property(unicode);
+ match = ((uniprop & p->u.uniprop.mask) == p->u.uniprop.value);
+ } else
+ match = (unicode >= p->u.unirange.low && unicode <= p->u.unirange.high);
+ // act if match
+ if (match == ((p->type & T_NEGATE) == 0)) {
+ if ((p->type & T_EXCLUDE) == 0)
+ included = true;
+ else
+ return false;
+ }
+ }
+
+ return !any_includes || included;
+}
+
+GlyphFilter::Pattern::Pattern(uint16_t ptype)
+ : type(ptype), data(D_NAME)
+{
+ // make sure that even unused data has a known value, to simplify
+ // operator==
+ u.unirange.low = u.unirange.high = 0;
+}
+
+int
+GlyphFilter::Pattern::compare(const GlyphFilter::Pattern& a, const GlyphFilter::Pattern& b)
+{
+ int cmp = a.type - b.type;
+ if (cmp == 0)
+ cmp = a.data - b.data;
+ if (cmp == 0)
+ cmp = (int) (a.u.unirange.low - b.u.unirange.low);
+ if (cmp == 0)
+ cmp = (int) (a.u.unirange.high - b.u.unirange.high);
+ if (cmp == 0)
+ cmp = String::compare(a.pattern, b.pattern);
+ return cmp;
+}
+
+void
+GlyphFilter::add_pattern(const String& pattern, int ptype, ErrorHandler* errh)
+{
+ _sorted = false;
+
+ const char* begin = pattern.begin();
+ const char* end = pattern.end();
+ while (begin < end && isspace((unsigned char) *begin))
+ begin++;
+ if (begin >= end)
+ errh->error("missing pattern");
+
+ while (begin < end) {
+ const char* word = begin;
+ while (word < end && !isspace((unsigned char) *word))
+ word++;
+ bool negated = false;
+ if (begin < word && begin[0] == '!')
+ negated = true, begin++;
+
+ // actually parse clause
+ Pattern p(ptype + (negated ? T_NEGATE : 0));
+
+ // unicode property
+ if (begin + 3 <= word && begin[0] == '<' && word[-1] == '>') {
+ p.data = D_UNIPROP;
+ if (UnicodeProperty::parse_property(pattern.substring(begin + 1, word - 1), p.u.uniprop.value, p.u.uniprop.mask))
+ _patterns.push_back(p);
+ else if (errh)
+ errh->error("unknown Unicode property %<%s%>", pattern.c_str());
+ goto next_clause;
+ }
+
+ // unicode values
+ {
+ const char* dash = std::find(begin, word, '-');
+ if (parse_unicode_number(begin, dash, 2, p.u.unirange.low)) {
+ if (dash == word)
+ p.u.unirange.high = p.u.unirange.low;
+ else if (dash == word - 1)
+ p.u.unirange.high = 0xFFFFFFFFU;
+ else if (parse_unicode_number(dash + 1, word, (begin[0] == 'U' ? 1 : 0), p.u.unirange.high))
+ /* do nothing */;
+ else
+ goto name_pattern; // assume it's a name
+ p.data = D_UNIRANGE;
+ _patterns.push_back(p);
+ goto next_clause;
+ }
+ }
+
+ // otherwise must be name pattern
+ name_pattern:
+ p.data = D_NAME;
+ p.pattern = pattern.substring(begin, word);
+ _patterns.push_back(p);
+
+ // move to next clause
+ next_clause:
+ for (begin = word; begin < end && isspace((unsigned char) *begin); begin++)
+ /* nada */;
+ }
+}
+
+void
+GlyphFilter::add_substitution_filter(const String& s, bool is_exclude, ErrorHandler* errh)
+{
+ add_pattern(s, is_exclude ? T_SRC + T_EXCLUDE : T_SRC, errh);
+}
+
+void
+GlyphFilter::add_alternate_filter(const String& s, bool is_exclude, ErrorHandler* errh)
+{
+ add_pattern(s, is_exclude ? T_DST + T_EXCLUDE : T_DST, errh);
+}
+
+GlyphFilter&
+GlyphFilter::operator+=(const GlyphFilter& gf)
+{
+ // be careful about self-addition
+ _patterns.reserve(gf._patterns.size());
+ const Pattern* end = gf._patterns.end();
+ for (const Pattern* p = gf._patterns.begin(); p < end; p++)
+ _patterns.push_back(*p);
+ return *this;
+}
+
+GlyphFilter
+operator+(const GlyphFilter& a, const GlyphFilter& b)
+{
+ if (!b)
+ return a;
+ if (!a)
+ return b;
+ GlyphFilter x(a);
+ x += b;
+ return x;
+}
+
+bool
+operator==(const GlyphFilter& a, const GlyphFilter& b)
+{
+ if (&a == &b)
+ return true;
+ if (a._patterns.size() != b._patterns.size())
+ return false;
+ const GlyphFilter::Pattern* pa = a._patterns.begin();
+ const GlyphFilter::Pattern* pb = b._patterns.begin();
+ for (; pa < a._patterns.end(); pa++, pb++)
+ if (!(*pa == *pb))
+ return false;
+ return true;
+}
+
+void
+GlyphFilter::sort()
+{
+ if (!_sorted) {
+ std::sort(_patterns.begin(), _patterns.end());
+ Pattern* true_end = std::unique(_patterns.begin(), _patterns.end());
+ _patterns.erase(true_end, _patterns.end());
+ _sorted = true;
+ }
+}
+
+void
+GlyphFilter::unparse(StringAccum& sa) const
+{
+ for (const Pattern* p = _patterns.begin(); p < _patterns.end(); p++) {
+ sa << (p->type & T_DST ? 'D' : 'S') << (p->type & T_NEGATE ? "!" : "") << (p->type & T_EXCLUDE ? "X" : "");
+ if (p->data == D_NAME)
+ sa << '<' << p->pattern << '>';
+ else if (p->data == D_UNIPROP)
+ sa << "[UNIPROP:" << p->u.uniprop.mask << '=' << p->u.uniprop.value << ']';
+ else
+ sa.snprintf(20, "[U+%02x-U+%02x]", p->u.unirange.low, p->u.unirange.high);
+ sa << ' ';
+ }
+ if (_patterns.size())
+ sa.pop_back();
+}