diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp | 590 |
1 files changed, 0 insertions, 590 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp deleted file mode 100644 index c2defd06fe9..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp +++ /dev/null @@ -1,590 +0,0 @@ -/************************************************************************* -** DVIToSVG.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 <config.h> -#include <cstdlib> -#include <ctime> -#include <fstream> -#include <iomanip> -#include <set> -#include <sstream> -#include "Calculator.hpp" -#include "DVIToSVG.hpp" -#include "DVIToSVGActions.hpp" -#include "FileSystem.hpp" -#include "Font.hpp" -#include "FontManager.hpp" -#include "GlyphTracerMessages.hpp" -#include "InputBuffer.hpp" -#include "InputReader.hpp" -#include "PageRanges.hpp" -#include "PageSize.hpp" -#include "PreScanDVIReader.hpp" -#include "SignalHandler.hpp" -#include "optimizer/SVGOptimizer.hpp" -#include "SVGOutput.hpp" -#include "utility.hpp" -#include "version.hpp" -#include "XXHashFunction.hpp" - -/////////////////////////////////// -// special handlers - -#include "BgColorSpecialHandler.hpp" -#include "ColorSpecialHandler.hpp" -#include "DvisvgmSpecialHandler.hpp" -#include "EmSpecialHandler.hpp" -#include "HtmlSpecialHandler.hpp" -#include "PapersizeSpecialHandler.hpp" -#include "PdfSpecialHandler.hpp" -#include "TpicSpecialHandler.hpp" -#ifndef HAVE_LIBGS - #include "NoPsSpecialHandler.hpp" -#endif -#ifndef DISABLE_GS - #include "PsSpecialHandler.hpp" -#endif - -/////////////////////////////////// - -using namespace std; - -/** 'a': trace all glyphs even if some of them are already cached - * 'm': trace missing glyphs, i.e. glyphs not yet cached - * 0 : only trace actually required glyphs */ -char DVIToSVG::TRACE_MODE = 0; -bool DVIToSVG::COMPUTE_PROGRESS = false; -DVIToSVG::HashSettings DVIToSVG::PAGE_HASH_SETTINGS; - - -DVIToSVG::DVIToSVG (istream &is, SVGOutputBase &out) : DVIReader(is), _out(out) -{ - _pageHeight = _pageWidth = 0; - _tx = _ty = 0; // no cursor translation - _pageByte = 0; - _prevXPos = _prevYPos = numeric_limits<double>::min(); - _prevWritingMode = WritingMode::LR; - _actions = util::make_unique<DVIToSVGActions>(*this, _svg); -} - - -/** Starts the conversion process. - * @param[in] first number of first page to convert - * @param[in] last number of last page to convert - * @param[in] hashFunc pointer to function to be used to compute page hashes */ -void DVIToSVG::convert (unsigned first, unsigned last, HashFunction *hashFunc) { - if (first > last) - swap(first, last); - if (first > numberOfPages()) { - ostringstream oss; - oss << "file contains only " << numberOfPages() << " page"; - if (numberOfPages() > 1) - oss << 's'; - throw DVIException(oss.str()); - } - last = min(last, numberOfPages()); - bool computeHashes = (hashFunc && !_out.ignoresHashes()); - string shortenedOptHash = XXH32HashFunction(PAGE_HASH_SETTINGS.optionsHash()).digestString(); - for (unsigned i=first; i <= last; ++i) { - string dviHash, combinedHash; - if (computeHashes) { - computePageHash(i, *hashFunc); - dviHash = hashFunc->digestString(); - hashFunc->update(PAGE_HASH_SETTINGS.optionsHash()); - combinedHash = hashFunc->digestString(); - } - const SVGOutput::HashTriple hashTriple(dviHash, shortenedOptHash, combinedHash); - FilePath path = _out.filepath(i, numberOfPages(), hashTriple); - if (!dviHash.empty() && !PAGE_HASH_SETTINGS.isSet(HashSettings::P_REPLACE) && path.exists()) { - Message::mstream(false, Message::MC_PAGE_NUMBER) << "skipping page " << i; - Message::mstream().indent(1); - Message::mstream(false, Message::MC_PAGE_WRITTEN) << "\nfile " << path.shorterAbsoluteOrRelative() << " exists\n"; - Message::mstream().indent(0); - } - else { - executePage(i); - SVGOptimizer(_svg).execute(); - embedFonts(_svg.rootNode()); - bool success = _svg.write(_out.getPageStream(currentPageNumber(), numberOfPages(), hashTriple)); - string fname = path.shorterAbsoluteOrRelative(); - if (fname.empty()) - fname = "<stdout>"; - if (success) - Message::mstream(false, Message::MC_PAGE_WRITTEN) << "\noutput written to " << fname << '\n'; - else - Message::wstream(true) << "failed to write output to " << fname << '\n'; - _svg.reset(); - _actions->reset(); - } - } -} - - -/** Creates a HashFunction object for a given algorithm name. - * @param[in] algo name of hash algorithm - * @return pointer to hash function - * @throw MessageException if algorithm name is invalid or not supported */ -static unique_ptr<HashFunction> create_hash_function (const string &algo) { - if (auto hashFunc = HashFunction::create(algo)) - return hashFunc; - - string msg = "unknown hash algorithm '"+algo+"' (supported algorithms: "; - for (const string &name : HashFunction::supportedAlgorithms()) - msg += name + ", "; - msg.pop_back(); - msg.back() = ')'; - throw MessageException(msg); -} - - -/** Convert DVI pages specified by a page range string. - * @param[in] rangestr string describing the pages to convert - * @param[out] pageinfo (number of converted pages, number of total pages) */ -void DVIToSVG::convert (const string &rangestr, pair<int,int> *pageinfo) { - PageRanges ranges; - if (!ranges.parse(rangestr, numberOfPages())) - throw MessageException("invalid page range format"); - - Message::mstream(false, Message::MC_PAGE_NUMBER) << "pre-processing DVI file (format version " << getDVIVersion() << ")\n"; - if (auto actions = dynamic_cast<DVIToSVGActions*>(_actions.get())) { - PreScanDVIReader prescan(getInputStream(), actions); - actions->setDVIReader(prescan); - prescan.executeAllPages(); - actions->setDVIReader(*this); - SpecialManager::instance().notifyPreprocessingFinished(); - executeFontDefs(); - } - - unique_ptr<HashFunction> hashFunc; - if (!PAGE_HASH_SETTINGS.algorithm().empty()) // name of hash algorithm present? - hashFunc = create_hash_function(PAGE_HASH_SETTINGS.algorithm()); - - for (const auto &range : ranges) - convert(range.first, range.second, hashFunc.get()); - if (pageinfo) { - pageinfo->first = ranges.numberOfPages(); - pageinfo->second = numberOfPages(); - } -} - - -/** Writes the hash values of a selected set of pages to an output stream. - * @param[in] rangestr string describing the pages to convert - * @param[in,out] os stream the output is written to */ -void DVIToSVG::listHashes (const string &rangestr, std::ostream &os) { - PageRanges ranges; - if (!ranges.parse(rangestr, numberOfPages())) - throw MessageException("invalid page range format"); - - XXH32HashFunction xxh32; - auto hashFunc = create_hash_function(PAGE_HASH_SETTINGS.algorithm()); - int width1 = util::ilog10(numberOfPages())+1; - int width2 = hashFunc->digestSize()*2; - int spaces1 = width1+2+(width2-3)/2; - int spaces2 = width1+2+width2+2-spaces1-3+(width2-7)/2; - string shortenedOptHash = XXH32HashFunction(PAGE_HASH_SETTINGS.optionsHash()).digestString(); - os << string(spaces1, ' ') << "DVI" - << string(spaces2, ' ') << "DVI+opt\n"; - for (const auto &range : ranges) { - for (int i=range.first; i <= range.second; i++) { - computePageHash(i, *hashFunc); - os << setw(width1) << i; - os << ": " << hashFunc->digestString(); - hashFunc->update(PAGE_HASH_SETTINGS.optionsHash()); - os << ", " << hashFunc->digestString() << '\n'; - } - } - os << "hash algorithm: " << PAGE_HASH_SETTINGS.algorithm() - << ", options hash: " << shortenedOptHash << '\n'; -} - - -int DVIToSVG::executeCommand () { - SignalHandler::instance().check(); - const streampos cmdpos = tell(); - int opcode = DVIReader::executeCommand(); - if (dviState().v+_ty != _prevYPos) { - _tx = _ty = 0; - _prevYPos = dviState().v; - } - _prevXPos = dviState().h+_tx; - _prevWritingMode = dviState().d; - if (COMPUTE_PROGRESS && inPage() && _actions) { - size_t pagelen = numberOfPageBytes(currentPageNumber()-1); - _pageByte += tell()-cmdpos; - _actions->progress(_pageByte, pagelen); - } - return opcode; -} - - -/** This template method is called by parent class DVIReader before - * executing the BOP actions. - * @param[in] pageno physical page number (1 = first page) - * @param[in] c contains information about the page (page number etc.) */ -void DVIToSVG::enterBeginPage (unsigned pageno, const vector<int32_t> &c) { - if (dynamic_cast<DVIToSVGActions*>(_actions.get())) { - Message::mstream().indent(0); - Message::mstream(false, Message::MC_PAGE_NUMBER) << "processing page " << pageno; - if (pageno != (unsigned)c[0]) // Does page number shown on page differ from physical page number? - Message::mstream(false) << " [" << c[0] << ']'; - Message::mstream().indent(1); - _svg.appendToDoc(util::make_unique<XMLComment>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); - } -} - - -/** This template method is called by DVIReader::cmdEop() after - * executing the EOP actions. */ -void DVIToSVG::leaveEndPage (unsigned) { - if (!dynamic_cast<DVIToSVGActions*>(_actions.get())) - return; - - // set bounding box and apply page transformations - BoundingBox bbox = _actions->bbox(); // bounding box derived from the DVI commands executed - if (_bboxFormatString == "min" || _bboxFormatString == "preview" || _bboxFormatString == "papersize") { - bbox.unlock(); - bbox.transform(getPageTransformation()); - } - else if (_bboxFormatString == "dvi") { - // center page content - double dx = (_pageWidth-bbox.width())/2; - double dy = (_pageHeight-bbox.height())/2; - bbox += BoundingBox(-dx, -dy, dx, dy); - } - else if (_bboxFormatString != "none") { - istringstream iss(_bboxFormatString); - StreamInputReader ir(iss); - ir.skipSpace(); - if (isalpha(ir.peek())) { - // set explicitly given page format - PageSize size(_bboxFormatString); - if (size.valid()) { - // convention: DVI position (0,0) equals (1in, 1in) relative - // to the upper left vertex of the page (see DVI specification) - const double border = -72; - bbox = BoundingBox(border, border, size.width().bp()+border, size.height().bp()+border); - } - } - else { // set/modify bounding box by explicitly given values - try { - vector<Length> lengths = BoundingBox::extractLengths(_bboxFormatString); - if (lengths.size() == 1 || lengths.size() == 2) { // relative box size? - // apply the page transformation and adjust the bbox afterwards - bbox.transform(getPageTransformation()); - } - bbox.set(lengths); - } - catch (const MessageException &e) { - } - } - } - if (bbox.width() == 0) - Message::wstream(false) << "\npage is empty\n"; - if (_bboxFormatString != "none") { - _svg.setBBox(bbox); - const double bp2pt = 72.27/72; - const double bp2mm = 25.4/72; - Message::mstream(false) << '\n'; - Message::mstream(false, Message::MC_PAGE_SIZE) << "graphic size: " << XMLString(bbox.width()*bp2pt) << "pt" - " x " << XMLString(bbox.height()*bp2pt) << "pt" - " (" << XMLString(bbox.width()*bp2mm) << "mm" - " x " << XMLString(bbox.height()*bp2mm) << "mm)"; - Message::mstream(false) << '\n'; - } -} - - -Matrix DVIToSVG::getPageTransformation () const { - Matrix matrix(1); // unity matrix - if (!_transCmds.empty()) { - Calculator calc; - if (_actions) { - const double bp2pt = (1_bp).pt(); - BoundingBox &bbox = _actions->bbox(); - calc.setVariable("ux", bbox.minX()*bp2pt); - calc.setVariable("uy", bbox.minY()*bp2pt); - calc.setVariable("w", bbox.width()*bp2pt); - calc.setVariable("h", bbox.height()*bp2pt); - } - // add constants for length units to calculator - for (const auto &unit : Length::getUnits()) - calc.setVariable(unit.first, Length(1, unit.second).pt()); - matrix.set(_transCmds, calc); - } - return matrix; -} - - -static void collect_chars (unordered_map<const Font*, set<int>> &fontmap) { - unordered_map<const Font*, set<int>> insertedChars; - for (const auto &entry : fontmap) { - const Font *unique_font = entry.first->uniqueFont(); - if (unique_font != entry.first) { - for (int c : entry.second) - insertedChars[unique_font].insert(c); - } - } - for (const auto &entry : insertedChars) - fontmap[entry.first].insert(entry.second.begin(), entry.second.end()); -} - - -/** Adds the font information to the SVG tree. - * @param[in] svgElement the font nodes are added to this node */ -void DVIToSVG::embedFonts (XMLElement *svgElement) { - if (!svgElement || !_actions) // no dvi actions => no chars written => no fonts to embed - return; - - const DVIToSVGActions *svgActions = static_cast<DVIToSVGActions*>(_actions.get()); - auto &usedCharsMap = svgActions->getUsedChars(); - - collect_chars(usedCharsMap); - - GlyphTracerMessages messages; - unordered_set<const Font*> tracedFonts; // collect unique fonts already traced - for (const auto &fontchar : usedCharsMap) { - const Font *font = fontchar.first; - if (auto ph_font = dynamic_cast<const PhysicalFont*>(font)) { - // Check if glyphs should be traced. Only trace the glyphs of unique fonts, i.e. - // avoid retracing the same glyphs again if they are referenced in various sizes. - if (TRACE_MODE != 0 && tracedFonts.find(ph_font->uniqueFont()) == tracedFonts.end()) { - ph_font->traceAllGlyphs(TRACE_MODE == 'a', &messages); - tracedFonts.insert(ph_font->uniqueFont()); - } - if (font->path()) // does font file exist? - _svg.append(*ph_font, fontchar.second, &messages); - else - Message::wstream(true) << "can't embed font '" << font->name() << "'\n"; - } - else - Message::wstream(true) << "can't embed font '" << font->name() << "'\n"; - } - _svg.appendFontStyles(svgActions->getUsedFonts()); -} - - -/** Enables or disables processing of specials. If ignorelist == 0, all - * supported special handlers are loaded. To disable selected sets of specials, - * the corresponding prefixes can be given separated by non alpha-numeric characters, - * e.g. "color, ps, em" or "color: ps em" etc. - * A single "*" in the ignore list disables all specials. - * @param[in] ignorelist list of special prefixes to ignore - * @param[in] pswarning if true, shows warning about disabled PS support - * @return the SpecialManager that handles special statements */ -void DVIToSVG::setProcessSpecials (const char *ignorelist, bool pswarning) { - if (ignorelist && strcmp(ignorelist, "*") == 0) // ignore all specials? - SpecialManager::instance().unregisterHandlers(); - else { - // add special handlers - vector<unique_ptr<SpecialHandler>> handlers; - handlers.emplace_back(util::make_unique<BgColorSpecialHandler>()); // handles background color special - handlers.emplace_back(util::make_unique<ColorSpecialHandler>()); // handles color specials - handlers.emplace_back(util::make_unique<DvisvgmSpecialHandler>()); // handles raw SVG embeddings - handlers.emplace_back(util::make_unique<EmSpecialHandler>()); // handles emTeX specials - handlers.emplace_back(util::make_unique<HtmlSpecialHandler>()); // handles hyperref specials - handlers.emplace_back(util::make_unique<PapersizeSpecialHandler>()); // handles papersize special - handlers.emplace_back(util::make_unique<PdfSpecialHandler>()); // handles pdf specials - handlers.emplace_back(util::make_unique<TpicSpecialHandler>()); // handles tpic specials -#ifndef DISABLE_GS - if (Ghostscript().available()) - handlers.emplace_back(util::make_unique<PsSpecialHandler>()); // handles PostScript specials - else -#endif - { -#ifndef HAVE_LIBGS - // dummy PS special handler that only prints warning messages - handlers.emplace_back(util::make_unique<NoPsSpecialHandler>()); - if (pswarning) { -#ifdef DISABLE_GS - Message::wstream() << "processing of PostScript specials has been disabled permanently\n"; -#else - Message::wstream() << "processing of PostScript specials is disabled (Ghostscript not found)\n"; -#endif - } -#endif - } - SpecialManager::instance().unregisterHandlers(); - SpecialManager::instance().registerHandlers(handlers, ignorelist); - } -} - - -FilePath DVIToSVG::getSVGFilePath (unsigned pageno) const { - return _out.filepath(pageno, numberOfPages()); -} - - -void DVIToSVG::moveRight (double dx, MoveMode mode) { - DVIReader::moveRight(dx, mode); - if (_actions) { - if (dviState().d == WritingMode::LR) - _actions->moveToX(dviState().h+_tx, mode == MoveMode::CHANGEPOS); - else - _actions->moveToY(dviState().v+_ty, mode == MoveMode::CHANGEPOS); - } -} - - -void DVIToSVG::moveDown (double dy, MoveMode mode) { - DVIReader::moveDown(dy, mode); - if (_actions) { - if (dviState().d == WritingMode::LR) - _actions->moveToY(dviState().v+_ty, mode == MoveMode::CHANGEPOS); - else - _actions->moveToX(dviState().h+_tx, mode == MoveMode::CHANGEPOS); - } -} - - -void DVIToSVG::dviPost (uint16_t, uint16_t pages, uint32_t pw, uint32_t ph, uint32_t, uint32_t, uint32_t, uint32_t) { - _pageHeight = ph; // height of tallest page in dvi units - _pageWidth = pw; // width of widest page in dvi units -} - - -void DVIToSVG::dviBop (const std::vector<int32_t> &c, int32_t) { - _pageByte = 0; - enterBeginPage(currentPageNumber(), c); - if (_actions) { - _actions->progress(0, 1); // ensure that progress is called at 0% - _actions->beginPage(currentPageNumber(), c); - } -} - - -void DVIToSVG::dviEop () { - if (_actions) { - _actions->endPage(currentPageNumber()); - _pageByte = numberOfPageBytes(currentPageNumber()-1); - _actions->progress(_pageByte, _pageByte); // ensure that progress is called at 100% - } - leaveEndPage(currentPageNumber()); -} - - -void DVIToSVG::dviSetChar0 (uint32_t c, const Font *font) { - if (_actions && !dynamic_cast<const VirtualFont*>(font)) - _actions->setChar(dviState().h+_tx, dviState().v+_ty, c, dviState().d != WritingMode::LR, *font); -} - - -void DVIToSVG::dviSetChar (uint32_t c, const Font *font) { - dviSetChar0(c, font); -} - - -void DVIToSVG::dviPutChar (uint32_t c, const Font *font) { - dviSetChar0(c, font); -} - - -void DVIToSVG::dviSetRule (double height, double width) { - if (_actions && height > 0 && width > 0) - _actions->setRule(dviState().h+_tx, dviState().v+_ty, height, width); -} - - -void DVIToSVG::dviPutRule (double height, double width) { - dviSetRule(height, width); -} - - -void DVIToSVG::dviPop () { - if (_actions) { - if (_prevXPos != dviState().h+_tx) - _actions->moveToX(dviState().h + _tx, true); // force setting the SVG position - if (_prevYPos != dviState().v+_ty) - _actions->moveToY(dviState().v + _ty, true); // force setting the SVG position - if (_prevWritingMode != dviState().d) - _actions->setTextOrientation(dviState().d != WritingMode::LR); - } -} - - -void DVIToSVG::dviFontNum (uint32_t fontnum, SetFontMode, const Font *font) { - if (_actions && font && !dynamic_cast<const VirtualFont*>(font)) - _actions->setFont(FontManager::instance().fontID(fontnum), *font); // all fonts get a recomputed ID -} - - -void DVIToSVG::dviDir (WritingMode dir) { - if (_actions) - _actions->setTextOrientation(dir != WritingMode::LR); -} - - -void DVIToSVG::dviXXX (const std::string &str) { - if (_actions) - _actions->special(str, dvi2bp()); -} - - -void DVIToSVG::dviXGlyphArray (std::vector<double> &dx, vector<double> &dy, vector<uint16_t> &glyphs, const Font &font) { - if (_actions) { - for (size_t i=0; i < glyphs.size(); i++) - _actions->setChar(dviState().h+dx[i]+_tx, dviState().v+dy[i]+_ty, glyphs[i], false, font); - } -} - - -void DVIToSVG::dviXGlyphString (vector<double> &dx, vector<uint16_t> &glyphs, const Font &font) { - if (_actions) { - for (size_t i=0; i < glyphs.size(); i++) - _actions->setChar(dviState().h+dx[i]+_tx, dviState().v+_ty, glyphs[i], false, font); - } -} - - -void DVIToSVG::dviXTextAndGlyphs (vector<double> &dx, vector<double> &dy, vector<uint16_t>&, vector<uint16_t> &glyphs, const Font &font) { - dviXGlyphArray(dx, dy, glyphs, font); -} - -/////////////////////////////////////////////////////////////// - -/** Parses a string consisting of comma-separated words, and assigns - * the values to the hash settings. */ -void DVIToSVG::HashSettings::setParameters (const string ¶mstr) { - auto paramnames = util::split(paramstr, ","); - map<string, Parameter> paramMap = { - {"list", P_LIST}, - {"replace", P_REPLACE} - }; - for (string &name : paramnames) { - name = util::trim(name); - auto it = paramMap.find(name); - if (it != paramMap.end()) - _params.insert(it->second); - else if (_algo.empty() && HashFunction::isSupportedAlgorithm(name)) - _algo = name; - else if (!name.empty()) { - string msg = "invalid hash parameter '"+name+"' (supported algorithms: "; - for (string str : HashFunction::supportedAlgorithms()) - msg += str + ", "; - msg.pop_back(); - msg.pop_back(); - msg += ')'; - throw MessageException(msg); - } - } - // set default hash algorithm if none is given - if (_algo.empty()) - _algo = "xxh64"; -} |