summaryrefslogtreecommitdiff
path: root/dviware/dvisvgm/src/ttf
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-01-12 03:01:29 +0000
committerNorbert Preining <norbert@preining.info>2023-01-12 03:01:29 +0000
commit6a7900c93acc16d1bbd2f1e26286c7dd7387e6c0 (patch)
tree76196287351cba68a51934c49468bf1a7846aa76 /dviware/dvisvgm/src/ttf
parentc1c19023b4b1d43cb874f84df5102b485853e672 (diff)
CTAN sync 202301120301
Diffstat (limited to 'dviware/dvisvgm/src/ttf')
-rw-r--r--dviware/dvisvgm/src/ttf/CmapTable.cpp131
-rw-r--r--dviware/dvisvgm/src/ttf/CmapTable.hpp43
-rw-r--r--dviware/dvisvgm/src/ttf/GlyfTable.cpp501
-rw-r--r--dviware/dvisvgm/src/ttf/GlyfTable.hpp96
-rw-r--r--dviware/dvisvgm/src/ttf/HeadTable.cpp78
-rw-r--r--dviware/dvisvgm/src/ttf/HeadTable.hpp49
-rw-r--r--dviware/dvisvgm/src/ttf/HheaTable.cpp67
-rw-r--r--dviware/dvisvgm/src/ttf/HheaTable.hpp47
-rw-r--r--dviware/dvisvgm/src/ttf/HmtxTable.cpp62
-rw-r--r--dviware/dvisvgm/src/ttf/HmtxTable.hpp52
-rw-r--r--dviware/dvisvgm/src/ttf/LocaTable.hpp56
-rw-r--r--dviware/dvisvgm/src/ttf/Makefile.am25
-rw-r--r--dviware/dvisvgm/src/ttf/Makefile.in743
-rw-r--r--dviware/dvisvgm/src/ttf/MaxpTable.cpp50
-rw-r--r--dviware/dvisvgm/src/ttf/MaxpTable.hpp42
-rw-r--r--dviware/dvisvgm/src/ttf/NameTable.cpp105
-rw-r--r--dviware/dvisvgm/src/ttf/NameTable.hpp37
-rw-r--r--dviware/dvisvgm/src/ttf/OS2Table.cpp246
-rw-r--r--dviware/dvisvgm/src/ttf/OS2Table.hpp46
-rw-r--r--dviware/dvisvgm/src/ttf/PostTable.cpp63
-rw-r--r--dviware/dvisvgm/src/ttf/PostTable.hpp37
-rw-r--r--dviware/dvisvgm/src/ttf/TTFAutohint.cpp161
-rw-r--r--dviware/dvisvgm/src/ttf/TTFAutohint.hpp52
-rw-r--r--dviware/dvisvgm/src/ttf/TTFTable.cpp94
-rw-r--r--dviware/dvisvgm/src/ttf/TTFTable.hpp108
-rw-r--r--dviware/dvisvgm/src/ttf/TTFWriter.cpp422
-rw-r--r--dviware/dvisvgm/src/ttf/TTFWriter.hpp113
-rw-r--r--dviware/dvisvgm/src/ttf/VheaTable.cpp66
-rw-r--r--dviware/dvisvgm/src/ttf/VheaTable.hpp47
-rw-r--r--dviware/dvisvgm/src/ttf/VmtxTable.cpp57
-rw-r--r--dviware/dvisvgm/src/ttf/VmtxTable.hpp49
31 files changed, 3745 insertions, 0 deletions
diff --git a/dviware/dvisvgm/src/ttf/CmapTable.cpp b/dviware/dvisvgm/src/ttf/CmapTable.cpp
new file mode 100644
index 0000000000..02731b57e9
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/CmapTable.cpp
@@ -0,0 +1,131 @@
+/*************************************************************************
+** CmapTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <algorithm>
+#include "CmapTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+#include "../utility.hpp"
+
+using namespace std;
+using namespace ttf;
+
+void CmapTable::write (ostream &os) const {
+ writeUInt16(os, 0); // version
+ writeUInt16(os, 2); // number of encoding tables
+
+ const RangeMap &charmap = ttfWriter()->getUnicodeCharMap();
+ bool isUCS2 = (charmap.maxKey() <= 0xFFFF);
+ uint32_t offset = 4+2*8; // offset to subtable
+
+ writeUInt16(os, 0); // platform ID 0 = Unicode
+ writeUInt16(os, isUCS2 ? 3 : 4); // encoding ID (Unicode 2.0, UCS-2 or UCS-4)
+ writeUInt32(os, offset);
+
+ writeUInt16(os, 3); // platform ID 3 = Windows
+ writeUInt16(os, isUCS2 ? 1 : 10); // encoding ID (UCS-2 or UCS-4)
+ writeUInt32(os, offset); // platform ID 0 = Unicode
+
+ if (isUCS2)
+ writeSubTableFormat4(os, charmap);
+ else
+ writeSubTableFormat12(os, charmap);
+}
+
+
+/** Writes mapping data in subtable format 0 (byte encoding table). */
+void CmapTable::writeSubTableFormat0 (ostream &os, const RangeMap &charmap) const {
+ writeUInt16(os, 0); // subtable format
+ writeUInt16(os, 3*2+256); // table length
+ writeUInt16(os, 0); // language: none
+ vector<uint8_t> indexes(256, 0);
+ int count=1;
+ for (auto cppair : charmap) {
+ if (cppair.first > 255 || count > 255)
+ break;
+ indexes[cppair.first] = uint8_t(count++);
+ }
+ for (uint8_t c : indexes)
+ writeUInt8(os, c);
+}
+
+
+/** Writes mapping data in subtable format 4 (segment mapping to delta values, UCS-2). */
+void CmapTable::writeSubTableFormat4 (ostream &os, const RangeMap &charmap) const {
+ uint16_t numSegments = charmap.numRanges()+1;
+ uint16_t searchRange = 1 << (util::ilog2(numSegments)+1);
+ uint16_t entrySelector = util::ilog2(searchRange/2);
+ uint16_t rangeShift = 2*numSegments - searchRange;
+
+ writeUInt16(os, 4); // subtable format
+ writeUInt16(os, 8*2+4*2*numSegments); // table length
+ writeUInt16(os, 0); // language: none
+ writeUInt16(os, numSegments*2);
+ writeUInt16(os, searchRange);
+ writeUInt16(os, entrySelector);
+ writeUInt16(os, rangeShift);
+ for (size_t i=0; i < charmap.numRanges(); i++)
+ writeUInt16(os, charmap.getRange(i).max()); // end character code of current segment
+ writeUInt16(os, 0xFFFF); // final end character code
+ writeUInt16(os, 0); // reserved pad
+ for (size_t i=0; i < charmap.numRanges(); i++)
+ writeUInt16(os, charmap.getRange(i).min()); // start character code of current segment
+ writeUInt16(os, 0xFFFF); // final start character code
+ int count=1;
+ for (size_t i=0; i < charmap.numRanges(); i++) {
+ const auto &range = charmap.getRange(i);
+ int cstart = range.min();
+ writeInt16(os, count-cstart); // idDelta of current segment
+ count += range.numKeys();
+ }
+ writeUInt16(os, 1); // final idRange (maps 0xFFFF to 0)
+ for (uint16_t i=0; i < numSegments; i++)
+ writeUInt16(os, 0); // idRangeOffsets = 0 (no offsets into glyphIdArray required)
+}
+
+
+/** Writes mapping data in subtable format 6 (trimmed table mapping, UCS-2). */
+void CmapTable::writeSubTableFormat6 (ostream &os, const RangeMap &charmap) const {
+ writeUInt16(os, 6); // subtable format
+ writeUInt16(os, 5*2+2*charmap.numValues()); // table length
+ writeUInt16(os, 0); // language: none
+ writeUInt16(os, charmap.getRange(0).min()); // first character code
+ writeUInt16(os, charmap.getRange(0).numKeys());
+ for (size_t i=0; i < charmap.getRange(0).numKeys(); i++)
+ writeUInt16(os, i+1);
+}
+
+
+/** Writes mapping data in subtable format 12 (segmented coverage, UCS-4). */
+void CmapTable::writeSubTableFormat12 (ostream &os, const RangeMap &charmap) const {
+ writeUInt16(os, 12); // subtable format
+ writeUInt16(os, 0); // reserved
+ writeUInt32(os, 2*2+3*4+charmap.numRanges()*3*4); // table length
+ writeUInt32(os, 0); // language
+ writeUInt32(os, charmap.numRanges());
+ uint32_t startIndex=1;
+ for (size_t i=0; i < charmap.numRanges(); i++) {
+ const auto &range = charmap.getRange(i);
+ writeUInt32(os, range.min()); // startCharCode
+ writeUInt32(os, range.max()); // endCharCode
+ writeUInt32(os, startIndex); // startGlyphID
+ startIndex += range.numKeys();
+ }
+}
diff --git a/dviware/dvisvgm/src/ttf/CmapTable.hpp b/dviware/dvisvgm/src/ttf/CmapTable.hpp
new file mode 100644
index 0000000000..d9c9eea5ae
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/CmapTable.hpp
@@ -0,0 +1,43 @@
+/*************************************************************************
+** CmapTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+#include <vector>
+#include "TTFTable.hpp"
+
+class RangeMap;
+
+namespace ttf {
+
+/** This class provides the functions required to write the character mapping table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/cmap.htm */
+class CmapTable : public TTFTable {
+ public:
+ uint32_t tag () const override {return name2id("cmap");}
+ void write (std::ostream &os) const override;
+
+ protected:
+ void writeSubTableFormat0 (std::ostream &os, const RangeMap &charmap) const;
+ void writeSubTableFormat4 (std::ostream &os, const RangeMap &charmap) const;
+ void writeSubTableFormat6 (std::ostream &os, const RangeMap &charmap) const;
+ void writeSubTableFormat12 (std::ostream &os, const RangeMap &charmap) const;
+};
+
+} // namespace ttf \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/GlyfTable.cpp b/dviware/dvisvgm/src/ttf/GlyfTable.cpp
new file mode 100644
index 0000000000..4005b661e0
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/GlyfTable.cpp
@@ -0,0 +1,501 @@
+/*************************************************************************
+** GlyfTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <algorithm>
+#include <limits>
+#include <cmath>
+#include <numeric>
+#include <sstream>
+#include "GlyfTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Bezier.hpp"
+#include "../Font.hpp"
+
+using namespace std;
+using namespace ttf;
+
+/** Creates a contour by concatenating several contours given in a list. */
+Contour::Contour (std::list<Contour> &&contours) {
+ if (_pointInfos.empty() && !contours.empty()) {
+ _pointInfos = std::move(contours.front()._pointInfos);
+ contours.pop_front();
+ }
+ for (auto it=contours.begin(); it != contours.end(); it=contours.erase(it))
+ std::move(it->begin(), it->end(), std::back_inserter(_pointInfos));
+}
+
+
+void Contour::reverse () {
+ std::reverse(_pointInfos.begin(), _pointInfos.end());
+}
+
+
+/** Converts the absolute coordinates of a Contour to relative ones. */
+void Contour::convertAbsoluteToRelative () {
+ Pair<int> prevPoint;
+ for (PointInfo &info : _pointInfos) {
+ Pair<int> p = info.coords;
+ info.coords -= prevPoint;
+ prevPoint = p;
+ }
+}
+
+
+/** Returns an iterator pointing to the next PointInfo object in a vector that isn't marked for removal.
+ * If there's no such object, the function returns infos.end().
+ * @param[in] it current position
+ * @param[in] infos vector the iterator belongs to */
+static vector<PointInfo>::iterator next (vector<PointInfo>::iterator it, const vector<PointInfo> &infos) {
+ do
+ ++it;
+ while (it != infos.end() && it->removed());
+ return it;
+}
+
+
+/** Reduces the number of contour points without affecting the appearance significantly. */
+void Contour::reduceNumberOfPoints () {
+ if (_pointInfos.size() > 2) {
+ for (auto it1 = _pointInfos.begin(); it1+2 != _pointInfos.end(); ++it1) {
+ auto it2 = it1+1;
+ auto it3 = it2+1;
+ bool remove=false;
+ if (it1->oncurve() && it2->offcurve() && it3->oncurve()) {
+ // remove off-curve points that are close to an on-curve point
+ Pair<int> diff12 = it1->coords - it2->coords;
+ Pair<int> diff23 = it2->coords - it3->coords;
+ int sqrdist12 = diff12.x()*diff12.x() + diff12.y()*diff12.y();
+ int sqrdist23 = diff23.x()*diff23.x() + diff23.y()*diff23.y();
+ remove = (sqrdist12 < 4 || sqrdist23 < 4);
+ if (!remove) {
+ // remove in-between off-curve points that are very close to
+ // the line through the two adjacent on-curve points (curve height <= 0.5)
+ // distance(line(p1,p3), p2) = |det(p1-p3, p1-p2)| / |p1-p3|
+ Pair<int> diff13 = it1->coords - it3->coords;
+ DPair extremum = QuadBezier(it1->coords, it2->coords, it3->coords).valueAt(0.5);
+ int sqrdist13 = diff13.x()*diff13.x() + diff13.y()*diff13.y();
+ double det1312 = det(DPair(diff13), DPair(it3->coords)-extremum);
+ remove = (sqrdist13 == 0 || det1312/sqrdist13*det1312 < 0.25);
+ }
+ }
+ else if (it2->offcurve() || (it1->oncurve() && it3->oncurve())) {
+ // remove in-between points located on same line
+ Pair<int> diff13 = it3->coords - it1->coords;
+ Pair<int> diff12 = it2->coords - it1->coords;
+ int sqrdist13 = diff13.x()*diff13.x() + diff13.y()*diff13.y();
+ double det1312 = det(diff13, diff12);
+ remove = (sqrdist13 == 0 || det1312/sqrdist13*det1312 < 1);
+ }
+ else if (it1->offcurve() && it2->oncurve() && it3->offcurve()) {
+ // remove on-curve points located (almost) halfway between two off-curve points
+ Pair<int> mid = DPair(it1->coords + it3->coords)/2.0;
+ Pair<int> vec = mid - it2->coords;
+ double dist2 = vec.x()*vec.x() + vec.y()*vec.y();
+ remove = (dist2 < 2.25); // remove point if dist < 1.5
+ }
+ if (remove)
+ it2->markForRemoval();
+ }
+ }
+ // remove duplicate points, prefer control (off-curve) points
+ for (auto it1 = _pointInfos.begin(); it1 != _pointInfos.end(); it1=next(it1, _pointInfos)) {
+ auto it2 = next(it1, _pointInfos);
+ if (it2 == _pointInfos.end())
+ it2 = _pointInfos.begin();
+ if (it1->oncurve() && it2->oncurve() && (it1->coords-it2->coords).length() < 6) {
+ auto i1=it1, i2=it2;
+ if (i1 == _pointInfos.begin())
+ swap(i1, i2);
+ i2->coords = DPair(i1->coords+i2->coords)/2.0;
+ i1->markForRemoval();
+ }
+ else if (it1->coords == it2->coords) {
+ if (it1->offcurve() || it2 == _pointInfos.begin())
+ it1->markForRemoval();
+ else
+ it2->markForRemoval();
+ }
+ }
+ // actually remove marked points from vector
+ _pointInfos.erase(
+ remove_if(_pointInfos.begin(), _pointInfos.end(), [](const PointInfo &pi) {
+ return pi.removed();
+ }),
+ _pointInfos.end());
+}
+
+
+/** Bits of the "Simple Glyph Flags". See section "Simple Glyph Description" of glyf table documentation. */
+enum : uint8_t {
+ ON_CURVE_PT = 1, ///< if set, corresponing point is on the curve, otherwise off the curve (= control point)
+ X_SHORT = 2, ///< if set, the corresponding x-coordinate is 1 byte long, otherwise it's two bytes long
+ Y_SHORT = 4, ///< if set, the corresponding y-coordinate is 1 byte long, otherwise it's two bytes long
+ REPEAT_FLAG = 8, ///< if set, the next byte specifies the number of additional times this flag is to be repeated
+ X_IS_SAME_OR_POSITIVE_SHORT = 16, ///< if X_SHORT set: indicates if value >0, else if x-coord equals prev. one
+ Y_IS_SAME_OR_POSITIVE_SHORT = 32 ///< if Y_SHORT set: indicates if value >0, else if y-coord equals prev. one
+};
+
+
+/** Computes the "simple glyph flags" (except the repeat flag) for a given contour.
+ * The function expects the contour points to be relative to the respective preceding point.
+ * In order to simplify checking the equality of two flag bytes, which requires to
+ * exclude the repeat flag, this function does not set the repeat flag. */
+vector<uint8_t> Contour::glyphFlags () const {
+ vector<uint8_t> flags(_pointInfos.size());
+ for (size_t i=0; i < _pointInfos.size(); i++) {
+ flags[i] = _pointInfos[i].oncurve() ? ON_CURVE_PT : 0;
+ if (_pointInfos[i].coords.x() == 0)
+ flags[i] |= X_IS_SAME_OR_POSITIVE_SHORT;
+ else if (abs(_pointInfos[i].coords.x()) <= 0xff) { // x-coordinate 1 byte long?
+ flags[i] |= X_SHORT;
+ if (_pointInfos[i].coords.x() > 0) // positive x-coordinate?
+ flags[i] |= X_IS_SAME_OR_POSITIVE_SHORT;
+ }
+ if (_pointInfos[i].coords.y() == 0)
+ flags[i] |= Y_IS_SAME_OR_POSITIVE_SHORT;
+ else if (abs(_pointInfos[i].coords.y()) <= 0xff) { // y-coordinate 1 byte long?
+ flags[i] |= Y_SHORT;
+ if (_pointInfos[i].coords.y() > 0) // positive y-coordinate?
+ flags[i] |= Y_IS_SAME_OR_POSITIVE_SHORT;
+ }
+ }
+ return flags;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+/** Writes the contours describing the glyphs to a given stream.
+ * The glyphs must be ordered by the local glyph index used in the generated TTF font.
+ * In order to get compact mapping tables, we ensure that a greater glyph index also
+ * indicates a greater Unicode point (idx1 > idx2 <=> cp1 > cp2). */
+void GlyfTable::write (ostream &os) const {
+ // add offset for .notdef character
+ size_t offset = 0;
+ ttfWriter()->addGlyphOffset(0);
+ ttfWriter()->updateGlobalBbox(0, 0, 0, 0, 0);
+ // iterate in ascending Unicode point order over all characters to be added to the TTF
+ for (auto cp2charcode : ttfWriter()->getUnicodeCharMap()) {
+ ttfWriter()->addGlyphOffset(offset); // update loca table
+ offset += writeGlyphContours(os, cp2charcode.second);
+ }
+ ttfWriter()->addGlyphOffset(offset); // add extra offset after last valid one
+}
+
+
+/** Writes the contour data of a single glyph to a given output stream.
+ * @param[in] os stream to write to
+ * @param[in] charcode character code of glyph in current font
+ * @return number of bytes written */
+size_t GlyfTable::writeGlyphContours (ostream &os, uint32_t charcode) const {
+ list<Contour> contours = computeContours(charcode);
+ if (contours.empty()) {
+ ttfWriter()->updateGlobalBbox(charcode, 0, 0, 0, 0);
+ return 0;
+ }
+ ttfWriter()->updateContourInfo(contours.size(),
+ std::accumulate(contours.begin(), contours.end(), size_t(0), [](size_t sum, const Contour &contour) {
+ return sum + contour.numPoints();
+ }));
+ auto offset = os.tellp();
+ // glyph header
+ writeInt16(os, int16_t(contours.size())); // numberOfContours
+
+ int xmin, xmax, ymin, ymax;
+ computeBbox(contours, xmin, ymin, xmax, ymax);
+ ttfWriter()->updateGlobalBbox(charcode, xmin, ymin, xmax, ymax);
+ writeInt16(os, xmin);
+ writeInt16(os, ymin);
+ writeInt16(os, xmax);
+ writeInt16(os, ymax);
+
+ // write indices of endpoints of each contour
+ size_t endPtsOfContours = 0;
+ for (const Contour &contour : contours) {
+ endPtsOfContours += contour.numPoints();
+ writeUInt16(os, endPtsOfContours-1);
+ }
+ writeUInt16(os, 0); // instructionLength
+
+ Contour combinedContour(std::move(contours));
+ combinedContour.convertAbsoluteToRelative();
+
+ // write contour flags
+ vector<uint8_t> flags = combinedContour.glyphFlags();
+ for (auto first=flags.begin(); first != flags.end(); ++first) {
+ auto last = std::find_if(first+1, flags.end(), [&first](uint8_t flagbyte) {
+ return flagbyte != *first;
+ });
+ if (--last == first) // run-length == 0?
+ writeUInt8(os, *first);
+ else {
+ writeUInt8(os, (*first) | REPEAT_FLAG); // write flag only once and
+ writeUInt8(os, last-first); // append number of additional repeats
+ first = last;
+ }
+ }
+ // write x-coordinates
+ for (size_t i=0; i < combinedContour.numPoints(); i++) {
+ if (flags[i] & X_SHORT) // short (one byte) x coordinate?
+ writeUInt8(os, abs(combinedContour[i].coords.x()));
+ else if ((flags[i] & X_IS_SAME_OR_POSITIVE_SHORT) == 0) // does long x-coordinate differ from previous one?
+ writeInt16(os, int16_t(combinedContour[i].coords.x()));
+ }
+ // write y-coordinates
+ for (size_t i=0; i < combinedContour.numPoints(); i++) {
+ if (flags[i] & Y_SHORT) // short (one byte) y coordinate?
+ writeUInt8(os, abs(combinedContour[i].coords.y()));
+ else if ((flags[i] & Y_IS_SAME_OR_POSITIVE_SHORT) == 0) // does long y-coordinate differ from previous one?
+ writeInt16(os, int16_t(combinedContour[i].coords.y()));
+ }
+ // ensure that the number of glyph data bytes is a multiple of 4 (pad at dword boundary)
+ for (int i = (1 + ~(os.tellp()-offset)) & 3; i > 0; i--)
+ writeUInt8(os, 0);
+ return os.tellp()-offset;
+}
+
+
+/** Computes the absolute global bounds of multiple contours.
+ * @param[in] contours point data with absolute coordinates */
+void GlyfTable::computeBbox (const list<Contour> &contours, int &xmin, int &ymin, int &xmax, int &ymax) {
+ if (contours.empty())
+ xmin = xmax = ymin = ymax = 0;
+ else {
+ xmin = ymin = numeric_limits<int16_t>::max();
+ xmax = ymax = numeric_limits<int16_t>::min();
+ for (const Contour &contour : contours) {
+ for (const PointInfo &info : contour) {
+ const auto &p = info.coords;
+ xmin = min(xmin, p.x());
+ xmax = max(xmax, p.x());
+ ymin = min(ymin, p.y());
+ ymax = max(ymax, p.y());
+ }
+ }
+ }
+}
+
+
+static Glyph::Point to_point (const DPair &p) {
+ return Glyph::Point(int(std::round(p.x())), int(std::round(p.y())));
+}
+
+
+struct GlyphToContourActions : Glyph::IterationActions {
+ GlyphToContourActions (list<Contour> &cnts, double s) : contours(cnts), scale(s) {}
+
+ void moveto (const Glyph::Point &p) override {
+ contours.emplace_back(Contour());
+ add(p, true);
+ }
+
+ void lineto (const Glyph::Point &p) override {
+ if (contours.empty())
+ moveto(currentPoint()); // (0, 0)
+ if (p != currentPoint())
+ add(p, true);
+ }
+
+ void quadto (const Glyph::Point &p1, const Glyph::Point &p2) override {
+ if (contours.empty())
+ moveto(currentPoint()); // (0, 0)
+ // if the maximum distance between the curve and the line through p0 and p2 is < 0.5,
+ // treat the curve as a line
+ DPair extremum = QuadBezier(currentPoint(), p1, p2).valueAt(0.5);
+ double height = det(DPair(currentPoint()-p2), DPair(currentPoint())-extremum)/(currentPoint()-p2).length();
+ if (p1 != currentPoint() && abs(height) >= 0.5 && p2 != currentPoint())
+ add(p1, false);
+ if (p2 != currentPoint())
+ add(p2, true);
+ }
+
+ void cubicto (const Glyph::Point &p1, const Glyph::Point &p2, const Glyph::Point &p3) override {
+ // approximate cubic Bézier curve with a sequence of quadratic ones
+ CubicBezier cubic(
+ DPair(currentPoint().x(), currentPoint().y()),
+ DPair(p1.x(), p1.y()),
+ DPair(p2.x(), p2.y()),
+ DPair(p3.x(), p3.y())
+ );
+ vector<QuadBezier> quadBeziers = cubic.toQuadBeziers(0.8);
+ for (const QuadBezier &quad : quadBeziers)
+ quadto(to_point(quad.point(1)), to_point(quad.point(2)));
+ }
+
+ void add (const Glyph::Point &p, bool oncurve) {
+ contours.back().append(PointInfo(scale*p.x(), scale*p.y(), oncurve));
+ }
+
+ list<Contour> &contours;
+ double scale;
+};
+
+
+/** Returns a sequence of contours describing the glyph of a given character.
+ * The contour points are stored with absolute coordinates. */
+list<Contour> GlyfTable::computeContours (uint32_t charcode) const {
+ list<Contour> contours;
+ Glyph glyph;
+ if (ttfWriter()->getFont().getGlyph(int(charcode), glyph, ttfWriter()->getTracerCallback())) {
+ if (!glyph.empty()) {
+ GlyphToContourActions actions(contours, ttfWriter()->unitsPerEmFactor());
+ glyph.iterate(actions, false);
+ for (auto it = contours.begin(); it != contours.end();) {
+ it->reverse(); // TTF contours must be clockwise-oriented
+ it->reduceNumberOfPoints();
+ if (it->numPoints() < 3)
+ it = contours.erase(it);
+ else
+ ++it;
+ }
+ }
+#ifdef TTFDEBUG
+ if (TTFWriter::CREATE_PS_GLYPH_OUTLINES) {
+ string fontname = ttfWriter()->getFont().name();
+ ostringstream oss;
+ oss << "g-" << ttfWriter()->getFont().name() << '-';
+ oss << setw(4) << setfill('0') << charcode;
+ oss << ".eps";
+ ofstream ofs(oss.str());
+ writePS(ofs, contours, charcode);
+ }
+#endif
+ }
+ return contours;
+}
+
+
+#if 0
+/** Creates a contour for the .notdef character. */
+Contour GlyfTable::getNotDefContour () const {
+ Contour contour;
+ const PhysicalFont &font = ttfWriter()->getFont();
+ double extend = font.style() ? font.style()->extend : 1;
+ double scale = ttfWriter()->unitsPerEmFactor();
+ int base = int(round(scale*extend*(font.ascent()+font.descent())));
+ Pair<int> pmin(base/30, 0);
+ Pair<int> pmax(3*base/5, 2*base/3);
+ contour.append(PointInfo(pmin.x(), pmin.y()));
+ contour.append(PointInfo(pmin.x(), pmax.y()));
+ contour.append(PointInfo(pmax.x(), pmax.y()));
+ contour.append(PointInfo(pmax.x(), pmin.y()));
+ return contour;
+}
+#endif
+
+
+#ifdef TTFDEBUG
+/** Creates PostScript code from a list of contours that describe the outline of a single glyph.
+ * This is just required for analysis and debugging purposes. */
+void GlyfTable::writePS (ostream &os, const list<Contour> &contours, uint32_t charcode) const {
+ os << "%!PS-Adobe-3.0 EPSF-3.0\n"
+ << "%%BoundingBox: (atend)\n"
+ << "/dot {moveto gsave 5 setlinewidth 1 setlinecap currentpoint lineto stroke grestore} bind def\n"
+ << "/oncurvedot {dot} bind def\n"
+ << "/offcurvedot {gsave 0 1 0 setrgbcolor dot grestore} bind def\n"
+ << "/Helvetica findfont 8 scalefont setfont\n\n";
+ auto &font = ttfWriter()->getFont();
+ os << "% Font: " << font.name() << " at " << font.designSize() << "pt, " << font.unitsPerEm() << " units per em\n"
+ << "% Glyph: " << charcode << "\n";
+ Pair<int> llp(numeric_limits<int>::max(), numeric_limits<int>::max());
+ Pair<int> urp(numeric_limits<int>::min(), numeric_limits<int>::min());
+ size_t count=0, numPoints=0;
+ for (const Contour &contour : contours) {
+ os << "\n% contour " << ++count << ", " << contour.numPoints() << " points\n";
+ contour.writePS(os);
+ numPoints += contour.numPoints();
+ }
+ int minx, miny, maxx, maxy;
+ computeBbox(contours, minx, miny, maxx, maxy);
+ os << minx << " " << maxy+30
+ << " moveto (Glyph " << charcode << " of font " << font.name() << ", "
+ << contours.size() << " contour" << (contours.size() > 1 ? "s" : "") << ", " << numPoints << " points) show\n";
+ os << "%%Trailer\n"
+ << "%%BoundingBox: " << minx-10 << " " << miny-10 << " " << maxx+10 << " " << maxy+50 << "\n";
+}
+
+
+static ostream& write (ostream &os, const Pair<int> &p) {
+ return os << p.x() << " " << p.y();
+}
+
+template <typename ...Ts>
+static ostream& write (ostream &os, const Pair<int> &p, const Ts& ...args) {
+ write(os, p) << " ";
+ return write(os, args...);
+}
+
+
+void Contour::writePS (ostream &os) const {
+ if (_pointInfos.empty())
+ return;
+ auto p0 = _pointInfos[0].coords;
+ write(os, p0) << " moveto\n";
+ for (size_t i=1; i <= _pointInfos.size(); i++) {
+ size_t imod = i % _pointInfos.size();
+ auto pi1 = _pointInfos[imod];
+ if (pi1.oncurve() && i == _pointInfos.size())
+ os << "closepath\n";
+ else
+ write(os, pi1.coords) << " ";
+ if (pi1.oncurve()) {
+ if (i < _pointInfos.size()) {
+ auto v = pi1.coords-p0;
+ os << " lineto % " << i << "; len=" << v.length()
+ << "; " << math::rad2deg(atan2(v.y(), v.x())) << "°\n";
+ }
+ p0 = pi1.coords;
+ }
+ else {
+ auto p1 = pi1.coords;
+ auto pi2 = _pointInfos[(i+1) % _pointInfos.size()];
+ auto p2 = pi2.oncurve() ? pi2.coords : (p1+pi2.coords)/2;
+ DPair v1 = p1-p0, v2 = p1-p2;
+ Pair<int> c1 = DPair(p0) + round(v1*2.0/3.0);
+ Pair<int> c2 = DPair(p2) + round(v2*2.0/3.0);
+ QuadBezier bezier(p0, p1, p2);
+ double cordlen = (p2-p0).length();
+ double arclen = bezier.arclen();
+ DPair extremum = bezier.valueAt(0.5);
+ double height = det(DPair(p0-p2), DPair(p0)-extremum)/(p0-p2).length();
+ write(os, c1, c2, p2) << " curveto"
+ << " % " << i
+ << "; (" << math::rad2deg(atan2(v1.y(), v1.x())) << "°," << math::rad2deg(atan2(v2.y(), v2.x())) << "°)"
+ << "; cordlen=" << cordlen
+ << "; arclen=" << arclen
+ << "; quot=" << cordlen/arclen
+ << "; diff=" << arclen-cordlen
+ << "; height=" << height
+ << "\n";
+ p0 = p2;
+ if (pi2.oncurve())
+ i++;
+ }
+ }
+ os << "stroke\n";
+ for (size_t i=0; i < _pointInfos.size(); i++) {
+ auto p = _pointInfos[i].coords;
+ write(os, p) << " 2 copy "
+ << (_pointInfos[i].oncurve() ? "on" : "off") << "curvedot "
+ << "moveto (" << i << ") show\n";
+ }
+}
+#endif
diff --git a/dviware/dvisvgm/src/ttf/GlyfTable.hpp b/dviware/dvisvgm/src/ttf/GlyfTable.hpp
new file mode 100644
index 0000000000..5ff80559a5
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/GlyfTable.hpp
@@ -0,0 +1,96 @@
+/*************************************************************************
+** GlyfTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+#include <cmath>
+#include <list>
+#include <ostream>
+#include <vector>
+#include "TTFTable.hpp"
+#include "../Pair.hpp"
+
+namespace ttf {
+
+struct PointInfo {
+ enum State {OFFCURVE, ONCURVE, REMOVED};
+
+ PointInfo (double x, double y, bool oncurve) : coords(std::round(x), std::round(y)), state(oncurve ? ONCURVE : OFFCURVE) {}
+ PointInfo (int x, int y) : coords(x, y), state(ONCURVE) {}
+ bool oncurve () const {return state == ONCURVE;}
+ bool offcurve () const {return state == OFFCURVE;}
+ bool removed () const {return state == REMOVED;}
+ void markForRemoval () {state = REMOVED;}
+ Pair<int> coords; ///< relative coordinates to previous one in contour
+ State state;
+};
+
+
+class Contour {
+ friend class GlyfTable;
+ using Iterator = std::vector<PointInfo>::iterator;
+ using ConstIterator = std::vector<PointInfo>::const_iterator;
+ public:
+ Contour () =default;
+ Contour (Contour &&contour) =default;
+ Contour (std::list<Contour> &&contours);
+ Contour (const Contour &contour) =delete;
+ Iterator begin () {return _pointInfos.begin();}
+ Iterator end () {return _pointInfos.end();}
+ ConstIterator begin () const {return _pointInfos.begin();}
+ ConstIterator end () const {return _pointInfos.end();}
+ size_t numPoints () const {return _pointInfos.size();}
+ const PointInfo& operator [] (size_t pos) const {return _pointInfos[pos];}
+ bool empty () const {return _pointInfos.empty();}
+ std::vector<uint8_t> glyphFlags () const;
+ void reverse ();
+ void reduceNumberOfPoints ();
+ void append (PointInfo &&pinfo) {_pointInfos.emplace_back(std::move(pinfo));}
+ void reserve (size_t n) {_pointInfos.reserve(n);}
+
+ protected:
+ void convertAbsoluteToRelative ();
+#ifdef TTFDEBUG
+ void writePS (std::ostream &os) const;
+#endif
+
+ private:
+ std::vector<PointInfo> _pointInfos;
+};
+
+
+/** This class provides the functions required to write the glyf data table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/glyf.htm */
+class GlyfTable : public TTFTable {
+ public:
+ uint32_t tag () const override {return name2id("glyf");}
+ void write (std::ostream &os) const override;
+
+ protected:
+ std::vector<Contour> computeContours () const;
+ std::list<Contour> computeContours (uint32_t charcode) const;
+ static void computeBbox (const std::list<Contour> &contours, int &xmin, int &ymin, int &xmax, int &ymax);
+ size_t writeGlyphContours (std::ostream &os, uint32_t charcode) const;
+// Contour getNotDefContour () const;
+#ifdef TTFDEBUG
+ void writePS (std::ostream &os, const std::list<Contour> &contours, uint32_t charcode) const;
+#endif
+};
+
+} // namespace ttf \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/HeadTable.cpp b/dviware/dvisvgm/src/ttf/HeadTable.cpp
new file mode 100644
index 0000000000..fff759898a
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/HeadTable.cpp
@@ -0,0 +1,78 @@
+/*************************************************************************
+** HeadTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <cmath>
+#include <chrono>
+#include <ctime>
+#include <utility>
+#include "HeadTable.hpp"
+#include "TTFWriter.hpp"
+
+using namespace std;
+using namespace ttf;
+
+
+void HeadTable::updateGlobalBbox (int16_t xmin, int16_t ymin, int16_t xmax, int16_t ymax) {
+ if (xmin < _xMin) _xMin = xmin;
+ if (ymin < _yMin) _yMin = ymin;
+ if (xmax > _xMax) _xMax = xmax;
+ if (ymax > _yMax) _yMax = ymax;
+}
+
+
+/** Returns the number of seconds elapsed since 1.1.1904 00:00:00 until now.
+ * @return number of seconds separated in upper and lower dword of a 64-bit value */
+static pair<uint32_t,uint32_t> seconds_since_1904 () {
+ auto now = chrono::system_clock::now();
+ time_t now_time = chrono::system_clock::to_time_t(now);
+ struct tm *comp = gmtime(&now_time);
+ util::Date date1(1904, 1, 1);
+ util::Date date2(comp->tm_year+1900, comp->tm_mon+1, comp->tm_mday);
+ uint64_t days = date2 - date1 - 1;
+ uint64_t seconds = ((days*24 + comp->tm_hour)*60 + comp->tm_min)*60 + comp->tm_sec;
+ return {uint32_t(seconds >> 32), uint32_t(seconds & 0xffffffff)};
+}
+
+
+/** Writes the head table to a given output stream.
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/head */
+void HeadTable::write (ostream &os) const {
+ writeUInt16(os, 1); // major version
+ writeUInt16(os, 0); // minor version
+ writeUInt32(os, 0x10000); // font revision (1.0)
+ writeUInt32(os, 0); // global checksum, computed and set by TTFWriter
+ writeUInt32(os, 0x5F0F3CF5); // magic number
+ writeUInt16(os, 1+2); // flags (baseline at y=0, left sidebearing point at x=0)
+ writeUInt16(os, uint16_t(std::round(ttfWriter()->targetUnitsPerEm())));
+ auto seconds = seconds_since_1904();
+ writeUInt32(os, seconds.first); // creation time, upper dword
+ writeUInt32(os, seconds.second); // creation time, lower dword
+ writeUInt32(os, seconds.first); // modification time, upper dword
+ writeUInt32(os, seconds.second); // modification time, lower dword
+ writeInt16(os, _xMin);
+ writeInt16(os, _yMin);
+ writeInt16(os, _xMax);
+ writeInt16(os, _yMax);
+ writeUInt16(os, 0); // macStyle
+ writeUInt16(os, 8); // smallest readable size in pixels
+ writeInt16(os, 2); // fontDirectionHint (deprecated, always 2)
+ writeInt16(os, _indexToLocFormat);
+ writeInt16(os, 0); // glyphDataFormat
+}
diff --git a/dviware/dvisvgm/src/ttf/HeadTable.hpp b/dviware/dvisvgm/src/ttf/HeadTable.hpp
new file mode 100644
index 0000000000..6c51957ba0
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/HeadTable.hpp
@@ -0,0 +1,49 @@
+/*************************************************************************
+** HeadTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <limits>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the font header table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/head.htm */
+class HeadTable : public TTFTable {
+ friend class TTFWriter;
+ public:
+ uint32_t tag () const override {return name2id("head");}
+ void updateGlobalBbox (int16_t xmin, int16_t ymin, int16_t xmax, int16_t ymax);
+ void write (std::ostream &os) const override;
+ static int offsetToChecksum () {return 2+2+4;}
+
+ protected:
+ void setLongOffsetFormat () {_indexToLocFormat = 1;}
+
+ private:
+ int16_t _xMin = std::numeric_limits<int16_t>::max();
+ int16_t _yMin = std::numeric_limits<int16_t>::max();
+ int16_t _xMax = std::numeric_limits<int16_t>::min();
+ int16_t _yMax = std::numeric_limits<int16_t>::min();
+ int16_t _indexToLocFormat = 0; // 0: short (16-bit) format, 1: long (32-bit) format
+};
+
+} // namespace ttf
diff --git a/dviware/dvisvgm/src/ttf/HheaTable.cpp b/dviware/dvisvgm/src/ttf/HheaTable.cpp
new file mode 100644
index 0000000000..76a41d86da
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/HheaTable.cpp
@@ -0,0 +1,67 @@
+/*************************************************************************
+** HheaTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 "HheaTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+
+using namespace std;
+using namespace ttf;
+
+
+void HheaTable::write (ostream &os) const {
+ const PhysicalFont &font = ttfWriter()->getFont();
+ double scale = ttfWriter()->unitsPerEmFactor();
+ writeUInt16(os, 1); // major version
+ writeUInt16(os, 0); // minor version
+ writeInt16(os, round(font.ascent()*scale));
+ writeInt16(os, round(-font.descent()*scale));
+ writeInt16(os, 0); // line gap
+ writeUInt16(os, _advanceWidthMax);
+ writeInt16(os, _minLeftSideBearing);
+ writeInt16(os, _minRightSideBearing);
+ writeInt16(os, _xMaxExtent);
+ writeInt16(os, 1); // caretSlopeRise (1 = vertical)
+ writeInt16(os, 0); // caretSlopeRun (0 = vertical)
+ writeInt16(os, 0); // caretOffset
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // metricDataFormat (always 0)
+ writeUInt16(os, _numberOfHMetrics);
+}
+
+
+void HheaTable::updateXMinMax (uint32_t c, int16_t xmin, int16_t xmax) {
+ const PhysicalFont &font = ttfWriter()->getFont();
+ double extend = font.style() ? font.style()->extend : 1;
+ double scale = ttfWriter()->unitsPerEmFactor();
+ int16_t advance = (c == 0 ? xmax : round(scale*extend*font.hAdvance(c)));
+ _xMaxExtent = max(_xMaxExtent, xmax);
+ _minLeftSideBearing = min(_minLeftSideBearing, xmin);
+ _minRightSideBearing = min(_minRightSideBearing, int16_t(advance-xmax));
+}
+
+
+void HheaTable::updateAdvanceWidth (uint16_t w, uint16_t numberOfHMetrics) {
+ _advanceWidthMax = max(_advanceWidthMax, w);
+ _numberOfHMetrics = numberOfHMetrics;
+}
diff --git a/dviware/dvisvgm/src/ttf/HheaTable.hpp b/dviware/dvisvgm/src/ttf/HheaTable.hpp
new file mode 100644
index 0000000000..56fc1ddc4e
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/HheaTable.hpp
@@ -0,0 +1,47 @@
+/*************************************************************************
+** HheaTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+#include <limits>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the horizontal header table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/hhea.htm */
+class HheaTable : public TTFTable {
+ friend class TTFWriter;
+ public:
+ uint32_t tag () const override {return name2id("hhea");}
+ void write (std::ostream &os) const override;
+
+ protected:
+ void updateXMinMax (uint32_t c, int16_t xmin, int16_t xmax);
+ void updateAdvanceWidth (uint16_t w, uint16_t numberOfHMetrics);
+
+ private:
+ uint16_t _advanceWidthMax = 0;
+ int16_t _minLeftSideBearing = std::numeric_limits<int16_t>::max();
+ int16_t _minRightSideBearing = std::numeric_limits<int16_t>::max();
+ int16_t _xMaxExtent = std::numeric_limits<int16_t>::min();
+ uint16_t _numberOfHMetrics = 0;
+};
+
+} // namespace ttf
diff --git a/dviware/dvisvgm/src/ttf/HmtxTable.cpp b/dviware/dvisvgm/src/ttf/HmtxTable.cpp
new file mode 100644
index 0000000000..6e849768fd
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/HmtxTable.cpp
@@ -0,0 +1,62 @@
+/*************************************************************************
+** HmtxTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <cmath>
+#include "HmtxTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+
+using namespace std;
+using namespace ttf;
+
+void HmtxTable::write (ostream &os) const {
+ auto runStart = _widthInfos.end();
+ if (!_widthInfos.empty())
+ runStart -= _runLengthOfAdvWidth-1;
+ // write longHorMetrics up to the beginning of the repeating
+ // advance widths at the end of the container
+ for (auto it = _widthInfos.begin(); it != runStart; ++it) {
+ writeUInt16(os, it->advWidth);
+ writeInt16(os, it->lsb);
+ }
+ // write the trailing left side bearings
+ for (; runStart != _widthInfos.end(); ++runStart)
+ writeInt16(os, runStart->lsb);
+}
+
+
+void HmtxTable::updateWidthData (uint32_t c, int16_t xmin, int16_t xmax) {
+ const PhysicalFont &font = ttfWriter()->getFont();
+ double extend = font.style() ? font.style()->extend : 1;
+ double scale = ttfWriter()->unitsPerEmFactor();
+ int16_t w = (c == 0 ? xmax : int16_t(round(scale*extend*font.hAdvance(c))));
+ if (_isFixedPitch && c > 0 && w != _width) {
+ if (_width == 0)
+ _width = w;
+ else
+ _isFixedPitch = false;
+ }
+ if (_widthInfos.empty() || w == _widthInfos.back().advWidth)
+ _runLengthOfAdvWidth++;
+ else
+ _runLengthOfAdvWidth = 1;
+ _widthInfos.emplace_back(CharWidthInfo(xmin, w));
+ ttfWriter()->updateGlobalAdvanceWidth(w, _widthInfos.size()-_runLengthOfAdvWidth+1);
+} \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/HmtxTable.hpp b/dviware/dvisvgm/src/ttf/HmtxTable.hpp
new file mode 100644
index 0000000000..95c9eba513
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/HmtxTable.hpp
@@ -0,0 +1,52 @@
+/*************************************************************************
+** HmtxTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <vector>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the horizontal metrics table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/hmtx.htm */
+class HmtxTable : public TTFTable {
+ friend TTFWriter;
+ struct CharWidthInfo {
+ CharWidthInfo (int16_t l, int16_t w) : lsb(l), advWidth(w) {}
+ uint16_t lsb; // left side bearing
+ uint16_t advWidth; // unscaled advance width
+ };
+ public:
+ uint32_t tag () const override {return name2id("hmtx");}
+ void write (std::ostream &os) const override;
+ bool isFixedPitch () const {return _isFixedPitch;}
+
+ protected:
+ void updateWidthData (uint32_t c, int16_t xmin, int16_t xmax);
+
+ private:
+ std::vector<CharWidthInfo> _widthInfos;
+ size_t _runLengthOfAdvWidth=0; // number of identical advWidth values at end of _widthInfos
+ bool _isFixedPitch=true;
+ int16_t _width=0;
+};
+
+} // namespace ttf
diff --git a/dviware/dvisvgm/src/ttf/LocaTable.hpp b/dviware/dvisvgm/src/ttf/LocaTable.hpp
new file mode 100644
index 0000000000..8ff51a7bb1
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/LocaTable.hpp
@@ -0,0 +1,56 @@
+/*************************************************************************
+** LocaTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <vector>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the loca table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/loca.htm */
+class LocaTable : public TTFTable {
+ friend class TTFWriter;
+ public:
+ uint32_t tag () const override {return name2id("loca");}
+
+ void write (std::ostream &os) const override {
+ for (uint32_t offs : _offsets) {
+ if (_isShortFormat)
+ writeUInt16(os, offs/2);
+ else
+ writeUInt32(os, offs);
+ }
+ }
+
+ protected:
+ void addOffset (uint32_t offset) {
+ _offsets.push_back(offset);
+ if (offset/2 > 0xFFFF)
+ _isShortFormat = false;
+ }
+
+ private:
+ bool _isShortFormat=true;
+ std::vector<uint32_t> _offsets;
+};
+
+} // namespace ttf
diff --git a/dviware/dvisvgm/src/ttf/Makefile.am b/dviware/dvisvgm/src/ttf/Makefile.am
new file mode 100644
index 0000000000..60883f64cc
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/Makefile.am
@@ -0,0 +1,25 @@
+noinst_LTLIBRARIES = libttf.la
+
+libttf_la_SOURCES = \
+ CmapTable.hpp CmapTable.cpp \
+ GlyfTable.hpp GlyfTable.cpp \
+ HeadTable.hpp HeadTable.cpp \
+ HheaTable.hpp HheaTable.cpp \
+ HmtxTable.hpp HmtxTable.cpp \
+ LocaTable.hpp MaxpTable.cpp \
+ MaxpTable.hpp NameTable.cpp \
+ NameTable.hpp OS2Table.cpp \
+ OS2Table.hpp PostTable.cpp \
+ PostTable.hpp \
+ TTFAutohint.hpp TTFAutohint.cpp \
+ TTFTable.hpp TTFTable.cpp \
+ TTFWriter.hpp TTFWriter.cpp \
+ VheaTable.hpp VheaTable.cpp \
+ VmtxTable.hpp VmtxTable.cpp
+
+include ../../libs/defs.am
+
+AM_CXXFLAGS = \
+ -I$(dvisvgm_srcdir)/libs/boost \
+ -I$(dvisvgm_srcdir)/libs/variant/include \
+ $(BROTLI_CFLAGS) $(WOFF2_CFLAGS)
diff --git a/dviware/dvisvgm/src/ttf/Makefile.in b/dviware/dvisvgm/src/ttf/Makefile.in
new file mode 100644
index 0000000000..b3e1721d82
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/Makefile.in
@@ -0,0 +1,743 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_BROTLI_FALSE@am__append_1 = -I$(dvisvgm_srcdir)/libs/brotli/include
+@HAVE_BROTLI_FALSE@am__append_2 = ../libs/brotli/libbrotli.a
+@HAVE_WOFF2_FALSE@am__append_3 = -I$(dvisvgm_srcdir)/libs/woff2/include
+@HAVE_WOFF2_FALSE@am__append_4 = ../libs/woff2/libwoff2.a
+subdir = src/ttf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \
+ $(top_srcdir)/m4/ax_ac_print_to_file.m4 \
+ $(top_srcdir)/m4/ax_add_am_macro_static.m4 \
+ $(top_srcdir)/m4/ax_am_macros_static.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_code_coverage.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_file_escapes.m4 \
+ $(top_srcdir)/m4/ax_gcc_builtin.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libttf_la_LIBADD =
+am_libttf_la_OBJECTS = CmapTable.lo GlyfTable.lo HeadTable.lo \
+ HheaTable.lo HmtxTable.lo MaxpTable.lo NameTable.lo \
+ OS2Table.lo PostTable.lo TTFAutohint.lo TTFTable.lo \
+ TTFWriter.lo VheaTable.lo VmtxTable.lo
+libttf_la_OBJECTS = $(am_libttf_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/CmapTable.Plo \
+ ./$(DEPDIR)/GlyfTable.Plo ./$(DEPDIR)/HeadTable.Plo \
+ ./$(DEPDIR)/HheaTable.Plo ./$(DEPDIR)/HmtxTable.Plo \
+ ./$(DEPDIR)/MaxpTable.Plo ./$(DEPDIR)/NameTable.Plo \
+ ./$(DEPDIR)/OS2Table.Plo ./$(DEPDIR)/PostTable.Plo \
+ ./$(DEPDIR)/TTFAutohint.Plo ./$(DEPDIR)/TTFTable.Plo \
+ ./$(DEPDIR)/TTFWriter.Plo ./$(DEPDIR)/VheaTable.Plo \
+ ./$(DEPDIR)/VmtxTable.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libttf_la_SOURCES)
+DIST_SOURCES = $(libttf_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/../../libs/defs.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BROTLI_CFLAGS = @BROTLI_CFLAGS@ $(am__append_1)
+BROTLI_LIBS = @BROTLI_LIBS@ $(am__append_2)
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@
+CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATE = @DATE@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GCOV = @GCOV@
+GENHTML = @GENHTML@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KPSE_CFLAGS = @KPSE_CFLAGS@
+KPSE_LIBS = @KPSE_LIBS@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TTFAUTOHINT_CFLAGS = @TTFAUTOHINT_CFLAGS@
+TTFAUTOHINT_LIBS = @TTFAUTOHINT_LIBS@
+VERSION = @VERSION@
+WOFF2_CFLAGS = @WOFF2_CFLAGS@ $(am__append_3)
+WOFF2_LIBS = @WOFF2_LIBS@ $(am__append_4)
+XMLTO = @XMLTO@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+dvisvgm_srcdir = @dvisvgm_srcdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+ifGNUmake = @ifGNUmake@
+ifnGNUmake = @ifnGNUmake@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libttf.la
+libttf_la_SOURCES = \
+ CmapTable.hpp CmapTable.cpp \
+ GlyfTable.hpp GlyfTable.cpp \
+ HeadTable.hpp HeadTable.cpp \
+ HheaTable.hpp HheaTable.cpp \
+ HmtxTable.hpp HmtxTable.cpp \
+ LocaTable.hpp MaxpTable.cpp \
+ MaxpTable.hpp NameTable.cpp \
+ NameTable.hpp OS2Table.cpp \
+ OS2Table.hpp PostTable.cpp \
+ PostTable.hpp \
+ TTFAutohint.hpp TTFAutohint.cpp \
+ TTFTable.hpp TTFTable.cpp \
+ TTFWriter.hpp TTFWriter.cpp \
+ VheaTable.hpp VheaTable.cpp \
+ VmtxTable.hpp VmtxTable.cpp
+
+@HAVE_POTRACE_FALSE@POTRACE_CFLAGS = -I$(dvisvgm_srcdir)/libs/potrace
+@HAVE_POTRACE_FALSE@POTRACE_LIBS = ../libs/potrace/libpotrace.a
+@HAVE_XXHASH_FALSE@XXHASH_CFLAGS = -I$(dvisvgm_srcdir)/libs/xxHash
+@HAVE_XXHASH_FALSE@XXHASH_LIBS = ../libs/xxHash/libxxhash.a
+AM_CXXFLAGS = \
+ -I$(dvisvgm_srcdir)/libs/boost \
+ -I$(dvisvgm_srcdir)/libs/variant/include \
+ $(BROTLI_CFLAGS) $(WOFF2_CFLAGS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../../libs/defs.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/ttf/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/ttf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(srcdir)/../../libs/defs.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libttf.la: $(libttf_la_OBJECTS) $(libttf_la_DEPENDENCIES) $(EXTRA_libttf_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(CXXLINK) $(libttf_la_OBJECTS) $(libttf_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CmapTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GlyfTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HeadTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HheaTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HmtxTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MaxpTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NameTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OS2Table.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PostTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TTFAutohint.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TTFTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TTFWriter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VheaTable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VmtxTable.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/CmapTable.Plo
+ -rm -f ./$(DEPDIR)/GlyfTable.Plo
+ -rm -f ./$(DEPDIR)/HeadTable.Plo
+ -rm -f ./$(DEPDIR)/HheaTable.Plo
+ -rm -f ./$(DEPDIR)/HmtxTable.Plo
+ -rm -f ./$(DEPDIR)/MaxpTable.Plo
+ -rm -f ./$(DEPDIR)/NameTable.Plo
+ -rm -f ./$(DEPDIR)/OS2Table.Plo
+ -rm -f ./$(DEPDIR)/PostTable.Plo
+ -rm -f ./$(DEPDIR)/TTFAutohint.Plo
+ -rm -f ./$(DEPDIR)/TTFTable.Plo
+ -rm -f ./$(DEPDIR)/TTFWriter.Plo
+ -rm -f ./$(DEPDIR)/VheaTable.Plo
+ -rm -f ./$(DEPDIR)/VmtxTable.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/CmapTable.Plo
+ -rm -f ./$(DEPDIR)/GlyfTable.Plo
+ -rm -f ./$(DEPDIR)/HeadTable.Plo
+ -rm -f ./$(DEPDIR)/HheaTable.Plo
+ -rm -f ./$(DEPDIR)/HmtxTable.Plo
+ -rm -f ./$(DEPDIR)/MaxpTable.Plo
+ -rm -f ./$(DEPDIR)/NameTable.Plo
+ -rm -f ./$(DEPDIR)/OS2Table.Plo
+ -rm -f ./$(DEPDIR)/PostTable.Plo
+ -rm -f ./$(DEPDIR)/TTFAutohint.Plo
+ -rm -f ./$(DEPDIR)/TTFTable.Plo
+ -rm -f ./$(DEPDIR)/TTFWriter.Plo
+ -rm -f ./$(DEPDIR)/VheaTable.Plo
+ -rm -f ./$(DEPDIR)/VmtxTable.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/dviware/dvisvgm/src/ttf/MaxpTable.cpp b/dviware/dvisvgm/src/ttf/MaxpTable.cpp
new file mode 100644
index 0000000000..176c9ffcb0
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/MaxpTable.cpp
@@ -0,0 +1,50 @@
+/*************************************************************************
+** MaxpTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <algorithm>
+#include "MaxpTable.hpp"
+#include "TTFWriter.hpp"
+
+using namespace std;
+using namespace ttf;
+
+void MaxpTable::write (ostream &os) const {
+ writeUInt32(os, 0x10000); // version 1.0, required for TTF fonts
+ writeUInt16(os, ttfWriter()->getUnicodeCharMap().numValues()+1); // number of glyphs including .notdef
+ writeUInt16(os, _maxPoints);
+ writeUInt16(os, _maxContours);
+ writeUInt16(os, 0); // maxCompositePoints
+ writeUInt16(os, 0); // maxCompositeContours
+ writeUInt16(os, 1); // maxZones (1 = don't use twilight zone, 2 otherwise)
+ writeUInt16(os, 0); // maxTwilightPoints
+ writeUInt16(os, 0); // maxStorage
+ writeUInt16(os, 0); // maxFunctionDefs
+ writeUInt16(os, 0); // maxInstructionDefs
+ writeUInt16(os, 0); // maxStackElements
+ writeUInt16(os, 0); // maxSizeOfInstructions
+ writeUInt16(os, 0); // maxComponentElements
+ writeUInt16(os, 0); // maxComponentDepth
+}
+
+
+void MaxpTable::updateContourInfo (uint16_t maxPoints, uint16_t maxContours) {
+ _maxPoints = max(_maxPoints, maxPoints);
+ _maxContours = max(_maxContours, maxContours);
+} \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/MaxpTable.hpp b/dviware/dvisvgm/src/ttf/MaxpTable.hpp
new file mode 100644
index 0000000000..b1a08a1aea
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/MaxpTable.hpp
@@ -0,0 +1,42 @@
+/*************************************************************************
+** MaxpTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the maximum profile table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/maxp.htm */
+class MaxpTable : public TTFTable {
+ friend class TTFWriter;
+ public:
+ uint32_t tag () const override {return name2id("maxp");}
+ void write(std::ostream &os) const override;
+
+ protected:
+ void updateContourInfo (uint16_t maxPoints, uint16_t maxContours);
+
+ private:
+ uint16_t _maxPoints=0; ///< maximum number of points used by a contour
+ uint16_t _maxContours=0; ///< maximum number of contours used by a glyph
+};
+
+} // namespace ttf
diff --git a/dviware/dvisvgm/src/ttf/NameTable.cpp b/dviware/dvisvgm/src/ttf/NameTable.cpp
new file mode 100644
index 0000000000..949b6c336c
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/NameTable.cpp
@@ -0,0 +1,105 @@
+/*************************************************************************
+** NameTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <array>
+#include "NameTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+#include "../version.hpp"
+
+using namespace std;
+using namespace ttf;
+
+enum NameID {
+ COPYRIGHT_NOTICE = 0,
+ FONT_FAMILY = 1,
+ FONT_SUBFAMILY = 2,
+ FONT_ID = 3,
+ FULL_FONT_NAME = 4,
+ VERSION_STRING = 5,
+ PS_NAME = 6,
+ TRADEMARK = 7,
+ MANUFACTURER_NAME = 8,
+ DESIGNER = 9,
+ DESCRIPTION = 10,
+ URL_VENDOR = 11,
+ URL_DESIGNER = 12,
+ LICENSE_DESCRIPTION = 13,
+ LICENSE_INFO_URL = 14,
+ TYPOGRAPHIC_FAMILY_NAME = 16,
+ TYPOGRAPHIC_SUBFAMILY_NAME = 17,
+ COMPATIBLE_FULL = 18,
+ SAMPLE_TEXT = 19,
+ PS_CID_FINDFONT_NAME = 20,
+ WWS_FAMILY_NAME = 21,
+ WWS_SUBFAMILY_NAME = 22,
+ LIGHT_BG_PALLETTE = 23,
+ DARK_BG_PALLETTE = 24,
+ VAR_PS_NAME_PREFIX = 25
+};
+
+
+void NameTable::write (ostream &os) const {
+ struct NameEntry {
+ NameID nameID;
+ std::string name;
+ };
+ array<NameEntry,5> nameEntries {{
+ {FONT_FAMILY, ttfWriter()->getFont().familyName()},
+ {FULL_FONT_NAME, ttfWriter()->getFont().name()},
+ {VERSION_STRING, string("Version 1.0")},
+ {PS_NAME, ttfWriter()->getFont().name()},
+ {DESCRIPTION, string("Generated by ")+PROGRAM_NAME+" "+PROGRAM_VERSION}
+ }};
+ writeUInt16(os, 0); // table format
+ writeUInt16(os, 2*nameEntries.size()); // number of name records
+ writeUInt16(os, 6+2*12*nameEntries.size()); // offset to start of string storage
+ size_t offset=0;
+ // write name entry records ordered by platform ID
+ for (const NameEntry &entry : nameEntries) {
+ writeUInt16(os, 1); // Mac
+ writeUInt16(os, 0); // Roman, UTF-8 encoding
+ writeUInt16(os, 0); // English
+ writeUInt16(os, entry.nameID);
+ writeUInt16(os, entry.name.length());
+ writeUInt16(os, offset);
+ offset += entry.name.length();
+ }
+ for (const NameEntry &entry : nameEntries) {
+ writeUInt16(os, 3); // Windows
+ writeUInt16(os, 1); // UCS-2 encoding
+ writeUInt16(os, 0x0409); // US English
+ writeUInt16(os, entry.nameID);
+ writeUInt16(os, 2*entry.name.length());
+ writeUInt16(os, offset);
+ offset += 2*entry.name.length();
+ }
+ // write string data
+ for (const NameEntry &entry : nameEntries) {
+ for (char c : entry.name)
+ writeUInt8(os, c);
+ }
+ for (const NameEntry &entry : nameEntries) {
+ for (char c : entry.name) {
+ writeUInt8(os, 0);
+ writeUInt8(os, c);
+ }
+ }
+}
diff --git a/dviware/dvisvgm/src/ttf/NameTable.hpp b/dviware/dvisvgm/src/ttf/NameTable.hpp
new file mode 100644
index 0000000000..78262ed927
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/NameTable.hpp
@@ -0,0 +1,37 @@
+/*************************************************************************
+** NameTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the naming table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/name.htm */
+class NameTable : public TTFTable {
+ public:
+ uint32_t tag () const override {return name2id("name");}
+ void write (std::ostream &os) const override;
+};
+
+} // namespace ttf \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/OS2Table.cpp b/dviware/dvisvgm/src/ttf/OS2Table.cpp
new file mode 100644
index 0000000000..4ce5ff613b
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/OS2Table.cpp
@@ -0,0 +1,246 @@
+/*************************************************************************
+** OS2Table.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <algorithm>
+#include <array>
+#include <cmath>
+#include <vector>
+#include "OS2Table.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+
+using namespace std;
+using namespace ttf;
+
+
+/** Returns the average width of all non-zero width glyphs.
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#acw */
+int16_t OS2Table::averageCharWidth () const {
+ const RangeMap &charmap = ttfWriter()->getUnicodeCharMap();
+ if (charmap.empty())
+ return 0;
+ int sum=ttfWriter()->hAdvance(0); // width of .notdef character
+ int count=1;
+ for (auto uc2charcode : charmap) {
+ int c = int(uc2charcode.second);
+ if (int w = ttfWriter()->hAdvance(c)) {
+ sum += w;
+ count++;
+ }
+ }
+ return int16_t(double(sum)/count);
+}
+
+static vector<uint32_t> compute_unicode_range_bits (const RangeMap &charmap);
+
+
+void OS2Table::write (ostream &os) const {
+ const PhysicalFont &font = ttfWriter()->getFont();
+ int upem = ttfWriter()->targetUnitsPerEm();
+ double scale = ttfWriter()->unitsPerEmFactor();
+ const RangeMap &charmap = ttfWriter()->getUnicodeCharMap();
+
+ writeUInt16(os, 3); // table version
+ writeInt16(os, averageCharWidth()); // average char width
+ writeUInt16(os, 400); // usWeightClass, "normal" for now
+ writeUInt16(os, 5); // usWidthClass, "medium" for now
+ writeUInt16(os, 0); // fsType
+ writeInt16(os, round(0.65*upem)); // ySubscriptXSize
+ writeInt16(os, round(0.7*upem)); // ySubscriptYSize
+ writeInt16(os, round(-0.48*upem)); // ySubscriptXOffset
+ writeInt16(os, round(0.14*upem)); // ySubscriptYOffset
+ writeInt16(os, round(0.65*upem)); // ySuperscriptXSize
+ writeInt16(os, round(0.7*upem)); // ySuperscriptYSize
+ writeInt16(os, round(0.48*upem)); // ySuperscriptXOffset
+ writeInt16(os, round(0.48*upem)); // ySuperscriptYOffset
+ writeInt16(os, 102*upem/2048); // yStrikeoutSize
+ writeInt16(os, 530*upem/2048); // yStrikeoutPosition
+ writeInt16(os, 0); // sFamilyClass (no classification)
+ for (uint8_t p : {0, 0, 6, 0, 0, 0, 0, 0, 0, 0}) // Panose
+ writeUInt8(os, p);
+ for (uint32_t bits : compute_unicode_range_bits(charmap))
+ writeUInt32(os, bits);
+ writeUInt32(os, name2id("dsvg"));
+ writeUInt16(os, 6); // fsSelection, "regular" for now
+ writeUInt16(os, min(charmap.minKey(), uint32_t(0xFFFF))); // usFirstCharIndex
+ writeUInt16(os, min(charmap.maxKey(), uint32_t(0xFFFF))); // usLastCharIndex
+ writeInt16(os, round(scale*font.ascent())); // sTypoAscender
+ writeInt16(os, round(-scale*font.descent())); // sTypoDescender
+ writeInt16(os, 0); // sTypoLineGap
+ writeUInt16(os, round(scale*font.ascent()));
+ writeUInt16(os, round(scale*font.descent()));
+ writeUInt32(os, 1); // ulCodePageRange1, "Latin 1" for now
+ writeUInt32(os, 0); // ulCodePageRange2
+ writeInt16(os, 0); // sxHeight
+ writeInt16(os, charmap.valueExists(0x48) ? 0x48 : 0); // sCapHeight
+ writeUInt16(os, 0); // usDefaultChar
+ writeUInt16(os, charmap.valueExists(0x20) ? 0x20 : 0xffff); // usBreakChar (space or .notdef)
+ writeUInt16(os, 0); // usMaxContext
+}
+
+#if 0
+void OS2Table::updateYMinMax (int16_t ymin, int16_t ymax) {
+ _usWinAscent = max(_usWinAscent, uint16_t(ymax));
+ _usWinDescent = max(_usWinDescent, uint16_t(ymin < 0 ? -ymin : 0));
+}
+#endif
+
+
+/** Returns the bit number denoting the Unicode range for a codepoint according to
+ * the OS/2 table specification. If there's no matching range for the codepoint,
+ * the function returns -1. Currently, only the ranges specified by OS/2 table
+ * version 1 are considered. */
+static int unicode_range_bit (uint32_t codepoint) {
+ struct UCRange {
+ UCRange (uint32_t cp) : first(cp), last(cp), os2bit(0) {}
+ UCRange (uint32_t cp1, uint32_t cp2, int bit) : first(cp1), last(cp2), os2bit(bit) {}
+ uint32_t first, last;
+ int os2bit;
+ };
+ // Unicode ranges according to http://unicode.org/Public/UNIDATA/Blocks.txt
+ static array<UCRange, 100> ucranges {{
+ {0x00020, 0x0007E, 0}, // Basic Latin
+ {0x000A0, 0x000FF, 1}, // Latin-1 Supplement
+ {0x00100, 0x0017F, 2}, // Latin Extended-A
+ {0x00180, 0x0024F, 3}, // Latin Extended-B
+ {0x00250, 0x002AF, 4}, // IPA Extensions
+ {0x002B0, 0x002FF, 5}, // Spacing Modifier Letters
+ {0x00300, 0x0036F, 6}, // Combining Diacritical Marks
+ {0x00370, 0x003FF, 7}, // Greek and Coptic
+ {0x00400, 0x0052F, 9}, // Cyrillic / Cyrillic Supplement
+ {0x00530, 0x0058F, 10}, // Armenian
+ {0x00590, 0x005FF, 11}, // Hebrew
+ {0x00600, 0x006FF, 13}, // Arabic
+ {0x00700, 0x0074F, 71}, // Syriac
+ {0x00750, 0x0077F, 13}, // Arabic Supplement
+ {0x00780, 0x007BF, 72}, // Thaana
+ {0x007C0, 0x007FF, 14}, // N'Ko
+ {0x00800, 0x0083F, 12}, // Samaritan
+ {0x00900, 0x0097F, 15}, // Devanagari
+ {0x00980, 0x009FF, 16}, // Bengali
+ {0x00A00, 0x00A7F, 17}, // Gurmukhi
+ {0x00A80, 0x00AFF, 18}, // Gujarati
+ {0x00B00, 0x00B7F, 19}, // Oriya
+ {0x00B80, 0x00BFF, 20}, // Tamil
+ {0x00C00, 0x00C7F, 21}, // Telugu
+ {0x00C80, 0x00CFF, 22}, // Kannada
+ {0x00D00, 0x00D7F, 23}, // Malayalam
+ {0x00E00, 0x00E7F, 24}, // Thai
+ {0x00E80, 0x00EFF, 25}, // Lao
+ {0x010A0, 0x010FF, 26}, // Georgian
+ {0x01100, 0x011FF, 28}, // Hangul Jamo
+ {0x01B00, 0x01B7F, 27}, // Balinese
+ {0x01D00, 0x01DBF, 4}, // Phonetic Extensions & Supplement
+ {0x01D80, 0x01DFF, 6}, // Combining Diacritical Marks Supplement
+ {0x01E00, 0x01EFF, 29}, // Latin Extended Additional
+ {0x01F00, 0x01FFF, 30}, // Greek Extended
+ {0x02000, 0x0206F, 31}, // General Punctuation
+ {0x02070, 0x0209F, 32}, // Superscripts and Subscripts
+ {0x020A0, 0x020CF, 33}, // Currency Symbols
+ {0x020D0, 0x020FF, 34}, // Combining Marks for Symbols
+ {0x02100, 0x0214F, 35}, // Letterlike Symbols
+ {0x02150, 0x0218F, 36}, // Number Forms
+ {0x02190, 0x021FF, 37}, // Arrows
+ {0x02200, 0x022FF, 38}, // Mathematical Operators
+ {0x02300, 0x0237F, 39}, // Miscellaneous Technical
+ {0x02400, 0x0243F, 40}, // Control Pictures
+ {0x02440, 0x0245F, 41}, // Optical Character Recognition
+ {0x02460, 0x024FF, 42}, // Enclosed Alphanumerics
+ {0x02500, 0x0257F, 43}, // Box Drawing
+ {0x02580, 0x0259F, 44}, // Block Elements
+ {0x025A0, 0x025FF, 45}, // Geometric Shapes
+ {0x02600, 0x0267F, 46}, // Miscellaneous Symbols
+ {0x02700, 0x027BF, 47}, // Dingbats
+ {0x027C0, 0x027EF, 38}, // Miscellaneous Mathematical Symbols-A
+ {0x027F0, 0x027FF, 37}, // Supplementary Arrows-A
+ {0x02800, 0x028FF, 82}, // Braille Patterns
+ {0x02900, 0x0297F, 37}, // Supplementary Arrows-B
+ {0x02980, 0x02AFF, 38}, // Miscellaneous Mathematical Symbols-B + Supplemental Mathematical Operators
+ {0x02B00, 0x02BFF, 37}, // Miscellaneous Symbols and Arrows
+ {0x02C60, 0x02C7F, 29}, // Latin Extended-C
+ {0x02C80, 0x02CFF, 8}, // Coptic
+ {0x02D00, 0x02D25, 26}, // Georgian Supplement
+ {0x02DE0, 0x02DFF, 9}, // Cyrillic Extended-A
+ {0x02E00, 0x02E7F, 31}, // Supplemental Punctuation
+ {0x02E80, 0x02FFF, 59}, // CJK Radicals Supplement + Kangxi Radicals + Ideographic Description Characters
+ {0x03000, 0x0303F, 48}, // CJK Symbols and Punctuation
+ {0x03040, 0x0309F, 49}, // Hiragana
+ {0x030A0, 0x030FF, 50}, // Katakana
+ {0x03100, 0x0312F, 51}, // Bopomofo
+ {0x03130, 0x0318F, 52}, // Hangul Compatibility Jamo
+ {0x03190, 0x0319F, 59}, // Kanbun
+ {0x031A0, 0x031BF, 51}, // Bopomofo Extended
+ {0x031F0, 0x031FF, 50}, // Katakana Phonetic Extensions
+ {0x03200, 0x032FF, 54}, // Enclosed CJK Letters and Months
+ {0x03300, 0x033FF, 55}, // CJK compatability
+ {0x03400, 0x04DBF, 59}, // CJK Unified Ideographs Extension A
+ {0x04E00, 0x09FFF, 59}, // CJK Unified Ideographs
+ {0x0A500, 0x0A62B, 12}, // Vai
+ {0x0A640, 0x0A69F, 9}, // Cyrillic Extended-B
+ {0x0A700, 0x0A71F, 5}, // Modifier Tone Letters
+ {0x0A720, 0x0A7FF, 29}, // Latin Extended-D
+ {0x0A840, 0x0A87F, 53}, // Phags-pa
+ {0x0AC00, 0x0D7AF, 56}, // Hangul Syllables
+ {0x0D800, 0x0DFFF, 57}, // Non-Plane 0
+ {0x0E000, 0x0F8FF, 60}, // Private Use Area
+ {0x0F900, 0x0FAFF, 61}, // CJK Compatibility Ideographs
+ {0x0FA2A, 0x0FAFF, 61}, // CJK Compatibility Ideographs
+ {0x0FB00, 0x0FB4F, 62}, // Alphabetic Presentation Forms
+ {0x0FB50, 0x0FDFF, 63}, // Arabic Presentation Forms-A
+ {0x0FE00, 0x0FE0F, 91}, // Variation Selectors
+ {0x0FE20, 0x0FE2F, 64}, // Combining Half Marks
+ {0x0FE30, 0x0FE4F, 65}, // CJK Compatibility Forms
+ {0x0FE50, 0x0FE6F, 66}, // Small Form Variants
+ {0x0FE70, 0x0FEEF, 67}, // Arabic Presentation Forms-B
+ {0x0FF00, 0x0FFEF, 68}, // Halfwidth and Fullwidth Forms
+ {0x0FFF0, 0x0FFFF, 69}, // Specials
+ {0x10900, 0x1091F, 58}, // Phoenician
+ {0x20000, 0x2A6DF, 59}, // CJK Unified Ideographs Extension B
+ {0x2A700, 0x2B73F, 59}, // CJK Unified Ideographs Extension C
+ {0x2B740, 0x2B81F, 59}, // CJK Unified Ideographs Extension D
+ {0x2F800, 0x2FA1F, 61}, // CJK Compatibility Ideographs Supplement
+ }};
+ auto it = lower_bound(ucranges.begin(), ucranges.end(), UCRange(codepoint), [](const UCRange &r1, const UCRange &r2) {
+ return r1.last < r2.first;
+ });
+ if (it != ucranges.end() && codepoint >= it->first && codepoint <= it->last)
+ return it->os2bit;
+ return -1;
+}
+
+
+/** Returns the Unicode ranges encompassed by the font. The ranges are encoded by four dwords,
+ * where each of the 128 bits represents a certain range. The returned vector contains the
+ * dwords in little-endian order, i.e. [bits 0-31, bits 32-63, bits 64-95, bits 96-127]. */
+static vector<uint32_t> compute_unicode_range_bits (const RangeMap &charmap) {
+ vector<uint32_t> rangeBits(4, 0);
+ for (auto uc2charcode : charmap) {
+ int bit = unicode_range_bit(uc2charcode.first);
+ if (bit >= 0) {
+ for (int i=0; i < 4; i++) {
+ if (bit < 32*(i+1)) {
+ rangeBits[i] |= (1 << (bit-32*i));
+ break;
+ }
+ }
+ }
+ }
+ return rangeBits;
+}
diff --git a/dviware/dvisvgm/src/ttf/OS2Table.hpp b/dviware/dvisvgm/src/ttf/OS2Table.hpp
new file mode 100644
index 0000000000..8861fdea7a
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/OS2Table.hpp
@@ -0,0 +1,46 @@
+/*************************************************************************
+** OS2Table.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <array>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the OS/2 and Windows metrics
+ * table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/os2.htm */
+class OS2Table : public TTFTable {
+ friend class TTFWriter;
+ public:
+ uint32_t tag () const override {return name2id("OS/2");}
+ void write (std::ostream &os) const override;
+
+ protected:
+ int16_t averageCharWidth () const;
+ void updateXMinMax (int16_t xmin, int16_t xmax) {_xmax = xmax;}
+ void updateYMinMax (int16_t ymin, int16_t ymax) {}
+
+ private:
+ int16_t _xmax=0;
+};
+
+} // namespace ttf \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/PostTable.cpp b/dviware/dvisvgm/src/ttf/PostTable.cpp
new file mode 100644
index 0000000000..650faf5467
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/PostTable.cpp
@@ -0,0 +1,63 @@
+/*************************************************************************
+** PostTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 "PostTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+
+using namespace std;
+using namespace ttf;
+
+#if 0
+/** Writes a string in Pascal format to an output stream. The string should not be
+ * longer than 255 characters. Otherwise, it's truncated accordingly. */
+static void write_pascal_string (ostream &os, const string &str) {
+ size_t len = std::min(str.length(), size_t(255));
+ writeUInt8(os, len); // first byte determines the string length
+ for (size_t i=0; i < len; i++)
+ writeUInt8(os, str[i]);
+}
+#endif
+
+
+void PostTable::write (ostream &os) const {
+ writeUInt32(os, 0x30000); // table version 3
+ writeInt32(os, 0); // italic angle
+ writeInt16(os, 0); // underline position
+ writeInt16(os, 0); // underline thickness
+ writeUInt32(os, ttfWriter()->isFixedPitch()); // 1 = fixed pitch
+ writeUInt32(os, 0); // minMemType42
+ writeUInt32(os, 0); // maxMemType42
+ writeUInt32(os, 0); // minMemType1
+ writeUInt32(os, 0); // maxMemType1
+/* writeUInt16(os, ttfWriter()->getUnicodeCharMap().numValues());
+ // write name indexes in glyph ID order (index 0 = ".notdef")
+ uint16_t index=0;
+ for (auto cp2charcode : ttfWriter()->getUnicodeCharMap()) {
+ string name = ttfWriter()->getFont().glyphName(cp2charcode.second);
+ writeUInt16(os, name.empty() || name == ".notdef" ? 0 : ++index);
+ }
+ // write the glyph names in glyph ID order
+ for (auto cp2charcode : ttfWriter()->getUnicodeCharMap()) {
+ string name = ttfWriter()->getFont().glyphName(cp2charcode.second);
+ if (!name.empty() && name != ".notdef")
+ write_pascal_string(os, name);
+ }*/
+}
diff --git a/dviware/dvisvgm/src/ttf/PostTable.hpp b/dviware/dvisvgm/src/ttf/PostTable.hpp
new file mode 100644
index 0000000000..782f15085e
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/PostTable.hpp
@@ -0,0 +1,37 @@
+/*************************************************************************
+** PostTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <algorithm>
+#include <map>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the PostScript table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/post.htm */
+class PostTable : public TTFTable {
+ public:
+ uint32_t tag () const override {return name2id("post");}
+ void write (std::ostream &os) const override;
+};
+
+} // namespace ttf \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/TTFAutohint.cpp b/dviware/dvisvgm/src/ttf/TTFAutohint.cpp
new file mode 100644
index 0000000000..fe6c6bafc2
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/TTFAutohint.cpp
@@ -0,0 +1,161 @@
+/*************************************************************************
+** TTFAutohint.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <fstream>
+#include <memory>
+#include "../MessageException.hpp"
+#include "../utility.hpp"
+#include "TTFAutohint.hpp"
+
+using namespace std;
+using namespace ttf;
+
+#ifndef HAVE_TTFAUTOHINT_H
+TTFAutohint::TTFAutohint () {}
+
+bool TTFAutohint::available () const {
+ return false;
+}
+
+int TTFAutohint::autohint (const string&, const string&, bool) {
+ return 0;
+}
+
+string TTFAutohint::lastErrorMessage () const {
+ return "";
+}
+
+string TTFAutohint::version () const {
+ return "";
+}
+
+#else // HAVE_TTFAUTOHINT_H
+
+#include <ttfautohint.h>
+
+#ifndef HAVE_LIBTTFAUTOHINT
+static string get_libttfautohint () {
+#ifdef _WIN32
+ return "ttfautohint.dll";
+#else
+ string dlname = "libttfautohint.so.1";
+#ifdef __APPLE__
+ DLLoader loader(dlname);
+ if (!loader.loaded())
+ dlname = "libttfautohint.1.dylib";
+#endif
+ return dlname;
+#endif // _WIN32
+}
+#endif // HAVE_LIBTTFAUTOHINT
+
+
+TTFAutohint::TTFAutohint ()
+#ifndef HAVE_LIBTTFAUTOHINT
+ : DLLoader(get_libttfautohint())
+#endif
+{
+}
+
+
+/** Returns true if the ttfautohint library is present. */
+bool TTFAutohint::available () const {
+#ifdef HAVE_LIBTTFAUTOHINT
+ return true;
+#else
+ return loaded();
+#endif
+}
+
+
+/** Runs ttfautohint on a given font file.
+ * @param[in] source name of TTF input file
+ * @param[in] target name of TTF output file
+ * @param[in] rehintIfSymbolFont if true, ttfautohint is run again with option "symbol" in case regular hinting is rejected.
+ * @return ttfautohint error code (0 = success) */
+int TTFAutohint::autohint (const string &source, const string &target, bool rehintIfSymbolFont) {
+#ifdef HAVE_LIBTTFAUTOHINT
+ auto fn = &TTF_autohint;
+#else
+ auto fn = LOAD_SYMBOL(TTF_autohint);
+#endif
+ int ret=0;
+ if (fn) {
+ _lastErrorMessage = nullptr;
+ ifstream ifs(source, ios::binary|ios::ate);
+ if (!ifs)
+ throw MessageException("failed to open '"+source+"' for reading");
+ size_t inbufSize = ifs.tellg();
+ ifs.seekg(0, ios::beg);
+ auto inbuf = util::make_unique<char[]>(inbufSize);
+ if (!ifs.read(inbuf.get(), inbufSize))
+ throw MessageException("failed to read from '"+source+"'");
+ char *outbuf = nullptr;
+ size_t outbufSize;
+ ret = fn("in-buffer, in-buffer-len, out-buffer, out-buffer-len, default-script, error-string, alloc-func",
+ inbuf.get(), inbufSize, &outbuf, &outbufSize, "latn", &_lastErrorMessage, &std::malloc);
+ if (ret == TA_Err_Missing_Glyph && rehintIfSymbolFont) {
+ ifs.clear();
+ ifs.seekg(0, ios::beg);
+ std::free(outbuf);
+ ret = fn("in-buffer, in-buffer-len, out-buffer, out-buffer-len, symbol, error-string, alloc-func",
+ inbuf.get(), inbufSize, &outbuf, &outbufSize, true, &_lastErrorMessage, &std::malloc);
+ }
+ if (ret == 0) {
+ ofstream ofs(target, ios::binary);
+ if (ofs)
+ ofs.write(outbuf, outbufSize);
+ else
+ throw MessageException("failed to open '"+target+"' for writing");
+ }
+ std::free(outbuf);
+ }
+ return ret;
+}
+
+
+/** Returns the error message of the last autohint call. */
+string TTFAutohint::lastErrorMessage () const {
+ string message;
+ if (_lastErrorMessage)
+ message = reinterpret_cast<const char*>(_lastErrorMessage);
+ return message;
+}
+
+
+/** Returns the version number of ttfautohint. */
+string TTFAutohint::version () const {
+#ifdef HAVE_LIBTTFAUTOHINT
+ auto fn = &TTF_autohint_version;
+#else
+ auto fn = LOAD_SYMBOL(TTF_autohint_version);
+#endif
+ string ret;
+ if (fn) {
+ int major, minor, revision;
+ fn(&major, &minor, &revision);
+ ret = to_string(major)+"."+to_string(minor);
+ if (revision)
+ ret += "."+to_string(revision);
+ }
+ return ret;
+}
+
+#endif // HAVE_TTFAUTOHINT_H
diff --git a/dviware/dvisvgm/src/ttf/TTFAutohint.hpp b/dviware/dvisvgm/src/ttf/TTFAutohint.hpp
new file mode 100644
index 0000000000..9389d33114
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/TTFAutohint.hpp
@@ -0,0 +1,52 @@
+/*************************************************************************
+** TTFAutohint.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <config.h>
+#include <string>
+
+#if defined(HAVE_TTFAUTOHINT_H) && !defined(HAVE_LIBTTFAUTOHINT)
+#include "../DLLoader.hpp"
+#endif
+
+namespace ttf {
+
+class TTFAutohint
+#if defined(HAVE_TTFAUTOHINT_H) && !defined(HAVE_LIBTTFAUTOHINT)
+ : public DLLoader
+#endif
+{
+ public:
+ TTFAutohint ();
+ TTFAutohint (const TTFAutohint &ta) =delete;
+ bool available () const;
+ int autohint (const std::string &source, const std::string &target, bool rehintIfSymbolFont);
+ std::string lastErrorMessage () const;
+ std::string version () const;
+
+#ifdef HAVE_TTFAUTOHINT_H
+ private:
+ const unsigned char *_lastErrorMessage; ///< message created by last call of 'autohint'
+#endif
+};
+
+} // namespace ttf
+
diff --git a/dviware/dvisvgm/src/ttf/TTFTable.cpp b/dviware/dvisvgm/src/ttf/TTFTable.cpp
new file mode 100644
index 0000000000..2b04f3335f
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/TTFTable.cpp
@@ -0,0 +1,94 @@
+/*************************************************************************
+** TTFTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <vectorstream.hpp>
+#include <zlib.h>
+#include "TTFTable.hpp"
+
+using namespace std;
+using namespace ttf;
+
+
+TableBuffer::TableBuffer (uint32_t tag, vector<char> data)
+ : _tag(tag), _unpaddedSize(data.size()), _compressedSize(_unpaddedSize), _data(std::move(data))
+{
+ _data.resize((_unpaddedSize+3) & ~3, 0); // ensure data.size() % 4 == 0
+ for (size_t i=0; i < paddedSize(); i+=4) {
+ auto *bytes = reinterpret_cast<const uint8_t*>(_data.data());
+ _checksum += bytes[i]*0x1000000 + bytes[i+1]*0x010000 + bytes[i+2]*0x0100 + bytes[i+3];
+ }
+}
+
+
+TableBuffer::TableBuffer (uint32_t tag, vector<char> data, size_t checksumExcludeOffset)
+ : TableBuffer(tag, std::move(data))
+{
+ if (checksumExcludeOffset+4 < _data.size())
+ _checksum -= getUInt32(checksumExcludeOffset);
+}
+
+
+string TableBuffer::name () const {
+ string ret;
+ for (int i=3; i >= 0; i--) {
+ char c = char(_tag >> (8*i));
+ ret += (c >= 32 && c <= 126 ? c : '*');
+ }
+ return ret;
+}
+
+
+/** Tries to compress the buffer data. If the size of the compressed buffer data is
+ * greater or equal than the size of the uncompressed data, the buffer stays uncompressed.
+ * @returns true if the data was compressed */
+void TableBuffer::compress () {
+ if (_data.size() < 16)
+ return;
+ uLong compressedSize = compressBound(_data.size());
+ vector<char> compressedData(compressedSize, 0);
+ // 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.
+ auto source = reinterpret_cast<const Bytef*>(_data.data());
+ auto target = reinterpret_cast<Bytef*>(&compressedData[0]);
+ if (compress2(target, &compressedSize, source, _unpaddedSize, Z_BEST_COMPRESSION) == Z_OK && compressedSize < _unpaddedSize) {
+ _compressedSize = compressedSize;
+ _data = std::move(compressedData);
+ _data.resize((compressedSize+3) & ~3, 0); // reduce buffer to padded compressed size
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+/** Creates a buffer object containing the binary data represented by this table. */
+TableBuffer TTFTable::createBuffer () const {
+ ovectorstream<vector<char>> vecstream;
+ write(vecstream);
+ vector<char> vec;
+ vecstream.swap_vector(vec); // move data from vector stream to vec
+ return TableBuffer(tag(), std::move(vec));
+}
+
+
+string TTFTable::name () const {
+ string ret;
+ for (int i=3; i >= 0; i--)
+ ret += char(tag() >> (8*i));
+ return ret;
+}
diff --git a/dviware/dvisvgm/src/ttf/TTFTable.hpp b/dviware/dvisvgm/src/ttf/TTFTable.hpp
new file mode 100644
index 0000000000..c47610ec7c
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/TTFTable.hpp
@@ -0,0 +1,108 @@
+/*************************************************************************
+** TTFTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+#include <ostream>
+#include <sstream>
+#include <vector>
+
+namespace ttf {
+
+/** Class to handle the binary TTF table data. */
+class TableBuffer {
+ friend class TTFWriter;
+ public:
+ TableBuffer (uint32_t tag, std::vector<char> data);
+ TableBuffer (uint32_t tag, std::vector<char> data, size_t checksumExcludeOffset);
+ uint32_t tag () const {return _tag;}
+ uint32_t unpaddedSize () const {return _unpaddedSize;}
+ uint32_t paddedSize () const {return uint32_t(_data.size());}
+ uint32_t compressedSize () const {return _compressedSize;}
+ uint32_t checksum () const {return _checksum;}
+ void compress ();
+ std::string name () const;
+
+ uint8_t getUInt8 (size_t offs) const {return _data[offs];}
+ uint16_t getUInt16 (size_t offs) const {return getUInt8(offs)*0x100 + getUInt8(offs+1);}
+ uint32_t getUInt32 (size_t offs) const {return getUInt16(offs)*0x10000 + getUInt16(offs+2);}
+
+ /** Writes the n bytes of a given value in big-endian order to the buffer.
+ * The buffer must be big enough to take the value at the desired position.
+ * It is not resized automatically.
+ * @param[in] offset offset/index the first byte is written to
+ * @param[in] val the value to write */
+ template <typename T>
+ void setData (size_t offset, const T val) {
+ if (offset+sizeof(T) <= _data.size()) {
+ typename std::make_unsigned<T>::type uval = val;
+ for (int i = sizeof(T)-1; i >= 0; i--) {
+ _data[offset+i] = uint8_t(uval & 0xff);
+ uval >>= 8;
+ }
+ }
+ }
+
+ /** Writes the buffer data to the given output stream. */
+ void write (std::ostream &os) const {
+ os.write(_data.data(), _data.size());
+ }
+
+ private:
+ uint32_t _tag; ///< tag/ID of corresponding TTF table
+ uint32_t _unpaddedSize; ///< size of the buffer excluding pad bytes
+ uint32_t _compressedSize; ///< sizeof compressed buffer excluding pad bytes
+ uint32_t _checksum=0; ///< checksum of uncompressed data
+ std::vector<char> _data; ///< the (compressed/uncompressed) table data including pad bytes
+};
+
+
+class TTFWriter;
+
+/** Abstract base class for all TTF tables. */
+class TTFTable {
+ friend class TTFWriter;
+ public:
+ virtual ~TTFTable () =default;
+ virtual uint32_t tag () const =0;
+ virtual void write (std::ostream &os) const =0;
+ bool active () const {return _ttfWriter != nullptr;}
+ TableBuffer createBuffer () const;
+ std::string name () const;
+
+ static constexpr uint32_t name2id (const char *str) {
+ return (str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3];
+ }
+
+ protected:
+ void setTTFWriter (TTFWriter *ttfWriter) {_ttfWriter = ttfWriter;}
+ TTFWriter* ttfWriter () const {return _ttfWriter;}
+
+ static void writeUInt8 (std::ostream &os, uint8_t val) {os.put(val);}
+ static void writeUInt16 (std::ostream &os, uint16_t val) {os.put(val >> 8); os.put(val & 0xff);}
+ static void writeUInt32 (std::ostream &os, uint32_t val) {writeUInt16(os, val >> 16); writeUInt16(os, val & 0xffff);}
+ static void writeInt8 (std::ostream &os, int8_t val) {writeUInt8(os, uint8_t(val));}
+ static void writeInt16 (std::ostream &os, int16_t val) {writeUInt16(os, uint16_t(val));}
+ static void writeInt32 (std::ostream &os, int32_t val) {writeUInt32(os, uint32_t(val));}
+
+ private:
+ TTFWriter *_ttfWriter=nullptr;
+};
+
+} // namespace ttf
diff --git a/dviware/dvisvgm/src/ttf/TTFWriter.cpp b/dviware/dvisvgm/src/ttf/TTFWriter.cpp
new file mode 100644
index 0000000000..2dacdfc567
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/TTFWriter.cpp
@@ -0,0 +1,422 @@
+/*************************************************************************
+** TTFWriter.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <cmath>
+#include <iterator>
+#include <fstream>
+#include <list>
+#include <numeric>
+#include <woff2/encode.h>
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+#include "../utility.hpp"
+
+using namespace std;
+using namespace ttf;
+
+#ifdef TTFDEBUG
+bool TTFWriter::CREATE_PS_GLYPH_OUTLINES;
+#endif
+
+
+TTFWriter::TTFWriter (const PhysicalFont &font, const set<int> &chars) :
+ _font(font),
+ _tracerCallback(),
+ _tables({&_cmap, &_glyf, &_hmtx, &_hhea, &_loca, &_maxp, &_name, &_os2, &_post, &_head}) // mandatory tables
+{
+ if (font.verticalLayout()) { // is font designed for vertical layout?
+ _tables.push_back(&_vmtx);
+ _tables.push_back(&_vhea);
+ }
+ for (TTFTable *table : _tables)
+ table->setTTFWriter(this);
+ for (uint32_t c : chars) {
+ uint32_t codepoint = font.unicode(c);
+ _unicodeCharMap.addRange(codepoint, codepoint, c);
+ }
+}
+
+
+/** Pseudo table representing the TTF header (aka "offset table"). */
+class TTFHeader : public TTFTable {
+ public:
+ explicit TTFHeader (uint16_t numTables) : _numTables(numTables) {}
+ uint32_t tag () const override {return 0;}
+
+ void write (ostream &os) const override {
+ writeUInt32(os, 0x00010000); // sfntVersion
+ writeUInt16(os, _numTables);
+ uint16_t entrySelector = util::ilog2(_numTables);
+ uint16_t searchRange = (1 << entrySelector)*16;
+ writeUInt16(os, searchRange);
+ writeUInt16(os, entrySelector);
+ writeUInt16(os, _numTables*16-searchRange); // rangeShift
+ }
+
+ private:
+ uint16_t _numTables;
+};
+
+
+/** Pseudo table representing the table records. */
+class TTFTableRecords : public TTFTable {
+ public:
+ explicit TTFTableRecords (const list<TableBuffer> &buffers) : _buffers(buffers) {}
+ uint32_t tag () const override {return 0;}
+
+ void write (ostream &os) const override {
+ int numTables = 0;
+ for (const TableBuffer &buffer : _buffers)
+ if (buffer.tag())
+ numTables++;
+ uint32_t offset = 12 + 16*numTables;
+ for (const TableBuffer &buffer : _buffers) {
+ if (buffer.tag()) {
+ writeUInt32(os, buffer.tag());
+ writeUInt32(os, buffer.checksum());
+ writeUInt32(os, offset);
+ writeUInt32(os, buffer.unpaddedSize());
+ offset += buffer.paddedSize();
+ }
+ }
+ }
+
+ private:
+ const list<TableBuffer> &_buffers;
+};
+
+
+/** Writes the font data in TrueType format to the given output stream. */
+bool TTFWriter::writeTTF (ostream &os) {
+ list<TableBuffer> buffers = createTableBuffers();
+ // write TTF data
+ for (; !buffers.empty(); buffers.pop_front())
+ buffers.front().write(os);
+ return true; // @@
+}
+
+
+/** Writes the font data in TrueType format to the given file. */
+bool TTFWriter::writeTTF (const string &ttfname) {
+ ofstream ofs(ttfname, ios::binary);
+ if (ofs)
+ return writeTTF(ofs);
+ return false;
+}
+
+
+/** Returns a list containing the binary TTF data segmented by the TTF tables.
+ * The first two list entries represent the TTF header (aka "offset table") and
+ * the table records, respectively. */
+std::list<TableBuffer> TTFWriter::createTableBuffers () {
+ list<TableBuffer> buffers;
+ for (const TTFTable *table : _tables)
+ buffers.emplace_back(table->createBuffer());
+ // sort table buffers according to their tag/ID in ascending order
+ buffers.sort([](const TableBuffer &buf1, const TableBuffer &buf2) {
+ return buf1.tag() < buf2.tag();
+ });
+ TTFHeader header(_tables.size());
+ TTFTableRecords records(buffers);
+ buffers.emplace_front(records.createBuffer());
+ buffers.emplace_front(header.createBuffer());
+ // compute global checksum (checkSumAdjustment entry of head table)
+ uint32_t checksum=0;
+ for (const TableBuffer &buffer : buffers)
+ checksum += buffer.checksum();
+ checksum = 0xB1B0AFBA-checksum;
+ // write checksum directly to the head table buffer
+ auto headBufferIt = find_if(buffers.begin(), buffers.end(), [](const TableBuffer &buf) {
+ return buf.tag() == TTFTable::name2id("head");
+ });
+ headBufferIt->setData(_head.offsetToChecksum(), checksum);
+ return buffers;
+}
+
+
+/** Returns a factor c that scales the units per EM of the source font to
+ * a value which is a power of 2, i.e. log2(c*upem) is an integer. */
+double TTFWriter::unitsPerEmFactor () const {
+ double target_upem = targetUnitsPerEm();
+ return target_upem > 0 ? (target_upem/_font.unitsPerEm()) : 0.0;
+}
+
+
+/** Returns the units per EM of the TTF font to be written.
+ * According to the OTF specification, the value should be a power of 2
+ * if the font contains TTF outlines. */
+int TTFWriter::targetUnitsPerEm () const {
+ int upem = _font.unitsPerEm();
+ if (upem == 0)
+ return 0;
+
+ if (upem < 16)
+ return 16; // minimum allowed upem in TTF/OTF
+ if (upem > 0x4000)
+ return 0x4000; // maximum allowed upem in TTF/OTF
+ int log2_upem = util::ilog2(upem);
+ if ((1 << log2_upem) == upem) // is upem of source font a power of 2?
+ return upem;
+ return 1 << (log2_upem+1);
+}
+
+
+int16_t TTFWriter::hAdvance (uint16_t c) const {
+ double scale = unitsPerEmFactor();
+ double extend = _font.style() ? _font.style()->extend : 1;
+ return int16_t(round(scale*extend*_font.hAdvance(c)));
+}
+
+
+void TTFWriter::updateGlobalBbox (uint32_t c, int16_t xmin, int16_t ymin, int16_t xmax, int16_t ymax) {
+ if (xmin != 0 || ymin != 0 || xmax != 0 || ymax != 0)
+ _hhea.updateXMinMax(c, xmin, xmax);
+ if (xmin == 0 && xmax == 0)
+ xmax = hAdvance(c);
+ _head.updateGlobalBbox(xmin, ymin, xmax, ymax);
+ _hmtx.updateWidthData(c, xmin, xmax);
+ _os2.updateXMinMax(xmin, xmax);
+ _os2.updateYMinMax(ymin, ymax);
+ if (_vhea.active()) {
+ _vhea.updateYMinMax(c, ymin, ymax);
+ _vmtx.updateHeightData(c, ymin, ymax);
+ }
+}
+
+
+/** Converts TTF data to WOFF2 and writes the result to an output stream.
+ * @param[in] buffer contents of TTF file
+ * @param[in,out] os WOFF2 output stream
+ * @return true on success */
+static bool ttf_to_woff2 (const string &buffer, ostream &os) {
+ const uint8_t* input_data = reinterpret_cast<const uint8_t*>(buffer.data());
+ size_t output_size = woff2::MaxWOFF2CompressedSize(input_data, buffer.size());
+ string output(output_size, 0);
+ uint8_t* 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;
+}
+
+
+/** Writes the font data in WOFF2 format to the given output stream. */
+bool TTFWriter::writeWOFF2 (ostream &os) {
+ ostringstream oss;
+ if (writeTTF(oss))
+ return ttf_to_woff2(oss.str(), os);
+ return false;
+}
+
+
+/** Writes the font data in WOFF2 format to the given file. */
+bool TTFWriter::writeWOFF2 (const string &woff2name) {
+ ofstream ofs(woff2name, ios::binary);
+ if (ofs)
+ return writeWOFF2(ofs);
+ return false;
+}
+
+
+/** Reads TTF data from an input stream, converts it to WOFF2, and
+ * writes the result to an output stream.
+ * @param[in,out] is TTF input stream
+ * @param[in,out] os WOFF2 output stream
+ * @return true on success */
+bool TTFWriter::convertTTFToWOFF2 (istream &is, ostream &os) {
+ ostringstream oss;
+ oss << is.rdbuf();
+ return ttf_to_woff2(oss.str(), os);
+}
+
+
+/** Reads TTF data from an input file, converts it to WOFF2, and
+ * writes the result to an output file.
+ * @param[in] ttfname name/path of TTF file
+ * @param[in] woff2name name/path of WOFF2 file
+ * @return true on success */
+bool TTFWriter::convertTTFToWOFF2 (const string &ttfname, const string &woff2name) {
+ ifstream ifs(ttfname, ios::binary);
+ if (ifs) {
+ ofstream ofs(woff2name, ios::binary);
+ if (ofs)
+ return convertTTFToWOFF2(ifs, ofs);
+ }
+ return false;
+}
+
+
+/** Pseudo table representing the WOFF header. */
+class WOFFHeader : public TTFTable {
+ public:
+ WOFFHeader (uint16_t numTables, uint32_t ttfSize, uint32_t woffSize)
+ : _numTables(numTables), _ttfSize(ttfSize), _woffSize(woffSize) {}
+
+ uint32_t tag () const override {return 0;}
+
+ void write (ostream &os) const override {
+ writeUInt32(os, 0x774F4646); // "WOFF"
+ writeUInt32(os, 0x10000); // version of contained TTF font (1.0)
+ writeUInt32(os, _woffSize); // total length of WOFF file
+ writeUInt16(os, _numTables); // number of tables
+ writeUInt16(os, 0); // reserved
+ writeUInt32(os, _ttfSize); // size of uncompressed TTF data
+ writeUInt32(os, 0); // WOFF version (not required)
+ writeUInt32(os, 0); // offset to metadata block
+ writeUInt32(os, 0); // compressed size of metadata block
+ writeUInt32(os, 0); // uncompressed size of metadata block
+ writeUInt32(os, 0); // offset to private data block
+ writeUInt32(os, 0); // size of private data block
+ }
+
+ private:
+ uint16_t _numTables; ///< number of tables in WOFF file
+ uint32_t _ttfSize; ///< total length of TTF file
+ uint32_t _woffSize; ///< total length of WOFF file
+};
+
+
+/** Pseudo table representing the WOFF table records. */
+class WOFFTableRecords : public TTFTable {
+ public:
+ explicit WOFFTableRecords (const list<TableBuffer> &buffers) : _buffers(buffers) {}
+ uint32_t tag () const override {return 0;}
+
+ void write (ostream &os) const override {
+ uint32_t offset = 44 + 20*_buffers.size(); // offset to first byte of table data
+ for (const TableBuffer &buffer : _buffers) {
+ if (buffer.tag()) {
+ writeUInt32(os, buffer.tag()); // table tag/ID
+ writeUInt32(os, offset); // offset to table from beginning of WOFF file
+ writeUInt32(os, buffer.compressedSize()); // compressed length excluding padding
+ writeUInt32(os, buffer.unpaddedSize()); // uncompressed length excluding padding
+ writeUInt32(os, buffer.checksum()); // checksum of the uncompressed table
+ }
+ offset += buffer.paddedSize();
+ }
+ }
+
+ private:
+ const list<TableBuffer> &_buffers;
+};
+
+
+static bool ttf_to_woff (list<TableBuffer> &&buffers, ostream &os) {
+ size_t ttfSize = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t sum, const TableBuffer &buf) {
+ return sum + buf.paddedSize();
+ });
+ buffers.pop_front(); // remove TTF header
+ buffers.pop_front(); // remove TTF table records
+ for (TableBuffer &buffer : buffers)
+ buffer.compress();
+ size_t woffSize = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t sum, const TableBuffer &buf) {
+ return sum + buf.paddedSize();
+ });
+ woffSize += 44 + 20*buffers.size(); // add size of header and table records
+ WOFFHeader header(buffers.size(), ttfSize, woffSize);
+ WOFFTableRecords records(buffers);
+ buffers.emplace_front(records.createBuffer());
+ buffers.emplace_front(header.createBuffer());
+ for (; !buffers.empty(); buffers.pop_front())
+ buffers.front().write(os);
+ return true; // @@
+}
+
+
+/** Writes the font data in WOFF format to the given output stream. */
+bool TTFWriter::writeWOFF (ostream &os) {
+ return ttf_to_woff(createTableBuffers(), os);
+}
+
+
+/** Writes the font data in WOFF format to the given file. */
+bool TTFWriter::writeWOFF (const string &woffname) {
+ ofstream ofs(woffname, ios::binary);
+ if (ofs)
+ return writeWOFF(ofs);
+ return false;
+}
+
+
+/** Reads TTF data from an input stream, converts it to WOFF, and
+ * writes the result to an output stream.
+ * @param[in,out] is TTF input stream
+ * @param[in,out] os WOFF output stream
+ * @return true on success */
+bool TTFWriter::convertTTFToWOFF (istream &is, ostream &os) {
+ list<TableBuffer> buffers;
+ // read and process TTF header
+ vector<char> bufvec(12, 0);
+ is.read(&bufvec[0], 12);
+ buffers.emplace_back(TableBuffer(0, std::move(bufvec)));
+ int numTables = buffers.back().getUInt16(4);
+
+ // read and process table records
+ bufvec.clear();
+ bufvec.resize(4 * 4 * numTables);
+ is.read(&bufvec[0], 4 * 4 * numTables);
+ buffers.emplace_back(TableBuffer(0, std::move(bufvec)));
+
+ struct TableRecord {
+ TableRecord (const TableBuffer &buf, size_t ofs)
+ : tag(buf.getUInt32(ofs)), checksum(buf.getUInt32(ofs+4)), offset(buf.getUInt32(ofs+8)), length(buf.getUInt32(ofs+12)) {}
+ uint32_t tag;
+ uint32_t checksum;
+ uint32_t offset;
+ uint32_t length;
+ };
+ vector<TableRecord> tableRecords;
+ tableRecords.reserve(numTables);
+ const TableBuffer &recbuf = buffers.back();
+ for (int i=0; i < numTables; i++)
+ tableRecords.emplace_back(TableRecord(recbuf, 16*i));
+
+ // read and process tables
+ for (const TableRecord &record : tableRecords) {
+ bufvec.clear();
+ bufvec.resize(record.length);
+ is.seekg(record.offset);
+ is.read(&bufvec[0], record.length);
+ if (record.tag == TTFTable::name2id("head"))
+ buffers.emplace_back(TableBuffer(record.tag, std::move(bufvec), HeadTable::offsetToChecksum()));
+ else
+ buffers.emplace_back(TableBuffer(record.tag, std::move(bufvec)));
+ }
+ return ttf_to_woff(std::move(buffers), os);
+}
+
+
+/** Reads TTF data from an input file, converts it to WOFF, and
+ * writes the result to an output file.
+ * @param[in] ttfname name/path of TTF file
+ * @param[in] woffname name/path of WOFF file
+ * @return true on success */
+bool TTFWriter::convertTTFToWOFF (const string &ttfname, const string &woffname) {
+ ifstream ifs(ttfname, ios::binary);
+ if (ifs) {
+ ofstream ofs(woffname, ios::binary);
+ if (ofs)
+ return convertTTFToWOFF(ifs, ofs);
+ }
+ return false;
+}
diff --git a/dviware/dvisvgm/src/ttf/TTFWriter.hpp b/dviware/dvisvgm/src/ttf/TTFWriter.hpp
new file mode 100644
index 0000000000..2580326859
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/TTFWriter.hpp
@@ -0,0 +1,113 @@
+/*************************************************************************
+** TTFWriter.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <set>
+#include <vector>
+#include "CmapTable.hpp"
+#include "GlyfTable.hpp"
+#include "HeadTable.hpp"
+#include "HheaTable.hpp"
+#include "HmtxTable.hpp"
+#include "LocaTable.hpp"
+#include "MaxpTable.hpp"
+#include "NameTable.hpp"
+#include "OS2Table.hpp"
+#include "PostTable.hpp"
+#include "VheaTable.hpp"
+#include "VmtxTable.hpp"
+#include "../GFGlyphTracer.hpp"
+#include "../RangeMap.hpp"
+
+class PhysicalFont;
+
+namespace ttf {
+
+class TTFWriter {
+ public:
+ TTFWriter (const PhysicalFont &font, const std::set<int> &chars);
+ bool writeTTF (std::ostream &os);
+ bool writeWOFF (std::ostream &os);
+ bool writeWOFF2 (std::ostream &os);
+ bool writeTTF (const std::string &ttfname);
+ bool writeWOFF (const std::string &woffname);
+ bool writeWOFF2 (const std::string &woff2name);
+ static bool convertTTFToWOFF (std::istream &is, std::ostream &os);
+ static bool convertTTFToWOFF2 (std::istream &is, std::ostream &os);
+ static bool convertTTFToWOFF (const std::string &ttfname, const std::string &woffname);
+ static bool convertTTFToWOFF2 (const std::string &ttfname, const std::string &woff2name);
+ void setTracerCallback (GFGlyphTracer::Callback &callback) {_tracerCallback = &callback;}
+ GFGlyphTracer::Callback* getTracerCallback () const {return _tracerCallback;}
+ const PhysicalFont& getFont () const {return _font;}
+ const RangeMap& getUnicodeCharMap () const {return _unicodeCharMap;}
+ int targetUnitsPerEm () const;
+ double unitsPerEmFactor () const;
+ int16_t hAdvance (uint16_t c) const;
+ void updateGlobalBbox (uint32_t c, int16_t xmin, int16_t ymin, int16_t xmax, int16_t ymax);
+ bool isFixedPitch () const {return _hmtx.isFixedPitch();}
+
+ void updateContourInfo (uint16_t maxContours, uint16_t maxPoints) {
+ _maxp.updateContourInfo(maxPoints, maxContours);
+ }
+
+ void updateGlobalAdvanceWidth (uint16_t w, uint16_t numHMetrics) {_hhea.updateAdvanceWidth(w, numHMetrics);}
+ void updateGlobalAdvanceHeight (uint16_t h, uint16_t numVMetrics) {
+ if (_vhea.active())
+ _vhea.updateAdvanceHeight(h, numVMetrics);
+ }
+
+ void addGlyphOffset (uint32_t offset) {
+ _loca.addOffset(offset);
+ if (offset > 0xFFFF)
+ _head.setLongOffsetFormat();
+ }
+
+#ifdef TTFDEBUG
+ static bool CREATE_PS_GLYPH_OUTLINES;
+#endif
+
+ protected:
+ std::list<TableBuffer> createTableBuffers ();
+
+ private:
+ const PhysicalFont &_font;
+ RangeMap _unicodeCharMap; ///< Unicode -> character code
+ GFGlyphTracer::Callback *_tracerCallback;
+ CmapTable _cmap; ///< glyph index to character code mapping table
+ GlyfTable _glyf; ///< glyph data table
+ HeadTable _head; ///< font header table
+ HheaTable _hhea; ///< horizontal header table
+ HmtxTable _hmtx; ///< horizontal metrics table
+ LocaTable _loca; ///< glyph index to location/offset table
+ MaxpTable _maxp; ///< maximum profile table
+ NameTable _name; ///< naming table
+ OS2Table _os2; ///< OS/2 and Windows specific metrics table
+ PostTable _post; ///< PostScript information table
+ VheaTable _vhea; ///< vertical header table
+ VmtxTable _vmtx; ///< vertical metrics table
+ // The following vector contains pointers to the TTF table objects declared above.
+ // If a table t1 contains data that computation depends on data of table t2,
+ // t1 must be inserted after t2. For example, the loca and head tables require data
+ // from the glyf table to compute their data, so that glyf must precede loca and head.
+ std::vector<TTFTable*> _tables;
+};
+
+} // namespace ttf \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/VheaTable.cpp b/dviware/dvisvgm/src/ttf/VheaTable.cpp
new file mode 100644
index 0000000000..d49b76f523
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/VheaTable.cpp
@@ -0,0 +1,66 @@
+/*************************************************************************
+** VheaTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 "VheaTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+
+using namespace std;
+using namespace ttf;
+
+
+void VheaTable::write (ostream &os) const {
+ const PhysicalFont &font = ttfWriter()->getFont();
+ double scale = ttfWriter()->unitsPerEmFactor();
+ writeUInt32(os, 0x10000); // table version 1.0
+ writeInt16(os, round(font.ascent()*scale));
+ writeInt16(os, round(-font.descent()*scale));
+ writeInt16(os, 0); // line gap, always 0
+ writeUInt16(os, _advanceHeightMax);
+ writeInt16(os, _minTopSideBearing);
+ writeInt16(os, _minBottomSideBearing);
+ writeInt16(os, _yMaxExtent);
+ writeInt16(os, 1); // caretSlopeRise (1 = vertical)
+ writeInt16(os, 0); // caretSlopeRun (0 = vertical)
+ writeInt16(os, 0); // caretOffset
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // reserved
+ writeInt16(os, 0); // metricDataFormat (always 0)
+ writeUInt16(os, _numberOfVMetrics);
+}
+
+
+void VheaTable::updateYMinMax (uint32_t c, int16_t ymin, int16_t ymax) {
+ const PhysicalFont &font = ttfWriter()->getFont();
+ double extend = font.style() ? font.style()->extend : 1;
+ double scale = ttfWriter()->unitsPerEmFactor();
+ int16_t advance = (c == 0 ? ymax : round(scale*extend*font.vAdvance(c)));
+ _yMaxExtent = max(_yMaxExtent, ymax);
+ _minTopSideBearing = min(_minTopSideBearing, ymin);
+ _minBottomSideBearing = min(_minBottomSideBearing, int16_t(advance-ymax));
+}
+
+
+void VheaTable::updateAdvanceHeight (uint16_t h, uint16_t numberOfVMetrics) {
+ _advanceHeightMax = max(_advanceHeightMax, h);
+ _numberOfVMetrics = numberOfVMetrics;
+}
diff --git a/dviware/dvisvgm/src/ttf/VheaTable.hpp b/dviware/dvisvgm/src/ttf/VheaTable.hpp
new file mode 100644
index 0000000000..3031da4999
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/VheaTable.hpp
@@ -0,0 +1,47 @@
+/*************************************************************************
+** VheaTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+#include <limits>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the vertical header table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/vhea.htm */
+class VheaTable : public TTFTable {
+ friend class TTFWriter;
+ public:
+ uint32_t tag () const override {return name2id("vhea");}
+ void write (std::ostream &os) const override;
+
+ protected:
+ void updateYMinMax (uint32_t c, int16_t ymin, int16_t ymax);
+ void updateAdvanceHeight (uint16_t h, uint16_t numberOfVMetrics);
+
+ private:
+ uint16_t _advanceHeightMax = 0;
+ int16_t _minTopSideBearing = std::numeric_limits<int16_t>::max();
+ int16_t _minBottomSideBearing = std::numeric_limits<int16_t>::max();
+ int16_t _yMaxExtent = std::numeric_limits<int16_t>::min();
+ uint16_t _numberOfVMetrics = 0;
+};
+
+} // namespace ttf
diff --git a/dviware/dvisvgm/src/ttf/VmtxTable.cpp b/dviware/dvisvgm/src/ttf/VmtxTable.cpp
new file mode 100644
index 0000000000..6873bac9d2
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/VmtxTable.cpp
@@ -0,0 +1,57 @@
+/*************************************************************************
+** VmtxTable.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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 <cmath>
+#include "VmtxTable.hpp"
+#include "TTFWriter.hpp"
+#include "../Font.hpp"
+
+using namespace std;
+using namespace ttf;
+
+
+void VmtxTable::write (ostream &os) const {
+ auto runStart = _heightInfos.end();
+ if (!_heightInfos.empty())
+ runStart -= _runLengthOfAdvHeight-1;
+ // write longVerMetrics up to the beginning of the repeating
+ // advance heights at the end of the container
+ for (auto it = _heightInfos.begin(); it != runStart; ++it) {
+ writeUInt16(os, it->advHeight);
+ writeInt16(os, it->tsb);
+ }
+ // write the trailing top side bearings
+ for (; runStart != _heightInfos.end(); ++runStart)
+ writeInt16(os, runStart->tsb);
+}
+
+
+void VmtxTable::updateHeightData (uint32_t c, int16_t ymin, int16_t ymax) {
+ const PhysicalFont &font = ttfWriter()->getFont();
+ double extend = font.style() ? font.style()->extend : 1;
+ double scale = ttfWriter()->unitsPerEmFactor();
+ int16_t h = (c == 0 ? ymax : round(scale*extend*font.vAdvance(c)));
+ if (_heightInfos.empty() || h == _heightInfos.back().advHeight)
+ _runLengthOfAdvHeight++;
+ else
+ _runLengthOfAdvHeight = 1;
+ _heightInfos.emplace_back(CharHeightInfo(ymin, h));
+ ttfWriter()->updateGlobalAdvanceHeight(h, _heightInfos.size()-_runLengthOfAdvHeight+1);
+} \ No newline at end of file
diff --git a/dviware/dvisvgm/src/ttf/VmtxTable.hpp b/dviware/dvisvgm/src/ttf/VmtxTable.hpp
new file mode 100644
index 0000000000..4bcdda0df0
--- /dev/null
+++ b/dviware/dvisvgm/src/ttf/VmtxTable.hpp
@@ -0,0 +1,49 @@
+/*************************************************************************
+** VmtxTable.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 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/>. **
+*************************************************************************/
+
+#pragma once
+
+#include <vector>
+#include "TTFTable.hpp"
+
+namespace ttf {
+
+/** This class provides the functions required to write the horizontal metrics table of a TTF/OTF font.
+ * https://www.microsoft.com/typography/otspec/vmtx.htm */
+class VmtxTable : public TTFTable {
+ friend TTFWriter;
+ struct CharHeightInfo {
+ CharHeightInfo (int16_t l, int16_t h) : tsb(l), advHeight(h) {}
+ uint16_t tsb; // top side bearing
+ uint16_t advHeight; // unscaled advance height
+ };
+ public:
+ uint32_t tag () const override {return name2id("vmtx");}
+ void write (std::ostream &os) const override;
+
+ protected:
+ void updateHeightData (uint32_t c, int16_t ymin, int16_t ymax);
+
+ private:
+ std::vector<CharHeightInfo> _heightInfos;
+ size_t _runLengthOfAdvHeight=0; // number of identical advHeight values at end of _heightInfos
+};
+
+} // namespace ttf