From a1b16cda03433510ac6a1679d2060a7c60d20be3 Mon Sep 17 00:00:00 2001 From: Shreevatsa R Date: Tue, 10 Dec 2019 07:25:13 -0800 Subject: [PATCH] HACK: For speed, write out font styles only once. To elaborate: **Background:** I had a few DVI files what were over 1000 pages long, on which dvisvgm would take hours to run. (Specifically, these files were the literate-programming listings of TeX/eTeX/pdfTeX/XeTeX programs, as typeset by WEAVE, except with each section on a separate page... but this situation may also be familiar to those trying to run dvisvgm on the TikZ manual, as in #x / #y .) With this change, the time to run dvisvgm went from hours to seconds. **What it does:** When invoked with certain options, for every page of the DVI file, dvisvgm writes out `@font-face` and text style CSS rules, like: @font-face{font-family:cmr10;src:url(data:application/x-font-ttf;base64,AAEAAAAN... and text.f12 {font-family:cmr10;font-size:9.96264px} All that this change does, in a hacky way, is accumulate these across pages, and write each of them only once. Then, the separate SVGs for each page can all just use the common style. **Caveats:** This is a giant hack, with MANY caveats: 1. assuming there are enough pages (SVGs) for all this to be worth it, 2. assuming only 7-bit fonts (having glyphs in positions 0 to 127), 3. assuming font has no license problems (so doesn't have to be subset), 4. assuming the user can do some postprocessing, namely generating CSS files by wrapping the `font-faces.txt` and `font-styles.txt` files within ` at the right place, where `common.css` is produced by (4) above. 6. assming dvisvgm is being invoked something like this: dvisvgm --page=1- --font-format=woff2,autohint then, it *may* help to just do the expensive font-writing once, as here. --- src/DVIToSVGActions.cpp | 3 +++ src/FontWriter.cpp | 3 +++ src/SVGTree.cpp | 29 ++++++++++++++++++++++------- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/DVIToSVGActions.cpp b/src/DVIToSVGActions.cpp index bb8e4d6f..34e26816 100644 --- a/src/DVIToSVGActions.cpp +++ b/src/DVIToSVGActions.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see . ** *************************************************************************/ +#include #include #include #include "BoundingBox.hpp" @@ -94,6 +95,8 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co // For a given font object, Font::uniqueFont() returns the same unique font object for // all fonts with the same name. _usedChars[SVGTree::USE_FONTS ? font.uniqueFont() : &font].insert(c); + assert(c >= 0 && c <= 127); + for (int cc = 0; cc <= 127; ++cc) _usedChars[SVGTree::USE_FONTS ? font.uniqueFont() : &font].insert(cc); // However, we record all required fonts _usedFonts.insert(&font); diff --git a/src/FontWriter.cpp b/src/FontWriter.cpp index d93402ba..e0169b07 100644 --- a/src/FontWriter.cpp +++ b/src/FontWriter.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "FontWriter.hpp" #include "Message.hpp" #include "utility.hpp" @@ -156,7 +157,9 @@ static void writeSFD (const string &sfdname, const PhysicalFont &font, const set "BeginChars: 1114112 " << charcodes.size() << '\n'; double extend = font.style() ? font.style()->extend : 1; + for (int c = 0; c <= 127; ++c) assert(charcodes.count(c) == 1); for (int c : charcodes) { + assert(0 <= c && c <= 127); string name = font.glyphName(c); if (name.empty()) { // if the font doesn't provide glyph names, use AGL name uFOO diff --git a/src/SVGTree.cpp b/src/SVGTree.cpp index 57b5fd5a..8576e9bc 100644 --- a/src/SVGTree.cpp +++ b/src/SVGTree.cpp @@ -213,10 +213,12 @@ void SVGTree::appendFontStyles (const unordered_set &fonts) { for (const Font *font : fonts) if (!dynamic_cast(font)) // skip virtual fonts sortmap[FontManager::instance().fontID(font)] = font; - ostringstream style; + ostringstream styles; + static set written_styles; // add font style definitions in ascending order for (auto &idfontpair : sortmap) { - if (CREATE_CSS) { + if (CREATE_CSS && written_styles.count(idfontpair.first) == 0) { + ostringstream style; style << "text.f" << idfontpair.first << ' ' << "{font-family:" << idfontpair.second->name() << ";font-size:" << XMLString(idfontpair.second->scaledSize()) << "px"; @@ -229,9 +231,14 @@ void SVGTree::appendFontStyles (const unordered_set &fonts) { style << " /* " << info << " */"; } style << '\n'; + styles << style.str(); + std::ofstream outfile; + outfile.open("font-styles.txt", std::ios_base::app); + outfile << style.str(); + written_styles.insert(idfontpair.first); } } - styleCDataNode()->append(style.str()); + // styleCDataNode()->append(styles.str()); } } @@ -244,12 +251,20 @@ void SVGTree::append (const PhysicalFont &font, const set &chars, GFGlyphTr if (chars.empty()) return; + static set written_fonts; if (USE_FONTS) { if (FONT_FORMAT != FontWriter::FontFormat::SVG) { - ostringstream style; - FontWriter fontWriter(font); - if (fontWriter.writeCSSFontFace(FONT_FORMAT, chars, style, callback)) - styleCDataNode()->append(style.str()); + if (written_fonts.count(font.name()) == 0) { + ostringstream style; + FontWriter fontWriter(font); + if (fontWriter.writeCSSFontFace(FONT_FORMAT, chars, style, callback)) { + std::ofstream outfile; + outfile.open("font-faces.txt", std::ios_base::app); + outfile << style.str(); + written_fonts.insert(font.name()); + } + // styleCDataNode()->append(style.str()); + } } else { if (ADD_COMMENTS) {