From 6a7900c93acc16d1bbd2f1e26286c7dd7387e6c0 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Thu, 12 Jan 2023 03:01:29 +0000 Subject: CTAN sync 202301120301 --- dviware/dvisvgm/src/ttf/CmapTable.cpp | 131 ++++++ dviware/dvisvgm/src/ttf/CmapTable.hpp | 43 ++ dviware/dvisvgm/src/ttf/GlyfTable.cpp | 501 +++++++++++++++++++++ dviware/dvisvgm/src/ttf/GlyfTable.hpp | 96 +++++ dviware/dvisvgm/src/ttf/HeadTable.cpp | 78 ++++ dviware/dvisvgm/src/ttf/HeadTable.hpp | 49 +++ dviware/dvisvgm/src/ttf/HheaTable.cpp | 67 +++ dviware/dvisvgm/src/ttf/HheaTable.hpp | 47 ++ dviware/dvisvgm/src/ttf/HmtxTable.cpp | 62 +++ dviware/dvisvgm/src/ttf/HmtxTable.hpp | 52 +++ dviware/dvisvgm/src/ttf/LocaTable.hpp | 56 +++ dviware/dvisvgm/src/ttf/Makefile.am | 25 ++ dviware/dvisvgm/src/ttf/Makefile.in | 743 ++++++++++++++++++++++++++++++++ dviware/dvisvgm/src/ttf/MaxpTable.cpp | 50 +++ dviware/dvisvgm/src/ttf/MaxpTable.hpp | 42 ++ dviware/dvisvgm/src/ttf/NameTable.cpp | 105 +++++ dviware/dvisvgm/src/ttf/NameTable.hpp | 37 ++ dviware/dvisvgm/src/ttf/OS2Table.cpp | 246 +++++++++++ dviware/dvisvgm/src/ttf/OS2Table.hpp | 46 ++ dviware/dvisvgm/src/ttf/PostTable.cpp | 63 +++ dviware/dvisvgm/src/ttf/PostTable.hpp | 37 ++ dviware/dvisvgm/src/ttf/TTFAutohint.cpp | 161 +++++++ dviware/dvisvgm/src/ttf/TTFAutohint.hpp | 52 +++ dviware/dvisvgm/src/ttf/TTFTable.cpp | 94 ++++ dviware/dvisvgm/src/ttf/TTFTable.hpp | 108 +++++ dviware/dvisvgm/src/ttf/TTFWriter.cpp | 422 ++++++++++++++++++ dviware/dvisvgm/src/ttf/TTFWriter.hpp | 113 +++++ dviware/dvisvgm/src/ttf/VheaTable.cpp | 66 +++ dviware/dvisvgm/src/ttf/VheaTable.hpp | 47 ++ dviware/dvisvgm/src/ttf/VmtxTable.cpp | 57 +++ dviware/dvisvgm/src/ttf/VmtxTable.hpp | 49 +++ 31 files changed, 3745 insertions(+) create mode 100644 dviware/dvisvgm/src/ttf/CmapTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/CmapTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/GlyfTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/GlyfTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/HeadTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/HeadTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/HheaTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/HheaTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/HmtxTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/HmtxTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/LocaTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/Makefile.am create mode 100644 dviware/dvisvgm/src/ttf/Makefile.in create mode 100644 dviware/dvisvgm/src/ttf/MaxpTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/MaxpTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/NameTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/NameTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/OS2Table.cpp create mode 100644 dviware/dvisvgm/src/ttf/OS2Table.hpp create mode 100644 dviware/dvisvgm/src/ttf/PostTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/PostTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/TTFAutohint.cpp create mode 100644 dviware/dvisvgm/src/ttf/TTFAutohint.hpp create mode 100644 dviware/dvisvgm/src/ttf/TTFTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/TTFTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/TTFWriter.cpp create mode 100644 dviware/dvisvgm/src/ttf/TTFWriter.hpp create mode 100644 dviware/dvisvgm/src/ttf/VheaTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/VheaTable.hpp create mode 100644 dviware/dvisvgm/src/ttf/VmtxTable.cpp create mode 100644 dviware/dvisvgm/src/ttf/VmtxTable.hpp (limited to 'dviware/dvisvgm/src/ttf') 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#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 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once +#include +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#include +#include +#include +#include +#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 &&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 prevPoint; + for (PointInfo &info : _pointInfos) { + Pair 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::iterator next (vector::iterator it, const vector &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 diff12 = it1->coords - it2->coords; + Pair 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 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 diff13 = it3->coords - it1->coords; + Pair 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 mid = DPair(it1->coords + it3->coords)/2.0; + Pair 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 Contour::glyphFlags () const { + vector 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 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 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 &contours, int &xmin, int &ymin, int &xmax, int &ymax) { + if (contours.empty()) + xmin = xmax = ymin = ymax = 0; + else { + xmin = ymin = numeric_limits::max(); + xmax = ymax = numeric_limits::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 &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 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 &contours; + double scale; +}; + + +/** Returns a sequence of contours describing the glyph of a given character. + * The contour points are stored with absolute coordinates. */ +list GlyfTable::computeContours (uint32_t charcode) const { + list 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 pmin(base/30, 0); + Pair 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 &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 llp(numeric_limits::max(), numeric_limits::max()); + Pair urp(numeric_limits::min(), numeric_limits::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 &p) { + return os << p.x() << " " << p.y(); +} + +template +static ostream& write (ostream &os, const Pair &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 c1 = DPair(p0) + round(v1*2.0/3.0); + Pair 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once +#include +#include +#include +#include +#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 coords; ///< relative coordinates to previous one in contour + State state; +}; + + +class Contour { + friend class GlyfTable; + using Iterator = std::vector::iterator; + using ConstIterator = std::vector::const_iterator; + public: + Contour () =default; + Contour (Contour &&contour) =default; + Contour (std::list &&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 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 _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 computeContours () const; + std::list computeContours (uint32_t charcode) const; + static void computeBbox (const std::list &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 &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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#include +#include +#include +#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 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#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::max(); + int16_t _yMin = std::numeric_limits::max(); + int16_t _xMax = std::numeric_limits::min(); + int16_t _yMax = std::numeric_limits::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 ** +** ** +** 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 . ** +*************************************************************************/ + +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once +#include +#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::max(); + int16_t _minRightSideBearing = std::numeric_limits::max(); + int16_t _xMaxExtent = std::numeric_limits::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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#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 _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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#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 _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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#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 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#include +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#include +#include +#include +#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 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 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 compute_unicode_range_bits (const RangeMap &charmap) { + vector 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#include +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#include +#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 + +#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(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(_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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#include + +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#include +#include "TTFTable.hpp" + +using namespace std; +using namespace ttf; + + +TableBuffer::TableBuffer (uint32_t tag, vector 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(_data.data()); + _checksum += bytes[i]*0x1000000 + bytes[i+1]*0x010000 + bytes[i+2]*0x0100 + bytes[i+3]; + } +} + + +TableBuffer::TableBuffer (uint32_t tag, vector 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 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(_data.data()); + auto target = reinterpret_cast(&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> vecstream; + write(vecstream); + vector 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once +#include +#include +#include + +namespace ttf { + +/** Class to handle the binary TTF table data. */ +class TableBuffer { + friend class TTFWriter; + public: + TableBuffer (uint32_t tag, std::vector data); + TableBuffer (uint32_t tag, std::vector 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 + void setData (size_t offset, const T val) { + if (offset+sizeof(T) <= _data.size()) { + typename std::make_unsigned::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 _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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#include +#include +#include +#include +#include +#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 &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 &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 &_buffers; +}; + + +/** Writes the font data in TrueType format to the given output stream. */ +bool TTFWriter::writeTTF (ostream &os) { + list 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 TTFWriter::createTableBuffers () { + list 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(buffer.data()); + size_t output_size = woff2::MaxWOFF2CompressedSize(input_data, buffer.size()); + string output(output_size, 0); + uint8_t* output_data = reinterpret_cast(&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(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 &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 &_buffers; +}; + + +static bool ttf_to_woff (list &&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 buffers; + // read and process TTF header + vector 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 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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#include +#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 &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 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 _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 ** +** ** +** 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 . ** +*************************************************************************/ + +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once +#include +#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::max(); + int16_t _minBottomSideBearing = std::numeric_limits::max(); + int16_t _yMaxExtent = std::numeric_limits::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 ** +** ** +** 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 . ** +*************************************************************************/ + +#include +#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 ** +** ** +** 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 . ** +*************************************************************************/ + +#pragma once + +#include +#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 _heightInfos; + size_t _runLengthOfAdvHeight=0; // number of identical advHeight values at end of _heightInfos +}; + +} // namespace ttf -- cgit v1.2.3