diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp | 393 |
1 files changed, 0 insertions, 393 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp deleted file mode 100644 index 09a88a2d2a8..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/************************************************************************* -** FontCache.cpp ** -** ** -** This file is part of dvisvgm -- a fast DVI to SVG converter ** -** Copyright (C) 2005-2021 Martin Gieseking <martin.gieseking@uos.de> ** -** ** -** This program is free software; you can redistribute it and/or ** -** modify it under the terms of the GNU General Public License as ** -** published by the Free Software Foundation; either version 3 of ** -** the License, or (at your option) any later version. ** -** ** -** This program is distributed in the hope that it will be useful, but ** -** WITHOUT ANY WARRANTY; without even the implied warranty of ** -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** -** GNU General Public License for more details. ** -** ** -** You should have received a copy of the GNU General Public License ** -** along with this program; if not, see <http://www.gnu.org/licenses/>. ** -*************************************************************************/ - -#include <algorithm> -#include <cstring> -#include <fstream> -#include <iomanip> -#include <sstream> -#include "FileSystem.hpp" -#include "FontCache.hpp" -#include "Pair.hpp" -#include "StreamReader.hpp" -#include "StreamWriter.hpp" -#include "XXHashFunction.hpp" - -using namespace std; - -const uint8_t FontCache::FORMAT_VERSION = 5; - - -static Pair32 read_pair (int bytes, StreamReader &sr) { - int32_t x = sr.readSigned(bytes); - int32_t y = sr.readSigned(bytes); - return Pair32(x, y); -} - - -/** Removes all data from the cache. This does not affect the cache files. */ -void FontCache::clear () { - _glyphs.clear(); - _fontname.clear(); -} - - -/** Assigns glyph data to a character and adds it to the cache. - * @param[in] c character code - * @param[in] glyph font glyph data */ -void FontCache::setGlyph (int c, const Glyph &glyph) { - _glyphs[c] = glyph; - _changed = true; -} - - -/** Returns the corresponding glyph data of a given character of the current font. - * @param[in] c character code - * @return font glyph data (0 if no matching data was found) */ -const Glyph* FontCache::getGlyph (int c) const { - auto it = _glyphs.find(c); - return (it != _glyphs.end()) ? &it->second : nullptr; -} - - -/** Writes the current cache data to a file (only if anything changed after - * the last call of read()). - * @param[in] fontname name of current font - * @param[in] dir directory where the cache file should go - * @return true if writing was successful */ -bool FontCache::write (const string &fontname, const string &dir) const { - if (!_changed) - return true; - - if (!fontname.empty()) { - string pathstr = dir.empty() ? FileSystem::getcwd() : dir; - pathstr += "/" + fontname + ".fgd"; - ofstream ofs(pathstr, ios::binary); - return write(fontname, ofs); - } - return false; -} - - -bool FontCache::write (const string &dir) const { - return _fontname.empty() ? false : write(_fontname, dir); -} - - -/** Returns the minimal number of bytes needed to store the given value. */ -static int max_number_of_bytes (int32_t value) { - int32_t limit = 0x7f; - for (int i=1; i <= 4; i++) { - if ((value < 0 && -value <= limit+1) || (value >= 0 && value <= limit)) - return i; - limit = (limit << 8) | 0xff; - } - return 4; -} - -static int max_int_size () { - return 0; -} - -template <typename ...Args> -static int max_int_size (const Glyph::Point &p1, const Args& ...args) { - int max1 = max(max_number_of_bytes(p1.x()), max_number_of_bytes(p1.y())); - return max(max1, max_int_size(args...)); -} - - -struct WriteActions : Glyph::IterationActions { - WriteActions (StreamWriter &sw, HashFunction &hashfunc) : _sw(sw), _hashfunc(hashfunc) {} - - using Point = Glyph::Point; - void moveto (const Point &p) override {write('M', p);} - void lineto (const Point &p) override {write('L', p);} - void quadto (const Point &p1, const Point &p2) override {write('Q', p1, p2);} - void cubicto (const Point &p1, const Point &p2, const Point &p3) override {write('C', p1, p2, p3); } - void closepath () override {write('Z');} - - template <typename ...Args> - void write (char cmd, Args ...args) { - int bytesPerValue = max_int_size(args...); - int cmdchar = (bytesPerValue << 5) | (cmd - 'A'); - _sw.writeUnsigned(cmdchar, 1, _hashfunc); - writeParams(bytesPerValue, args...); - } - - static void writeParams (int bytesPerValue) {} - - template <typename ...Args> - void writeParams (int bytesPerValue, const Point &p, const Args& ...args) { - _sw.writeSigned(p.x(), bytesPerValue, _hashfunc); - _sw.writeSigned(p.y(), bytesPerValue, _hashfunc); - writeParams(bytesPerValue, args...); - } - - StreamWriter &_sw; - HashFunction &_hashfunc; -}; - - -/** Writes the current cache data to a stream (only if anything changed after - * the last call of read()). - * @param[in] fontname name of current font - * @param[in] os output stream - * @return true if writing was successful */ -bool FontCache::write (const string &fontname, ostream &os) const { - if (!_changed) - return true; - if (!os) - return false; - - StreamWriter sw(os); - XXH32HashFunction hashfunc; - - sw.writeUnsigned(FORMAT_VERSION, 1, hashfunc); - sw.writeBytes(hashfunc.digestBytes()); // space for checksum - sw.writeString(fontname, hashfunc, true); - sw.writeUnsigned(_glyphs.size(), 4, hashfunc); - WriteActions actions(sw, hashfunc); - for (const auto &charglyphpair : _glyphs) { - const Glyph &glyph = charglyphpair.second; - sw.writeUnsigned(charglyphpair.first, 4, hashfunc); - sw.writeUnsigned(glyph.size(), 2, hashfunc); - glyph.iterate(actions, false); - } - os.seekp(1); - auto digest = hashfunc.digestBytes(); - sw.writeBytes(digest); // insert checksum - os.seekp(0, ios::end); - return true; -} - - -/** Reads font glyph information from a file. - * @param[in] fontname name of font data to read - * @param[in] dir directory where the cache files are located - * @return true if reading was successful */ -bool FontCache::read (const string &fontname, const string &dir) { - if (fontname.empty()) - return false; - if (_fontname == fontname) - return true; - clear(); - string dirstr = dir.empty() ? FileSystem::getcwd() : dir; - ostringstream oss; - oss << dirstr << '/' << fontname << ".fgd"; - ifstream ifs(oss.str(), ios::binary); - return read(fontname, ifs); -} - - -/** Reads font glyph information from a stream. - * @param[in] fontname name of font data to read - * @param[in] is input stream to read the glyph data from - * @return true if reading was successful */ -bool FontCache::read (const string &fontname, istream &is) { - if (_fontname == fontname) - return true; - clear(); - _fontname = fontname; - if (!is) - return false; - - StreamReader sr(is); - XXH32HashFunction hashfunc; - if (sr.readUnsigned(1, hashfunc) != FORMAT_VERSION) - return false; - - auto hashcmp = sr.readBytes(hashfunc.digestSize()); - hashfunc.update(is); - if (hashfunc.digestBytes() != hashcmp) - return false; - - is.clear(); - is.seekg(hashfunc.digestSize()+1); // continue reading after checksum - - string fname = sr.readString(); - if (fname != fontname) - return false; - - uint32_t num_glyphs = sr.readUnsigned(4); - while (num_glyphs-- > 0) { - uint32_t c = sr.readUnsigned(4); // character code - uint16_t s = sr.readUnsigned(2); // number of path commands - Glyph &glyph = _glyphs[c]; - while (s-- > 0) { - uint8_t cmdval = sr.readUnsigned(1); - uint8_t cmdchar = (cmdval & 0x1f) + 'A'; - int bytes = cmdval >> 5; - switch (cmdchar) { - case 'C': { - Pair32 p1 = read_pair(bytes, sr); - Pair32 p2 = read_pair(bytes, sr); - Pair32 p3 = read_pair(bytes, sr); - glyph.cubicto(p1, p2, p3); - break; - } - case 'L': - glyph.lineto(read_pair(bytes, sr)); - break; - case 'M': - glyph.moveto(read_pair(bytes, sr)); - break; - case 'Q': { - Pair32 p1 = read_pair(bytes, sr); - Pair32 p2 = read_pair(bytes, sr); - glyph.quadto(p1, p2); - break; - } - case 'Z': - glyph.closepath(); - } - } - } - _changed = false; - return true; -} - - -/** Collects font cache information. - * @param[in] dirname path to font cache directory - * @param[out] infos the collected font information - * @param[out] invalid names of outdated/corrupted cache files - * @return true on success */ -bool FontCache::fontinfo (const string &dirname, vector<FontInfo> &infos, vector<string> &invalid) { - infos.clear(); - invalid.clear(); - if (!dirname.empty()) { - vector<string> fnames; - FileSystem::collect(dirname, fnames); - for (const string &fname : fnames) { - if (fname[0] == 'f' && fname.length() > 5 && fname.substr(fname.length()-4) == ".fgd") { - FontInfo info; - string path = dirname+"/"+(fname.substr(1)); - ifstream ifs(path, ios::binary); - if (fontinfo(ifs, info)) - infos.emplace_back(move(info)); - else - invalid.emplace_back(fname.substr(1)); - } - } - } - return !infos.empty(); -} - - -/** Collects font cache information of a single font. - * @param[in] is input stream of the cache file - * @param[out] info the collected data - * @return true if data could be read, false if cache file is unavailable, outdated, or corrupted */ -bool FontCache::fontinfo (std::istream &is, FontInfo &info) { - info.name.clear(); - info.numchars = info.numbytes = info.numcmds = 0; - if (is) { - is.clear(); - is.seekg(0); - try { - StreamReader sr(is); - XXH32HashFunction hashfunc; - if ((info.version = sr.readUnsigned(1, hashfunc)) != FORMAT_VERSION) - return false; - - info.checksum = sr.readBytes(hashfunc.digestSize()); - hashfunc.update(is); - if (hashfunc.digestBytes() != info.checksum) - return false; - - is.clear(); - is.seekg(hashfunc.digestSize()+1); // continue reading after checksum - - info.name = sr.readString(); - info.numchars = sr.readUnsigned(4); - for (uint32_t i=0; i < info.numchars; i++) { - sr.readUnsigned(4); // character code - uint16_t s = sr.readUnsigned(2); // number of path commands - while (s-- > 0) { - uint8_t cmdval = sr.readUnsigned(1); - uint8_t cmdchar = (cmdval & 0x1f) + 'A'; - int bytes = cmdval >> 5; - int bc = 0; - switch (cmdchar) { - case 'C': bc = 6*bytes; break; - case 'H': - case 'L': - case 'M': - case 'T': - case 'V': bc = 2*bytes; break; - case 'Q': - case 'S': bc = 4*bytes; break; - case 'Z': break; - default : return false; - } - info.numbytes += bc+1; // command length + command - info.numcmds++; - is.seekg(bc, ios::cur); - } - info.numbytes += 6; // number of path commands + char code - } - info.numbytes += 6+info.name.length(); // version + 0-byte + fontname + number of chars - } - catch (StreamReaderException &e) { - return false; - } - } - return true; -} - - -/** Collects font cache information and write it to a stream. - * @param[in] dirname path to font cache directory - * @param[in] os output is written to this stream - * @param[in] purge if true, outdated and corrupted cache files are removed */ -void FontCache::fontinfo (const string &dirname, ostream &os, bool purge) { - if (!dirname.empty()) { - ios::fmtflags osflags(os.flags()); - vector<FontInfo> infos; - vector<string> invalid_files; - if (!fontinfo(dirname, infos, invalid_files)) - os << "cache is empty\n"; - else { - os << "cache format version " << infos[0].version << endl; - map<string, const FontInfo*> sortmap; - for (const FontInfo &info : infos) - sortmap[info.name] = &info; - for (const auto &strinfopair : sortmap) { - os << dec << setfill(' ') << left - << setw(10) << left << strinfopair.second->name - << setw(5) << right << strinfopair.second->numchars << " glyph" << (strinfopair.second->numchars == 1 ? ' ':'s') - << setw(10) << right << strinfopair.second->numcmds << " cmd" << (strinfopair.second->numcmds == 1 ? ' ':'s') - << setw(12) << right << strinfopair.second->numbytes << " byte" << (strinfopair.second->numbytes == 1 ? ' ':'s') - << " hash:" << hex; - for (int byte : strinfopair.second->checksum) - os << setw(2) << setfill('0') << byte; - os << '\n'; - } - } - if (purge) { - for (const string &str : invalid_files) { - string path=dirname+"/"+str; - if (FileSystem::remove(path)) - os << "invalid cache file " << str << " removed\n"; - } - } - os.flags(osflags); // restore format flags - } -} |