summaryrefslogtreecommitdiff
path: root/Build/source/utils/lcdf-typetools/libefont/otf.cc
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-11-26 01:57:09 +0000
committerKarl Berry <karl@freefriends.org>2006-11-26 01:57:09 +0000
commit31ff7ecb412ee470d0464bb210a0e9adabed065a (patch)
tree3a6d93ad2c99327f924b7b916db51314d98572b0 /Build/source/utils/lcdf-typetools/libefont/otf.cc
parentbc57bba3992e10b518e1578cef31afba9b226bfa (diff)
update to lcdf-typetools 2.46
git-svn-id: svn://tug.org/texlive/trunk@2536 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/lcdf-typetools/libefont/otf.cc')
-rw-r--r--Build/source/utils/lcdf-typetools/libefont/otf.cc192
1 files changed, 180 insertions, 12 deletions
diff --git a/Build/source/utils/lcdf-typetools/libefont/otf.cc b/Build/source/utils/lcdf-typetools/libefont/otf.cc
index 22987bee00b..6b23caf7c64 100644
--- a/Build/source/utils/lcdf-typetools/libefont/otf.cc
+++ b/Build/source/utils/lcdf-typetools/libefont/otf.cc
@@ -2,7 +2,7 @@
/* otf.{cc,hh} -- OpenType font basics
*
- * Copyright (c) 2002-2004 Eddie Kohler
+ * Copyright (c) 2002-2006 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
@@ -24,6 +24,7 @@
#include <string.h>
#include <algorithm>
#include <efont/otfdata.hh> // for ntohl()
+#include <efont/otfname.hh>
#ifndef static_assert
#define static_assert(c) switch (c) case 0: case (c):
@@ -41,7 +42,7 @@ Font::Font(const String &s, ErrorHandler *errh)
: _str(s)
{
_str.align(4);
- _error = parse_header(errh ? errh : ErrorHandler::silent_handler());
+ _error = parse_header(errh ? errh : ErrorHandler::ignore_handler());
}
int
@@ -87,6 +88,38 @@ Font::parse_header(ErrorHandler *errh)
return 0;
}
+bool
+Font::check_checksums(ErrorHandler *errh) const
+{
+ if (error() < 0)
+ return false;
+ int nt = ntables();
+ bool ok = true;
+ for (int i = 0; i < nt; i++) {
+ const uint8_t *entry = data() + HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * i;
+ String tbl = _str.substring(ULONG_AT(entry + 8), ULONG_AT(entry + 12));
+ uint32_t sum = checksum(tbl);
+ if (ULONG_AT(entry) == 0x68656164 // 'head'
+ && tbl.length() >= 12)
+ sum -= ULONG_AT(tbl.data() + 8);
+ if (sum != ULONG_AT(entry + 4)) {
+ if (errh)
+ errh->error("table '%s' checksum error: %x vs. %x", Tag(ULONG_AT(entry)).text().c_str(), sum, ULONG_AT(entry + 4));
+ ok = false;
+ }
+ }
+ return ok;
+}
+
+int
+Font::ntables() const
+{
+ if (error() < 0)
+ return 0;
+ else
+ return USHORT_AT(data() + 4);
+}
+
String
Font::table(Tag tag) const
{
@@ -99,13 +132,16 @@ Font::table(Tag tag) const
return String();
}
-int
-Font::ntables() const
+uint32_t
+Font::table_checksum(Tag tag) const
{
if (error() < 0)
- return 0;
+ return String();
+ const uint8_t *entry = tag.table_entry(data() + HEADER_SIZE, USHORT_AT(data() + 4), TABLE_DIR_ENTRY_SIZE);
+ if (entry)
+ return ULONG_AT(entry + 4);
else
- return USHORT_AT(data() + 4);
+ return 0;
}
Tag
@@ -117,6 +153,111 @@ Font::table_tag(int i) const
return Tag(ULONG_AT(data() + HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * i));
}
+uint32_t
+Font::checksum(const uint8_t *begin, const uint8_t *end)
+{
+ uint32_t sum = 0;
+ if (reinterpret_cast<uintptr_t>(begin) % 4)
+ for (; begin + 3 < end; begin += 4)
+ sum += (begin[0] << 24) + (begin[1] << 16) + (begin[2] << 8) + begin[3];
+ else
+ for (; begin + 3 < end; begin += 4)
+ sum += ULONG_AT(begin);
+ uint32_t leftover = 0;
+ for (int i = 0; i < 4; i++)
+ leftover = (leftover << 8) + (begin < end ? *begin++ : 0);
+ return sum + leftover;
+}
+
+uint32_t
+Font::checksum(const String &s)
+{
+ return checksum(reinterpret_cast<const uint8_t *>(s.begin()), reinterpret_cast<const uint8_t *>(s.end()));
+}
+
+namespace {
+class TagCompar { public:
+ TagCompar(const Vector<Tag> &tags) : _tags(tags) { }
+ bool operator()(int a, int b) { return _tags[a] < _tags[b]; }
+ const Vector<Tag> &_tags;
+};
+}
+
+Font
+Font::make(bool truetype, const Vector<Tag>& tags, const Vector<String>& data)
+{
+ StringAccum sa;
+
+ // create offset table
+ {
+ union {
+ uint8_t c[HEADER_SIZE];
+ uint16_t s[HEADER_SIZE / 2];
+ uint32_t l[HEADER_SIZE / 4];
+ } hdr;
+ hdr.l[0] = (truetype ? htonl(0x00010000) : htonl(0x4F54544F));
+ hdr.s[2] = htons(tags.size());
+ int entrySelector;
+ for (entrySelector = 0; (2 << entrySelector) <= tags.size(); entrySelector++)
+ /* nada */;
+ hdr.s[3] = htons((1 << entrySelector) * 16);
+ hdr.s[4] = htons(entrySelector);
+ hdr.s[5] = htons((tags.size() - (1 << entrySelector)) * 16);
+ sa.append(&hdr.c[0], HEADER_SIZE);
+ }
+
+ // sort tags
+ Vector<int> permut;
+ for (int i = 0; i < tags.size(); i++)
+ permut.push_back(i);
+ std::sort(permut.begin(), permut.end(), TagCompar(tags));
+
+ // table listing
+ uint32_t offset = HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * tags.size();
+ for (int *tp = permut.begin(); tp < permut.end(); tp++) {
+ union {
+ uint8_t c[TABLE_DIR_ENTRY_SIZE];
+ uint32_t l[TABLE_DIR_ENTRY_SIZE / 4];
+ } tdir;
+ tdir.l[0] = htonl(tags[*tp].value());
+
+ // discount current checksum adjustment in head table
+ uint32_t sum = checksum(data[*tp]);
+ if (tags[*tp] == Tag("head") && data[*tp].length() >= 12) {
+ const uint8_t *x = data[*tp].udata() + 8;
+ sum -= (x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3];
+ }
+ tdir.l[1] = htonl(sum);
+
+ tdir.l[2] = htonl(offset);
+ tdir.l[3] = htonl(data[*tp].length());
+ sa.append(&tdir.c[0], TABLE_DIR_ENTRY_SIZE);
+ offset += (data[*tp].length() + 3) & ~3;
+ }
+
+ // actual tables
+ for (int *tp = permut.begin(); tp < permut.end(); tp++) {
+ sa << data[*tp];
+ while (sa.length() % 4)
+ sa << '\0';
+ }
+
+ // fix 'head' table
+ for (int i = 0; i < tags.size(); i++) {
+ char *thdr = sa.data() + HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * i;
+ if (ULONG_AT(thdr) == 0x68656164 && ULONG_AT(thdr + 12) >= 12) {
+ uint32_t offset = ULONG_AT(thdr + 8);
+ char *head = sa.data() + offset;
+ memset(head + 8, '\0', 4);
+ uint32_t allsum = checksum(reinterpret_cast<uint8_t *>(sa.data()), reinterpret_cast<uint8_t *>(sa.data() + sa.length()));
+ uint32_t *adj = reinterpret_cast<uint32_t *>(head + 8);
+ *adj = htonl(0xB1B0AFBA - allsum);
+ }
+ }
+
+ return Font(sa.take_string());
+}
+
/**************************
* Tag *
@@ -223,7 +364,7 @@ ScriptList::assign(const String &str, ErrorHandler *errh)
{
_str = str;
_str.align(4);
- int result = check_header(errh ? errh : ErrorHandler::silent_handler());
+ int result = check_header(errh ? errh : ErrorHandler::ignore_handler());
if (result < 0)
_str = String();
return result;
@@ -368,7 +509,7 @@ FeatureList::assign(const String &str, ErrorHandler *errh)
{
_str = str;
_str.align(2);
- int result = check_header(errh ? errh : ErrorHandler::silent_handler());
+ int result = check_header(errh ? errh : ErrorHandler::ignore_handler());
if (result < 0)
_str = String();
return result;
@@ -404,7 +545,7 @@ FeatureList::params(int fid, int length, ErrorHandler *errh, bool old_style_offs
if (_str.length() == 0 || length < 0)
return String();
if (errh == 0)
- errh = ErrorHandler::silent_handler();
+ errh = ErrorHandler::ignore_handler();
const uint8_t *data = _str.udata();
int len = _str.length();
@@ -425,6 +566,33 @@ FeatureList::params(int fid, int length, ErrorHandler *errh, bool old_style_offs
return _str.substring(poff, length);
}
+String
+FeatureList::size_params(int fid, const Name &name, ErrorHandler *errh) const
+{
+ // implement 'size' checks from Read Roberts
+ for (int i = 0; i < 2; i++) {
+ String s = params(fid, 10, errh, i != 0);
+ const uint8_t *data = s.udata();
+ if (USHORT_AT(data) == 0) // design size == 0
+ continue;
+ if (USHORT_AT(data + 2) == 0 // subfamily ID == 0
+ && USHORT_AT(data + 6) == 0 // range start == 0
+ && USHORT_AT(data + 8) == 0 // range end == 0
+ && USHORT_AT(data + 4) == 0) // menu name ID == 0
+ return s;
+ if (USHORT_AT(data) >= USHORT_AT(data + 6) // design size >= range start
+ && USHORT_AT(data) <= USHORT_AT(data + 8) // design size <= range end
+ && USHORT_AT(data + 6) < USHORT_AT(data + 8) // range start < range end
+ && USHORT_AT(data + 4) >= 256 // menu name ID >= 256
+ && USHORT_AT(data + 4) <= 32767 // menu name ID <= 32767
+ && name.english_name(USHORT_AT(data + 4))) // menu name ID is a name ID defined by the font
+ return s;
+ }
+ if (errh)
+ errh->error("no valid 'size' feature data in the 'size' feature");
+ return String();
+}
+
int
FeatureList::find(Tag tag, const Vector<int> &fids) const
{
@@ -486,7 +654,7 @@ FeatureList::lookups(int fid, Vector<int> &results, ErrorHandler *errh, bool cle
if (_str.length() == 0)
return -1;
if (errh == 0)
- errh = ErrorHandler::silent_handler();
+ errh = ErrorHandler::ignore_handler();
const uint8_t *data = _str.udata();
int len = _str.length();
@@ -587,7 +755,7 @@ Coverage::Coverage(const String &str, ErrorHandler *errh, bool do_check) throw (
{
_str.align(2);
if (do_check) {
- if (check(errh ? errh : ErrorHandler::silent_handler()) < 0)
+ if (check(errh ? errh : ErrorHandler::ignore_handler()) < 0)
_str = String();
} else { // check()'s shorten-string side effect
const uint8_t *data = _str.udata();
@@ -987,7 +1155,7 @@ ClassDef::ClassDef(const String &str, ErrorHandler *errh) throw ()
: _str(str)
{
_str.align(2);
- if (check(errh ? errh : ErrorHandler::silent_handler()) < 0)
+ if (check(errh ? errh : ErrorHandler::ignore_handler()) < 0)
_str = String();
}