summaryrefslogtreecommitdiff
path: root/dviware/dvisvgm/src/OFM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/dvisvgm/src/OFM.cpp')
-rw-r--r--dviware/dvisvgm/src/OFM.cpp270
1 files changed, 270 insertions, 0 deletions
diff --git a/dviware/dvisvgm/src/OFM.cpp b/dviware/dvisvgm/src/OFM.cpp
new file mode 100644
index 0000000000..63872671f1
--- /dev/null
+++ b/dviware/dvisvgm/src/OFM.cpp
@@ -0,0 +1,270 @@
+/*************************************************************************
+** OFM.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2023 Martin Gieseking <martin.gieseking@uos.de> **
+** **
+** This program is free software; you can redistribute it and/or **
+** modify it under the terms of the GNU General Public License as **
+** published by the Free Software Foundation; either version 3 of **
+** the License, or (at your option) any later version. **
+** **
+** This program is distributed in the hope that it will be useful, but **
+** WITHOUT ANY WARRANTY; without even the implied warranty of **
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
+** GNU General Public License for more details. **
+** **
+** You should have received a copy of the GNU General Public License **
+** along with this program; if not, see <http://www.gnu.org/licenses/>. **
+*************************************************************************/
+
+#include <cstdint>
+#include <string>
+#include "Length.hpp"
+#include "OFM.hpp"
+
+using namespace std;
+
+
+static uint32_t read_uint32 (StreamReader &reader, const string &name) {
+ uint32_t quad = reader.readUnsigned(4);
+ if (quad & 0x80000000)
+ throw FontMetricException("negative '"+name+"' value not permitted");
+ return quad;
+}
+
+void OFM::FileDimensions::read (StreamReader &reader) {
+ lf = read_uint32(reader, "lf");
+ lh = read_uint32(reader, "lh");
+ bc = read_uint32(reader, "bc");
+ ec = read_uint32(reader, "ec");
+ nw = read_uint32(reader, "nw");
+ nh = read_uint32(reader, "nh");
+ nd = read_uint32(reader, "nd");
+ ni = read_uint32(reader, "ni");
+ nl = read_uint32(reader, "nl");
+ nk = read_uint32(reader, "nk");
+ ne = read_uint32(reader, "ne");
+ np = read_uint32(reader, "np");
+ dir = read_uint32(reader, "font-dir");
+}
+
+
+/** Reads the common beginning of OFM level 0 and 1 files, and initializes
+ * the corresponding members.
+ * @param[in] is reads from this stream
+ * @param[in] maxNumWidths maximum number of width entries
+ * @return the collected data (file offsets, table sizes, writing direction) */
+OFM::FileDimensions OFM::read (istream &is, uint32_t maxNumWidths) {
+ OFM::FileDimensions dim;
+ if (is) {
+ is.seekg(0);
+ StreamReader sr(is);
+ uint32_t ofmLevel = sr.readUnsigned(4);
+ if (ofmLevel > 1)
+ throw FontMetricException("OFM level "+to_string(ofmLevel)+" not supported");
+ if (int(ofmLevel) != level())
+ throw FontMetricException("OFM level "+to_string(level())+" expected but found level "+to_string(ofmLevel));
+ dim.read(sr);
+ if (dim.nw > maxNumWidths)
+ throw FontMetricException("invalid size of width table");
+ _firstChar = dim.bc; // smallest character code in font
+ _lastChar = dim.ec; // largest character code in font
+ _vertical = (dim.dir > 0);
+ }
+ return dim;
+}
+
+
+/** Reads and stores the required data from the OFM header. */
+void OFM::readHeader (StreamReader &reader) {
+ _checksum = reader.readUnsigned(4);
+ _designSize = double(FixWord(reader.readSigned(4)))*Length::pt2bp;
+}
+
+
+/** Reads a sequence of values and stores them in a vector.
+ * @param[in] reader the TFM data is read from this object
+ * @param[out] words vector taking the read words
+ * @param[in] n number of entries to read */
+static void read_words (StreamReader &reader, vector<FixWord> &words, size_t n) {
+ words.resize(n);
+ for (size_t i=0; i < n; i++)
+ words[i] = reader.readSigned(4);
+}
+
+
+/** Reads and stores the required OFM tables (characters widths, heights, depths, ...). */
+void OFM::readTables (StreamReader &reader, const FileDimensions &dim) {
+ read_words(reader, _widthTable, dim.nw);
+ read_words(reader, _heightTable, dim.nh);
+ read_words(reader, _depthTable, dim.nd);
+ read_words(reader, _italicTable, dim.ni);
+ reader.skip(8*dim.nl + 4*dim.nk + 8*dim.ne);
+ read_words(reader, _params, min(dim.np, 7u)); // we only need params 0-6
+ _params.resize(7, 0); // ensure 7 parameters
+ for (FixWord h : _heightTable)
+ _ascent = max(_ascent, h);
+ for (FixWord d : _depthTable)
+ _descent = max(_descent, d);
+}
+
+
+/** Returns the character index for a given character or -1 if
+ * the OFM file doesn't contain information on the character. */
+size_t OFM::charIndex (int c) const {
+ uint32_t chr=c;
+ if (chr < _firstChar || chr > _lastChar || size_t(chr-_firstChar) >= numCharInfos())
+ return -1;
+ return chr-_firstChar;
+}
+
+
+/** Returns the width of a character in bp units. */
+double OFM::getCharWidth (int c) const {
+ auto cindex = charIndex(c);
+ if (cindex == size_t(-1))
+ return 0;
+ return double(_widthTable[widthIndex(cindex)])*_designSize;
+}
+
+
+/** Returns the height of a character in bp units. */
+double OFM::getCharHeight (int c) const {
+ auto cindex = charIndex(c);
+ if (cindex == size_t(-1))
+ return 0;
+ return double(_heightTable[heightIndex(cindex)])*_designSize;
+}
+
+
+/** Returns the depth of a character in bp units. */
+double OFM::getCharDepth (int c) const {
+ auto cindex = charIndex(c);
+ if (cindex == size_t(-1))
+ return 0;
+ return double(_depthTable[depthIndex(cindex)])*_designSize;
+}
+
+
+/** Returns the italic correction width of a character in bp units. */
+double OFM::getItalicCorr (int c) const {
+ auto cindex = charIndex(c);
+ if (cindex == size_t(-1))
+ return 0;
+ return double(_italicTable[italicIndex(cindex)])*_designSize;
+}
+
+/** Returns the optimal space width between words in bp units. */
+double OFM::getSpace () const {
+ return _params.empty() ? 0 : double(_params[1])*_designSize;
+}
+
+
+/** Returns the amount of glue stretching between words in bp units. */
+double OFM::getSpaceStretch () const {
+ return _params.empty() ? 0 : double(_params[2])*_designSize;
+}
+
+
+/** Returns the amount of glue shrinking between words in bp units. */
+double OFM::getSpaceShrink () const {
+ return _params.empty() ? 0 : double(_params[3])*_designSize;
+}
+
+
+/** Returns the size of one EM unit in bp units. */
+double OFM::getQuad () const {
+ if (_params.empty() || _params[5] == 0)
+ return _designSize;
+ return double(_params[5])*_designSize;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+/** Reads and stores the required data from an OFM level 0 data stream. */
+void OFM0::read (std::istream &is) {
+ auto dim = OFM::read(is, 0xFFFF);
+ if (_firstChar >= _lastChar || _lastChar > 0xFFFF)
+ throw FontMetricException("character codes out of range");
+ if (14 + dim.lh + 2*(dim.ec-dim.bc+1) + dim.nw + dim.nh + dim.nd + dim.ni +2*dim.nl + dim.nk + 2*dim.ne + dim.np != dim.lf)
+ throw FontMetricException("inconsistent table size values");
+ StreamReader sr(is);
+ readHeader(sr);
+ sr.seek(56 + dim.lh*4); // move to char info table
+ readCharInfos(sr);
+ readTables(sr, dim);
+}
+
+
+/** Reads and stores the required data from the char-info section.
+ * Expects the stream pointer to be located on the first byte of the first char-info entry. */
+void OFM0::readCharInfos (StreamReader &reader) {
+ auto numChars = _lastChar-_firstChar+1;
+ _charInfos.resize(numChars);
+ for (size_t i=0; i < numChars; i++) {
+ _charInfos[i] = uint64_t(reader.readUnsigned(4)) << 32;
+ _charInfos[i] |= reader.readUnsigned(4);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/** Reads and stores the required data from an OFM level 1 data stream. */
+void OFM1::read (std::istream &is) {
+ auto dim = OFM::read(is, 0x110000);
+ if (_firstChar >= _lastChar || _lastChar > 0x10FFFF)
+ throw FontMetricException("character codes out of range");
+ StreamReader sr(is);
+ uint32_t nco = sr.readUnsigned(4); // OFM1: offset of char-info table (in 4-byte words)
+ _ncw = sr.readUnsigned(4); // total number of character info words in OFM file
+ _npc = sr.readUnsigned(4); // number of parameters per character
+ // check validity of number entries for new (OFM level 1) table types
+ size_t sum=0, numTables=0;
+ for (int i=0; i < 12; i++) {
+ uint32_t num = sr.readUnsigned(4);
+ sum += num;
+ if (i%2 == 0)
+ numTables += num;
+ }
+ if (numTables > 32)
+ throw FontMetricException("too many OFM level 1 tables");
+ if (29 + dim.lh + _ncw + dim.nw + dim.nh + dim.nd + dim.ni +2*dim.nl + dim.nk + 2*dim.ne + dim.np + sum != dim.lf)
+ throw FontMetricException("inconsistent table size values");
+ readHeader(sr);
+ sr.seek(4*nco); // move to char info table
+ readCharInfos(sr);
+ readTables(sr, dim);
+}
+
+
+/** Reads and stores the required data from the char-info section.
+ * Expects the stream pointer to be located on the first byte of the first char-info entry. */
+void OFM1::readCharInfos (StreamReader &reader) {
+ auto numCharInfos = _ncw/(3 + _npc/2); // number of char info entries in file
+ auto numChars = _lastChar-_firstChar+1;
+ size_t numCharsRead=0;
+ _charInfos.reserve(numChars);
+ while (numCharsRead <= numChars && numCharInfos > 0) {
+ CharInfo info;
+ info.widthIndex = uint16_t(reader.readUnsigned(2));
+ info.heightIndex = uint8_t(reader.readUnsigned(1));
+ info.depthIndex = uint8_t(reader.readUnsigned(1));
+ info.italicIndex = uint8_t(reader.readUnsigned(1));
+ reader.skip(3); // skip RFU, ext-tag, tag, and remainder
+ auto repeats = uint16_t(reader.readUnsigned(2));
+ if (numCharsRead + repeats > numChars)
+ throw FontMetricException("number of characters exceeded due to too many char-info repeats");
+ reader.skip(_npc*2); // skip parameters
+ if (_npc%2 == 0)
+ reader.skip(2); // skip padding bytes
+ for (int j=0; j <= repeats; j++)
+ _charInfos.push_back(info);
+ numCharsRead += repeats+1;
+ numCharInfos--;
+ }
+ if (numCharInfos > 0)
+ throw FontMetricException("more char-info entries present than characters");
+ if (numCharsRead < numChars)
+ throw FontMetricException("not all characters covered by char-info entries");
+}