summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp175
1 files changed, 175 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp
new file mode 100644
index 00000000000..945c20bd403
--- /dev/null
+++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp
@@ -0,0 +1,175 @@
+/*************************************************************************
+** TrueTypeFont.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2021 Martin Gieseking <martin.gieseking@uos.de> **
+** **
+** 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 3 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. **
+** **
+** You should have received a copy of the GNU General Public License **
+** along with this program; if not, see <http://www.gnu.org/licenses/>. **
+*************************************************************************/
+
+#include <iterator>
+#include <sstream>
+#include <woff2/encode.h>
+#include <zlib.h>
+#include "StreamReader.hpp"
+#include "StreamWriter.hpp"
+#include "TrueTypeFont.hpp"
+#include "utility.hpp"
+
+using namespace std;
+
+
+/** Reads the font data from a TTF file.
+ * OTF specification: https://www.microsoft.com/typography/otspec/otff.htm
+ * @param[in] fname name/path of file to read
+ * @return true on success */
+bool TrueTypeFont::read (const string &fname) {
+ _tableRecords.clear();
+ _buffer = util::read_file_contents(fname);
+ if (_buffer.empty())
+ return false;
+ istringstream iss(_buffer);
+ StreamReader reader(iss);
+ _version = reader.readUnsigned(4);
+ uint16_t numTables = reader.readUnsigned(2);
+ if (numTables == 0 || _buffer.size() <= 12u+16u*numTables)
+ return false;
+
+ // read table records
+ reader.seek(12); // skip searchRange, entrySelector, and rangeShift
+ for (uint16_t i=0; i < numTables; i++) {
+ uint32_t tag = reader.readUnsigned(4);
+ uint32_t checksum = reader.readUnsigned(4);
+ uint32_t offset = reader.readUnsigned(4);
+ uint32_t length = reader.readUnsigned(4);
+ if ((offset | length) > _buffer.size() || offset+length > _buffer.size())
+ return false;
+ TTFTableRecord record = {tag, checksum, length, reinterpret_cast<const uint8_t*>(_buffer.data())+offset};
+ _tableRecords.emplace_back(std::move(record));
+ }
+ return true;
+}
+
+
+/** Compresses the data of the referenced TTF table and updated the record data accordingly.
+ * @return true if the data was compressed */
+bool TrueTypeFont::WOFFTableRecord::compressTableData () {
+ if (ttfRecord.size < 16)
+ return false;
+ uLong compressedSize = compressBound(ttfRecord.size);
+ compressedData.resize(compressedSize);
+ // Compress with zlib for now. We could also use zopfli for slightly better but much slower compression.
+ // Only use the compressed data if it actually leads to a size reduction. Otherwise, use the original table data.
+ if (compress2(compressedData.data(), &compressedSize, ttfRecord.data, ttfRecord.size, Z_BEST_COMPRESSION) != Z_OK
+ || compressedSize >= ttfRecord.size) {
+ compressedData.clear();
+ return false;
+ }
+ size = compressedSize;
+ data = compressedData.data();
+ return true;
+}
+
+
+/** Writes font data in WOFF format to a given output stream.
+ WOFF specifiction: https://www.w3.org/TR/WOFF */
+void TrueTypeFont::writeWOFF (ostream &os) const {
+ // compute WOFF table records first
+ vector<WOFFTableRecord> woffRecords;
+ uint32_t woffSize = static_cast<uint32_t>(44 + 20*_tableRecords.size());
+ uint32_t ttfSize = static_cast<uint32_t>(12 + 16*_tableRecords.size());
+ for (const TTFTableRecord &ttfRecord : _tableRecords) {
+ WOFFTableRecord woffRecord(woffSize, ttfRecord);
+ woffRecord.compressTableData();
+ woffSize += woffRecord.paddedSize();
+ ttfSize += ttfRecord.paddedSize();
+ woffRecords.emplace_back(std::move(woffRecord));
+ }
+ // write WOFF header
+ StreamWriter writer(os);
+ writer.writeUnsigned(0x774F4646, 4); // "WOFF"
+ writer.writeUnsigned(_version, 4); // version of contained TTF font
+ writer.writeUnsigned(woffSize, 4); // total length of WOFF file
+ writer.writeUnsigned(_tableRecords.size(), 2); // number of tables
+ writer.writeBytes(0, 2); // reserved
+ writer.writeUnsigned(ttfSize, 4); // size of uncompressed TTF data
+ writer.writeBytes(0, 4); // WOFF version (not required)
+ writer.writeBytes(0, 12); // offset, compressed and uncompressed size of metadata block
+ writer.writeBytes(0, 8); // offset and size of private data block
+
+ // write WOFF table directory
+ for (const WOFFTableRecord &woffRecord : woffRecords) {
+ writer.writeUnsigned(woffRecord.ttfRecord.tag, 4);
+ writer.writeUnsigned(woffRecord.offset, 4);
+ writer.writeUnsigned(woffRecord.size, 4);
+ writer.writeUnsigned(woffRecord.ttfRecord.size, 4);
+ writer.writeUnsigned(woffRecord.ttfRecord.checksum, 4);
+ }
+
+ // write WOFF tables
+ for (const WOFFTableRecord &woffRecord : woffRecords) {
+ writer.writeBytes(woffRecord.data, woffRecord.size);
+ size_t padding = woffRecord.paddedSize()-woffRecord.size;
+ writer.writeBytes(0, padding);
+ }
+}
+
+
+void TrueTypeFont::writeWOFF (const string &fname) const {
+ ofstream ofs(fname, ios::binary);
+ writeWOFF(ofs);
+}
+
+
+/** Puts the TrueType data in a WOFF2 container and writes the resulting data to a given stream.
+ * @param[out] os stream to write the WOFF2 data to
+ * @return true on success */
+bool TrueTypeFont::writeWOFF2 (ostream &os) const {
+ auto input_data = reinterpret_cast<const uint8_t*>(_buffer.data());
+ size_t output_size = woff2::MaxWOFF2CompressedSize(input_data, _buffer.size());
+ string output(output_size, 0);
+ auto output_data = reinterpret_cast<uint8_t*>(&output[0]);
+ woff2::WOFF2Params params;
+ if (woff2::ConvertTTFToWOFF2(input_data, _buffer.size(), output_data, &output_size, params)) {
+ output.resize(output_size);
+ copy(output.begin(), output.end(), ostream_iterator<uint8_t>(os));
+ return true;
+ }
+ return false;
+}
+
+
+bool TrueTypeFont::writeWOFF2 (const string &fname) const {
+ ofstream ofs(fname, ios::binary);
+ return writeWOFF2(ofs);
+}
+
+
+/** Converts the numeric table tag (which represents a four-character ID) to a string. */
+string TrueTypeFont::TTFTableRecord::name () const {
+ string ret;
+ for (int i=24; i >= 0; i-= 8)
+ ret += static_cast<char>(tag >> i);
+ return ret;
+}
+
+
+uint32_t TrueTypeFont::TTFTableRecord::computeChecksum () const {
+ uint32_t sum=0;
+ auto startptr = reinterpret_cast<const uint32_t*>(data);
+ auto endptr = startptr + paddedSize()/sizeof(uint32_t);
+ while (startptr < endptr)
+ sum += *startptr++;
+ return sum;
+}