diff options
author | Norbert Preining <preining@logic.at> | 2019-11-22 02:37:37 +0000 |
---|---|---|
committer | Norbert Preining <preining@logic.at> | 2019-11-22 02:37:37 +0000 |
commit | ed122ac9332b07846c8f32309a90ee20351b89c3 (patch) | |
tree | 1278ed5b65e4815140098fa574e662cd405e25ab /Build/source/texk/dvisvgm/dvisvgm-src/src | |
parent | 4d251c1585708a66ebdec74139a6bf13049aa49c (diff) |
dvisvgm update to 2.8.1 (from Martin Gieseking)
git-svn-id: svn://tug.org/texlive/trunk@52883 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src')
186 files changed, 5604 insertions, 2387 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp index 350e130166a..272c88c3ad1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp @@ -19,7 +19,6 @@ *************************************************************************/ #include <algorithm> -#include <sstream> #include "BasicDVIReader.hpp" using namespace std; @@ -100,11 +99,8 @@ int BasicDVIReader::evalCommand (CommandHandler &handler, int ¶m) { handler = &BasicDVIReader::cmdDir; num_param_bytes = 1; } - else if (opcode > OP_POSTPOST) { - ostringstream oss; - oss << "undefined DVI command (opcode " << opcode << ')'; - throw DVIException(oss.str()); - } + else if (opcode > OP_POSTPOST) + throw DVIException("undefined DVI command (opcode " + to_string(opcode) + ")"); else { const int offset = opcode < OP_FNTNUM0 ? OP_SET1 : (OP_FNTNUM63+1)-(OP_FNTNUM0-OP_SET1); handler = commands[opcode-offset].handler; @@ -194,9 +190,7 @@ void BasicDVIReader::setDVIVersion (DVIVersion version) { case DVI_XDV7: break; default: - ostringstream oss; - oss << "DVI version " << _dviVersion << " not supported"; - throw DVIException(oss.str()); + throw DVIException("DVI version " + to_string(_dviVersion) + " not supported"); } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp index ce3c0ac4061..14a1fb9858a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp @@ -51,7 +51,6 @@ class BasicDVIReader : public StreamReader { public: explicit BasicDVIReader (std::istream &is); - virtual ~BasicDVIReader () =default; virtual void executeAllPages (); virtual double getXPos () const {return 0;} virtual double getYPos () const {return 0;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp index c98f6331930..d2077bcfebe 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp @@ -21,11 +21,12 @@ #include <algorithm> #include <utility> #include "Bezier.hpp" +#include "Matrix.hpp" using namespace std; Bezier::Bezier () { - _points[0] = _points[1] = _points[2] = _points[3] = 0; + _points[0] = _points[1] = _points[2] = _points[3] = DPair(0); } @@ -51,13 +52,13 @@ Bezier::Bezier (const Bezier &source, double t0, double t1) { if (t0 > t1) swap(t0, t1); if (t0 == 0) - source.subdivide(t1, this, 0); + source.subdivide(t1, this, nullptr); else if (t1 == 1) - source.subdivide(t0, 0, this); + source.subdivide(t0, nullptr, this); else { Bezier subcurve; - source.subdivide(t0, 0, &subcurve); - subcurve.subdivide((t1-t0)/(1-t0), this, 0); + source.subdivide(t0, nullptr, &subcurve); + subcurve.subdivide((t1-t0)/(1-t0), this, nullptr); } } } @@ -230,8 +231,8 @@ static bool solve_quadratic_equation (double a, double b, double c, double &x1, /** Returns a tight bounding box parallel to the x- and y-axis. */ -void Bezier::getBBox (BoundingBox &bbox) const { - bbox.invalidate(); +BoundingBox Bezier::getBBox () const { + BoundingBox bbox; // coefficients of the derivative DPair pa = _points[3] - _points[2]*3.0 + _points[1]*3.0 - _points[0]; DPair pb = (_points[2]-_points[1]*2.0+_points[0])*2.0; @@ -253,4 +254,12 @@ void Bezier::getBBox (BoundingBox &bbox) const { } bbox.embed(_points[0]); bbox.embed(_points[3]); + return bbox; +} + + +Bezier& Bezier::transform (const Matrix &matrix) { + for (int i=0; i < 4; i++) + _points[i] = matrix*_points[i]; + return *this; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp index 7ba44418ea4..525ef23435b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp @@ -25,8 +25,9 @@ #include "BoundingBox.hpp" #include "Pair.hpp" -class Bezier -{ +class Matrix; + +class Bezier { public: Bezier (); Bezier (const DPair &p0, const DPair &p1, const DPair &p2); @@ -37,10 +38,11 @@ class Bezier DPair valueAt (double t) const; DPair blossomValue (double u, double v, double w) const; void subdivide (double t, Bezier *bezier1, Bezier *bezier2) const; - int approximate (double delta, std::vector<DPair> &p, std::vector<double> *t=0) const; + Bezier& transform (const Matrix &matrix); + int approximate (double delta, std::vector<DPair> &p, std::vector<double> *t=nullptr) const; const DPair& point (int i) const {return _points[i];} int reduceDegree (double delta, std::vector<DPair> &p) const; - void getBBox (BoundingBox &bbox) const; + BoundingBox getBBox () const; protected: int approximate (double delta, double t0, double t1, std::vector<DPair> &p, std::vector<double> *t) const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp index 1512e3fbe7c..10c05fca051 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp @@ -54,7 +54,7 @@ void BgColorSpecialHandler::dviBeginPage (unsigned pageno, SpecialActions &actio if (_pageColors.empty()) return; // find number of page with bg color change not lower than the current one - vector<PageColor>::iterator it = lower_bound(_pageColors.begin(), _pageColors.end(), PageColor(pageno, Color::BLACK)); + auto it = lower_bound(_pageColors.begin(), _pageColors.end(), PageColor(pageno, Color::BLACK)); if (it != _pageColors.end() && it->first == pageno) actions.setBgColor(it->second); else if (it != _pageColors.begin()) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp index e39ad79c476..3fa554eed42 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp @@ -25,10 +25,6 @@ using namespace std; -Bitmap::Bitmap () : _rows(0), _cols(0), _xshift(0), _yshift(0), _bpr(0), _bytes(0) -{ -} - /** Constructs a Bitmap */ Bitmap::Bitmap (int minx, int maxx, int miny , int maxy) { @@ -48,8 +44,7 @@ void Bitmap::resize (int minx, int maxx, int miny , int maxy) { _yshift = miny; _bpr = _cols/8 + (_cols % 8 ? 1 : 0); // bytes per row _bytes.resize(_rows*_bpr); - for (uint8_t &byte : _bytes) - byte = 0; + std::fill(_bytes.begin(), _bytes.end(), 0); } @@ -69,7 +64,7 @@ void Bitmap::setBits (int row, int col, int n) { int m = min(n, b+1); // number of bits to be set in current byte int bitseq = (1 << m)-1; // sequence of n set bits (bits 0..n-1 are set) bitseq <<= b-m+1; // move bit sequence so that bit b is the leftmost set bit - *byte |= uint8_t(bitseq); // apply bit sequence to current byte + *byte |= uint8_t(bitseq); // apply bit sequence to current byte byte++; n -= m; col += m; @@ -90,10 +85,8 @@ void Bitmap::forAllPixels (Callback &data) const { } -class BBoxCallback : public Bitmap::Callback -{ +class BBoxCallback : public Bitmap::Callback { public: - BBoxCallback () : _changed(false), _minx(numeric_limits<int>::max()), _miny(_minx), _maxx(0), _maxy(0) {} int minx () const {return _minx;} int miny () const {return _miny;} int maxx () const {return _maxx;} @@ -116,8 +109,9 @@ class BBoxCallback : public Bitmap::Callback } private: - bool _changed; - int _minx, _miny, _maxx, _maxy; + bool _changed = false; + int _minx = numeric_limits<int>::max(), _miny=_minx; + int _maxx = 0, _maxy = 0; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp index fe9f31f0536..026edae9a21 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp @@ -25,8 +25,7 @@ #include <vector> -class Bitmap -{ +class Bitmap { public: struct Callback { virtual ~Callback() =default; @@ -36,7 +35,7 @@ class Bitmap }; public: - Bitmap (); + Bitmap () =default; Bitmap (int minx, int maxx, int miny , int maxy); void resize (int minx, int maxx, int miny , int maxy); void setBits(int row, int col, int n); @@ -60,9 +59,9 @@ class Bitmap // std::ostream& write (std::ostream &os) const; private: - int _rows, _cols; ///< number of rows, columns - int _xshift, _yshift; ///< horizontal/vertical shift - int _bpr; ///< number of bytes per row + int _rows=0, _cols=0; ///< number of rows, columns + int _xshift=0, _yshift=0; ///< horizontal/vertical shift + int _bpr=0; ///< number of bytes per row std::vector<uint8_t> _bytes; }; @@ -81,7 +80,7 @@ int Bitmap::copy (std::vector<T> &target, bool vflip) const { int targetrow = vflip ? _rows-r-1 : r; for (int b=0; b < _bpr; b++) { T &t = target[targetrow*tpr + b/s]; - T chunk = (T)_bytes[r*_bpr+b] << (8*(s-1-b%s)); + T chunk = static_cast<T>(_bytes[r*_bpr+b]) << (8*(s-1-b%s)); if (b % s == 0) t = chunk; else @@ -107,5 +106,4 @@ void Bitmap::write (std::ostream &os, const std::vector<T> &v) const { } }*/ - #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp index 968a1517526..a076b523639 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp @@ -74,7 +74,7 @@ vector<Length> BoundingBox::extractLengths (string boxstr) { boxstr = util::replace(boxstr, ",", " "); boxstr = util::normalize_space(boxstr); vector<string> lengthStrings = util::split(boxstr, " "); - for (string lenstr : lengthStrings) { + for (const string &lenstr : lengthStrings) { if (!lenstr.empty()) lengths.emplace_back(Length(lenstr)); } @@ -263,8 +263,8 @@ ostream& BoundingBox::write (ostream &os) const { } -unique_ptr<XMLElementNode> BoundingBox::createSVGRect () const { - auto rect = util::make_unique<XMLElementNode>("rect"); +unique_ptr<XMLElement> BoundingBox::createSVGRect () const { + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", minX()); rect->addAttribute("y", minY()); rect->addAttribute("width", width()); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp index 3ff775d02bf..8848f60f288 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp @@ -31,11 +31,11 @@ class Matrix; -class XMLElementNode; +class XMLElement; struct BoundingBoxException : MessageException { - BoundingBoxException (const std::string &msg) : MessageException(msg) {} + explicit BoundingBoxException (const std::string &msg) : MessageException(msg) {} }; @@ -45,7 +45,7 @@ class BoundingBox { BoundingBox (double ulxx, double ulyy, double lrxx, double lryy); BoundingBox (const DPair &p1, const DPair &p2); BoundingBox (const Length &ulxx, const Length &ulyy, const Length &lrxx, const Length &lryy); - BoundingBox (const std::string &boxstr); + explicit BoundingBox (const std::string &boxstr); void set (const std::string &boxstr); void set (const std::vector<Length> &lengths); void embed (double x, double y); @@ -78,7 +78,7 @@ class BoundingBox { void transform (const Matrix &tm); std::string toSVGViewBox () const; std::ostream& write (std::ostream &os) const; - std::unique_ptr<XMLElementNode> createSVGRect () const; + std::unique_ptr<XMLElement> createSVGRect () const; private: double _ulx, _uly; ///< coordinates of upper left vertex (in PS point units) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp index 9b399a2b021..2b0c1b5359e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp @@ -39,7 +39,7 @@ void CommandLine::parse (int argc, char **argv) { for (int i=1; i < argc; i++) { istringstream iss(argv[i]); if (filesOnly || iss.peek() != '-') - _files.push_back(argv[i]); + _files.emplace_back(argv[i]); else { iss.get(); // skip dash if (iss.peek() < 0) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp index e012b21a4c9..a80d9b87d75 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp @@ -37,7 +37,7 @@ class CommandLine { virtual ~CommandLine () =default; void parse (int argc, char **argv); void help (std::ostream &os, int mode=0) const; - void addFilename (std::string fname) {_files.emplace_back(fname);} + void addFilename (const std::string &fname) {_files.emplace_back(fname);} bool singleDashGiven () const {return _singleDashParsed;} const std::vector<std::string>& filenames () const {return _files;} @@ -60,7 +60,7 @@ class CommandLine { struct CommandLineException : public MessageException { - CommandLineException (const std::string &msg) : MessageException(msg) {} + explicit CommandLineException (const std::string &msg) : MessageException(msg) {} }; } // namespace CL diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp index 22b16dced0a..0f0259e8538 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp @@ -28,9 +28,7 @@ #include "RangeMap.hpp" -struct CMap : public NamedFontEncoding -{ - virtual ~CMap () =default; +struct CMap : public NamedFontEncoding { virtual bool vertical () const =0; virtual bool mapsToCID () const =0; virtual uint32_t cid (uint32_t c) const =0; @@ -48,8 +46,7 @@ struct CMap : public NamedFontEncoding }; -struct IdentityCMap : public CMap -{ +struct IdentityCMap : public CMap { uint32_t cid (uint32_t c) const override {return c;} uint32_t bfcode (uint32_t cid) const override {return 0;} std::string getROString () const override {return "Adobe-Identity";} @@ -57,38 +54,34 @@ struct IdentityCMap : public CMap }; -struct IdentityHCMap : public IdentityCMap -{ +struct IdentityHCMap : public IdentityCMap { bool vertical () const override {return false;} const char* name () const override {return "Identity-H";} }; -struct IdentityVCMap : public IdentityCMap -{ +struct IdentityVCMap : public IdentityCMap { bool vertical () const override {return true;} const char* name () const override {return "Identity-V";} }; -struct UnicodeCMap : public CMap -{ +struct UnicodeCMap : public CMap { bool vertical () const override {return false;} const char* name () const override {return "unicode";} bool mapsToCID () const override {return false;} - const char* path () const override {return 0;} + const char* path () const override {return nullptr;} uint32_t cid (uint32_t c) const override {return c;} uint32_t bfcode (uint32_t cid) const override {return cid;} std::string getROString () const override {return "";} }; -class SegmentedCMap : public CMap -{ +class SegmentedCMap : public CMap { friend class CMapReader; public: - SegmentedCMap (const std::string &fname) : _filename(fname), _basemap(0), _vertical(false), _mapsToCID(true) {} + explicit SegmentedCMap (std::string fname) : _filename(std::move(fname)) {} const char* name () const override {return _filename.c_str();} uint32_t cid (uint32_t c) const override; uint32_t bfcode (uint32_t cid) const override; @@ -105,9 +98,9 @@ class SegmentedCMap : public CMap std::string _filename; std::string _registry; std::string _ordering; - CMap *_basemap; - bool _vertical; - bool _mapsToCID; // true: chrcode->CID, false: CID->charcode + CMap *_basemap = nullptr; + bool _vertical = false; + bool _mapsToCID = true; // true: chrcode->CID, false: CID->charcode RangeMap _cidranges; RangeMap _bfranges; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp index f033da7efc0..779c6ee3a83 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp @@ -44,9 +44,7 @@ CMap* CMapManager::lookup (const string &name) { if (_includedCMaps.find(name) != _includedCMaps.end()) { _level = 0; - ostringstream oss; - oss << "circular reference of CMap " << name; - throw CMapReaderException(oss.str()); + throw CMapReaderException("circular reference of CMap " + name); } unique_ptr<CMap> cmap_ptr; @@ -124,8 +122,8 @@ const CMap* CMapManager::findCompatibleBaseFontMap (const PhysicalFont *font, co const bool is_unicode_map = bool(dynamic_cast<const UnicodeCMap*>(cmap)); const string ro = cmap->getROString(); for (const CharMapIDToEncName &enc : encodings) { - for (size_t i=0; i < charmapIDs.size(); i++) { - if (enc.id == charmapIDs[i]) { + for (const CharMapID &id : charmapIDs) { + if (enc.id == id) { string cmapname = ro+"-"+enc.encname; if (is_unicode_map || FileFinder::instance().lookup(cmapname, "cmap", false)) { charmapID = enc.id; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp index 35f31d78d64..6661afbbb10 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp @@ -32,10 +32,6 @@ using namespace std; -CMapReader::CMapReader () : _inCMap(false) { -} - - /** Reads a cmap file and returns the corresponding CMap object. * @param fname[in] name/path of cmap file * @return CMap object representing the read data, or 0 if file could not be read */ @@ -74,7 +70,7 @@ unique_ptr<CMap> CMapReader::read (std::istream& is, const string &name) { } } catch (CMapReaderException &e) { - _cmap.release(); + _cmap.reset(); throw; } return std::move(_cmap); @@ -89,9 +85,10 @@ void CMapReader::executeOperator (const string &opname, InputReader &ir) { const char *name; void (CMapReader::*handler)(InputReader&); }; - constexpr array<Operator, 6> operators {{ + constexpr array<Operator, 7> operators {{ {"beginbfchar", &CMapReader::op_beginbfchar}, {"beginbfrange", &CMapReader::op_beginbfrange}, + {"begincidchar", &CMapReader::op_begincidchar}, {"begincidrange", &CMapReader::op_begincidrange}, {"def", &CMapReader::op_def}, {"endcmap", &CMapReader::op_endcmap}, @@ -135,7 +132,7 @@ void CMapReader::op_usecmap (InputReader &) { throw CMapReaderException("stack underflow while processing usecmap"); else { const string name = popToken().strvalue(); - if ((_cmap->_basemap = CMapManager::instance().lookup(name)) == 0) + if ((_cmap->_basemap = CMapManager::instance().lookup(name)) == nullptr) throw CMapReaderException("CMap file '"+name+"' not found"); } } @@ -154,17 +151,19 @@ static uint32_t parse_hexentry (InputReader &ir) { } -void CMapReader::op_begincidrange (InputReader &ir) { +void CMapReader::parseCIDChars (InputReader &ir, bool isRange) { if (!_tokens.empty() && _tokens.back().type() == Token::Type::NUMBER) { ir.skipSpace(); int num_entries = static_cast<int>(popToken().numvalue()); while (num_entries > 0 && ir.peek() == '<') { uint32_t first = parse_hexentry(ir); - uint32_t last = parse_hexentry(ir); - uint32_t cid; + uint32_t last = first; + if (isRange) + last = parse_hexentry(ir); ir.skipSpace(); + uint32_t cid; if (!ir.parseUInt(cid)) - throw CMapReaderException("invalid range entry (decimal value expected)"); + throw CMapReaderException("invalid char entry (decimal value expected)"); _cmap->addCIDRange(first, last, cid); ir.skipSpace(); } @@ -172,6 +171,16 @@ void CMapReader::op_begincidrange (InputReader &ir) { } +void CMapReader::op_begincidchar (InputReader &ir) { + parseCIDChars(ir, false); +} + + +void CMapReader::op_begincidrange (InputReader &ir) { + parseCIDChars(ir, true); +} + + void CMapReader::op_beginbfrange (InputReader &ir) { if (!_tokens.empty() && _tokens.back().type() == Token::Type::NUMBER) { ir.skipSpace(); @@ -249,9 +258,7 @@ void CMapReader::Token::scan (InputReader &ir) { else if (isdigit(ir.peek())) { // number? double val; if (ir.parseDouble(val)) { - ostringstream oss; - oss << val; - _value = oss.str(); + _value = util::to_string(val); _type = Type::NUMBER; } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp index 4b04156d53d..3e5b841e0cf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp @@ -38,7 +38,7 @@ class CMapReader { enum class Type {UNKNOWN, END, DELIM, NUMBER, STRING, NAME, OPERATOR}; public: - Token (InputReader &ir); + explicit Token (InputReader &ir); void scan (InputReader &ir); Type type () const {return _type;} const std::string& strvalue () const {return _value;} @@ -50,15 +50,16 @@ class CMapReader { }; public: - CMapReader (); std::unique_ptr<CMap> read (const std::string &fname); std::unique_ptr<CMap> read (std::istream &is, const std::string &name); protected: Token popToken () {Token t=_tokens.back(); _tokens.pop_back(); return t;} void executeOperator (const std::string &op, InputReader &ir); + void parseCIDChars (InputReader &ir, bool isRange); void op_beginbfchar (InputReader &ir); void op_beginbfrange (InputReader &ir); + void op_begincidchar (InputReader &ir); void op_begincidrange (InputReader &ir); void op_def (InputReader &ir); void op_endcmap (InputReader &ir); @@ -67,13 +68,12 @@ class CMapReader { private: std::unique_ptr<SegmentedCMap> _cmap; ///< pointer to CMap being read std::vector<Token> _tokens; ///< stack of tokens to be processed - bool _inCMap; ///< operator begincmap has been executed + bool _inCMap=false; ///< true if operator begincmap has been executed }; - struct CMapReaderException : public MessageException { - CMapReaderException (const std::string &msg) : MessageException(msg) {} + explicit CMapReaderException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp deleted file mode 100644 index 583b019324e..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************************************* -** CRC32.cpp ** -** ** -** This file is part of dvisvgm -- a fast DVI to SVG converter ** -** Copyright (C) 2005-2019 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 <cstring> -#include "CRC32.hpp" - -using namespace std; - - -CRC32::CRC32 () : _crc32(0xFFFFFFFF) -{ - const uint32_t poly = 0xEDB88320; - for (int i = 0; i < 256; i++) { - uint32_t crc=i; - for (int j=8; j > 0; j--) { - if (crc & 1) - crc = (crc >> 1) ^ poly; - else - crc >>= 1; - } - _tab[i] = crc; - } -} - - -/** Resets CRC32 sum to 0. */ -void CRC32::reset () { - _crc32 = 0xFFFFFFFF; -} - - -/** Appends string bytes to the previous data and computes the resulting checksum. - * @param[in] data string to update the checksum with */ -void CRC32::update (const char *data) { - update((const uint8_t*)data, strlen(data)); -} - - -/** Appends a single value to the previous data and computes the resulting checksum. - * @param[in] n value to update the checksum with - * @param[in] bytes number of bytes to consider (0-4) */ -void CRC32::update (uint32_t n, int bytes) { - for (int i=bytes-1; i >= 0; --i) { - uint8_t byte = uint8_t((n >> (8*i)) & 0xff); - update(&byte, 1); - } -} - - -/** Appends a sequence of bytes to the previous data and computes the resulting checksum. - * @param[in] bytes pointer to array of bytes - * @param[in] len number of bytes in array */ -void CRC32::update (const uint8_t *bytes, size_t len) { - for (size_t i=0; i < len; ++i) - _crc32 = ((_crc32 >> 8) & 0x00FFFFFF) ^ _tab[(_crc32 ^ *bytes++) & 0xFF]; -} - - -void CRC32::update (istream &is) { - char buf [4096]; - while (is) { - is.read(buf, 4096); - update((uint8_t*)buf, is.gcount()); - } -} - - -/** Returns the checksum computed from values added with the update functions. */ -uint32_t CRC32::get () const { - return _crc32 ^ 0xFFFFFFFF; -} - - -/** Computes the CRC32 checksum of a sequence of bytes. - * @param[in] bytes pointer to array of bytes - * @param[in] len number of bytes in array - * @return CRC32 checksum */ -uint32_t CRC32::compute (const uint8_t *bytes, size_t len) { - CRC32 crc32; - crc32.update(bytes, len); - return crc32.get(); -} - - -/** Computes the CRC32 checksum of a string. */ -uint32_t CRC32::compute (const char *str) { - return compute((const uint8_t*)str, strlen(str)); -} - - -uint32_t CRC32::compute (istream &is) { - CRC32 crc32; - crc32.update(is); - return crc32.get(); -} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp index 876e5e07834..f498365e544 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp @@ -28,7 +28,7 @@ struct CalculatorException : public MessageException { - CalculatorException (const std::string &msg) : MessageException(msg) {} + explicit CalculatorException (const std::string &msg) : MessageException(msg) {} }; class Calculator { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp index befd5ee2eac..e79c64b24fc 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp @@ -25,8 +25,8 @@ /** Represents a character map of a font. */ struct CharMapID { - CharMapID () : platform_id(0), encoding_id(0) {} - CharMapID (uint8_t plf_id, uint8_t enc_id) : platform_id(plf_id), encoding_id(enc_id) {} + CharMapID () noexcept : platform_id(0), encoding_id(0) {} + CharMapID (uint8_t plf_id, uint8_t enc_id) noexcept : platform_id(plf_id), encoding_id(enc_id) {} bool operator == (const CharMapID &ids) const { return platform_id == ids.platform_id && encoding_id == ids.encoding_id; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp index 338a0fb4982..e232401fb80 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp @@ -22,11 +22,10 @@ #define CHARACTER_HPP -class Character -{ +class Character { public: enum Type {CHRCODE, INDEX, NAME}; - Character (const char *name) : _type(NAME), _name(name) {} + explicit Character (const char *name) : _type(NAME), _name(name) {} Character (Type type, uint32_t val) : _type(type), _number(val) {} Character (Type type, const Character &c) : _type(type), _number(c.type() != NAME ? c._number : 0) {} Type type () const {return _type;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp index aa6b90b4063..de7e9074abf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp @@ -40,7 +40,7 @@ const Color Color::TRANSPARENT(uint32_t(0xff000000)); static inline uint8_t double_to_byte (double v) { v = max(0.0, min(1.0, v)); - return uint8_t(floor(255*v+0.5)); + return uint8_t(round(255.0*v)); } @@ -61,7 +61,7 @@ void Color::setRGB (double r, double g, double b) { * @return true if color name could be applied properly */ bool Color::setPSName (string name, bool case_sensitive) { if (name[0] == '#') { - char *p=0; + char *p=nullptr; _rgb = uint32_t(strtol(name.c_str()+1, &p, 16)); while (isspace(*p)) p++; @@ -213,7 +213,7 @@ Color Color::operator *= (double c) { else if (abs(c-trunc(c)) < 0.999) { uint32_t rgb=0; for (int i=0; i < 3; i++) { - rgb |= uint32_t((_rgb & 0xff)*c+0.5) << (8*i); + rgb |= lround((_rgb & 0xff)*c) << (8*i); _rgb >>= 8; } _rgb = rgb; @@ -394,7 +394,7 @@ string Color::svgColorString (bool rgbonly) const { {0xfffff0, "ivory"}, {0xffffff, "white"} }}; - ColorName cmppair = {_rgb, 0}; + ColorName cmppair = {_rgb, nullptr}; auto it = lower_bound(colornames.begin(), colornames.end(), cmppair, [](const ColorName &c1, const ColorName &c2) { return c1.rgb < c2.rgb; }); @@ -632,14 +632,14 @@ double Color::deltaE (const Color &c) const { c.getLab(l2, a2, b2); const double deltaL = l2-l1; const double lBar = (l1+l2)/2; - const double c1 = sqrt(a1*a1 + b1*b1); - const double c2 = sqrt(a2*a2 + b2*b2); + const double c1 = hypot(a1, b1); + const double c2 = hypot(a2, b2); const double cBar = (c1+c2)/2.0; const double g = (1.0-sqrt(pow(cBar, 7.0)/(pow(cBar, 7.0)+6103515625.0)))/2.0; const double aa1 = a1*(1.0+g); const double aa2 = a2*(1.0+g); - const double cc1 = sqrt(aa1*aa1 + b1*b1); - const double cc2 = sqrt(aa2*aa2 + b2*b2); + const double cc1 = hypot(aa1, b1); + const double cc2 = hypot(aa2, b2); const double ccBar = (cc1+cc2)/2.0; const double deltaCC = cc2-cc1; double hh1 = atan2(b1, aa1); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp index 27efa3a5988..f522bded55e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp @@ -30,8 +30,7 @@ #undef TRANSPARENT #endif -class Color -{ +class Color { public: static bool SUPPRESS_COLOR_NAMES; static const Color BLACK; @@ -41,12 +40,12 @@ class Color enum class ColorSpace {GRAY, RGB, CMYK, LAB}; public: - Color () : _rgb(0) {} - Color (uint32_t rgb) : _rgb(rgb) {} - Color (uint8_t r, uint8_t g, uint8_t b) {setRGB(r,g,b);} - Color (double r, double g, double b) {setRGB(r,g,b);} - Color (const std::valarray<double> &rgb) {setRGB(rgb);} - Color (const std::string &name); + Color () noexcept : _rgb(0) {} + explicit Color (uint32_t rgb) noexcept : _rgb(rgb) {} + Color (uint8_t r, uint8_t g, uint8_t b) noexcept {setRGB(r,g,b);} + Color (double r, double g, double b) noexcept {setRGB(r,g,b);} + explicit Color (const std::valarray<double> &rgb) noexcept {setRGB(rgb);} + explicit Color (const std::string &name); explicit operator uint32_t () const {return _rgb;} bool operator == (const Color &c) const {return _rgb == c._rgb;} bool operator != (const Color &c) const {return _rgb != c._rgb;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp index c6a756be17e..4bfd4940039 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp @@ -40,10 +40,10 @@ static double read_double (istream &is) { /** Reads multiple double values from a given stream. The number of * values read is determined by the size of the result vector. * @param[in] is stream to be read from - * @param[out] v the resulting values */ -static void read_doubles (istream &is, vector<double> &v) { - for (size_t i=0; i < v.size(); i++) - v[i] = read_double(is); + * @param[out] vec the resulting values */ +static void read_doubles (istream &is, vector<double> &vec) { + for (double &val : vec) + val = read_double(is); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp index d60ad44511f..b1f2636040f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp @@ -35,7 +35,7 @@ class CommandLine : public CL::CommandLine { Option colornamesOpt {"colornames", '\0', "prefer color names to RGB values if possible"}; Option commentsOpt {"comments", '\0', "add comments with additional information"}; Option epsOpt {"eps", 'E', "convert EPS file to SVG"}; - Option exactOpt {"exact", 'e', "compute exact glyph boxes"}; + Option exactBboxOpt {"exact-bbox", 'e', "compute exact glyph bounding boxes"}; TypedOption<std::string, Option::ArgMode::REQUIRED> fontFormatOpt {"font-format", 'f', "format", "svg", "select file format of embedded fonts"}; TypedOption<std::string, Option::ArgMode::REQUIRED> fontmapOpt {"fontmap", 'm', "filenames", "evaluate (additional) font map files"}; Option gradOverlapOpt {"grad-overlap", '\0', "create overlapping color gradient segments"}; @@ -52,6 +52,7 @@ class CommandLine : public CL::CommandLine { Option noMktexmfOpt {"no-mktexmf", '\0', "don't try to create missing fonts"}; TypedOption<std::string, Option::ArgMode::OPTIONAL> noSpecialsOpt {"no-specials", 'S', "prefixes", "don't process [selected] specials"}; Option noStylesOpt {"no-styles", '\0', "don't use CSS styles to reference fonts"}; + TypedOption<std::string, Option::ArgMode::OPTIONAL> optimizeOpt {"optimize", 'O', "modules", "all", "perform several SVG optimizations"}; TypedOption<std::string, Option::ArgMode::REQUIRED> outputOpt {"output", 'o', "pattern", "set name pattern of output files"}; TypedOption<std::string, Option::ArgMode::REQUIRED> pageOpt {"page", 'p', "ranges", "1", "choose page(s) to convert"}; TypedOption<std::string, Option::ArgMode::OPTIONAL> pageHashesOpt {"page-hashes", 'H', "params", "xxh64", "activate usage of page hashes"}; @@ -114,6 +115,7 @@ class CommandLine : public CL::CommandLine { {&gradSimplifyOpt, 1}, #endif {&linkmarkOpt, 1}, + {&optimizeOpt, 1}, {&outputOpt, 1}, {&precisionOpt, 1}, {&relativeOpt, 1}, @@ -129,7 +131,7 @@ class CommandLine : public CL::CommandLine { {&transformOpt, 2}, {&zoomOpt, 2}, {&cacheOpt, 3}, - {&exactOpt, 3}, + {&exactBboxOpt, 3}, {&keepOpt, 3}, #if !defined(HAVE_LIBGS) && !defined(DISABLE_GS) {&libgsOpt, 3}, diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp index 47839216010..6bfff573e27 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp @@ -33,7 +33,7 @@ class DLLoader { public: DLLoader () =delete; - DLLoader (const std::string &dlname); + explicit DLLoader (const std::string &dlname); DLLoader (DLLoader &&loader) =default; virtual ~DLLoader () {closeLibrary();} bool loaded () const {return _handle != nullptr;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp index ac57eb25edc..c42f446d9ee 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp @@ -40,7 +40,7 @@ struct DVIActions { virtual void beginPage (unsigned pageno, const std::vector<int32_t> &c) {} virtual void endPage (unsigned pageno) {} virtual BoundingBox& bbox () =0; - virtual void progress (size_t current, size_t total, const char *id=0) {} + virtual void progress (size_t current, size_t total, const char *id=nullptr) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp index 415b97dc438..b0bbabee947 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp @@ -277,7 +277,7 @@ void DVIReader::cmdPop (int) { * @param[in] font current font (corresponding to _currFontNum) * @param[in] c character to typeset */ void DVIReader::putVFChar (Font *font, uint32_t c) { - if (VirtualFont *vf = dynamic_cast<VirtualFont*>(font)) { // is current font a virtual font? + if (auto vf = dynamic_cast<VirtualFont*>(font)) { // is current font a virtual font? if (const vector<uint8_t> *dvi = vf->getDVI(c)) { // try to get DVI snippet that represents character c FontManager &fm = FontManager::instance(); DVIState savedState = _dviState; // save current cursor position @@ -457,11 +457,8 @@ void DVIReader::cmdDir (int) { uint8_t wmode = readUnsigned(1); if (wmode == 4) // yoko mode (4) equals default LR mode (0) wmode = 0; - if (wmode == 2 || wmode > 3) { - ostringstream oss; - oss << "invalid writing mode value " << wmode << " (0, 1, 3, or 4 expected)"; - throw DVIException(oss.str()); - } + if (wmode == 2 || wmode > 3) + throw DVIException("invalid writing mode value " + std::to_string(wmode) + " (0, 1, 3, or 4 expected)"); _dviState.d = (WritingMode)wmode; dviDir(_dviState.d); } @@ -485,11 +482,8 @@ void DVIReader::setFont (int fontnum, SetFontMode mode) { _currFontNum = fontnum; dviFontNum(uint32_t(fontnum), mode, font); } - else { - ostringstream oss; - oss << "undefined font number " << fontnum; - throw DVIException(oss.str()); - } + else + throw DVIException("undefined font number " + std::to_string(fontnum)); } @@ -522,7 +516,7 @@ const Font* DVIReader::defineFont (uint32_t fontnum, const string &name, uint32_ if (!font) { int id = fm.registerFont(fontnum, name, cs, ds, ss); font = fm.getFontById(id); - if (VirtualFont *vf = dynamic_cast<VirtualFont*>(font)) { + if (auto vf = dynamic_cast<VirtualFont*>(font)) { // read vf file, register its font and character definitions fm.enterVF(vf); ifstream ifs(vf->path(), ios::binary); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp index 82eeb8a7c9f..4801bd80a01 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp @@ -38,6 +38,7 @@ #include "PageSize.hpp" #include "PreScanDVIReader.hpp" #include "SignalHandler.hpp" +#include "optimizer/SVGOptimizer.hpp" #include "SVGOutput.hpp" #include "utility.hpp" #include "version.hpp" @@ -110,18 +111,19 @@ void DVIToSVG::convert (unsigned first, unsigned last, HashFunction *hashFunc) { combinedHash = hashFunc->digestString(); } const SVGOutput::HashTriple hashTriple(dviHash, shortenedOptHash, combinedHash); - string fname = _out.filename(i, numberOfPages(), hashTriple); - if (!dviHash.empty() && !PAGE_HASH_SETTINGS.isSet(HashSettings::P_REPLACE) && FileSystem::exists(fname)) { + 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 " << fname << " exists\n"; + Message::mstream(false, Message::MC_PAGE_WRITTEN) << "\nfile " << path.shorterAbsoluteOrRelative() << " exists\n"; Message::mstream().indent(0); } else { executePage(i); - _svg.removeRedundantElements(); + 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) @@ -161,7 +163,7 @@ void DVIToSVG::convert (const string &rangestr, pair<int,int> *pageinfo) { throw MessageException("invalid page range format"); Message::mstream(false, Message::MC_PAGE_NUMBER) << "pre-processing DVI file (format version " << getDVIVersion() << ")\n"; - if (DVIToSVGActions *actions = dynamic_cast<DVIToSVGActions*>(_actions.get())) { + if (auto actions = dynamic_cast<DVIToSVGActions*>(_actions.get())) { PreScanDVIReader prescan(getInputStream(), actions); actions->setDVIReader(prescan); prescan.executeAllPages(); @@ -243,7 +245,7 @@ void DVIToSVG::enterBeginPage (unsigned pageno, const vector<int32_t> &c) { 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<XMLCommentNode>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); + _svg.appendToDoc(util::make_unique<XMLComment>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); } } @@ -322,7 +324,7 @@ Matrix DVIToSVG::getPageTransformation () const { calc.setVariable("h", bbox.height()*bp2pt); } // add constants for length units to calculator - for (auto unit : Length::getUnits()) + for (const auto &unit : Length::getUnits()) calc.setVariable(unit.first, Length(1, unit.second).pt()); matrix.set(_transCmds, calc); } @@ -331,18 +333,22 @@ Matrix DVIToSVG::getPageTransformation () const { static void collect_chars (unordered_map<const Font*, set<int>> &fontmap) { + unordered_map<const Font*, set<int>> insertedChars; for (const auto &entry : fontmap) { - if (entry.first->uniqueFont() != entry.first) { + const Font *unique_font = entry.first->uniqueFont(); + if (unique_font != entry.first) { for (int c : entry.second) - fontmap[entry.first->uniqueFont()].insert(c); + 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 (XMLElementNode *svgElement) { +void DVIToSVG::embedFonts (XMLElement *svgElement) { if (!svgElement || !_actions) // no dvi actions => no chars written => no fonts to embed return; @@ -355,7 +361,7 @@ void DVIToSVG::embedFonts (XMLElementNode *svgElement) { unordered_set<const Font*> tracedFonts; // collect unique fonts already traced for (const auto &fontchar : usedCharsMap) { const Font *font = fontchar.first; - if (const PhysicalFont *ph_font = dynamic_cast<const PhysicalFont*>(font)) { + 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()) { @@ -420,8 +426,8 @@ void DVIToSVG::setProcessSpecials (const char *ignorelist, bool pswarning) { } -string DVIToSVG::getSVGFilename (unsigned pageno) const { - return _out.filename(pageno, numberOfPages()); +FilePath DVIToSVG::getSVGFilePath (unsigned pageno) const { + return _out.filepath(pageno, numberOfPages()); } @@ -567,6 +573,15 @@ void DVIToSVG::HashSettings::setParameters (const string ¶mstr) { _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()) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp index b738239408e..40dbdc884ff 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp @@ -25,6 +25,7 @@ #include <string> #include <utility> #include "DVIReader.hpp" +#include "FilePath.hpp" #include "SVGTree.hpp" struct DVIActions; @@ -50,7 +51,8 @@ class DVIToSVG : public DVIReader { public: explicit DVIToSVG (std::istream &is, SVGOutputBase &out); - void convert (const std::string &range, std::pair<int,int> *pageinfo=0); + DVIToSVG (const DVIToSVG&) =delete; + void convert (const std::string &range, std::pair<int,int> *pageinfo=nullptr); void setPageSize (const std::string &format) {_bboxFormatString = format;} void setPageTransformation (const std::string &cmds) {_transCmds = cmds;} Matrix getPageTransformation () const override; @@ -61,9 +63,9 @@ class DVIToSVG : public DVIReader { void finishLine () override {_prevYPos = std::numeric_limits<double>::min();} void listHashes (const std::string &rangestr, std::ostream &os); - std::string getSVGFilename (unsigned pageno) const; + FilePath getSVGFilePath (unsigned pageno) const; std::string getUserBBoxString () const {return _bboxFormatString;} - static void setProcessSpecials (const char *ignorelist=0, bool pswarning=false); + static void setProcessSpecials (const char *ignorelist=nullptr, bool pswarning=false); public: static bool COMPUTE_PROGRESS; ///< if true, an action to handle the progress ratio of a page is triggered @@ -71,12 +73,11 @@ class DVIToSVG : public DVIReader { static HashSettings PAGE_HASH_SETTINGS; protected: - DVIToSVG (const DVIToSVG&) =delete; void convert (unsigned firstPage, unsigned lastPage, HashFunction *hashFunc); int executeCommand () override; void enterBeginPage (unsigned pageno, const std::vector<int32_t> &c); void leaveEndPage (unsigned pageno); - void embedFonts (XMLElementNode *svgElement); + void embedFonts (XMLElement *svgElement); void moveRight (double dx, MoveMode mode) override; void moveDown (double dy, MoveMode mode) override; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp index 226d434bae5..bb8e4d6f845 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp @@ -32,14 +32,6 @@ using namespace std; -DVIToSVGActions::DVIToSVGActions (DVIToSVG &dvisvg, SVGTree &svg) - : _svg(svg), _dvireader(&dvisvg), _bgcolor(Color::TRANSPARENT) -{ - _currentFontNum = -1; - _pageCount = 0; -} - - void DVIToSVGActions::reset() { _usedChars.clear(); _usedFonts.clear(); @@ -69,17 +61,19 @@ void DVIToSVGActions::moveToY (double y, bool forceSVGMove) { } -string DVIToSVGActions::getSVGFilename (unsigned pageno) const { - if (DVIToSVG *dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) - return dvi2svg->getSVGFilename(pageno); - return ""; +FilePath DVIToSVGActions::getSVGFilePath (unsigned pageno) const { + FilePath path; + if (auto dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) + path = dvi2svg->getSVGFilePath(pageno); + return path; } string DVIToSVGActions::getBBoxFormatString () const { - if (DVIToSVG *dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) - return dvi2svg->getUserBBoxString(); - return ""; + string boxstr; + if (auto dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) + boxstr = dvi2svg->getUserBBoxString(); + return boxstr; } @@ -91,6 +85,9 @@ string DVIToSVGActions::getBBoxFormatString () const { * @param[in] vertical true if we're in vertical mode * @param[in] font font to be used */ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, const Font &font) { + if (_outputLocked) + return; + // If we use SVG fonts there is no need to record all font name/char/size combinations // because the SVG font mechanism handles this automatically. It's sufficient to // record font names and chars. The various font sizes can be ignored here. @@ -108,7 +105,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co GlyphMetrics metrics; font.getGlyphMetrics(c, vertical, metrics); - const PhysicalFont* pf = dynamic_cast<const PhysicalFont*>(&font); + auto pf = dynamic_cast<const PhysicalFont*>(&font); if (PhysicalFont::EXACT_BBOX && pf) { GlyphMetrics exact_metrics; pf->getExactGlyphBox(c, exact_metrics, vertical, &callback); @@ -125,7 +122,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co bbox.transform(getMatrix()); embed(bbox); #if 0 - XMLElementNode *rect = new XMLElementNode("rect"); + XMLElement *rect = new XMLElement("rect"); rect->addAttribute("x", x-metrics.wl); rect->addAttribute("y", y-metrics.h); rect->addAttribute("width", metrics.wl+metrics.wr); @@ -135,7 +132,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co rect->addAttribute("stroke-width", "0.5"); _svg.appendToPage(rect); if (metrics.d > 0) { - XMLElementNode *line = new XMLElementNode("line"); + XMLElement *line = new XMLElement("line"); line->addAttribute("x1", x-metrics.wl); line->addAttribute("y1", y); line->addAttribute("x2", x+metrics.wr); @@ -145,7 +142,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co _svg.appendToPage(line); } if (metrics.wl > 0) { - XMLElementNode *line = new XMLElementNode("line"); + XMLElement *line = new XMLElement("line"); line->addAttribute("x1", x); line->addAttribute("y1", y-metrics.h); line->addAttribute("x2", x); @@ -165,14 +162,17 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co * @param[in] height length of the vertical edges * @param[in] width length of the horizontal edges */ void DVIToSVGActions::setRule (double x, double y, double height, double width) { + if (_outputLocked) + return; + // (x,y) is the lower left corner of the rectangle - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", x); rect->addAttribute("y", y-height); rect->addAttribute("height", height); rect->addAttribute("width", width); if (!getMatrix().isIdentity()) - rect->addAttribute("transform", getMatrix().getSVG()); + rect->addAttribute("transform", getMatrix().toSVG()); if (getColor() != Color::BLACK) rect->addAttribute("fill", _svg.getColor().svgColorString()); _svg.appendToPage(std::move(rect)); @@ -232,7 +232,7 @@ void DVIToSVGActions::endPage (unsigned pageno) { _svg.transformPage(matrix); if (_bgcolor != Color::TRANSPARENT) { // create a rectangle filled with the background color - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", _bbox.minX()); rect->addAttribute("y", _bbox.minY()); rect->addAttribute("width", _bbox.width()); @@ -306,7 +306,7 @@ static int digits (int n) { void DVIToSVGActions::progress (size_t current, size_t total, const char *id) { static double time=0; static bool draw=false; // show progress indicator? - static const char *prev_id=0; + static const char *prev_id=nullptr; if (current == 0 && total > 0) { time = System::time(); draw = false; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp index 04a345865b9..e9adc63e38b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp @@ -42,7 +42,7 @@ class DVIToSVGActions : public DVIActions, public SpecialActions { using BoxMap = std::unordered_map<std::string,BoundingBox>; public: - DVIToSVGActions (DVIToSVG &dvisvg, SVGTree &svg); + DVIToSVGActions (DVIToSVG &dvisvg, SVGTree &svg) : _svg(svg), _dvireader(&dvisvg) {} void reset () override; void setChar (double x, double y, unsigned c, bool vertical, const Font &f) override; void setRule (double x, double y, double height, double width) override; @@ -52,32 +52,31 @@ class DVIToSVGActions : public DVIActions, public SpecialActions { const Matrix& getMatrix () const override {return _svg.getMatrix();} Matrix getPageTransformation () const override {return _dvireader->getPageTransformation();} Color getColor () const override {return _svg.getColor();} - int getDVIStackDepth() const override {return _dvireader->stackDepth();} - unsigned getCurrentPageNumber() const override {return _dvireader->currentPageNumber();} - void appendToPage(std::unique_ptr<XMLNode> &&node) override {_svg.appendToPage(std::move(node));} - void appendToDefs(std::unique_ptr<XMLNode> &&node) override {_svg.appendToDefs(std::move(node));} - void prependToPage(std::unique_ptr<XMLNode> &&node) override {_svg.prependToPage(std::move(node));} - void pushContextElement (std::unique_ptr<XMLElementNode> &&node) override {_svg.pushContextElement(std::move(node));} - void popContextElement () override {_svg.popContextElement();} - void setTextOrientation(bool vertical) override {_svg.setVertical(vertical);} + int getDVIStackDepth () const override {return _dvireader->stackDepth();} + unsigned getCurrentPageNumber () const override {return _dvireader->currentPageNumber();} + void setTextOrientation (bool vertical) override {_svg.setVertical(vertical);} void moveToX (double x, bool forceSVGMove) override; void moveToY (double y, bool forceSVGMove) override; void setFont (int num, const Font &font) override; void special (const std::string &spc, double dvi2bp, bool preprocessing=false) override; void beginPage (unsigned pageno, const std::vector<int32_t> &c) override; void endPage (unsigned pageno) override; - void progress (size_t current, size_t total, const char *id=0) override; + void progress (size_t current, size_t total, const char *id=nullptr) override; void progress (const char *id) override; double getX() const override {return _dvireader->getXPos();} double getY() const override {return _dvireader->getYPos();} void setX (double x) override {_dvireader->translateToX(x); _svg.setX(x);} void setY (double y) override {_dvireader->translateToY(y); _svg.setY(y);} void finishLine () override {_dvireader->finishLine();} + void lockOutput () override {_outputLocked = true;} + void unlockOutput () override {_outputLocked = false;} + bool outputLocked () const override {return _outputLocked;} + const SVGTree& svgTree () const override {return _svg;} BoundingBox& bbox () override {return _bbox;} BoundingBox& bbox (const std::string &name, bool reset=false) override; void embed (const BoundingBox &bbox) override; void embed (const DPair &p, double r=0) override; - std::string getSVGFilename (unsigned pageno) const override; + FilePath getSVGFilePath (unsigned pageno) const override; std::string getBBoxFormatString () const override; CharMap& getUsedChars () const {return _usedChars;} const FontSet& getUsedFonts () const {return _usedFonts;} @@ -87,12 +86,13 @@ class DVIToSVGActions : public DVIActions, public SpecialActions { SVGTree &_svg; BasicDVIReader *_dvireader; BoundingBox _bbox; - int _pageCount; - int _currentFontNum; + int _pageCount=0; + int _currentFontNum=-1; mutable CharMap _usedChars; FontSet _usedFonts; - Color _bgcolor; + Color _bgcolor=Color::TRANSPARENT; BoxMap _boxes; + bool _outputLocked=false; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp index beb6f887da6..ccc05a2e92c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp @@ -25,7 +25,7 @@ using namespace std; #ifdef _WIN32 #include "windows.hpp" #else - #include <errno.h> + #include <cerrno> #include <sys/stat.h> #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp index ade36daf80d..a703c18977c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp @@ -34,7 +34,7 @@ class Directory { public: Directory (); - Directory (const std::string &path); + explicit Directory (const std::string &path); ~Directory (); bool open (std::string path); void close (); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp index 23e9b7107c7..dadf196f779 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp @@ -26,6 +26,7 @@ #include "InputReader.hpp" #include "Length.hpp" #include "SpecialActions.hpp" +#include "SVGTree.hpp" #include "utility.hpp" #include "XMLNode.hpp" #include "XMLString.hpp" @@ -33,8 +34,10 @@ using namespace std; -DvisvgmSpecialHandler::DvisvgmSpecialHandler () - : _currentMacro(_macros.end()), _nestingLevel(0) +DvisvgmSpecialHandler::DvisvgmSpecialHandler () : + _currentMacro(_macros.end()), + _defsParser(&SVGTree::appendToDefs, &SVGTree::pushDefsContext, &SVGTree::popDefsContext), + _pageParser(&SVGTree::appendToPage, &SVGTree::pushPageContext, &SVGTree::popPageContext) { } @@ -54,12 +57,12 @@ void DvisvgmSpecialHandler::preprocess (const string&, istream &is, SpecialActio StreamInputReader ir(is); const string cmdstr = ir.getWord(); - for (const Command &command : commands) { - if (command.name == cmdstr) { - ir.skipSpace(); - (this->*command.handler)(ir); - return; - } + auto it = find_if(commands.begin(), commands.end(), [&](const Command &cmd) { + return cmd.name == cmdstr; + }); + if (it != commands.end()) { + ir.skipSpace(); + (this->*it->handler)(ir); } } @@ -133,12 +136,12 @@ bool DvisvgmSpecialHandler::process (const string &prefix, istream &is, SpecialA }}; StreamInputReader ir(is); const string cmdstr = ir.getWord(); - for (const Command &command : commands) { - if (command.name == cmdstr) { - ir.skipSpace(); - (this->*command.handler)(ir, actions); - return true; - } + auto it = find_if(commands.begin(), commands.end(), [&](const Command &cmd) { + return cmd.name == cmdstr; + }); + if (it != commands.end()) { + ir.skipSpace(); + (this->*it->handler)(ir, actions); } return true; } @@ -169,10 +172,11 @@ static void expand_constants (string &str, SpecialActions &actions) { const char *name; string val; }; - const array<Constant, 4> constants {{ - {"x", XMLString(actions.getX())}, - {"y", XMLString(actions.getY())}, - {"color", actions.getColor().svgColorString()}, + const array<Constant, 5> constants {{ + {"x", XMLString(actions.getX())}, + {"y", XMLString(actions.getY())}, + {"color", actions.getColor().svgColorString()}, + {"matrix", actions.getMatrix().toSVG()}, {"nl", "\n"}, }}; for (const Constant &constant : constants) { @@ -186,12 +190,17 @@ static void expand_constants (string &str, SpecialActions &actions) { } +/** Processes raw SVG fragments from the input stream. The SVG data must represent + * a single or multiple syntactically complete XML parts, like opening/closing tags, + * comments, or CDATA blocks. These must not be split and distributed over several + * 'raw' statements. Elements can be split but element tags can't. + * Example: "<g transform=" is invalid, "<g transform='scale(2,3)'>" is ok. */ void DvisvgmSpecialHandler::processRaw (InputReader &ir, SpecialActions &actions) { if (_nestingLevel == 0) { - string str = ir.getLine(); - if (!str.empty()) { - expand_constants(str, actions); - actions.appendToPage(util::make_unique<XMLTextNode>(str)); + string xml = ir.getLine(); + if (!xml.empty()) { + expand_constants(xml, actions); + _pageParser.parse(xml, actions); } } } @@ -199,10 +208,10 @@ void DvisvgmSpecialHandler::processRaw (InputReader &ir, SpecialActions &actions void DvisvgmSpecialHandler::processRawDef (InputReader &ir, SpecialActions &actions) { if (_nestingLevel == 0) { - string str = ir.getLine(); - if (!str.empty()) { - expand_constants(str, actions); - actions.appendToDefs(util::make_unique<XMLTextNode>(str)); + string xml = ir.getLine(); + if (!xml.empty()) { + expand_constants(xml, actions); + _defsParser.parse(xml, actions); } } } @@ -234,9 +243,9 @@ void DvisvgmSpecialHandler::processRawPut (InputReader &ir, SpecialActions &acti if ((type == 'P' || type == 'D') && !def.empty()) { expand_constants(def, actions); if (type == 'P') - actions.appendToPage(util::make_unique<XMLTextNode>(def)); + _pageParser.parse(def, actions); else { // type == 'D' - actions.appendToDefs(util::make_unique<XMLTextNode>(def)); + _defsParser.parse(def, actions); type = 'L'; // locked } } @@ -249,70 +258,92 @@ void DvisvgmSpecialHandler::processRawPut (InputReader &ir, SpecialActions &acti * @param[in] w width of the rectangle in PS point units * @param[in] h height of the rectangle in PS point units * @param[in] d depth of the rectangle in PS point units + * @param[in] transform if true, apply the current transformation matrix to the rectangle * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ -static void update_bbox (Length w, Length h, Length d, SpecialActions &actions) { +static void update_bbox (Length w, Length h, Length d, bool transform, SpecialActions &actions) { double x = actions.getX(); double y = actions.getY(); - actions.embed(BoundingBox(x, y, x+w.bp(), y-h.bp())); - actions.embed(BoundingBox(x, y, x+w.bp(), y+d.bp())); + BoundingBox bbox1(x, y, x+w.bp(), y-h.bp()); + BoundingBox bbox2(x, y, x+w.bp(), y+d.bp()); + if (transform) { + bbox1.transform(actions.getMatrix()); + bbox2.transform(actions.getMatrix()); + } + actions.embed(bbox1); + actions.embed(bbox2); } /** Reads a length value including a trailing unit specifier and returns it. */ static Length read_length (InputReader &ir) { + Length length; ir.skipSpace(); - double val = ir.getDouble(); - string unit = isalpha(ir.peek()) ? ir.getString(2) : "pt"; - return Length(val, unit); + if (!isalpha(ir.peek())) { + double val = ir.getDouble(); + string unit = isalpha(ir.peek()) ? ir.getString(2) : "pt"; + length = Length(val, unit); + } + return length; } /** Evaluates the special dvisvgm:bbox. - * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>] - * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2> - * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2> - * variant 4: dvisvgm:bbox n[ew] <name> */ + * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>] [transform] + * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2> [transform] + * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2> [transform] + * variant 4: dvisvgm:bbox n[ew] <name> + * variant 5: dvisvgm:bbox lock | unlock */ void DvisvgmSpecialHandler::processBBox (InputReader &ir, SpecialActions &actions) { ir.skipSpace(); - int c = ir.peek(); - try { - if (!isalpha(c)) - c = 'r'; // no mode specifier => relative box parameters - else { - while (!isspace(ir.peek())) // skip trailing characters - ir.get(); - if (c == 'n') { // "new": create new local bounding box - ir.skipSpace(); - string name; - while (isalnum(ir.peek())) - name += char(ir.get()); - ir.skipSpace(); - if (!name.empty() && ir.eof()) - actions.bbox(name, true); // create new user box - } - else if (c == 'a' || c == 'f') { // "abs" or "fix" - Length lengths[4]; - for (int i=0; i < 4; i++) - lengths[i] = read_length(ir); - BoundingBox b(lengths[0], lengths[1], lengths[2], lengths[3]); - if (c == 'a') - actions.embed(b); - else { - actions.bbox() = b; - actions.bbox().lock(); + if (ir.check("lock")) + actions.bbox().lock(); + else if (ir.check("unlock")) + actions.bbox().unlock(); + else { + int c = ir.peek(); + try { + if (!isalpha(c)) + c = 'r'; // no mode specifier => relative box parameters + else { + while (!isspace(ir.peek())) // skip trailing characters + ir.get(); + if (c == 'n') { // "new": create new local bounding box + ir.skipSpace(); + string name; + while (isalnum(ir.peek())) + name += char(ir.get()); + ir.skipSpace(); + if (!name.empty() && ir.eof()) + actions.bbox(name, true); // create new user box } + else if (c == 'a' || c == 'f') { // "abs" or "fix" + Length lengths[4]; + for (Length &len : lengths) + len = read_length(ir); + BoundingBox b(lengths[0], lengths[1], lengths[2], lengths[3]); + ir.skipSpace(); + if (ir.check("transform")) + b.transform(actions.getMatrix()); + if (c == 'a') + actions.embed(b); + else { + actions.bbox() = b; + actions.bbox().lock(); + } + } + } + if (c == 'r') { + Length w = read_length(ir); + Length h = read_length(ir); + Length d = read_length(ir); + ir.skipSpace(); + update_bbox(w, h, d, ir.check("transform"), actions); } } - if (c == 'r') { - Length w = read_length(ir); - Length h = read_length(ir); - Length d = read_length(ir); - update_bbox(w, h, d, actions); + catch (const UnitException &e) { + throw SpecialException(string("dvisvgm:bbox: ") + e.what()); } } - catch (const UnitException &e) { - throw SpecialException(string("dvisvgm:bbox: ") + e.what()); - } } @@ -321,16 +352,16 @@ void DvisvgmSpecialHandler::processImg (InputReader &ir, SpecialActions &actions Length w = read_length(ir); Length h = read_length(ir); string f = ir.getString(); - update_bbox(w, h, 0, actions); - auto img = util::make_unique<XMLElementNode>("image"); + update_bbox(w, h, Length(0), false, actions); + auto img = util::make_unique<XMLElement>("image"); img->addAttribute("x", actions.getX()); img->addAttribute("y", actions.getY()); img->addAttribute("width", w.bp()); img->addAttribute("height", h.bp()); img->addAttribute("xlink:href", f); if (!actions.getMatrix().isIdentity()) - img->addAttribute("transform", actions.getMatrix().getSVG()); - actions.appendToPage(std::move(img)); + img->addAttribute("transform", actions.getMatrix().toSVG()); + actions.svgTree().appendToPage(std::move(img)); } catch (const UnitException &e) { throw SpecialException(string("dvisvgm:img: ") + e.what()); @@ -350,7 +381,10 @@ void DvisvgmSpecialHandler::dviPreprocessingFinished () { } -void DvisvgmSpecialHandler::dviEndPage (unsigned, SpecialActions&) { +void DvisvgmSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) { + _defsParser.flush(actions); + _pageParser.flush(actions); + actions.bbox().unlock(); for (auto &strvecpair : _macros) { StringVector &vec = strvecpair.second; for (string &str : vec) { @@ -366,3 +400,140 @@ vector<const char*> DvisvgmSpecialHandler::prefixes() const { vector<const char*> pfx {"dvisvgm:"}; return pfx; } + +//////////////////////////////////////////////////////////////////////////////// + +/** Parses a fragment of XML code, creates corresponding XML nodes and adds them + * to the SVG tree. The code may be split and processed by several calls of this + * function. Incomplete chunks that can't be processed yet are stored and picked + * up again together with the next incoming XML fragment. If no further code should + * be appended, parameter 'finish' must be set. + * @param[in] xml XML fragment to parse + * @param[in] actions object providing the SVG tree functions + * @param[in] finish if true, no more XML is expected and parsing is finished */ +void DvisvgmSpecialHandler::XMLParser::parse (const string &xml, SpecialActions &actions, bool finish) { + // collect/extract an XML fragment that only contains complete tags + // incomplete tags are held back + _xmlbuf += xml; + size_t left=0, right; + while (left != string::npos) { + right = _xmlbuf.find('<', left); + if (left < right && left < _xmlbuf.length()) // plain text found? + (actions.svgTree().*_append)(util::make_unique<XMLText>(_xmlbuf.substr(left, right-left))); + if (right != string::npos) { + left = right; + if (_xmlbuf.compare(left, 9, "<![CDATA[") == 0) { + right = _xmlbuf.find("]]>", left+9); + if (right == string::npos) { + if (finish) throw SpecialException("expected ']]>' at end of CDATA block"); + break; + } + (actions.svgTree().*_append)(util::make_unique<XMLCData>(_xmlbuf.substr(left+9, right-left-9))); + right += 2; + } + else if (_xmlbuf.compare(left, 4, "<!--") == 0) { + right = _xmlbuf.find("-->", left+4); + if (right == string::npos) { + if (finish) throw SpecialException("expected '-->' at end of comment"); + break; + } + (actions.svgTree().*_append)(util::make_unique<XMLComment>(_xmlbuf.substr(left+4, right-left-4))); + right += 2; + } + else if (_xmlbuf.compare(left, 2, "<?") == 0) { + right = _xmlbuf.find("?>", left+2); + if (right == string::npos) { + if (finish) throw SpecialException("expected '?>' at end of processing instruction"); + break; + } + (actions.svgTree().*_append)(util::make_unique<XMLText>(_xmlbuf.substr(left, right-left+2))); + right++; + } + else if (_xmlbuf.compare(left, 2, "</") == 0) { + right = _xmlbuf.find('>', left+2); + if (right == string::npos) { + if (finish) throw SpecialException("missing '>' at end of closing XML tag"); + break; + } + closeElement(_xmlbuf.substr(left+2, right-left-2), actions); + } + else { + right = _xmlbuf.find('>', left+1); + if (right == string::npos) { + if (finish) throw SpecialException("missing '>' or '/>' at end of opening XML tag"); + break; + } + openElement(_xmlbuf.substr(left+1, right-left-1), actions); + } + } + left = right; + if (right != string::npos) + left++; + } + if (left == string::npos) + _xmlbuf.clear(); + else + _xmlbuf.erase(0, left); +} + + +/** Processes an opening element tag. + * @param[in] tag tag without leading and trailing angle brackets */ +void DvisvgmSpecialHandler::XMLParser::openElement (const string &tag, SpecialActions &actions) { + StringInputBuffer ib(tag); + BufferInputReader ir(ib); + string name = ir.getString("/ \t\n\r"); + ir.skipSpace(); + auto elemNode = util::make_unique<XMLElement>(name); + map<string, string> attribs; + if (ir.parseAttributes(attribs, true, "\"'")) { + for (const auto &attrpair : attribs) + elemNode->addAttribute(attrpair.first, attrpair.second); + } + ir.skipSpace(); + if (ir.peek() == '/') // end of empty element tag + (actions.svgTree().*_append)(std::move(elemNode)); + else if (ir.peek() < 0) { // end of opening tag + _nameStack.push_back(name); + (actions.svgTree().*_pushContext)(std::move(elemNode)); + } + else + throw SpecialException("'>' or '/>' expected at end of opening tag <"+name); +} + + +/** Processes a closing element tag. + * @param[in] tag tag without leading and trailing angle brackets */ +void DvisvgmSpecialHandler::XMLParser::closeElement (const string &tag, SpecialActions &actions) { + StringInputBuffer ib(tag); + BufferInputReader ir(ib); + string name = ir.getString(" \t\n\r"); + ir.skipSpace(); + if (ir.peek() >= 0) + throw SpecialException("'>' expected at end of closing tag </"+name); + if (_nameStack.empty()) + throw SpecialException("spurious closing tag </" + name + ">"); + if (_nameStack.back() != name) + throw SpecialException("expected </" + name + "> but found </" + _nameStack.back() + ">"); + (actions.svgTree().*_popContext)(); + _nameStack.pop_back(); +} + + +/** Processes any remaining XML fragments, checks for missing closing tags, + * and resets the parser state. */ +void DvisvgmSpecialHandler::XMLParser::flush (SpecialActions &actions) { + if (!_xmlbuf.empty()) { + parse("", actions, true); + _xmlbuf.clear(); + } + string tags; + while (!_nameStack.empty()) { + tags += "</"+_nameStack.back()+">, "; + _nameStack.pop_back(); + } + if (!tags.empty()) { + tags.resize(tags.length()-2); + throw SpecialException("missing closing tags: "+tags); + } +}
\ No newline at end of file diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp index 3a72b04f931..a8bde952e6f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp @@ -21,6 +21,7 @@ #ifndef DVISVGMSPECIALHANDLER_HPP #define DVISVGMSPECIALHANDLER_HPP +#include <memory> #include <string> #include <unordered_map> #include <vector> @@ -28,8 +29,44 @@ class InputReader; class SpecialActions; +class SVGTree; +class XMLElement; +class XMLNode; + +#ifdef _MSC_VER +// MSVC: Prevent aggressive optimization of pointers to member functions. +// Instatiating class DvisvgmSpecialHandler without the following pragma +// leads to memory corruption. +// https://docs.microsoft.com/en-us/cpp/preprocessor/pointers-to-members +#pragma pointers_to_members(full_generality, single_inheritance) +#endif class DvisvgmSpecialHandler : public SpecialHandler { + class XMLParser { + using AppendFunc = void (SVGTree::*)(std::unique_ptr<XMLNode>); + using PushFunc = void (SVGTree::*)(std::unique_ptr<XMLElement>); + using PopFunc = void (SVGTree::*)(); + using NameStack = std::vector<std::string>; + + public: + XMLParser (AppendFunc append, PushFunc push, PopFunc pop) + : _append(append), _pushContext(push), _popContext(pop) {} + + void parse (const std::string &xml, SpecialActions &actions, bool finish=false); + void flush (SpecialActions &actions); + + protected: + void openElement (const std::string &tag, SpecialActions &actions); + void closeElement (const std::string &tag, SpecialActions &actions); + + private: + AppendFunc _append; + PushFunc _pushContext; + PopFunc _popContext; + std::string _xmlbuf; + NameStack _nameStack; ///< names of nested elements still missing a closing tag + }; + using StringVector = std::vector<std::string>; using MacroMap = std::unordered_map<std::string, StringVector>; @@ -60,7 +97,9 @@ class DvisvgmSpecialHandler : public SpecialHandler { private: MacroMap _macros; MacroMap::iterator _currentMacro; - int _nestingLevel; + int _nestingLevel=0; ///< nesting depth of rawset specials + XMLParser _defsParser; ///< parses XML added by 'rawdef' specials + XMLParser _pageParser; ///< parses XML added by 'raw' specials }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp index 21b1967fc6f..5a5fccc08f4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <array> #include <cstring> #include <istream> #include <limits> @@ -66,8 +67,8 @@ EPSFile::EPSFile (const string &fname) : _ifs(fname, ios::binary) { _ifs.seekg(_offset); // continue reading at the beginning of the PS section } string str; - str += _ifs.get(); - str += _ifs.get(); + str += char(_ifs.get()); + str += char(_ifs.get()); _headerValid = (str == "%!"); _ifs.seekg(0); } @@ -98,12 +99,12 @@ BoundingBox EPSFile::bbox () const { ir.skip(14); ir.skipSpace(); if (!ir.check("(atend)", true)) { - int val[4]; - for (int i=0; i < 4; i++) { + array<int, 4> values; + for (int &v : values) { ir.skipSpace(); - ir.parseInt(val[i]); + ir.parseInt(v); } - box = BoundingBox(val[0], val[1], val[2], val[3]); + box = BoundingBox(values[0], values[1], values[2], values[3]); break; } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp index 713aecb2395..4fdd03ee1b3 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp @@ -28,7 +28,7 @@ class EPSFile { public: - EPSFile (const std::string &fname); + explicit EPSFile (const std::string &fname); std::istream& istream () const; bool hasValidHeader () const {return _headerValid;} BoundingBox bbox () const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp new file mode 100644 index 00000000000..b820af00523 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp @@ -0,0 +1,260 @@ +/************************************************************************* +** EllipticalArc.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 <cmath> +#include "EllipticalArc.hpp" +#include "utility.hpp" + +using namespace std; + + +/** Constructs an elliptical arc from end point parameterization. + * @param[in] start start point of arc + * @param[in] rx length of semi-major axis + * @param[in] ry length of semi-minor axis + * @param[in] angle rotation of ellipse around its center (in radians) + * @param[in] laf if true, choose the larger arc between start and end point + * @param[in] sweep if true, arc is drawn in the direction of increasing angles + * @param[in] end end point of the arc */ +EllipticalArc::EllipticalArc (const DPair &start, double rx, double ry, double angle, bool laf, bool sweep, const DPair &end) + : _rx(abs(rx)), _ry(abs(ry)), _rotationAngle(math::normalize_angle(angle, math::PI)), + _largeArc(laf), _sweepPositive(sweep), _startPoint(start), _endPoint(end) +{ + if (!isStraightLine()) { + // fix out-of-range radii according to section F.6.6.3 in + // https://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + DPair p = (_startPoint-_endPoint)/2.0; + p = DPair(c*p.x()+s*p.y(), c*p.y()-s*p.x()); + double lambda = (p.x()*p.x())/(_rx*_rx) + (p.y()*p.y())/(_ry*_ry); + if (lambda > 1) { + lambda = sqrt(lambda); + _rx *= lambda; + _ry *= lambda; + } + } +} + + +/** Constructs an elliptical arc from center parameterization + * @param[in] center absolute coordinates of the center of the ellipse + * @param[in] rx length of semi-major axis + * @param[in] ry length of semi-minor axis + * @param[in] rot rotation of ellipse around its center (in radians) + * @param[in] startAngle angle between major axis and vector from center to start point + * @param[in] deltaAngle angle between the vectors from center to start and end point, respectively */ +EllipticalArc::EllipticalArc (const DPair ¢er, double rx, double ry, double rot, double startAngle, double deltaAngle) + : _rx(rx), _ry(ry), _rotationAngle(math::normalize_angle(rot, math::TWO_PI)), + _largeArc(abs(deltaAngle) > math::PI), _sweepPositive(deltaAngle > 0) +{ + // https://www.w3.org/TR/SVG/implnote.html#ArcConversionCenterToEndpoint + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + double c1 = cos(startAngle); + double s1 = sin(startAngle); + double c2 = cos(startAngle+deltaAngle); + double s2 = sin(startAngle+deltaAngle); + _startPoint = DPair(c*rx*c1*c - s*ry*s1, s*rx*c1 + c*ry*s1) + center; + _endPoint = DPair(c*rx*c2*c - s*ry*s2, s*rx*c2 + c*ry*s2) + center; +} + + +/** Returns the angle between (1, 0) and a given vector. + * The angle is normalized to the range [0, 2pi). */ +static inline double angle (const DPair &p) { + return math::normalize_0_2pi(atan2(p.y(), p.x())); +} + + +/** Computes the center parameterization of the arc. */ +EllipticalArc::CenterParams EllipticalArc::getCenterParams () const { + EllipticalArc::CenterParams params; + if (isStraightLine()) { + params.center = (_endPoint-_startPoint)/2.0; + params.startAngle = params.deltaAngle = 0; + } + else { + // https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + DPair p = (_startPoint-_endPoint)/2.0; + p = DPair(c*p.x()+s*p.y(), c*p.y()-s*p.x()); + double rx2 = _rx*_rx, ry2 = _ry*_ry; + double px2 = p.x()*p.x(), py2 = p.y()*p.y(); + double radicand = rx2*ry2 - rx2*py2 - ry2*px2; + if (radicand < 0) // should not happen if out-of-range radii were fixed correctly + radicand = 0; + else + radicand /= rx2*py2 + ry2*px2; + double root = sqrt(radicand) * (_largeArc == _sweepPositive ? -1 : 1); + DPair cp(root*p.y()*_rx/_ry, -root*p.x()*_ry/_rx); + DPair mid = (_startPoint+_endPoint)/2.0; + params.center = DPair(c*cp.x() - s*cp.y() + mid.x(), s*cp.x() + c*cp.y() + mid.y()); + DPair q1((p.x() - cp.x())/_rx, (p.y() - cp.y())/_ry); + DPair q2(-(p.x() + cp.x())/_rx, -(p.y() + cp.y())/_ry); + params.startAngle = angle(q1); + params.deltaAngle = angle(q2) - params.startAngle; + if (_sweepPositive && params.deltaAngle < 0) + params.deltaAngle += math::TWO_PI; + else if (!_sweepPositive && params.deltaAngle > 0) + params.deltaAngle -= math::TWO_PI; + } + return params; +} + + +/** Applies the affine transformation described by a given matrix to the arc. */ +void EllipticalArc::transform (const Matrix &matrix) { + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + Matrix ellipse({_rx*c, -_ry*s, 0, _rx*s, _ry*c}); // E := rotate(xrot)*scale(rx, ry) + ellipse.lmultiply(matrix); // E':= M*E + // Compute the singular value decomposition of the transformed ellipse shape: + // E' = rotate(phi)*scale(sx, sy)*rotate(theta) + // The initial, right-hand rotation can be ignored because it rotates the unit circle + // around the origin, i.e. rotate(theta) maps the circle to itself. + // The signs of sx and sy don't matter either. They just flip the yet unrotated + // ellipse on the x- and/or y-axis. Thus, |sx| and |sy| are the new radii, + // and phi the new rotation angle. + auto vec = math::svd({{ellipse.get(0,0), ellipse.get(0,1)}, {ellipse.get(1,0), ellipse.get(1,1)}}); + if (std::abs(vec[1]-vec[2]) < 1e-7) { // circle? + _rx = _ry = vec[1]; // always >= 0 + _rotationAngle = 0; + } + else { + _rx = vec[1]; // always >= 0 + _ry = abs(vec[2]); // ensure >= 0 + _rotationAngle = math::normalize_angle(vec[0], math::HALF_PI); + } + // change drawing direction (clockwise vs. counter-clockwise) if 'matrix' + // flipped the ellipse horizontally or vertically but not both + if ((matrix.get(0, 0) < 0) != (matrix.get(1, 1) < 0)) + _sweepPositive = !_sweepPositive; + _startPoint = matrix * _startPoint; + _endPoint = matrix * _endPoint; +} + + +/** Approximates an arc of the unit circle by a single cubic Bézier curve. + * @param[in] phi start angle of the arc in radians + * @param[in] delta length of the arc */ +static Bezier approx_unit_arc (double phi, double delta) { + double c = 0.551915024494; // see http://spencermortensen.com/articles/bezier-circle + if (abs(delta + math::HALF_PI) < 1e-7) + c = -c; + else + c = 4.0/3*tan(delta/4); + DPair p1(cos(phi), sin(phi)); + DPair p4(cos(phi+delta), sin(phi+delta)); + DPair p2(p1.x()-c*p1.y(), p1.y()+c*p1.x()); + DPair p3(p4.x()+c*p4.y(), p4.y()-c*p4.x()); + return Bezier(p1, p2, p3, p4); +} + + +/** Approximates the arc by a sequence of cubic Bézier curves. */ +vector<Bezier> EllipticalArc::approximate () const { + vector<Bezier> beziers; + if (_startPoint != _endPoint) { + if (isStraightLine()) { + DPair dir = (_endPoint - _startPoint); + dir /= dir.length()/3.0; + beziers.emplace_back(Bezier(_startPoint, _startPoint+dir, _endPoint-dir, _endPoint)); + } + else { + CenterParams cparams = getCenterParams(); + int numCurves = ceil(cparams.deltaAngle/math::HALF_PI); + double remainder = abs(fmod(cparams.deltaAngle, math::HALF_PI)); + if (remainder < 1e-7) + numCurves--; + else if (math::HALF_PI-remainder < 1e-7) + numCurves++; + if (numCurves > 0) { + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + Matrix ellipse = {_rx*c, -_ry*s, cparams.center.x(), _rx*s, _ry*c, cparams.center.y()}; + double angle = cparams.startAngle; + double diff = cparams.deltaAngle/numCurves; + while (numCurves-- > 0) { + beziers.emplace_back(approx_unit_arc(angle, diff).transform(ellipse)); + angle += diff; + } + } + } + } + return beziers; +} + + +static inline bool is_angle_between (double t, double angle1, double angle2) { + if (angle1 < angle2) + return angle1 < t && t < angle2; + return angle2 > t || t > angle1; +} + + +/** Returns the tight bounding box of the arc. */ +BoundingBox EllipticalArc::getBBox () const { + BoundingBox bbox; + bbox.embed(_startPoint); + bbox.embed(_endPoint); + if (!isStraightLine()) { + // compute extremes of ellipse centered at the origin + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + double tx1 = math::normalize_0_2pi(-atan2(_ry*s, _rx*c)); // position of vertical tangent, d/dt E(tx1)=(0, y) + double tx2 = math::normalize_0_2pi(math::PI+tx1); // position of second vertical tangent + double ct = cos(tx1); + double st = sin(tx1); + DPair pv1(_rx*c*ct - _ry*s*st, _rx*s*ct + _ry*c*st); // E(tx1), 1st point on ellipse with vertical tangent + DPair pv2 = -pv1; // E(tx2), 2nd point on ellipse with vertical tangent + + double ty1 = math::normalize_0_2pi(atan2(_ry*c, _rx*s)); // position of horizontal tangent, d/dt E(ty1)=(x, 0) + double ty2 = math::normalize_0_2pi(math::PI+ty1); // position of second horizontal tangent + ct = cos(ty1); + st = sin(ty1); + DPair ph1(_rx*c*ct - _ry*s*st, _rx*s*ct + _ry*c*st); // E(ty1), 1st point on ellipse with horizontal tangent + DPair ph2 = -ph1; // E(ty2), 2nd point on ellipse with horizontal tangent + + // translate extreme points to actual coordinates + CenterParams cparams = getCenterParams(); + pv1 += cparams.center; + pv2 += cparams.center; + ph1 += cparams.center; + ph2 += cparams.center; + + double angle1 = cparams.startAngle; + double angle2 = math::normalize_0_2pi(angle1+cparams.deltaAngle); + if (!_sweepPositive) + swap(angle1, angle2); + + // only consider extreme points located on the arc + if (is_angle_between(tx1, angle1, angle2)) + bbox.embed(pv1); + if (is_angle_between(tx2, angle1, angle2)) + bbox.embed(pv2); + if (is_angle_between(ty1, angle1, angle2)) + bbox.embed(ph1); + if (is_angle_between(ty2, angle1, angle2)) + bbox.embed(ph2); + } + return bbox; +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp new file mode 100644 index 00000000000..5d205581967 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp @@ -0,0 +1,59 @@ +/************************************************************************* +** EllipticalArc.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +#include "Bezier.hpp" +#include "BoundingBox.hpp" +#include "Matrix.hpp" +#include "Pair.hpp" + +class EllipticalArc { + public: + struct CenterParams { + DPair center; ///< absolute coordinates of the center point + double startAngle; ///< angle of start point relative to semi-major axis (in radians) + double deltaAngle; ///< difference between angles of the start and end point (>0 if sweep flag is set) + }; + + public: + EllipticalArc (const DPair &start, double rx, double ry, double angle, bool laf, bool sweep, const DPair &end); + EllipticalArc (const DPair ¢er, double rx, double ry, double rot, double startAngle, double deltaAngle); + CenterParams getCenterParams () const; + double rx () const {return _rx;} + double ry () const {return _ry;} + bool largeArc () const {return _largeArc;} + bool sweepPositive () const {return _sweepPositive;} + double rotationAngle () const {return _rotationAngle;} + DPair startPoint () const {return _startPoint;} + DPair endPoint () const {return _endPoint;} + bool isStraightLine () const {return _rx < 1e-7 || _ry < 1e-7;} + BoundingBox getBBox () const; + void transform (const Matrix &matrix); + std::vector<Bezier> approximate () const; + + private: + double _rx, _ry; ///< length of semi-major and semi-minor axes + double _rotationAngle; ///< rotation angle around center (in radians) + bool _largeArc; ///< if true, the longer arc from start to end point is chosen, else the shorter one + bool _sweepPositive; ///< if true, arc is drawn in direction of positive angles, else the opposite direction + DPair _startPoint, _endPoint; ///< absolute coordinates of start and end point +}; + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp index f2725ad1fa2..c93a798fd74 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp @@ -24,16 +24,13 @@ #include "InputReader.hpp" #include "Length.hpp" #include "SpecialActions.hpp" +#include "SVGTree.hpp" #include "XMLNode.hpp" #include "XMLString.hpp" using namespace std; -EmSpecialHandler::EmSpecialHandler () : _linewidth(0.4*72/72.27) { -} - - /** Computes the "cut vector" that is used to compute the line shape. * Because each line has a width > 0 the actual shape of the line is a tetragon. * The 4 vertices can be influenced by the cut parameter c that specifies @@ -78,11 +75,13 @@ static DPair cut_vector (char cuttype, const DPair &linedir, double linewidth) { * @param[in] lw line width in PS point units * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, double lw, SpecialActions &actions) { - unique_ptr<XMLElementNode> node; + if (actions.outputLocked()) + return; + unique_ptr<XMLElement> node; DPair dir = p2-p1; if (dir.x() == 0 || dir.y() == 0 || (c1 == 'p' && c2 == 'p')) { // draw regular line - node = util::make_unique<XMLElementNode>("line"); + node = util::make_unique<XMLElement>("line"); node->addAttribute("x1", p1.x()); node->addAttribute("y1", p1.y()); node->addAttribute("x2", p2.x()); @@ -107,7 +106,7 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou << XMLString(q12.x()) << ',' << XMLString(q12.y()) << ' ' << XMLString(q22.x()) << ',' << XMLString(q22.y()) << ' ' << XMLString(q21.x()) << ',' << XMLString(q21.y()); - node = util::make_unique<XMLElementNode>("polygon"); + node = util::make_unique<XMLElement>("polygon"); node->addAttribute("points", oss.str()); if (actions.getColor() != Color::BLACK) node->addAttribute("fill", actions.getColor().svgColorString()); @@ -117,7 +116,7 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou actions.embed(q21); actions.embed(q22); } - actions.appendToPage(std::move(node)); + actions.svgTree().appendToPage(std::move(node)); } @@ -126,8 +125,8 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou static double read_length (InputReader &in) { double val = in.getDouble(); string unitstr; - if (isalpha(in.peek())) unitstr += in.get(); - if (isalpha(in.peek())) unitstr += in.get(); + if (isalpha(in.peek())) unitstr += char(in.get()); + if (isalpha(in.peek())) unitstr += char(in.get()); Length::Unit unit = Length::Unit::PT; try { unit = Length::stringToUnit(unitstr); @@ -163,7 +162,7 @@ bool EmSpecialHandler::process (const string &prefix, istream &is, SpecialAction {"moveto", &EmSpecialHandler::moveto}, {"lineto", &EmSpecialHandler::lineto}, {"linewidth", &EmSpecialHandler::linewidth}, - {0, 0} + {nullptr, nullptr} }; StreamInputReader ir(is); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp index 546702c97ca..242ef248ef7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp @@ -38,7 +38,6 @@ class EmSpecialHandler : public SpecialHandler { }; public: - EmSpecialHandler (); const char* name () const override {return "em";} const char* info () const override {return "line drawing statements of the emTeX special set";} std::vector<const char*> prefixes() const override; @@ -54,9 +53,9 @@ class EmSpecialHandler : public SpecialHandler { private: std::unordered_map<int, DPair> _points; ///< points defined by special em:point - std::vector<Line> _lines; ///< list of lines with undefined end points - double _linewidth; ///< global line width - DPair _pos; ///< current position of "graphic cursor" + std::vector<Line> _lines; ///< list of lines with undefined end points + double _linewidth=0.4*72/72.27; ///< global line width + DPair _pos; ///< current position of "graphic cursor" }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp index 292ad722d7f..dba0a2544ab 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp @@ -32,7 +32,7 @@ static string read_entry (InputReader &in); static bool valid_name_char (int c); -EncFile::EncFile (const string &encname) : _encname(encname) +EncFile::EncFile (string encname) : _encname(std::move(encname)) { read(); } @@ -101,7 +101,7 @@ static string read_entry (InputReader &in) { while (!in.eof() && ((in.peek() == '/' && accept_slashes) || valid_name_char(in.peek()))) { if (in.peek() != '/') accept_slashes = false; - entry += in.get(); + entry += char(in.get()); } if (entry.length() > 1) { // strip leading slashes @@ -127,6 +127,6 @@ static bool valid_name_char (int c) { * @return character name assigned to character code c*/ const char* EncFile::charName (uint32_t c) const { if (c < _table.size()) - return !_table[c].empty() ? _table[c].c_str() : 0; - return 0; + return !_table[c].empty() ? _table[c].c_str() : nullptr; + return nullptr; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp index 2eab020b655..fac26fd201f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp @@ -28,10 +28,9 @@ #include "FontEncoding.hpp" -class EncFile : public NamedFontEncoding -{ +class EncFile : public NamedFontEncoding { public: - EncFile (const std::string &name); + explicit EncFile (std::string encname); void read (); void read (std::istream &is); int size () const {return _table.size();} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp index a5b4ed2ef2e..dfd60412cb8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp @@ -69,7 +69,7 @@ FileFinder::FileFinder () { void FileFinder::init (const std::string &argv0, const std::string &progname, bool enable_mktexmf) { _argv0 = argv0; - _progname = progname.c_str(); + _progname = progname; _enableMktex = enable_mktexmf; } @@ -174,6 +174,11 @@ const char* FileFinder::findFile (const std::string &fname, const char *ftype) c {"pro", kpse_tex_ps_header_format}, {"sfd", kpse_sfd_format}, {"eps", kpse_pict_format}, + {"png", kpse_pict_format}, + {"jpg", kpse_pict_format}, + {"jpeg", kpse_pict_format}, + {"svg", kpse_pict_format}, + {"pdf", kpse_tex_format}, }; auto it = types.find(ext); if (it == types.end()) @@ -205,10 +210,10 @@ const char* FileFinder::findMappedFile (std::string fname) const { if (const FontMap::Entry *entry = FontMap::instance().lookup(base)) { const char *path=nullptr; if (entry->fontname.find('.') != std::string::npos) // does the mapped filename has an extension? - path = findFile(entry->fontname, 0); // look for that file + path = findFile(entry->fontname, nullptr); // look for that file else { // otherwise, use extension of unmapped file fname = entry->fontname + "." + ext; - (path = findFile(fname, 0)) || (path = mktex(fname)); + (path = findFile(fname, nullptr)) || (path = mktex(fname)); } return path; } @@ -233,7 +238,7 @@ const char* FileFinder::mktex (const std::string &fname) const { // maketfm and makemf are located in miktex/bin which is in the search PATH std::string toolname = (ext == "tfm" ? "miktex-maketfm" : "miktex-makemf"); system((toolname+".exe "+fname).c_str()); - path = findFile(fname, 0); + path = findFile(fname, nullptr); #else kpse_file_format_type type = (ext == "tfm" ? kpse_tfm_format : kpse_mf_format); path = kpse_make_tex(type, fname.c_str()); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp index f7f8f783d87..b01c26b10c0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp @@ -34,7 +34,7 @@ class FileFinder { std::string version () const; void addLookupDir (const std::string &path); const char* lookup (const std::string &fname, const char *ftype, bool extended=true) const; - const char* lookup (const std::string &fname, bool extended=true) const {return lookup(fname, 0, extended);} + const char* lookup (const std::string &fname, bool extended=true) const {return lookup(fname, nullptr, extended);} protected: FileFinder (); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp index d8834499d38..c859d30469d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp @@ -87,10 +87,28 @@ FilePath::FilePath (const string &path, bool isfile, const string ¤t_dir) } -/** Assigns a new path. Relative paths are relative to the current working directory. +/** Assigns a new path of a file or directory that already exists. + * Relative paths are relative to the current working directory. * @param[in] path absolute or relative path to a file or directory */ -void FilePath::set(const string &path) { - init(path, !FileSystem::isDirectory(path), FileSystem::getcwd()); +void FilePath::set (const string &path) { + set(path, !FileSystem::isDirectory(path)); +} + + +/** Assigns a new path. Relative paths are relative to the current working directory. + * @param[in] path absolute or relative path to a file or directory + * @param[in] isfile true if 'path' references a file, false if a directory is referenced */ +void FilePath::set (const string &path, bool isfile) { + init(path, isfile, FileSystem::getcwd()); +} + + +/** Assigns a new path. Relative paths are relative to the current working directory. + * @param[in] path absolute or relative path to a file or directory + * @param[in] isfile true if 'path' references a file, false if a directory is referenced + * @param[in] current_dir if 'path' is a relative path expression it will be related to 'current_dir' */ +void FilePath::set (const string &path, bool isfile, const string ¤t_dir) { + init(path, isfile, current_dir); } @@ -152,7 +170,7 @@ void FilePath::add (const string &dir) { if (dir == ".." && !_dirs.empty()) _dirs.pop_back(); else if (dir.length() > 0 && dir != ".") - _dirs.push_back(dir); + _dirs.emplace_back(dir); } @@ -257,3 +275,37 @@ string FilePath::relative (string reldir, bool with_filename) const { path = "."; return single_slashes(path); } + + +string FilePath::relative (const FilePath &filepath, bool with_filename) const { + return relative(filepath.absolute(false), with_filename); +} + + +/** Return the absolute or relative path whichever is shorter. +* @param[in] reldir absolute path to a directory +* @param[in] with_filename if false, the filename is omitted */ +string FilePath::shorterAbsoluteOrRelative (string reldir, bool with_filename) const { + string abs = absolute(with_filename); + string rel = relative(reldir, with_filename); + return abs.length() < rel.length() ? abs : rel; +} + + +bool FilePath::exists () const { + return empty() ? false : FileSystem::exists(absolute()); +} + + +/** Checks if a given path is absolute or relative. + * @param[in] path path string to check + * @return true if path is absolute */ +bool FilePath::isAbsolute (string path) { + path = util::trim(path); +#ifdef _WIN32 + path = FileSystem::adaptPathSeperators(path); + if (path.length() >= 2 && path[1] == ':' && isalpha(path[0])) + path.erase(0, 2); // remove drive letter and colon +#endif + return !path.empty() && path[0] == '/'; +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp index f3efed020b0..32a9be68149 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp @@ -28,8 +28,8 @@ class FilePath { class Directory { public: - Directory (const std::string &dir) : _dirstr(dir) {} - Directory (std::string &&dir) : _dirstr(std::move(dir)) {} + explicit Directory (std::string dir) : _dirstr(std::move(dir)) {} + explicit Directory (std::string &&dir) : _dirstr(std::move(dir)) {} bool operator == (const Directory &dir) const; bool operator != (const Directory &dir) const {return !(*this == dir);} explicit operator std::string () const {return _dirstr;} @@ -39,12 +39,17 @@ class FilePath { }; public: - FilePath (const std::string &path) {set(path);} + FilePath () =default; + explicit FilePath (const std::string &path) {set(path);} FilePath (const std::string &path, bool isfile) : FilePath(path, isfile, "") {} FilePath (const std::string &path, bool isfile, const std::string ¤t_dir); void set (const std::string &path); + void set (const std::string &path, bool isfile); + void set (const std::string &path, bool isfile, const std::string ¤t_dir); std::string absolute (bool with_filename=true) const; std::string relative (std::string reldir="", bool with_filename=true) const; + std::string relative (const FilePath &filepath, bool with_filename=true) const; + std::string shorterAbsoluteOrRelative (std::string reldir="", bool with_filename=true) const; std::string basename () const; std::string suffix () const; void suffix (const std::string &s); @@ -53,16 +58,18 @@ class FilePath { bool empty () const {return _dirs.empty() && _fname.empty();} const std::string& filename () const {return _fname;} void filename (const std::string &fname) {_fname = fname;} + bool exists () const; + static bool isAbsolute (std::string path); protected: void init (std::string path, bool isfile, std::string current_dir); void add (const std::string &elem); private: - std::vector<std::string> _dirs; + std::vector<Directory> _dirs; std::string _fname; #ifdef _WIN32 - char _drive; + char _drive=0; #endif }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp index 9540a5e9c7d..35621465a53 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp @@ -175,7 +175,7 @@ const char* FileSystem::userdir () { if (!ret.empty()) return ret.c_str(); } - return 0; + return nullptr; #else const char *dir=getenv("HOME"); if (!dir) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp index b83bb849a85..97520c59534 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp @@ -99,8 +99,8 @@ const char* Font::filename () const { /////////////////////////////////////////////////////////////////////////////////////// -TFMFont::TFMFont (const string &name, uint32_t cs, double ds, double ss) - : _fontname(name), _checksum(cs), _dsize(ds), _ssize(ss) +TFMFont::TFMFont (string name, uint32_t cs, double ds, double ss) + : _fontname(std::move(name)), _checksum(cs), _dsize(ds), _ssize(ss) { } @@ -159,7 +159,7 @@ bool TFMFont::verifyChecksums () const { // static class variables bool PhysicalFont::EXACT_BBOX = false; bool PhysicalFont::KEEP_TEMP_FILES = false; -const char *PhysicalFont::CACHE_PATH = 0; +string PhysicalFont::CACHE_PATH; double PhysicalFont::METAFONT_MAG = 4; FontCache PhysicalFont::_cache; @@ -175,14 +175,14 @@ unique_ptr<Font> PhysicalFont::create (const string &name, int fontindex, uint32 const char* PhysicalFont::path () const { - const char *ext=0; + const char *ext=nullptr; switch (type()) { case Type::OTF: ext = "otf"; break; case Type::PFB: ext = "pfb"; break; case Type::TTC: ext = "ttc"; break; case Type::TTF: ext = "ttf"; break; case Type::MF : ext = "mf"; break; - default : ext = 0; + default : ext = nullptr; } if (ext) return FileFinder::instance().lookup(name()+"."+ext); @@ -323,8 +323,8 @@ std::string PhysicalFont::styleName () const { * @return true if outline could be computed */ bool PhysicalFont::getGlyph (int c, GraphicsPath<int32_t> &glyph, GFGlyphTracer::Callback *callback) const { if (type() == Type::MF) { - const Glyph *cached_glyph=0; - if (CACHE_PATH) { + const Glyph *cached_glyph=nullptr; + if (!CACHE_PATH.empty()) { _cache.write(CACHE_PATH); _cache.read(name(), CACHE_PATH); cached_glyph = _cache.getGlyph(c); @@ -342,7 +342,7 @@ bool PhysicalFont::getGlyph (int c, GraphicsPath<int32_t> &glyph, GFGlyphTracer: tracer.setGlyph(glyph); tracer.executeChar(c); glyph.closeOpenSubPaths(); - if (CACHE_PATH) + if (!CACHE_PATH.empty()) _cache.setGlyph(c, glyph); return true; } @@ -392,7 +392,7 @@ bool PhysicalFont::createGF (string &gfname) const { * @return number of glyphs traced */ int PhysicalFont::traceAllGlyphs (bool includeCached, GFGlyphTracer::Callback *cb) const { int count = 0; - if (type() == Type::MF && CACHE_PATH) { + if (type() == Type::MF && !CACHE_PATH.empty()) { if (const FontMetrics *metrics = getMetrics()) { int fchar = metrics->firstChar(); int lchar = metrics->lastChar(); @@ -479,7 +479,7 @@ PhysicalFontImpl::PhysicalFontImpl (const string &name, int fontindex, uint32_t PhysicalFontImpl::~PhysicalFontImpl () { - if (CACHE_PATH) + if (!CACHE_PATH.empty()) _cache.write(CACHE_PATH); if (!KEEP_TEMP_FILES) tidy(); @@ -548,7 +548,7 @@ uint32_t PhysicalFontImpl::unicode (uint32_t c) const { const FontStyle* PhysicalFontImpl::style () const { - if (auto *entry = fontMapEntry()) + if (auto entry = fontMapEntry()) return &entry->style; return nullptr; } @@ -671,6 +671,6 @@ void VirtualFontImpl::assignChar (uint32_t c, DVIVector &&dvi) { * @return pointer to vector of DVI commands, or 0 if character doesn't exist */ const vector<uint8_t>* VirtualFontImpl::getDVI (int c) const { auto it = _charDefs.find(c); - return (it == _charDefs.end() ? 0 : &it->second); + return (it == _charDefs.end() ? nullptr : &it->second); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp index 294ad4738ee..3273a0c14b8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp @@ -69,7 +69,7 @@ class Font { virtual const char* path () const =0; virtual const char* filename () const; virtual const FontEncoding* encoding () const; - virtual bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *callback=0) const =0; + virtual bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *callback=nullptr) const =0; virtual void getGlyphMetrics (int c, bool vertical, GlyphMetrics &metrics) const; virtual uint32_t unicode (uint32_t c) const; virtual void tidy () const {} @@ -88,7 +88,7 @@ class Font { * The metric values returned by the member functions are based on cmr10. */ class EmptyFont : public Font { public: - EmptyFont (const std::string &name) : _fontname(name) {} + explicit EmptyFont (std::string name) : _fontname(std::move(name)) {} std::unique_ptr<Font> clone (double ds, double sc) const override {return util::make_unique<EmptyFont>(*this);} const Font* uniqueFont () const override {return this;} std::string name () const override {return _fontname;} @@ -100,7 +100,7 @@ class EmptyFont : public Font { double italicCorr (int c) const override {return 0;} const FontMetrics* getMetrics () const override {return nullptr;} const char* path () const override {return nullptr;} - bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=0) const override {return false;} + bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=nullptr) const override {return false;} private: std::string _fontname; @@ -115,7 +115,7 @@ class PhysicalFont : public virtual Font { static std::unique_ptr<Font> create (const std::string &name, uint32_t checksum, double dsize, double ssize, PhysicalFont::Type type); static std::unique_ptr<Font> create (const std::string &name, int fontindex, uint32_t checksum, double dsize, double ssize); virtual Type type () const =0; - virtual bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=nullptr) const override; + bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=nullptr) const override; virtual bool getExactGlyphBox (int c, BoundingBox &bbox, GFGlyphTracer::Callback *cb=nullptr) const; virtual bool getExactGlyphBox (int c, GlyphMetrics &metrics, bool vertical, GFGlyphTracer::Callback *cb=nullptr) const; virtual bool isCIDFont () const; @@ -142,7 +142,7 @@ class PhysicalFont : public virtual Font { public: static bool EXACT_BBOX; static bool KEEP_TEMP_FILES; - static const char *CACHE_PATH; ///< path to cache directory (0 if caching is disabled) + static std::string CACHE_PATH; ///< path to cache directory ("" if caching is disabled) static double METAFONT_MAG; ///< magnification factor for Metafont calls protected: @@ -168,7 +168,7 @@ class VirtualFont : public virtual Font { class TFMFont : public virtual Font { public: - TFMFont (const std::string &name, uint32_t checksum, double dsize, double ssize); + TFMFont (std::string name, uint32_t cs, double ds, double ss); const FontMetrics* getMetrics () const override; std::string name () const override {return _fontname;} double designSize () const override {return _dsize;} @@ -227,7 +227,7 @@ class PhysicalFontProxy : public PhysicalFont { class PhysicalFontImpl : public PhysicalFont, public TFMFont { friend class PhysicalFont; public: - ~PhysicalFontImpl(); + ~PhysicalFontImpl () override; std::unique_ptr<Font> clone (double ds, double ss) const override { return std::unique_ptr<PhysicalFontProxy>(new PhysicalFontProxy(this, ds, ss)); @@ -258,7 +258,7 @@ class PhysicalFontImpl : public PhysicalFont, public TFMFont { class NativeFont : public PhysicalFont { public: virtual std::unique_ptr<NativeFont> clone (double ptsize, const FontStyle &style, Color color) const =0; - virtual std::unique_ptr<Font> clone (double ds, double sc) const override =0; + std::unique_ptr<Font> clone (double ds, double sc) const override =0; std::string name () const override; Type type () const override; double designSize () const override {return _ptsize;} @@ -312,8 +312,8 @@ class NativeFontProxy : public NativeFont { class NativeFontImpl : public NativeFont { public: - NativeFontImpl (const std::string &fname, int fontIndex, double ptsize, const FontStyle &style, Color color) - : NativeFont(ptsize, style, color), _path(fname), _fontIndex(fontIndex) {} + NativeFontImpl (std::string fname, int fontIndex, double ptsize, const FontStyle &style, Color color) + : NativeFont(ptsize, style, color), _path(std::move(fname)), _fontIndex(fontIndex) {} std::unique_ptr<NativeFont> clone (double ptsize, const FontStyle &style, Color color) const override { return std::unique_ptr<NativeFontProxy>(new NativeFontProxy(this, ptsize, style, color)); @@ -391,7 +391,7 @@ class VirtualFontImpl : public VirtualFont, public TFMFont { struct FontException : public MessageException { - FontException (const std::string &msg) : MessageException(msg) {} + explicit FontException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp index 1e2f19a780b..34478542dfb 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp @@ -23,13 +23,12 @@ #include <fstream> #include <iomanip> #include <sstream> -#include "CRC32.hpp" #include "FileSystem.hpp" #include "FontCache.hpp" -#include "Glyph.hpp" #include "Pair.hpp" #include "StreamReader.hpp" #include "StreamWriter.hpp" +#include "XXHashFunction.hpp" using namespace std; @@ -64,7 +63,7 @@ void FontCache::setGlyph (int c, const Glyph &glyph) { * @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 : 0; + return (it != _glyphs.end()) ? &it->second : nullptr; } @@ -78,10 +77,9 @@ bool FontCache::write (const string &fontname, const string &dir) const { return true; if (!fontname.empty()) { - string dirstr = dir.empty() ? FileSystem::getcwd() : dir; - ostringstream oss; - oss << dirstr << '/' << fontname << ".fgd"; - ofstream ofs(oss.str(), ios::binary); + string pathstr = dir.empty() ? FileSystem::getcwd() : dir; + pathstr += "/" + fontname + ".fgd"; + ofstream ofs(pathstr, ios::binary); return write(fontname, ofs); } return false; @@ -94,7 +92,7 @@ bool FontCache::write (const string &dir) const { /** Returns the minimal number of bytes needed to store the given value. */ -static int max_int_size (int32_t 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)) @@ -104,19 +102,49 @@ static int max_int_size (int32_t value) { return 4; } +static int max_int_size () { + return 0; +} -/** Returns the minimal number of bytes needed to store the biggest - * pair component of the given vector. */ -static int max_int_size (const Pair<int32_t> *pairs, size_t n) { - int ret=0; - for (size_t i=0; i < n; i++) { - ret = max(ret, max_int_size(pairs[i].x())); - ret = max(ret, max_int_size(pairs[i].y())); - } - return ret; +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 @@ -129,36 +157,22 @@ bool FontCache::write (const string &fontname, ostream &os) const { return false; StreamWriter sw(os); - CRC32 crc32; - - struct WriteActions : Glyph::Actions { - WriteActions (StreamWriter &sw, CRC32 &crc32) : _sw(sw), _crc32(crc32) {} - - void draw (char cmd, const Glyph::Point *points, int n) override { - int bytes = max_int_size(points, n); - int cmdchar = (bytes << 5) | (cmd - 'A'); - _sw.writeUnsigned(cmdchar, 1, _crc32); - for (int i=0; i < n; i++) { - _sw.writeSigned(points[i].x(), bytes, _crc32); - _sw.writeSigned(points[i].y(), bytes, _crc32); - } - } - StreamWriter &_sw; - CRC32 &_crc32; - } actions(sw, crc32); - - sw.writeUnsigned(FORMAT_VERSION, 1, crc32); - sw.writeUnsigned(0, 4); // space for checksum - sw.writeString(fontname, crc32, true); - sw.writeUnsigned(_glyphs.size(), 4, crc32); + XXH32HashFunction hashfunc; + + sw.writeUnsigned(FORMAT_VERSION, 1, hashfunc); + sw.writeBytes(hashfunc.digestValue()); // 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, crc32); - sw.writeUnsigned(glyph.size(), 2, crc32); + sw.writeUnsigned(charglyphpair.first, 4, hashfunc); + sw.writeUnsigned(glyph.size(), 2, hashfunc); glyph.iterate(actions, false); } os.seekp(1); - sw.writeUnsigned(crc32.get(), 4); // insert CRC32 checksum + auto digest = hashfunc.digestValue(); + sw.writeBytes(digest); // insert checksum os.seekp(0, ios::end); return true; } @@ -195,17 +209,17 @@ bool FontCache::read (const string &fontname, istream &is) { return false; StreamReader sr(is); - CRC32 crc32; - if (sr.readUnsigned(1, crc32) != FORMAT_VERSION) + XXH32HashFunction hashfunc; + if (sr.readUnsigned(1, hashfunc) != FORMAT_VERSION) return false; - uint32_t crc32_cmp = sr.readUnsigned(4); - crc32.update(is); - if (crc32.get() != crc32_cmp) + auto hashcmp = sr.readBytes(hashfunc.digestSize()); + hashfunc.update(is); + if (hashfunc.digestValue() != hashcmp) return false; is.clear(); - is.seekg(5); // continue reading after checksum + is.seekg(hashfunc.digestSize()+1); // continue reading after checksum string fname = sr.readString(); if (fname != fontname) @@ -237,7 +251,7 @@ bool FontCache::read (const string &fontname, istream &is) { case 'Q': { Pair32 p1 = read_pair(bytes, sr); Pair32 p2 = read_pair(bytes, sr); - glyph.conicto(p1, p2); + glyph.quadto(p1, p2); break; } case 'Z': @@ -289,17 +303,17 @@ bool FontCache::fontinfo (std::istream &is, FontInfo &info) { is.seekg(0); try { StreamReader sr(is); - CRC32 crc32; - if ((info.version = sr.readUnsigned(1, crc32)) != FORMAT_VERSION) + XXH32HashFunction hashfunc; + if ((info.version = sr.readUnsigned(1, hashfunc)) != FORMAT_VERSION) return false; - info.checksum = sr.readUnsigned(4); - crc32.update(is); - if (crc32.get() != info.checksum) + info.checksum = sr.readBytes(hashfunc.digestSize()); + hashfunc.update(is); + if (hashfunc.digestValue() != info.checksum) return false; is.clear(); - is.seekg(5); // continue reading after checksum + is.seekg(hashfunc.digestSize()+1); // continue reading after checksum info.name = sr.readString(); info.numchars = sr.readUnsigned(4); @@ -361,8 +375,10 @@ void FontCache::fontinfo (const string &dirname, ostream &os, bool purge) { << 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') - << setw(6) << "crc:" << setw(8) << hex << right << setfill('0') << strinfopair.second->checksum - << endl; + << " hash:" << hex; + for (int byte : strinfopair.second->checksum) + os << setw(2) << setfill('0') << byte; + os << '\n'; } } if (purge) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp index 24c977818e7..0068b6c78bf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp @@ -30,16 +30,15 @@ class FontCache { public: struct FontInfo { - std::string name; // fontname - uint16_t version; // file format version - uint32_t checksum; // CRC32 checksum of file data - uint32_t numchars; // number of characters - uint32_t numbytes; // number of bytes - uint32_t numcmds; // number of path commands + std::string name; // fontname + uint16_t version; // file format version + std::vector<uint8_t> checksum; // checksum of file data + uint32_t numchars; // number of characters + uint32_t numbytes; // number of bytes + uint32_t numcmds; // number of path commands }; public: - FontCache () : _changed(false) {} ~FontCache () {clear();} bool read (const std::string &fontname, const std::string &dir); bool read (const std::string &fontname, std::istream &is); @@ -59,7 +58,7 @@ class FontCache { static const uint8_t FORMAT_VERSION; std::string _fontname; std::map<int, Glyph> _glyphs; - bool _changed; + bool _changed=false; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp index add5cfc5ff6..3b038b63c6f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp @@ -32,7 +32,7 @@ using namespace std; * @return pointer to encoding object, or 0 if there is no encoding defined */ FontEncoding* FontEncoding::encoding (const string &encname) { if (encname.empty()) - return 0; + return nullptr; using EncodingMap = unordered_map<string, unique_ptr<EncFile>>; static EncodingMap encmap; @@ -77,7 +77,7 @@ const FontEncoding* FontEncodingPair::findCompatibleBaseFontMap (const PhysicalF return _enc2->findCompatibleBaseFontMap(font, charmapID); if (_enc1) return _enc1->findCompatibleBaseFontMap(font, charmapID); - return 0; + return nullptr; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp index de8ece6bb80..fffccd4224a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp @@ -32,7 +32,7 @@ struct FontEncoding { virtual ~FontEncoding () =default; virtual Character decode (uint32_t c) const =0; virtual bool mapsToCharIndex () const =0; - virtual const FontEncoding* findCompatibleBaseFontMap (const PhysicalFont *font, CharMapID &charmapID) const {return 0;} + virtual const FontEncoding* findCompatibleBaseFontMap (const PhysicalFont *font, CharMapID &charmapID) const {return nullptr;} static FontEncoding* encoding (const std::string &encname); }; @@ -45,7 +45,7 @@ struct NamedFontEncoding : public FontEncoding { class FontEncodingPair : public FontEncoding { public: - FontEncodingPair (const FontEncoding *enc1) : _enc1(enc1), _enc2(0) {} + explicit FontEncodingPair (const FontEncoding *enc1) : _enc1(enc1), _enc2(nullptr) {} FontEncodingPair (const FontEncoding *enc1, const FontEncoding *enc2) : _enc1(enc1), _enc2(enc2) {} Character decode (uint32_t c) const override; bool mapsToCharIndex () const override; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp index 1bdcbcdbedb..61efd68916f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <cmath> #include <sstream> #include <ft2build.h> #include FT_ADVANCES_H @@ -36,7 +37,7 @@ using namespace std; /** Converts a floating point value to a 16.16 fixed point value. */ static inline FT_Fixed to_16dot16 (double val) { - return static_cast<FT_Fixed>(val*65536.0 + 0.5); + return static_cast<FT_Fixed>(lround(val*65536.0)); } @@ -49,9 +50,7 @@ static inline FT_Fixed to_16dot16 (int val) { /////////////////////////////////////////////////////////////////////////// -FontEngine::FontEngine () : _currentFace(0), _currentFont(0) -{ - _currentChar = _currentGlyphIndex = 0; +FontEngine::FontEngine () { if (FT_Init_FreeType(&_library)) Message::estream(true) << "failed to initialize FreeType library\n"; } @@ -104,7 +103,7 @@ bool FontEngine::setFont (const Font &font) { return true; if (const char *path=font.path()) { - const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(&font); + auto pf = dynamic_cast<const PhysicalFont*>(&font); if (setFont(path, font.fontIndex(), pf ? pf->getCharMapID() : CharMapID())) { _currentFont = &font; return true; @@ -212,7 +211,7 @@ int FontEngine::getAdvance (int c) const { int FontEngine::getHAdvance () const { if (_currentFace) { - TT_OS2 *table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); + auto table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); return table ? table->xAvgCharWidth : 0; } return 0; @@ -294,7 +293,7 @@ string FontEngine::getGlyphName (const Character &c) const { vector<int> FontEngine::getPanose () const { vector<int> panose(10); if (_currentFace) { - TT_OS2 *table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); + auto table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); if (table) for (int i=0; i < 10; i++) panose[i] = table->panose[i]; @@ -339,35 +338,35 @@ CharMapID FontEngine::setCustomCharMap () { // Callback functions used by trace_outline/FT_Outline_Decompose static int moveto (FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); + auto glyph = static_cast<Glyph*>(user); glyph->moveto(to->x, to->y); return 0; } static int lineto (FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); + auto glyph = static_cast<Glyph*>(user); glyph->lineto(to->x, to->y); return 0; } -static int conicto (FTVectorPtr control, FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); - glyph->conicto(control->x, control->y, to->x, to->y); +static int quadto (FTVectorPtr control, FTVectorPtr to, void *user) { + auto glyph = static_cast<Glyph*>(user); + glyph->quadto(control->x, control->y, to->x, to->y); return 0; } static int cubicto (FTVectorPtr control1, FTVectorPtr control2, FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); + auto glyph = static_cast<Glyph*>(user); glyph->cubicto(control1->x, control1->y, control2->x, control2->y, to->x, to->y); return 0; } /** Traces the outline of a glyph by calling the corresponding "drawing" functions. - * Each glyph is composed of straight lines, quadratic (conic) or cubic B�zier curves. + * Each glyph is composed of straight lines, quadratic or cubic Bézier curves. * This function creates a Glyph object representing these graphics segments. * @param[in] face FreeType object representing the font to scan * @param[in] font corresponding Font object providing additional data @@ -393,7 +392,7 @@ static bool trace_outline (FT_Face face, const Font *font, int index, Glyph &gly if (style->bold != 0) FT_Outline_Embolden(&outline, style->bold/font->scaledSize()*face->units_per_EM); } - const FT_Outline_Funcs funcs = {moveto, lineto, conicto, cubicto, 0, 0}; + const FT_Outline_Funcs funcs = {moveto, lineto, quadto, cubicto, 0, 0}; FT_Outline_Decompose(&outline, &funcs, &glyph); return true; } @@ -403,7 +402,7 @@ static bool trace_outline (FT_Face face, const Font *font, int index, Glyph &gly /** Traces the outline of a glyph by calling the corresponding "drawing" functions. - * Each glyph is composed of straight lines, quadratic (conic) or cubic B�zier curves. + * Each glyph is composed of straight lines, quadratic or cubic Bézier curves. * This function creates a Glyph object representing these graphics segments. * @param[in] c the glyph of this character will be traced * @param[out] glyph resulting Glyph object containing the graphics segments diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp index 071f7fcf4b5..33c9b96da2a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp @@ -73,10 +73,10 @@ class FontEngine { int charIndex (const Character &c) const; private: - mutable unsigned int _currentChar, _currentGlyphIndex; - FT_Face _currentFace; + mutable unsigned int _currentChar=0, _currentGlyphIndex=0; + FT_Face _currentFace = nullptr; FT_Library _library; - const Font *_currentFont; + const Font *_currentFont = nullptr; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp index 7805cc1d53e..4f236b38664 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp @@ -187,11 +187,11 @@ int FontManager::registerFont (uint32_t fontnum, const string &name, uint32_t ch fontindex = map_entry->fontindex; } // try to find font file with the exact given name - if (filename.rfind(".") != string::npos) + if (filename.rfind('.') != string::npos) newfont = create_font(filename, name, fontindex, checksum, dsize, ssize); else { // try various font file formats if the given file has no extension - const char *exts[] = {"pfb", "otf", "ttc", "ttf", "vf", "mf", 0}; + const char *exts[] = {"pfb", "otf", "ttc", "ttf", "vf", "mf", nullptr}; for (const char **p = exts; *p && !newfont; ++p) newfont = create_font(filename+"."+*p, name, fontindex, checksum, dsize, ssize); } @@ -204,7 +204,7 @@ int FontManager::registerFont (uint32_t fontnum, const string &name, uint32_t ch else { // create dummy font as a placeholder if the proper font is not available newfont = util::make_unique<EmptyFont>(name); - if (filename.rfind(".") == string::npos) + if (filename.rfind('.') == string::npos) filename += ".mf"; // print warning message about missing font file (only once for each filename) static set<string> missing_fonts; @@ -263,7 +263,7 @@ int FontManager::registerFont (uint32_t fontnum, string filename, int fontIndex, const int newid = _fonts.size(); // the new font gets this ID auto it = _name2id.find(fontname); if (it != _name2id.end()) { // font with same name already registered? - if (NativeFont *font = dynamic_cast<NativeFont*>(_fonts[it->second].get())) + if (auto font = dynamic_cast<NativeFont*>(_fonts[it->second].get())) newfont = font->clone(ptsize, style, color); } else { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp index 2228c0c46ae..4405f67ecde 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp @@ -66,7 +66,7 @@ class FontManager void enterVF (VirtualFont *vf); void leaveVF (); void assignVFChar (int c, std::vector<uint8_t> &&dvi); - std::ostream& write (std::ostream &os, Font *font=0, int level=0); + std::ostream& write (std::ostream &os, Font *font=nullptr, int level=0); protected: FontManager () =default; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp index ee64c335f71..cd109c1809b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp @@ -34,7 +34,7 @@ class Subfont; class FontMap { public: struct Entry { - Entry (const MapLine &mapline, Subfont *subfont=nullptr); + explicit Entry (const MapLine &mapline, Subfont *subfont=nullptr); Entry (const Entry &entry) =delete; Entry (Entry &&entry) =default; Entry& operator = (Entry &&entry) =default; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp index 3f5296877b0..ccba26b727c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp @@ -67,7 +67,7 @@ struct NullFontMetric : public FontMetrics { struct FontMetricException : public MessageException { - FontMetricException (const std::string &msg) : MessageException(msg) {} + explicit FontMetricException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp index 3c5173e5a85..d93402baf54 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp @@ -39,21 +39,19 @@ const array<FontWriter::FontFormatInfo, 4> FontWriter::_formatInfos {{ /** Returns the corresponding FontFormat for a given format name (e.g. "svg", "woff" etc.). */ FontWriter::FontFormat FontWriter::toFontFormat (string formatstr) { formatstr = util::tolower(formatstr); - for (const FontFormatInfo &info : _formatInfos) { - if (formatstr == info.formatstr_short) - return info.format; - } - return FontFormat::UNKNOWN; + auto it = find_if(_formatInfos.begin(), _formatInfos.end(), [&](const FontFormatInfo &info) { + return info.formatstr_short == formatstr; + }); + return it != _formatInfos.end() ? it->format : FontFormat::UNKNOWN; } /** Returns the corresponding FontFormatInfo for a given FontFormat. */ const FontWriter::FontFormatInfo* FontWriter::fontFormatInfo (FontFormat format) { - for (const FontFormatInfo &info : _formatInfos) { - if (format == info.format) - return &info; - } - return nullptr; + auto it = find_if(_formatInfos.begin(), _formatInfos.end(), [&](const FontFormatInfo &info) { + return info.format == format; + }); + return it != _formatInfos.end() ? &(*it) : nullptr; } @@ -97,33 +95,38 @@ FontWriter::FontWriter (const PhysicalFont &font) : _font(font) { } -struct SFDActions : Glyph::Actions { - SFDActions (ostream &os) : _os(os) {} - void draw (char cmd, const Glyph::Point *points, int n) override { - if (cmd == 'Q') { - // convert quadratic Bézier curve to cubic one - DPair p0(_currentPoint.x(), _currentPoint.y()); - DPair p1(points[0].x(), points[0].y()); - DPair p2(points[1].x(), points[1].y()); - Bezier bezier(p0, p1, p2); - for (int i=1; i < 4; i++) - _os << lround(bezier.point(i).x()) << ' ' << lround(bezier.point(i).y()) << ' '; - _os << 'c'; - } - else { - for (int i=0; i < n; i++) - _os << points[i].x() << ' ' << points[i].y() << ' '; - switch (cmd) { - case 'M': _os << 'm'; _startPoint = points[0]; break; - case 'L': _os << 'l'; break; - case 'C': _os << 'c'; break; - case 'Z': _os << _startPoint.x() << ' ' << _startPoint.y() << " l"; _currentPoint = _startPoint; break; - } - } - if (n > 0) - _currentPoint = points[n-1]; - _os << " 0\n"; +struct SFDActions : Glyph::IterationActions { + explicit SFDActions (ostream &os) : _os(os) {} + + using Point = Glyph::Point; + void moveto (const Point &p) override {write('m', p);} + void lineto (const Point &p) override {write('l', p);} + void cubicto (const Point &p1, const Point &p2, const Point &p3) override {write('c', p1, p2, p3); } + void closepath () override {write('m', startPoint());} + + void quadto (const Point &p1, const Point &p2) override { + // convert quadratic Bézier curve to cubic one + DPair pt0(currentPoint().x(), currentPoint().y()); + DPair pt1(p1.x(), p1.y()); + DPair pt2(p2.x(), p2.y()); + Bezier b(pt0, pt1, pt2); + write('c', round(b.point(0)), round(b.point(1)), round(b.point(2)), round(b.point(3))); } + + template <typename ...Args> + void write (char cmd, const Args& ...args) { + writeParams(args...); + _os << cmd << " 0\n"; + } + + static void writeParams () {} + + template <typename Pt, typename ...Args> + void writeParams (const Pt &p, const Args& ...args) const { + _os << p.x() << ' ' << p.y() << ' '; + writeParams(args...); + } + ostream &_os; Glyph::Point _startPoint, _currentPoint; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp index 3becdf2618d..458952cad9b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp @@ -36,9 +36,9 @@ class FontWriter { static bool AUTOHINT_FONTS; public: - FontWriter (const PhysicalFont &font); - std::string createFontFile (FontFormat format, const std::set<int> &charcodes, GFGlyphTracer::Callback *cb=0) const; - bool writeCSSFontFace (FontFormat format, const std::set<int> &charcodes, std::ostream &os, GFGlyphTracer::Callback *cb=0) const; + explicit FontWriter (const PhysicalFont &font); + std::string createFontFile (FontFormat format, const std::set<int> &charcodes, GFGlyphTracer::Callback *cb=nullptr) const; + bool writeCSSFontFace (FontFormat format, const std::set<int> &charcodes, std::ostream &os, GFGlyphTracer::Callback *cb=nullptr) const; static FontFormat toFontFormat (std::string formatstr); static std::vector<std::string> supportedFormats (); @@ -59,7 +59,7 @@ class FontWriter { struct FontWriterException : MessageException { - FontWriterException (const std::string &msg) : MessageException(msg) {} + explicit FontWriterException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp index 0a3b653540d..85f7c2cab56 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp @@ -22,7 +22,7 @@ using namespace std; -GFGlyphTracer::GFGlyphTracer () : GFTracer(_ifs, 0), _glyph(0), _callback(0) +GFGlyphTracer::GFGlyphTracer () : GFTracer(_ifs, 0) { } @@ -30,7 +30,7 @@ GFGlyphTracer::GFGlyphTracer () : GFTracer(_ifs, 0), _glyph(0), _callback(0) * @param[in] is GF input stream * @param[in] upp target units per PS point */ GFGlyphTracer::GFGlyphTracer (string &fname, double upp, Callback *cb) - : GFTracer(_ifs, upp), _glyph(0), _callback(cb) + : GFTracer(_ifs, upp), _callback(cb) { if (_callback) _callback->setFont(fname); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp index c6304c090b3..49f69b69ec7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp @@ -39,7 +39,7 @@ class GFGlyphTracer : public GFTracer public: GFGlyphTracer (); - GFGlyphTracer (std::string &fname, double upp, Callback *cb=0); + GFGlyphTracer (std::string &fname, double upp, Callback *cb=nullptr); void reset (std::string &fname, double upp); void setCallback (Callback *cb) {_callback = cb;} bool executeChar (uint8_t c) override; @@ -53,8 +53,8 @@ class GFGlyphTracer : public GFTracer private: std::ifstream _ifs; - Glyph *_glyph; - Callback *_callback; + Glyph *_glyph = nullptr; + Callback *_callback = nullptr; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp index 3cba8e50691..32ba354443f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp @@ -106,11 +106,8 @@ int GFReader::executeCommand () { cmdPaint0(opcode); else if (opcode >= 74 && opcode <= 238) cmdNewRow(opcode-74); - else if (opcode >= 250) { - ostringstream oss; - oss << "undefined GF command (opcode " << opcode << ")"; - throw GFException(oss.str()); - } + else if (opcode >= 250) + throw GFException("undefined GF command (opcode " + std::to_string(opcode) + ")"); else { int offset = opcode <= 73 ? 64 : 239-(73-64+1); const GFCommand &cmd = commands[opcode-offset]; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp index 87a9a75f5f2..3dfceb98cd6 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp @@ -31,16 +31,13 @@ class CharInfo; -struct GFException : public MessageException -{ - GFException (const std::string &msg) : MessageException(msg) {} +struct GFException : public MessageException { + explicit GFException (const std::string &msg) : MessageException(msg) {} }; -class GFReader -{ - struct CharInfo - { +class GFReader { + struct CharInfo { CharInfo () : dx(0), dy(0), width(0), location(0) {} CharInfo (int32_t dxx, int32_t dyy, int32_t w, uint32_t p) : dx(dxx), dy(dyy), width(w), location(p) {} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp index 6e7875eba39..8fe746cc05d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp @@ -24,12 +24,10 @@ #include <istream> #include "GFReader.hpp" -class GFTracer : public GFReader -{ +class GFTracer : public GFReader { public: - GFTracer (std::istream &is); + explicit GFTracer (std::istream &is); GFTracer (std::istream &is, double upp); - virtual ~GFTracer () =default; virtual void moveTo (double x, double y) =0; virtual void lineTo (double x, double y) =0; virtual void curveTo (double c1x, double c1y, double c2x, double c2y, double x, double y) =0; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp index ff57d213b1d..c097ace667a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp @@ -66,7 +66,7 @@ static string get_path_from_registry () { if (major_version >= 7) { char dll_path[512]; // path to Ghostscript DLL stored in the registry DWORD length = 512; - if (RegGetValueA(hkey, subkey, "GS_DLL", RRF_RT_REG_SZ, 0, dll_path, &length) == ERROR_SUCCESS) { + if (RegGetValueA(hkey, subkey, "GS_DLL", RRF_RT_REG_SZ, nullptr, dll_path, &length) == ERROR_SUCCESS) { RegCloseKey(hkey); return dll_path; } @@ -160,7 +160,6 @@ Ghostscript::Ghostscript () : DLLoader(get_libgs(LIBGS_NAME)) #endif { - _inst = 0; } @@ -173,7 +172,6 @@ Ghostscript::Ghostscript (int argc, const char **argv, void *caller) : DLLoader(get_libgs(LIBGS_NAME)) #endif { - _inst = 0; init(argc, argv, caller); } @@ -191,12 +189,12 @@ bool Ghostscript::init (int argc, const char **argv, void *caller) { if (!_inst) { int status = new_instance(&_inst, caller); if (status < 0) - _inst = 0; + _inst = nullptr; else { init_with_args(argc, const_cast<char**>(argv)); } } - return _inst != 0; + return _inst != nullptr; } @@ -257,7 +255,7 @@ int Ghostscript::new_instance (void **psinst, void *caller) { #else if (auto fn = LOAD_SYMBOL(gsapi_new_instance)) return fn(psinst, caller); - *psinst = 0; + *psinst = nullptr; return 0; #endif } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp index 676da3909d8..4ea62f775f5 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp @@ -73,10 +73,10 @@ class Ghostscript public: Ghostscript (); - Ghostscript (int argc, const char **argv, void *caller=0); + Ghostscript (int argc, const char **argv, void *caller=nullptr); Ghostscript (const Ghostscript &gs) =delete; ~Ghostscript (); - bool init (int argc, const char **argv, void *caller=0); + bool init (int argc, const char **argv, void *caller=nullptr); bool available (); bool revision (gsapi_revision_t *r); int revision (); @@ -96,7 +96,7 @@ class Ghostscript void delete_instance (); private: - void *_inst; ///< Ghostscript handle needed to call the gsapi_foo functions + void *_inst = nullptr; ///< Ghostscript handle needed to call the gsapi_foo functions }; #endif // DISABLE_GS diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp index 579d6720b94..8a41b811d99 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp @@ -25,12 +25,11 @@ #include "GFGlyphTracer.hpp" #include "Message.hpp" -class GlyphTracerMessages : public GFGlyphTracer::Callback -{ +class GlyphTracerMessages : public GFGlyphTracer::Callback { public: - GlyphTracerMessages (bool sfmsg=true, bool autonl=true) : _sfmsg(sfmsg), _autonl(autonl), _traced(false) {} + explicit GlyphTracerMessages (bool sfmsg=true, bool autonl=true) : _sfmsg(sfmsg), _autonl(autonl), _traced(false) {} - ~GlyphTracerMessages () { + ~GlyphTracerMessages () override { if (_autonl) Message::mstream() << '\n'; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp index 31e8e3521d1..78b29d46307 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp @@ -18,17 +18,148 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#ifndef GRAPHICSPATH_HPP -#define GRAPHICSPATH_HPP +#pragma once +#include <array> #include <cctype> #include <deque> #include <ostream> +#include <type_traits> +#include <mpark/variant.hpp> #include "BoundingBox.hpp" +#include "EllipticalArc.hpp" #include "Matrix.hpp" #include "Pair.hpp" +#include "utility.hpp" #include "XMLString.hpp" +template <typename T> +class GraphicsPath; + +namespace gp { + +/// Base class for all path data commands, like moveto, lineto, curveto, etc. +struct CommandBase {}; + +/** Base class for all path data commands with NUM_POINTS point parameters + * @tparam NUM_POINTS number of parameter pairs representing points, e.g. 1 for moveto and lineto */ +template <typename T, int NUM_POINTS> +class Command : public CommandBase { + friend class GraphicsPath<T>; + public: + int numPoints () const {return NUM_POINTS;} + Pair<T>& point (int n) {return points[n];} + const Pair<T>& point (int n) const {return points[n];} + + /** Transforms the command by a given transformation matrix. + * @params[in] matrix describes the affine transformation to apply + * @params[in] currentPoint the untransformed end point of the preceding command */ + void transform (const Matrix &matrix, const Pair<T> ¤tPoint) { + for (Pair<T> &p : points) + p = matrix * p; + } + + /** Returns true if all points are identical to those of another command. */ + bool pointsEqual (const Command &cmd) const { + for (int i=0; i < NUM_POINTS; i++) + if (points[i] != cmd.points[i]) + return false; + return true; + } + + protected: + explicit Command () =default; + explicit Command (std::array<Pair<T>, NUM_POINTS> &&pts) : points(std::move(pts)) {} + + protected: + std::array<Pair<T>, NUM_POINTS> points; +}; + +template <typename T> +struct MoveTo : public Command<T, 1> { + explicit MoveTo (const Pair<T> &p) : Command<T, 1>({p}) {} +}; + +template <typename T> +struct LineTo : public Command<T, 1> { + explicit LineTo (const Pair<T> &p) : Command<T, 1>({p}) {} +}; + +template <typename T> +struct CubicTo : public Command<T, 3> { + explicit CubicTo (const Pair<T> &p1, const Pair<T> &p2, const Pair<T> &p3) : Command<T, 3>({p1, p2, p3}) {} +}; + +template <typename T> +struct QuadTo : public Command<T, 2> { + explicit QuadTo (const Pair<T> &p1, const Pair<T> &p2) : Command<T, 2>({p1, p2}) {} +}; + +template <typename T> +struct ClosePath : public Command<T, 0> { + ClosePath () : Command<T, 0>() {} +}; + +template <typename T> +struct ArcTo : Command<T, 1> { + ArcTo (T rxx, T ryy, double xrot, bool laf, bool sf, const Pair<T> &pp) + : Command<T, 1>({pp}), rx(rxx < 0 ? -rxx : rxx), ry(ryy < 0 ? -ryy : ryy), + xrotation(xrot), largeArcFlag(laf), sweepFlag(sf) {} + + bool operator == (const ArcTo &arc) const { + return rx == arc.rx + && ry == arc.ry + && xrotation == arc.xrotation + && largeArcFlag == arc.largeArcFlag + && sweepFlag == arc.sweepFlag + && this->points[0] == arc.points[0]; + } + + void transform (const Matrix &matrix, const Pair<T> ¤tPoint); + + bool operator != (const ArcTo &arc) const {return !(*this == arc);} + + T rx, ry; ///< length of the semi-major and semi-minor axes + double xrotation; ///< rotation of the semi-major axis in degrees + bool largeArcFlag; ///< if true, the longer arc from start to end point is chosen, else the shorter one + bool sweepFlag; ///< if true, arc is drawn in direction of positive angles, else the opposite direction +}; + +/** Applies an affine transformation described by a given matrix to the arc segment. + * @params[in] matrix describes the affine transformation to apply + * @params[in] currentPoint the untransformed end point of the preceding command */ +template <typename T> +void ArcTo<T>::transform (const Matrix &matrix, const Pair<T> ¤tPoint) { + EllipticalArc arc(currentPoint, rx, ry, math::deg2rad(xrotation), largeArcFlag, sweepFlag, this->points[0]); + arc.transform(matrix); + rx = arc.rx(); + ry = arc.ry(); + xrotation = math::rad2deg(arc.rotationAngle()); + largeArcFlag = arc.largeArc(); + sweepFlag = arc.sweepPositive(); + this->points[0] = Pair<T>(arc.endPoint()); +} + +/** Returns true if two path command objects are identical (same command and same parameters). */ +template <typename Cmd1, typename Cmd2> +inline typename std::enable_if<std::is_base_of<CommandBase, Cmd1>::value, bool>::type +operator == (const Cmd1 &cmd1, const Cmd2 &cmd2) { + if (std::is_convertible<Cmd1, Cmd2>::value && std::is_convertible<Cmd2, Cmd1>::value) + return cmd1.pointsEqual(cmd2); + return false; +} + +/** Returns true if two path command objects differ (different commands or different parameters). */ +template <typename Cmd1, typename Cmd2> +inline typename std::enable_if<std::is_base_of<CommandBase, Cmd1>::value, bool>::type +operator != (const Cmd1 &cmd1, const Cmd2 &cmd2) { + if (std::is_convertible<Cmd1, Cmd2>::value && std::is_convertible<Cmd2, Cmd1>::value) + return !cmd1.pointsEqual(cmd2); + return true; +} + +} // namespace gp + template <typename T> class GraphicsPath { @@ -37,78 +168,272 @@ class GraphicsPath { enum class WindingRule {EVEN_ODD, NON_ZERO}; using Point = Pair<T>; - struct Command { - enum class Type {MOVETO, LINETO, CONICTO, CUBICTO, CLOSEPATH}; + protected: - Command (Type t) : type(t) {} + static XMLString to_param_str (double v, double s, double d, bool leadingSpace) { + XMLString str(v*s + d); + if (leadingSpace && (str[0] != '-')) + str.insert(0, " "); + return str; + } - Command (Type t, const Point &p) : type(t) { - params[0] = p; - } + static XMLString to_param_str (double val, double prev, double s, double d, bool leadingSpace) { + XMLString str((val-prev)*s + d); + if (leadingSpace && (str[0] != '-')) + str.insert(0, " "); + return str; + } - Command (Type t, const Point &p1, const Point &p2) : type(t) { - params[0] = p1; - params[1] = p2; - } + static std::string to_param_str (const Point &p, double sx, double sy, double dx, double dy, bool leadingSpace) { + return to_param_str(p.x(), sx, dx, leadingSpace) + to_param_str(p.y(), sy, dy, true); + } - Command (Type t, const Point &p1, const Point &p2, const Point &p3) : type(t) { - params[0] = p1; - params[1] = p2; - params[2] = p3; - } + static std::string to_param_str (const Point &p, const Point &prev, double sx, double sy, double dx, double dy, bool leadingSpace) { + return to_param_str(p.x()-prev.x(), sx, dx, leadingSpace) + to_param_str(p.y()-prev.y(), sy, dy, true); + } + + using MoveTo = gp::MoveTo<T>; + using LineTo = gp::LineTo<T>; + using CubicTo = gp::CubicTo<T>; + using QuadTo = gp::QuadTo<T>; + using ArcTo = gp::ArcTo<T>; + using ClosePath = gp::ClosePath<T>; + + /// Variant representing a single path command + using CommandVariant = mpark::variant<MoveTo, LineTo, CubicTo, QuadTo, ArcTo, ClosePath>; + + class IterationVisitor; + + public: + /** Base class providing several template methods being called when executing + * GraphicsPath::iterate(). */ + class IterationActions { + friend class IterationVisitor; + public: + virtual ~IterationActions () =default; + virtual void moveto (const Point &p) {} + virtual void lineto (const Point &p) {} + virtual void hlineto (const T &x) {} + virtual void vlineto (const T &y) {} + virtual void quadto (const Point &p) {} + virtual void quadto (const Point &p1, const Point &p2) {} + virtual void cubicto (const Point &p1, const Point &p2) {} + virtual void cubicto (const Point &p1, const Point &p2, const Point &p3) {} + virtual void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) {} + virtual void closepath () {} + virtual bool quit () {return false;} + virtual void finished () {} + const Point& startPoint () const {return _startPoint;} + const Point& currentPoint () const {return _currentPoint;} + + private: + Point _startPoint; ///< first point of the current sub-path + Point _currentPoint; ///< point reached by preceding path command, or (0,0) otherwise + }; + + protected: + class ModificationActions : public IterationActions { + friend class GraphicsPath; + public: + explicit ModificationActions (GraphicsPath &path) : _path(path) {} - int numParams () const { - switch (type) { - case Type::CLOSEPATH : return 0; - case Type::MOVETO : - case Type::LINETO : return 1; - case Type::CONICTO : return 2; - case Type::CUBICTO : return 3; + protected: + GraphicsPath& path () {return _path;} + int commandPos () const {return _commandPos;} + + private: + GraphicsPath &_path; + int _commandPos=0; ///< number of command in path being processed + }; + + class WriteActions : public IterationActions { + public: + WriteActions (std::ostream &os, bool rel, double sx, double sy, double dx, double dy) + : _os(os), _relative(rel), _sx(sx), _sy(sy), _dx(dx), _dy(dy) {} + + void moveto (const Point &p) override {write('M', {p});} + void lineto (const Point &p) override {write('L', {p});} + void hlineto (const T &x) override {write('H', x, this->currentPoint().x(), _sx, _dx);} + void vlineto (const T &y) override {write('V', y, this->currentPoint().y(), _sy, _dy);} + void quadto (const Point &p) override {write('T', {p});} + void quadto (const Point &p1, const Point &p2) override {write('Q', {p1, p2});} + void cubicto (const Point &p1, const Point &p2) override {write('S', {p1, p2});} + void cubicto (const Point &p1, const Point &p2, const Point &p3) override {write('C', {p1, p2, p3});} + void closepath () override {_os << (_relative ? 'z' : 'Z');} + + void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) override { + Point diff = p-this->currentPoint(); + if (std::abs(diff.x()) < 1e-7 && std::abs(diff.y()) < 1e-7) + return; + if (std::abs(rx) < 1e-7 && std::abs(ry) < 1e-7) + lineto(p); + else { + if (std::abs(std::abs(_sx) - std::abs(_sy)) < 1e-7) { // symmetric scaling? + angle *= math::sgn(_sx) * math::sgn(_sy); + rx *= std::abs(_sx); + ry *= std::abs(_sx); + } + else { // asymmetric scaling => compute new shape parameters + EllipticalArc arc(this->currentPoint(), double(rx), double(ry), math::deg2rad(angle), largeArcFlag, sweepFlag, p); + arc.transform(ScalingMatrix(_sx, _sy)); + angle = math::rad2deg(arc.rotationAngle()); + rx = arc.rx(); + ry = arc.ry(); + } + _os << (_relative ? 'a' : 'A') + << to_param_str(rx, 1.0, 0, false) + << to_param_str(ry, 1.0, 0, true) + << to_param_str(angle, 1.0, 0, true) + << ' ' << (largeArcFlag ? 1 : 0) + << ' ' << (sweepFlag ? 1 : 0); + if (_relative) + _os << to_param_str(p, this->currentPoint(), _sx, _sy, _dx, _dy, true); + else + _os << to_param_str(p, _sx, _sy, _dx, _dy, true); + } } - return 0; - } - void transform (const Matrix &matrix) { - for (int i=0; i < numParams(); i++) - params[i] = matrix * params[i]; - } + protected: + void write (char cmdchar, std::initializer_list<Point> points) const { + int count=0; + if (_relative) { + _os << char(tolower(cmdchar)); + for (const Point &p : points) + _os << to_param_str(p, this->currentPoint(), _sx, _sy, _dx, _dy, count++ > 0); + } + else { + _os << cmdchar; + for (const Point &p : points) + _os << to_param_str(p, _sx, _sy, _dx, _dy, count++ > 0); + } + } - bool operator == (const Command &cmd) const { - bool ret = (type == cmd.type); - for (int i=0; ret && i < numParams(); i++) - ret &= (params[i] == cmd.params[i]); - return ret; - } + void write (char cmdchar, T val, T relval, double s, double d) const { + if (_relative) + _os << char(tolower(cmdchar)) << to_param_str(val, relval, s, d, false); + else + _os << cmdchar << to_param_str(val, s, d, false); + } - bool operator != (const Command &cmd) const { - bool ret = (type != cmd.type); - for (int i=0; !ret && i < numParams(); i++) - ret |= (params[i] != cmd.params[i]); - return ret; - } + private: + std::ostream &_os; ///< write output to this stream + bool _relative; ///< if true, use relative coordinates in path commands + double _sx, _sy; ///< horizontal and vertical scaling factors + double _dx, _dy; ///< horizontal and vertical translation values + }; + + /////////////////////////////////////////////////////////////////////////////// + + /** Calls the corresponding template method of an Action object for the current path command. + * If parameter 'useShortCmds' is true, the visitor operators check whether a command + * can be shortened due to special cases, e.g. horizontal or vertical lines, smooth + * curve connections etc. Otherwise, the full command templates are triggered. */ + class IterationVisitor { + public: + IterationVisitor (IterationActions &actions, bool useShortCmds, double eps=1e-7) + : _actions(actions), _shortCommandsActive(useShortCmds), _eps(eps) {} + + void setPrevCommand (const CommandVariant &prevCommand) { + _prevCommand = &prevCommand; + } + + void operator () (const MoveTo &cmd) { + _actions.moveto(cmd.points[0]); + _actions._startPoint = _actions._currentPoint = cmd.points[0]; + } + + void operator () (const LineTo &cmd) { + Point diff = abs(_actions._currentPoint-cmd.points[0]); + if (diff.x() >= _eps || diff.y() >= _eps) { + if (!_shortCommandsActive) + _actions.lineto(cmd.points[0]); + else { + if (diff.x() < _eps) + _actions.vlineto(cmd.points[0].y()); + else if (diff.y() < _eps) + _actions.hlineto(cmd.points[0].x()); + else + _actions.lineto(cmd.points[0]); + } + } + _actions._currentPoint = cmd.points[0]; + } + + void operator () (const CubicTo &cmd) { + bool smooth=false; + if (_shortCommandsActive) { + if (auto *prevCubic = mpark::get_if<CubicTo>(_prevCommand)) { + Point diff = abs(cmd.points[0] - prevCubic->points[2]*T(2) + prevCubic->points[1]); + if ((smooth = (diff.x() < _eps && diff.y() < _eps))) + _actions.cubicto(cmd.points[1], cmd.points[2]); + } + } + if (!smooth) + _actions.cubicto(cmd.points[0], cmd.points[1], cmd.points[2]); + _actions._currentPoint = cmd.points[2]; + } + + void operator () (const QuadTo &cmd) { + bool smooth=false; + if (_shortCommandsActive) { + if (auto *prevQuad = mpark::get_if<QuadTo>(_prevCommand)) { + Point diff = abs(cmd.points[0] - prevQuad->points[1] * T(2) + prevQuad->points[0]); + if ((smooth = (diff.x() < _eps && diff.y() < _eps))) // is reflection? + _actions.quadto(cmd.points[1]); + } + } + if (!smooth) + _actions.quadto(cmd.points[0], cmd.points[1]); + _actions._currentPoint = cmd.points[1]; + } + + void operator () (const ClosePath &cmd) { + _actions.closepath(); + _actions._currentPoint = _actions._startPoint; + } + + void operator () (const ArcTo &cmd) { + _actions.arcto(cmd.rx, cmd.ry, cmd.xrotation, cmd.largeArcFlag, cmd.sweepFlag, cmd.points[0]); + _actions._currentPoint = cmd.points[0]; + } - Type type; - Point params[3]; + private: + IterationActions &_actions; + bool _shortCommandsActive=false; + double _eps=1e-7; + const CommandVariant *_prevCommand=nullptr; }; - struct Actions { - virtual ~Actions () =default; - virtual void moveto (const Point &p) {} - virtual void lineto (const Point &p) {} - virtual void hlineto (const T &y) {} - virtual void vlineto (const T &x) {} - virtual void conicto (const Point &p) {} - virtual void conicto (const Point &p1, const Point &p2) {} - virtual void cubicto (const Point &p1, const Point &p2) {} - virtual void cubicto (const Point &p1, const Point &p2, const Point &p3) {} - virtual void closepath () {} - virtual void draw (char cmd, const Point *points, int n) {} - virtual bool quit () {return false;} - virtual void finished () {} + /////////////////////////////////////////////////////////////////////////////// + + /** Transforms all Point parameters of a path command. */ + class TransformVisior { + public: + explicit TransformVisior (const Matrix &m) : matrix(m) {} + + template <typename Cmd> void operator () (Cmd &cmd) { + Point cp = cmd.point(cmd.numPoints()-1); + cmd.transform(matrix, _currentPoint); + _currentPoint = cp; + } + + void operator () (MoveTo &cmd) { + Point cp = cmd.point(0); + cmd.transform(matrix, _currentPoint); + _startPoint = _currentPoint = cp; + } + + void operator () (ClosePath &cmd) { + _currentPoint = _startPoint; + } + + private: + const Matrix &matrix; + Point _startPoint, _currentPoint; ///< untransformed start end current point }; public: - GraphicsPath (WindingRule wr=WindingRule::NON_ZERO) : _windingRule(wr) {} + explicit GraphicsPath (WindingRule wr=WindingRule::NON_ZERO) : _windingRule(wr) {} void setWindingRule (WindingRule wr) {_windingRule = wr;} WindingRule windingRule () const {return _windingRule;} @@ -127,6 +452,9 @@ class GraphicsPath { return _commands.size(); } + const Point& startPoint () const {return _startPoint;} + const Point& finalPoint () const {return _finalPoint;} + /// Insert another path at the beginning of this one. void prepend (const GraphicsPath &path) { _commands.insert(_commands.begin(), path._commands.begin(), path._commands.end()); @@ -138,10 +466,11 @@ class GraphicsPath { void moveto (const Point &p) { // avoid sequences of several MOVETOs; always use latest - if (_commands.empty() || _commands.back().type != Command::Type::MOVETO) - _commands.emplace_back(Command(Command::Type::MOVETO, p)); + if (_commands.empty() || !mpark::get_if<MoveTo>(&_commands.back())) + _commands.emplace_back(MoveTo{p}); else - _commands.back().params[0] = p; + mpark::get<MoveTo>(_commands.back()).points[0] = p; + _startPoint = _finalPoint = p; } void lineto (const T &x, const T &y) { @@ -149,57 +478,94 @@ class GraphicsPath { } void lineto (const Point &p) { - _commands.emplace_back(Command(Command::Type::LINETO, p)); + _commands.emplace_back(LineTo{p}); + _finalPoint = p; } - void conicto (const T &x1, const T &y1, const T &x2, const T &y2) { - conicto(Point(x1, y1), Point(x2, y2)); + void quadto (const T &x1, const T &y1, const T &x2, const T &y2) { + quadto(Point(x1, y1), Point(x2, y2)); } - void conicto (const Point &p1, const Point &p2) { - _commands.emplace_back(Command(Command::Type::CONICTO, p1, p2)); + /** Creates a quadratic Bézier segment. */ + void quadto (const Point &p1, const Point &p2) { + _commands.emplace_back(QuadTo{p1, p2}); + _finalPoint = p2; + } + + /** Creates a quadratic Bézier segment smoothly extending a preceding one, i.e. the gradients + * of the two curves are identical at the connection point. The control point of the second + * curve is computed as the reflection of the preceding curve's control point at the connection + * point. */ + void quadto (const Point &p2) { + Point p1; + if (!_commands.empty()) { + if (auto qto = mpark::get_if<QuadTo>(&_commands.back())) + p1 = _finalPoint*T(2) - qto->point(0); // reflect previous control point at current point + else // previous command isn't a quadto? + p1 = _finalPoint; // => use current point as control point + } + quadto(p1, p2); } void cubicto (const T &x1, const T &y1, const T &x2, const T &y2, const T &x3, const T &y3) { cubicto(Point(x1, y1), Point(x2, y2), Point(x3, y3)); } + /** Creates a cubic Bézier segment. */ void cubicto (const Point &p1, const Point &p2, const Point &p3) { - _commands.emplace_back(Command(Command::Type::CUBICTO, p1, p2, p3)); + _commands.emplace_back(CubicTo{p1, p2, p3}); + _finalPoint = p3; } - void closepath () { - _commands.emplace_back(Command(Command::Type::CLOSEPATH)); + /** Creates a cubic Bézier segment smoothly extending a preceding one, i.e. the gradients + * of the two curves are identical at the connection point. The first control point of + * the second curve is computed as the reflection of the preceding curve's second control + * point at the connection point. */ + void cubicto (const Point &p2, const Point &p3) { + Point p1; + if (!_commands.empty()) { + if (auto cto = mpark::get_if<CubicTo>(&_commands.back())) + p1 = _finalPoint*T(2) - cto->point(1); // reflect previous control point at current point + else // previous command isn't a cubicto? + p1 = _finalPoint; // => use current point as control point + } + cubicto(p1, p2, p3); } - const std::vector<Command>& commands () const { - return _commands; + void closepath () { + if (!_commands.empty() && !mpark::get_if<ClosePath>(&_commands.back())) { + _commands.emplace_back(ClosePath{}); + _finalPoint = _startPoint; + } } + void arcto (double rx, double ry, double angle, bool laf, bool sweep, const Point &p) { + _commands.emplace_back(ArcTo{rx, ry, angle, laf, sweep, p}); + _finalPoint = p; + } /** Detects all open subpaths and closes them by adding a closePath command. * Most font formats only support closed outline paths so there are no explicit closePath statements * in the glyph's outline description. All open paths are automatically closed by the renderer. * This method detects all open paths and adds the missing closePath statement. */ void closeOpenSubPaths () { - Command *prevCommand=0; + CommandVariant *prevCmd = nullptr; for (auto it=_commands.begin(); it != _commands.end(); ++it) { - if (it->type == Command::Type::MOVETO && prevCommand && prevCommand->type != Command::Type::CLOSEPATH) { - prevCommand = &(*it); - it = _commands.insert(it, Command(Command::Type::CLOSEPATH))+1; + if (mpark::get_if<MoveTo>(&*it) && prevCmd && !mpark::get_if<ClosePath>(prevCmd)) { + prevCmd = &*it; + it = _commands.insert(it, ClosePath{})+1; } else - prevCommand = &(*it); + prevCmd = &*it; } - if (!_commands.empty() && _commands.back().type != Command::Type::CLOSEPATH) + if (!_commands.empty() && !mpark::get_if<ClosePath>(&_commands.back())) closepath(); } - - /** Removes redundant path commands commands. Currently, it only removes movetos. */ + /** Removes redundant path commands commands. Currently, only removes movetos. */ void removeRedundantCommands () { // remove trailing moveto commands - while (!_commands.empty() && _commands.back().type == Command::Type::MOVETO) + while (!_commands.empty() && mpark::get_if<MoveTo>(&_commands.back())) _commands.pop_back(); // resolve intermediate sequences of moveto commands auto it=_commands.begin(); @@ -207,7 +573,7 @@ class GraphicsPath { return; auto prev = it++; while (it != _commands.end()) { - if (prev->type != Command::Type::MOVETO || it->type != Command::Type::MOVETO) + if (!mpark::get_if<MoveTo>(&*prev) || !mpark::get_if<MoveTo>(&*it)) prev = it++; else { prev = _commands.erase(prev); // remove leading MOVETO and advance 'prev' to 'it' @@ -216,7 +582,6 @@ class GraphicsPath { } } - /** Writes the path data as SVG path drawing command to a given output stream. * @param[in] os output stream used to write the SVG commands to * @param[in] relative if true, create relative rather than absolute coordinate values @@ -225,94 +590,38 @@ class GraphicsPath { * @param[in] dx horizontal translation in PS point units * @param[in] dy vertical translation in PS point units */ void writeSVG (std::ostream &os, bool relative, double sx=1.0, double sy=1.0, double dx=0.0, double dy=0.0) const { - struct WriteActions : Actions { - WriteActions (std::ostream &os, bool relative, double sx, double sy, double dx, double dy) - : _os(os), _relative(relative), _sx(sx), _sy(sy), _dx(dx), _dy(dy) {} - - void draw (char cmd, const Point *points, int n) override { - if (_relative) - cmd = tolower(cmd); - _os << cmd; - switch (cmd) { - case 'h': _os << XMLString(_sx*(points->x()-_currentPoint.x())+_dx); break; - case 'v': _os << XMLString(_sy*(points->y()-_currentPoint.y())+_dy); break; - case 'z': _currentPoint = _startPoint; break; - case 'H': _os << XMLString(_sx*points->x()+_dx); break; - case 'V': _os << XMLString(_sy*points->y()+_dy); break; - default : - for (int i=0; i < n; i++) { - if (i > 0) - _os << ' '; - Point p = points[i]; - if (_relative) - p -= _currentPoint; - _os << XMLString(_sx*p.x()+_dx) << ' ' << XMLString(_sy*p.y()+_dy); - } - } - if (cmd == 'm') - _startPoint = points[0]; - if (islower(cmd) && n > 0) - _currentPoint = points[n-1]; - } - std::ostream &_os; - bool _relative; - double _sx, _sy, _dx, _dy; - Point _startPoint, _currentPoint; - } actions(os, relative, sx, sy, dx, dy); + WriteActions actions(os, relative, sx, sy, dx, dy); iterate(actions, true); } -#if 0 - void writePS (std::ostream &os, double sx=1.0, double sy=1.0, double dx=0.0, double dy=0.0) const { - struct WriteActions : Actions { - WriteActions (std::ostream &os, double sx, double sy, double dx, double dy) - : _os(os), _sx(sx), _sy(sy), _dx(dx), _dy(dy) {} - void draw (char cmd, const Point *points, int n) { - for (int i=0; i < n; i++) - _os << _sx*points[i].x()+_dx << ' ' << _sy*points[i].y()+_dy << ' '; - switch (cmd) { - case 'M': _os << "moveto"; break; - case 'L': _os << "lineto"; break; - case 'C': _os << "curveto"; break; - case 'Z': _os << "closepath"; break; - default: ; - } - _os << '\n'; - } - std::ostream &_os; - bool _relative; - double _sx, _sy, _dx, _dy; - } actions(os, sx, sy, dx, dy); - iterate(actions, false); - } -#endif - - /** Computes the bounding box of the current path. * @param[out] bbox the computed bounding box */ void computeBBox (BoundingBox &bbox) const { - struct BBoxActions : Actions { - BBoxActions (BoundingBox &bb) : bbox(bb) {} + struct BBoxActions : IterationActions { + explicit BBoxActions (BoundingBox &bb) : bbox(bb) {} void moveto (const Point &p) override {bbox.embed(p);} void lineto (const Point &p) override {bbox.embed(p);} - void conicto (const Point &p1, const Point &p2) override {bbox.embed(p1); bbox.embed(p2);} + void quadto (const Point &p1, const Point &p2) override {bbox.embed(p1); bbox.embed(p2);} void cubicto (const Point &p1, const Point &p2, const Point &p3) override {bbox.embed(p1); bbox.embed(p2); bbox.embed(p3);} + void arcto (T rx, T ry, double angle, bool laf, bool sweep, const Point &p) override { + bbox.embed(EllipticalArc(this->currentPoint(), double(rx), double(ry), angle, laf, sweep, p).getBBox()); + } BoundingBox &bbox; } actions(bbox); iterate(actions, false); } - /** Checks whether the current path describes a dot/point only (with no extent). * @param[out] p coordinates of the point if path describes a dot * @return true if path is a dot/point */ bool isDot (Point &p) const { - struct DotActions : Actions { + struct DotActions : IterationActions { DotActions () : differs(false) {} void moveto (const Point &p) override {point = p;} void lineto (const Point &p) override {differs = (p != point);} - void conicto (const Point &p1, const Point &p2) override {differs = (point != p1 || point != p2);} + void quadto (const Point &p1, const Point &p2) override { differs = (point != p1 || point != p2);} void cubicto (const Point &p1, const Point &p2, const Point &p3) override {differs = (point != p1 || point != p2 || point != p3);} + void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) override { differs = (point != p);} bool quit () override {return differs;} Point point; bool differs; @@ -322,125 +631,105 @@ class GraphicsPath { return !actions.differs; } + /** Replaces all elliptic arcs with cubic Bézier curves. */ + void approximateArcs () { + struct ArcActions : ModificationActions { + explicit ArcActions (GraphicsPath &path) : ModificationActions(path) {} + void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) override { + EllipticalArc arc(this->currentPoint(), rx, ry, angle, largeArcFlag, sweepFlag, p); + std::vector<CommandVariant> cmds; + for (const Bezier &bezier : arc.approximate()) + cmds.emplace_back(CubicTo{bezier.point(1), bezier.point(2), bezier.point(3)}); + this->path().replace(this->commandPos(), cmds); + } + } actions(*this); + iterate(actions); + } /** Transforms the path according to a given Matrix. * @param[in] matrix Matrix describing the affine transformation */ void transform (const Matrix &matrix) { - for (Command &command : _commands) - command.transform(matrix); + TransformVisior visior(matrix); + for (CommandVariant &command : _commands) + mpark::visit(visior, command); } - + /** Returns true if this path equals another one, i.e. it consists the same sequence + * of commands and coordinates. */ bool operator == (const GraphicsPath &path) const { if (size() != path.size()) return false; auto it = _commands.begin(); - for (const Command &cmd : path._commands) { + for (const auto &cmd : path._commands) { if (*it++ != cmd) return false; } return true; } - + /** Returns true if this path differs from another one (command-wise). */ bool operator != (const GraphicsPath &path) const { if (size() != path.size()) return true; auto it = _commands.begin(); - for (const Command &cmd : path._commands) { + for (const auto &cmd : path._commands) { if (*it++ != cmd) return true; } return false; } + /** Iterates over all commands defining this path and calls the corresponding template methods. + * In the case of successive bezier curve sequences, control points or tangent slopes are often + * identical so that the path description contains redundant information. SVG provides shorthand + * curve commands that require less parameters. If 'optimize' is true, this method detects such + * command sequences. + * @param[in] actions template methods called by each iteration step + * @param[in] optimize if true, shorthand drawing commands (hlineto, vlineto,...) are considered */ + void iterate (IterationActions &actions, bool optimize) const { + double eps = XMLString::DECIMAL_PLACES > 0 ? pow(10, -XMLString::DECIMAL_PLACES) : 1e-7; + IterationVisitor visitor(actions, optimize, eps); + for (const CommandVariant &cmd : _commands) { + if (actions.quit()) + break; + mpark::visit(visitor, cmd); + visitor.setPrevCommand(cmd); + } + actions.finished(); + } - void iterate (Actions &actions, bool optimize) const; + protected: + /** Replaces a command by a sequence of other ones. + * @param[in] pos position of command to replace (0-based) + * @param[in] cmds commands to insert */ + void replace (int pos, const std::vector<CommandVariant> &cmds) { + auto it = _commands.end(); + if (!_commands.empty()) { + it = _commands.begin()+pos; + it = _commands.erase(it); + } + _commands.insert(it, cmds.begin(), cmds.end()); + } + + /** Iterates over all commands of the path and calls the corresponding template methods. + * In contrast to the public iterate() method, this one allows to modify the command sequence. + * @param[in] actions template methods called by each iteration step */ + void iterate (ModificationActions &actions) { + IterationVisitor visitor(actions, false); + // no iterators here since they may be invalidated during path modifications + for (size_t i=0; i < _commands.size(); i++) { + if (actions.quit()) + break; + actions._commandPos = i; + mpark::visit(visitor, _commands[i]); + visitor.setPrevCommand(_commands[i]); + } + actions.finished(); + } private: - std::deque<Command> _commands; + std::deque<CommandVariant> _commands; ///< sequence of path commands WindingRule _windingRule; + Point _startPoint; ///< start point of final sub-path + Point _finalPoint; ///< final point reached by last command in path }; - - -/** Iterates over all commands defining this path and calls the corresponding template methods. - * In the case of successive bezier curve sequences, control points or tangent slopes are often - * identical so that the path description contains redundant information. SVG provides shorthand - * curve commands that require less parameters. If 'optimize' is true, this method detects such - * command sequences. - * @param[in] actions template methods called by each iteration step - * @param[in] optimize if true, shorthand drawing commands (hlineto, vlineto,...) are considered */ -template <typename T> -void GraphicsPath<T>::iterate (Actions &actions, bool optimize) const { - auto prev = _commands.end(); // pointer to preceding command - Point fp; // first point of current path - Point cp; // current point - Point pstore[2]; - for (auto it=_commands.begin(); it != _commands.end() && !actions.quit(); ++it) { - const Point *params = it->params; - switch (it->type) { - case Command::Type::MOVETO: - actions.moveto(params[0]); - actions.draw('M', params, 1); - fp = params[0]; - break; - case Command::Type::LINETO: - if (optimize) { - if (cp.x() == params[0].x()) { - actions.vlineto(params[0].y()); - actions.draw('V', params, 1); - } - else if (cp.y() == params[0].y()) { - actions.hlineto(params[0].x()); - actions.draw('H', params, 1); - } - else { - actions.lineto(params[0]); - actions.draw('L', params, 1); - } - } - else { - actions.lineto(params[0]); - actions.draw('L', params, 1); - } - break; - case Command::Type::CONICTO: - if (optimize && prev != _commands.end() && prev->type == Command::Type::CONICTO && params[0] == pstore[1]*T(2)-pstore[0]) { - actions.conicto(params[1]); - actions.draw('T', params+1, 1); - } - else { - actions.conicto(params[0], params[1]); - actions.draw('Q', params, 2); - } - pstore[0] = params[0]; // store control point and - pstore[1] = params[1]; // curve endpoint - break; - case Command::Type::CUBICTO: - // is first control point reflection of preceding second control point? - if (optimize && prev != _commands.end() && prev->type == Command::Type::CUBICTO && params[0] == pstore[1]*T(2)-pstore[0]) { - actions.cubicto(params[1], params[2]); - actions.draw('S', params+1, 2); - } - else { - actions.cubicto(params[0], params[1], params[2]); - actions.draw('C', params, 3); - } - pstore[0] = params[1]; // store second control point and - pstore[1] = params[2]; // curve endpoint - break; - case Command::Type::CLOSEPATH: - actions.closepath(); - actions.draw('Z', params, 0); - cp = fp; - } - // update current point - const int np = it->numParams(); - if (np > 0) - cp = it->params[np-1]; - prev = it; - } - actions.finished(); -} - -#endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp index 7479fca604f..517cc8f3ccb 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp @@ -31,7 +31,12 @@ using namespace std; /** Returns a vector containing the names of the currently supported hash algorithms. */ vector<string> HashFunction::supportedAlgorithms () { - return vector<string> {"md5", "xxh32", "xxh64"}; + return vector<string> { + "md5", "xxh32", "xxh64", +#ifdef ENABLE_XXH128 + "xxh128" +#endif + }; } @@ -52,6 +57,10 @@ unique_ptr<HashFunction> HashFunction::create (const string &name) { return util::make_unique<XXH32HashFunction>(); if (lowerName == "xxh64") return util::make_unique<XXH64HashFunction>(); +#ifdef ENABLE_XXH128 + if (lowerName == "xxh128") + return util::make_unique<XXH128HashFunction>(); +#endif return nullptr; } @@ -74,6 +83,15 @@ std::unique_ptr<HashFunction> HashFunction::create (const string &name, const ve } +void HashFunction::update (istream &is) { + char buf[4096]; + while (is) { + is.read(buf, 4096); + update(buf, is.gcount()); + } +} + + /** Returns the current digest as hexadecimal value. */ string HashFunction::digestString () const { ostringstream oss; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp index 1b1259393fa..bba61918ed9 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp @@ -21,6 +21,7 @@ #ifndef HASHFUNCTION_HPP #define HASHFUNCTION_HPP +#include <istream> #include <memory> #include <string> #include <vector> @@ -35,6 +36,7 @@ class HashFunction { virtual void update (const std::string &data) =0; virtual void update (const std::vector<uint8_t> &data) =0; virtual std::vector<uint8_t> digestValue () const =0; + void update (std::istream &is); std::string digestString () const; static std::vector<std::string> supportedAlgorithms (); static bool isSupportedAlgorithm (const std::string &algo); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp index b7f4e9664f6..43d3dbc2244 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp @@ -31,7 +31,7 @@ void HtmlSpecialHandler::preprocess (const string&, istream &is, SpecialActions ir.skipSpace(); // collect page number and ID of named anchors map<string,string> attribs; - if (ir.check("<a ") && ir.parseAttributes(attribs, "\"") > 0) { + if (ir.check("<a ") && ir.parseAttributes(attribs, true, "\"") > 0) { map<string,string>::iterator it; if ((it = attribs.find("name")) != attribs.end()) HyperlinkManager::instance().addNameAchor(it->second, actions.getCurrentPageNumber()); @@ -47,7 +47,7 @@ bool HtmlSpecialHandler::process (const string&, istream &is, SpecialActions &ac ir.skipSpace(); map<string,string> attribs; map<string,string>::iterator it; - if (ir.check("<a ") && ir.parseAttributes(attribs, "\"") > 0) { + if (ir.check("<a ") && ir.parseAttributes(attribs, true, "\"") > 0) { if ((it = attribs.find("href")) != attribs.end()) // <a href="URI"> HyperlinkManager::instance().createLink(it->second, actions); else if ((it = attribs.find("name")) != attribs.end()) // <a name="ID"> @@ -59,7 +59,7 @@ bool HtmlSpecialHandler::process (const string&, istream &is, SpecialActions &ac HyperlinkManager::instance().closeAnchor(actions); else if (ir.check("<img src=")) { } - else if (ir.check("<base ") && ir.parseAttributes(attribs, "\"") > 0 && (it = attribs.find("href")) != attribs.end()) + else if (ir.check("<base ") && ir.parseAttributes(attribs, true, "\"") > 0 && (it = attribs.find("href")) != attribs.end()) HyperlinkManager::instance().setBaseUrl(it->second); return true; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp index 9d610426808..de412afcdc0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp @@ -88,7 +88,7 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { string name; if (uri[0] == '#') { // reference to named anchor? name = uri.substr(1); - NamedAnchors::iterator it = _namedAnchors.find(name); + auto it = _namedAnchors.find(name); if (it == _namedAnchors.end() || it->second.id < 0) Message::wstream(true) << "reference to undefined anchor '" << name << "'\n"; else { @@ -96,7 +96,7 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { uri = "#loc"+XMLString(id); if (actions.getCurrentPageNumber() != it->second.pageno) { ostringstream oss; - oss << actions.getSVGFilename(it->second.pageno) << uri; + oss << actions.getSVGFilePath(it->second.pageno).relative() << uri; uri = oss.str(); } } @@ -106,10 +106,10 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { uri = "/" + uri; uri = _base + uri; } - auto anchorNode = util::make_unique<XMLElementNode>("a"); + auto anchorNode = util::make_unique<XMLElement>("a"); anchorNode->addAttribute("xlink:href", uri); anchorNode->addAttribute("xlink:title", XMLString(name.empty() ? uri : name, false)); - actions.pushContextElement(std::move(anchorNode)); + actions.svgTree().pushPageContext(std::move(anchorNode)); actions.bbox("{anchor}", true); // start computing the bounding box of the linked area _depthThreshold = actions.getDVIStackDepth(); _anchorType = AnchorType::HREF; @@ -119,7 +119,7 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { void HyperlinkManager::closeAnchor (SpecialActions &actions) { if (_anchorType == AnchorType::HREF) { markLinkedBox(actions); - actions.popContextElement(); + actions.svgTree().popPageContext(); _depthThreshold = 0; } _anchorType = AnchorType::NONE; @@ -148,7 +148,7 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { if (bbox.width() > 0 && bbox.height() > 0) { // does the bounding box extend in both dimensions? if (MARKER_TYPE != MarkerType::NONE) { const double linewidth = _linewidth >= 0 ? _linewidth : min(0.5, bbox.height()/15); - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); double x = bbox.minX(); double y = bbox.maxY()+linewidth; double w = bbox.width(); @@ -179,7 +179,7 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { rect->addAttribute("y", y); rect->addAttribute("width", w); rect->addAttribute("height", h); - actions.prependToPage(std::move(rect)); + actions.svgTree().prependToPage(std::move(rect)); if (MARKER_TYPE == MarkerType::BOX || MARKER_TYPE == MarkerType::BGCOLOR) { // slightly enlarge the boxed area x -= linewidth/2; @@ -192,14 +192,14 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { // Create an invisible rectangle around the linked area so that it's easier to access. // This is only necessary when using paths rather than real text elements together with fonts. if (!SVGTree::USE_FONTS) { - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", bbox.minX()); rect->addAttribute("y", bbox.minY()); rect->addAttribute("width", bbox.width()); rect->addAttribute("height", bbox.height()); rect->addAttribute("fill", "white"); rect->addAttribute("fill-opacity", 0); - actions.appendToPage(std::move(rect)); + actions.svgTree().appendToPage(std::move(rect)); } } } @@ -213,10 +213,10 @@ void HyperlinkManager::createViews (unsigned pageno, SpecialActions &actions) { ostringstream oss; oss << pagebox.minX() << ' ' << stranchorpair.second.pos << ' ' << pagebox.width() << ' ' << pagebox.height(); - auto view = util::make_unique<XMLElementNode>("view"); + auto view = util::make_unique<XMLElement>("view"); view->addAttribute("id", "loc"+XMLString(stranchorpair.second.id)); view->addAttribute("viewBox", oss.str()); - actions.appendToDefs(std::move(view)); + actions.svgTree().appendToDefs(std::move(view)); } } closeAnchor(actions); @@ -229,7 +229,7 @@ void HyperlinkManager::createViews (unsigned pageno, SpecialActions &actions) { bool HyperlinkManager::setLinkMarker (const string &marker) { string type; // "none", "box", "line", or a background color specifier string color; // optional line color specifier - size_t seppos = marker.find(":"); + size_t seppos = marker.find(':'); if (seppos == string::npos) type = marker; else { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp index 294b6adf951..26edb3c753c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp @@ -27,6 +27,7 @@ #include "MessageException.hpp" #include "PageRanges.hpp" #include "PsSpecialHandler.hpp" +#include "optimizer/SVGOptimizer.hpp" #include "SVGOutput.hpp" #include "System.hpp" #include "utility.hpp" @@ -72,19 +73,19 @@ void ImageToSVG::convert (int pageno) { _psHandler.process(psSpecialCmd(), ss, *this); } catch (...) { - progress(0); // remove progress message + progress(nullptr); // remove progress message throw; } - progress(0); + progress(nullptr); Matrix matrix = getUserMatrix(_bbox); // output SVG file - _svg.removeRedundantElements(); + SVGOptimizer(_svg).execute(); _svg.transformPage(matrix); _bbox.transform(matrix); _svg.setBBox(_bbox); - _svg.appendToDoc(util::make_unique<XMLCommentNode>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); + _svg.appendToDoc(util::make_unique<XMLComment>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); bool success = _svg.write(_out.getPageStream(pageno, totalPageCount())); - string svgfname = _out.filename(pageno, totalPageCount()); + string svgfname = _out.filepath(pageno, totalPageCount()).shorterAbsoluteOrRelative(); if (svgfname.empty()) svgfname = "<stdout>"; if (!success) @@ -144,10 +145,11 @@ void ImageToSVG::convert (const std::string &rangestr, pair<int,int> *pageinfo) } -string ImageToSVG::getSVGFilename (unsigned pageno) const { +FilePath ImageToSVG::getSVGFilePath (unsigned pageno) const { + FilePath path; if (pageno == 1) - return _out.filename(1, 1); - return ""; + path = _out.filepath(1, 1); + return path; } @@ -162,13 +164,13 @@ void ImageToSVG::progress (const char *id) { Terminal::cursor(false); Message::mstream(false) << "\n"; } - if (draw && ((System::time() - time > 0.05) || id == 0)) { + if (draw && ((System::time() - time > 0.05) || id == nullptr)) { const size_t DIGITS=6; Message::mstream(false, Message::MC_PROGRESS) << string(DIGITS-min(DIGITS, static_cast<size_t>(log10(count))), ' ') << count << " PostScript instructions processed\r"; // overprint indicator when finished - if (id == 0) { + if (id == nullptr) { Message::estream().clearline(); Terminal::cursor(true); } @@ -190,7 +192,7 @@ Matrix ImageToSVG::getUserMatrix (const BoundingBox &bbox) const { calc.setVariable("w", bbox.width()*bp2pt); calc.setVariable("h", bbox.height()*bp2pt); // add constants for length units to calculator - for (auto unit : Length::getUnits()) + for (const auto &unit : Length::getUnits()) calc.setVariable(unit.first, Length(1, unit.second).pt()); matrix.set(_transCmds, calc); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp index dcbce9b3242..a4e4de223f6 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp @@ -32,8 +32,7 @@ struct SVGOutputBase; class ImageToSVG : protected SpecialActions { public: - ImageToSVG (const std::string &fname, SVGOutputBase &out) : _fname(fname), _out(out) {} - virtual ~ImageToSVG () =default; + ImageToSVG (std::string fname, SVGOutputBase &out) : _fname(std::move(fname)), _out(out) {} void convert (int pageno); void convert (int firstPage, int lastPage, std::pair<int,int> *pageinfo); void convert (const std::string &rangestr, std::pair<int,int> *pageinfo); @@ -61,19 +60,15 @@ class ImageToSVG : protected SpecialActions { Color getColor () const override {return _svg.getColor();} void setMatrix (const Matrix &m) override {_svg.setMatrix(m);} const Matrix& getMatrix () const override {return _svg.getMatrix();} + const SVGTree& svgTree () const override {return _svg;} void setBgColor (const Color &color) override {} - void appendToPage(std::unique_ptr<XMLNode> &&node) override {_svg.appendToPage(std::move(node));} - void appendToDefs(std::unique_ptr<XMLNode> &&node) override {_svg.appendToDefs(std::move(node));} - void prependToPage(std::unique_ptr<XMLNode> &&node) override {_svg.prependToPage(std::move(node));} - void pushContextElement (std::unique_ptr<XMLElementNode> &&node) override {_svg.pushContextElement(std::move(node));} - void popContextElement () override {_svg.popContextElement();} void embed (const BoundingBox &bbox) override {_bbox.embed(bbox);} void embed (const DPair &p, double r=0) override {if (r==0) _bbox.embed(p); else _bbox.embed(p, r);} void progress (const char *id) override; unsigned getCurrentPageNumber() const override {return 0;} BoundingBox& bbox () override {return _bbox;} BoundingBox& bbox (const std::string &name, bool reset=false) override {return _bbox;} - std::string getSVGFilename (unsigned pageno) const override; + FilePath getSVGFilePath (unsigned pageno) const override; std::string getBBoxFormatString () const override {return "";} private: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp index b144d34336d..8a62b6b0118 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp @@ -27,8 +27,7 @@ #include <string> #include <ostream> -struct InputBuffer -{ +struct InputBuffer { virtual ~InputBuffer () =default; virtual int get () =0; virtual int peek () const =0; @@ -38,11 +37,10 @@ struct InputBuffer }; -class StreamInputBuffer : public InputBuffer -{ +class StreamInputBuffer : public InputBuffer { public: - StreamInputBuffer (std::istream &is, size_t bufsize=1024); - ~StreamInputBuffer (); + explicit StreamInputBuffer (std::istream &is, size_t bufsize=1024); + ~StreamInputBuffer () override; int get () override; int peek () const override; int peek (size_t n) const override; @@ -64,24 +62,23 @@ class StreamInputBuffer : public InputBuffer }; -class StringInputBuffer : public InputBuffer -{ +class StringInputBuffer : public InputBuffer { public: - StringInputBuffer (const std::string &str) : _str(str), _pos(0) {} - int get () override {return _pos < _str.length() ? _str[_pos++] : -1;} - int peek () const override {return _pos < _str.length() ? _str[_pos] : -1;} - int peek (size_t n) const override {return _pos+n < _str.length() ? _str[_pos+n] : -1;} - bool eof () const override {return _pos >= _str.length();} - void invalidate () override {_pos = _str.length();} + explicit StringInputBuffer (const std::string &str) : _str(&str) {} + void assign (const std::string &str) {_str = &str; _pos=0;} + int get () override {return _pos < _str->length() ? _str->at(_pos++) : -1;} + int peek () const override {return _pos < _str->length() ? _str->at(_pos) : -1;} + int peek (size_t n) const override {return _pos+n < _str->length() ? _str->at(_pos+n) : -1;} + bool eof () const override {return _pos >= _str->length();} + void invalidate () override {_pos = _str->length();} private: - const std::string &_str; - size_t _pos; + const std::string *_str; + size_t _pos=0; }; -class CharInputBuffer : public InputBuffer -{ +class CharInputBuffer : public InputBuffer { public: CharInputBuffer (const char *buf, size_t size) : _pos(buf), _size(buf ? size : 0) {} @@ -112,8 +109,7 @@ class CharInputBuffer : public InputBuffer }; -class SplittedCharInputBuffer : public InputBuffer -{ +class SplittedCharInputBuffer : public InputBuffer { public: SplittedCharInputBuffer (const char *buf1, size_t s1, const char *buf2, size_t s2); int get () override; @@ -129,16 +125,15 @@ class SplittedCharInputBuffer : public InputBuffer }; -class TextStreamInputBuffer : public StreamInputBuffer -{ +class TextStreamInputBuffer : public StreamInputBuffer { public: - TextStreamInputBuffer (std::istream &is) : StreamInputBuffer(is), _line(1), _col(1) {} + explicit TextStreamInputBuffer (std::istream &is) : StreamInputBuffer(is) {} int get () override; int line () const {return _line;} int col () const {return _col;} private: - int _line, _col; + int _line=1, _col=1; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp index 9a317b4bf96..5c9b9f5c621 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp @@ -19,6 +19,7 @@ *************************************************************************/ #include <cmath> +#include <cstring> #include <functional> #include "InputReader.hpp" @@ -41,11 +42,15 @@ void StringMatcher::setPattern (const string &pattern) { } +/** Reads characters from an input stream until the pattern string or EOF is reached. + * The matching string is read too if found. An empty pattern matches any character, i.e. + * reading stops after the first character. + * @return true if the pattern was found */ bool StringMatcher::match (InputReader &ir) { - _charsRead = 0; int c; int i=0; const int len = static_cast<int>(_pattern.length()); + _charsRead = 0; while ((c = ir.get()) >= 0) { _charsRead++; while (i >= 0 && c != _pattern[i]) @@ -56,6 +61,25 @@ bool StringMatcher::match (InputReader &ir) { return false; } + +/** Reads characters from an input stream until the pattern string or EOF is reached + * and returns them as a string. The matching string is also appended to the returned string. */ +string StringMatcher::read (InputReader &ir) { + string ret; + int c; + int i=0; + const int len = static_cast<int>(_pattern.length()); + while ((c = ir.get()) >= 0) { + ret += char(c); + while (i >= 0 && c != _pattern[i]) + i = _borders[i]; + if (++i == len) + break; + } + _charsRead = ret.length(); + return ret; +} + /////////////////////////////////////////////////////////////////////////// /** Skips n characters. */ @@ -73,15 +97,26 @@ void InputReader::skipSpace () { } -/** Tries to find a given string and skips all characters preceding that string. +/** Tries to find a given string and skips all characters preceding that string. If + * the string can't be found, all characters until EOF are skipped. * @param[in] str string to look for (must not be longer than the maximal buffer size) - * @return true if s was found */ + * @return true if str was found */ bool InputReader::skipUntil (const char *str) { StringMatcher matcher(str); return matcher.match(*this); } +/** Tries to find a given string and returns all characters including that string. If + * the string can't be found, all characters until EOF are read. + * @param[in] str string to look for (must not be longer than the maximal buffer size) + * @return the read characters */ +string InputReader::readUntil (const char *str) { + StringMatcher matcher(str); + return matcher.read(*this); +} + + /** Looks for the first occurrence of a given character. * @param[in] c character to lookup * @return position of character relative to current location, -1 if character was not found */ @@ -246,7 +281,7 @@ string InputReader::getWord () { string ret; skipSpace(); while (isalpha(peek())) - ret += get(); + ret += char(get()); return ret; } @@ -261,7 +296,7 @@ char InputReader::getPunct () { } -/** Reads a string optionally delimited by a given quotation character. +/** Reads a string optionally enclosed by a given quotation character. * Before reading the string, all leading whitespace is skipped. Then, the function checks * for one of the the given quotation characters. If it is found, all characters until the * second appearance of the same quotation char are appended to the result. Otherwise, an @@ -278,7 +313,7 @@ string InputReader::getQuotedString (const char *quotechars) { if (const char *quotechar = strchr(quotechars, peek())) { get(); while (!eof() && peek() != *quotechar) - ret += get(); + ret += char(get()); get(); } return ret; @@ -294,7 +329,7 @@ string InputReader::getString () { string ret; skipSpace(); while (!eof() && !isspace(peek()) && isprint(peek())) - ret += get(); + ret += char(get()); return ret; } @@ -305,7 +340,7 @@ string InputReader::getString () { string InputReader::getString (size_t n) { string ret; while (n-- > 0) - ret += get(); + ret += char(get()); return ret; } @@ -319,7 +354,7 @@ string InputReader::getString (const char *delim) { string ret; skipSpace(); while (!eof() && peek() > 0 && !strchr(delim, peek())) - ret += get(); + ret += char(get()); return ret; } @@ -328,33 +363,37 @@ string InputReader::getLine () { string ret; skipSpace(); while (!eof() && peek() > 0 && peek() != '\n') - ret += get(); + ret += char(get()); // trim trailing whitespace ret.erase(std::find_if(ret.rbegin(), ret.rend(), not1(ptr_fun<int, int>(isspace))).base(), ret.end()); return ret; } -/** Parses a sequence of key-value pairs of the form KEY=VALUE or KEY="VALUE" +/** Parses a sequence of key-value pairs of the form KEY=VALUE or KEY="VALUE". + * If parameter 'requireValues' is false, attributes may also consist of a key only. * @param[out] attr the scanned atributes + * @param[in] requireValues true if all attributes require a value * @param[in] quotechars recognized quote characters used to enclose the attribute values * @return number of attributes scanned */ -int InputReader::parseAttributes (map<string,string> &attr, const char *quotechars) { - bool ready=false; - while (!eof() && !ready) { +int InputReader::parseAttributes (map<string,string> &attr, bool requireValues, const char *quotechars) { + while (!eof()) { string key; skipSpace(); - while (isalnum(peek())) - key += get(); + if (!isalpha(peek())) // first character of attribute name must be a letter + break; + key += char(get()); + while (isalnum(peek()) || strchr("-:._", peek())) + key += char(get()); skipSpace(); if (peek() == '=') { get(); skipSpace(); string val = getQuotedString(quotechars); - attr[key] = val; + attr.emplace(std::move(key), std::move(val)); } - else - ready = true; + else if (!requireValues) + attr.emplace(std::move(key), ""); } return attr.size(); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp index 5523499f073..0ca4f107722 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp @@ -37,7 +37,8 @@ class InputReader { virtual bool check (char c) const {return peek() == c;} virtual bool check (const char *s, bool consume=true); virtual void skip (size_t n); - virtual bool skipUntil (const char *s); + virtual bool skipUntil (const char *str); + virtual std::string readUntil (const char *str); virtual int find (char c) const; virtual void skipSpace (); virtual int getInt (); @@ -53,14 +54,14 @@ class InputReader { virtual std::string getString (size_t n); virtual std::string getString (const char *delim); virtual std::string getLine (); - virtual int parseAttributes (std::map<std::string,std::string> &attr, const char *quotechars=nullptr); + virtual int parseAttributes (std::map<std::string,std::string> &attr, bool requireValues, const char *quotechars=nullptr); virtual operator bool () const {return !eof();} }; class StreamInputReader : public InputReader { public: - StreamInputReader (std::istream &is) : _is(is) {} + explicit StreamInputReader (std::istream &is) : _is(is) {} int get () override {return _is.get();} int peek () const override {return _is.peek();} int peek (size_t n) const override; @@ -74,7 +75,7 @@ class StreamInputReader : public InputReader { class BufferInputReader : public InputReader { public: - BufferInputReader (InputBuffer &ib) : _ib(&ib) {} + explicit BufferInputReader (InputBuffer &ib) : _ib(&ib) {} void assign (InputBuffer &ib) {_ib = &ib;} int get () override {return _ib->get();} int peek () const override {return _ib->peek();} @@ -91,9 +92,10 @@ class BufferInputReader : public InputReader { class StringMatcher { public: StringMatcher () : _charsRead(0) {} - StringMatcher (const std::string &pattern) : _charsRead(0) {setPattern(pattern);} + explicit StringMatcher (const std::string &pattern) : _charsRead(0) {setPattern(pattern);} void setPattern (const std::string &pattern); bool match (InputReader &ir); + std::string read (InputReader &ir); size_t charsRead () const {return _charsRead;} private: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp index a1835f6732c..a79fdf0c03b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp @@ -32,11 +32,9 @@ JFM::JFM (istream &is) { is.seekg(0); StreamReader reader(is); uint16_t id = uint16_t(reader.readUnsigned(2)); // JFM ID (9 or 11) - if (id != 9 && id != 11) { - ostringstream oss; - oss << "invalid JFM identifier " << id << " (9 or 11 expected)"; - throw FontMetricException(oss.str()); - } + if (id != 9 && id != 11) + throw FontMetricException("invalid JFM identifier " + std::to_string(id) + " (9 or 11 expected)"); + _vertical = (id == 9); uint16_t nt = uint16_t(reader.readUnsigned(2)); // length of character type table uint16_t lf = uint16_t(reader.readUnsigned(2)); // length of entire file in 4 byte words diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp index 5b5901ee61f..c51f371a5ec 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp @@ -27,7 +27,7 @@ class JFM : public TFM { public: - JFM (std::istream &is); + explicit JFM (std::istream &is); bool verticalLayout () const override {return _vertical;} uint32_t minChar () const {return _minchar;} uint32_t maxChar () const {return static_cast<uint32_t>(_minchar+_charTypeTable.size()-1);} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp index ba7dd2a2252..cbee103d49b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp @@ -60,9 +60,7 @@ void Length::set (double val, Unit unit) { case Unit::SP: _pt = val/pt2sp; break; default: // this isn't supposed to happen - ostringstream oss; - oss << "invalid length unit: (" << static_cast<int>(unit) << ")"; - throw UnitException(oss.str()); + throw UnitException("invalid length unit: (" + std::to_string(static_cast<int>(unit)) + ")"); } } @@ -80,9 +78,7 @@ double Length::get (Unit unit) const { case Unit::SP: return sp(); } // this isn't supposed to happen - ostringstream oss; - oss << "invalid length unit: (" << static_cast<int>(unit) << ")"; - throw UnitException(oss.str()); + throw UnitException("invalid length unit: (" + std::to_string(static_cast<int>(unit)) + ")"); } @@ -111,7 +107,7 @@ Length::Unit Length::stringToUnit (const std::string &unitstr) { case unit_id('s','p'): return Unit::SP; } } - throw UnitException(string("invalid length unit: ")+unitstr); + throw UnitException(string("invalid length unit: ") + unitstr); } @@ -136,7 +132,7 @@ void Length::set (double val, string unitstr) { if (unitstr.empty()) unitstr = "pt"; else if (unitstr.length() != 2) - throw UnitException(string("invalid length unit: ")+unitstr); + throw UnitException(string("invalid length unit: ") + unitstr); set(val, stringToUnit(unitstr)); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp index 0c9aa6526bf..4454eec168e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp @@ -30,7 +30,7 @@ #endif struct UnitException : MessageException { - UnitException (const std::string &msg) : MessageException(msg) {} + explicit UnitException (const std::string &msg) : MessageException(msg) {} }; @@ -40,10 +40,10 @@ class Length { public: constexpr Length () : _pt(0) {} - constexpr Length (long double pt) : _pt(static_cast<double>(pt)) {} + explicit constexpr Length (long double pt) : _pt(static_cast<double>(pt)) {} Length (double val, Unit unit) {set(val, unit);} Length (double val, const std::string &unitstr) {set(val, unitstr);} - Length (const std::string &lenstr) {set(lenstr);} + explicit Length (const std::string &lenstr) {set(lenstr);} void set (double val, Unit unit); void set (double val, std::string unit); void set (const std::string &lenstr); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp index 3ccbdfe12c1..e233673d36d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp @@ -34,8 +34,8 @@ class MD5HashFunction : public HashFunction { public: MD5HashFunction () {MD5_Init(&_context);} MD5HashFunction (const char *data, size_t length) : MD5HashFunction() {update(data, length);} - MD5HashFunction (const std::string &data) : MD5HashFunction() {update(data);} - MD5HashFunction (const std::vector<uint8_t> &data) : MD5HashFunction() {update(data);} + explicit MD5HashFunction (const std::string &data) : MD5HashFunction() {update(data);} + explicit MD5HashFunction (const std::vector<uint8_t> &data) : MD5HashFunction() {update(data);} int digestSize () const override {return 16;} void reset () override {MD5_Init(&_context);} void update (const char *data, size_t length) override {MD5_Update(&_context, data, length);} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am index 421ccd840e1..8c7786e9dd1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am @@ -5,6 +5,7 @@ bin_PROGRAMS = dvisvgm noinst_LIBRARIES = libdvisvgm.a +SUBDIRS = optimizer dvisvgm_SOURCES = \ CommandLine.hpp \ @@ -14,6 +15,7 @@ include ../libs/defs.am dvisvgm_LDADD = \ $(noinst_LIBRARIES) \ + optimizer/liboptimizer.a \ ../libs/clipper/libclipper.a \ $(POTRACE_LIBS) \ $(XXHASH_LIBS) @@ -43,217 +45,123 @@ dvisvgm_DEPENDENCIES += $(KPATHSEA_DEPEND) $(ZLIB_DEPEND) $(FREETYPE2_DEPEND) libdvisvgm_a_SOURCES = \ AGLTable.hpp \ - BasicDVIReader.cpp \ - BasicDVIReader.hpp \ - Bezier.cpp \ - Bezier.hpp \ - BgColorSpecialHandler.cpp \ - BgColorSpecialHandler.hpp \ - Bitmap.cpp \ - Bitmap.hpp \ - BoundingBox.cpp \ - BoundingBox.hpp \ - Calculator.cpp \ - Calculator.hpp \ + BasicDVIReader.hpp BasicDVIReader.cpp \ + Bezier.hpp Bezier.cpp \ + BgColorSpecialHandler.hpp BgColorSpecialHandler.cpp \ + Bitmap.hpp Bitmap.cpp \ + BoundingBox.hpp BoundingBox.cpp \ + Calculator.hpp Calculator.cpp \ Character.hpp \ - CharMapID.cpp \ - CharMapID.hpp \ - CLCommandLine.cpp \ - CLCommandLine.hpp \ + CharMapID.hpp CharMapID.cpp \ + CLCommandLine.hpp CLCommandLine.cpp \ + CMap.hpp CMap.cpp \ + CMapManager.hpp CMapManager.cpp \ + CMapReader.hpp CMapReader.cpp \ CLOption.hpp \ - CMap.cpp \ - CMap.hpp \ - CMapManager.cpp \ - CMapManager.hpp \ - CMapReader.cpp \ - CMapReader.hpp \ - Color.cpp \ - Color.hpp \ - ColorSpecialHandler.cpp \ - ColorSpecialHandler.hpp \ - CRC32.cpp \ - CRC32.hpp \ - DependencyGraph.hpp \ - Directory.cpp \ - Directory.hpp \ - DLLoader.cpp \ - DLLoader.hpp \ + Color.hpp Color.cpp \ + ColorSpecialHandler.hpp ColorSpecialHandler.cpp \ + CommandLine.hpp \ + Directory.hpp Directory.cpp \ DVIActions.hpp \ - DVIReader.cpp \ - DVIReader.hpp \ - DvisvgmSpecialHandler.cpp \ - DvisvgmSpecialHandler.hpp \ - DVIToSVG.cpp \ - DVIToSVG.hpp \ - DVIToSVGActions.cpp \ - DVIToSVGActions.hpp \ - EmSpecialHandler.cpp \ - EmSpecialHandler.hpp \ - EncFile.cpp \ - EncFile.hpp \ - EPSFile.cpp \ - EPSFile.hpp \ + DLLoader.hpp DLLoader.cpp \ + DVIReader.hpp DVIReader.cpp \ + DvisvgmSpecialHandler.hpp DvisvgmSpecialHandler.cpp \ + DVIToSVG.hpp DVIToSVG.cpp \ + DVIToSVGActions.hpp DVIToSVGActions.cpp \ + EllipticalArc.hpp EllipticalArc.cpp \ + EmSpecialHandler.hpp EmSpecialHandler.cpp \ + EncFile.hpp EncFile.cpp \ + EPSFile.hpp EPSFile.cpp \ EPSToSVG.hpp \ - FileFinder.cpp \ - FileFinder.hpp \ - FilePath.cpp \ - FilePath.hpp \ - FileSystem.cpp \ - FileSystem.hpp \ + FileFinder.hpp FileFinder.cpp \ + FilePath.hpp FilePath.cpp \ + FileSystem.hpp FileSystem.cpp \ FixWord.hpp \ - Font.cpp \ - Font.hpp \ - FontCache.cpp \ - FontCache.hpp \ - FontEncoding.cpp \ - FontEncoding.hpp \ - FontEngine.cpp \ - FontEngine.hpp \ - FontManager.cpp \ - FontManager.hpp \ - FontMap.cpp \ - FontMap.hpp \ - FontMetrics.cpp \ - FontMetrics.hpp \ + Font.hpp Font.cpp \ + FontCache.hpp FontCache.cpp \ + FontEncoding.hpp FontEncoding.cpp \ + FontEngine.hpp FontEngine.cpp \ + FontManager.hpp FontManager.cpp \ + FontMap.hpp FontMap.cpp \ + FontMetrics.hpp FontMetrics.cpp \ FontStyle.hpp \ - FontWriter.cpp \ - FontWriter.hpp \ - GFGlyphTracer.cpp \ - GFGlyphTracer.hpp \ - GFReader.cpp \ - GFReader.hpp \ - GFTracer.cpp \ - GFTracer.hpp \ - Ghostscript.cpp \ - Ghostscript.hpp \ + FontWriter.hpp FontWriter.cpp \ + GFGlyphTracer.hpp GFGlyphTracer.cpp \ + GFReader.hpp GFReader.cpp \ + GFTracer.hpp GFTracer.cpp \ + Ghostscript.hpp Ghostscript.cpp \ Glyph.hpp \ GlyphTracerMessages.hpp \ GraphicsPath.hpp \ - HashFunction.cpp \ - HashFunction.hpp \ - HtmlSpecialHandler.cpp \ - HtmlSpecialHandler.hpp \ - HyperlinkManager.cpp \ - HyperlinkManager.hpp \ - ImageToSVG.cpp \ - ImageToSVG.hpp \ - InputBuffer.cpp \ - InputBuffer.hpp \ - InputReader.cpp \ - InputReader.hpp \ - JFM.cpp \ - JFM.hpp \ - Length.cpp \ - Length.hpp \ + HashFunction.hpp HashFunction.cpp \ + HtmlSpecialHandler.hpp HtmlSpecialHandler.cpp \ + HyperlinkManager.hpp HyperlinkManager.cpp \ + ImageToSVG.hpp ImageToSVG.cpp \ + InputBuffer.hpp InputBuffer.cpp \ + InputReader.hpp InputReader.cpp \ + JFM.hpp JFM.cpp \ + Length.hpp Length.cpp \ macros.hpp \ - MapLine.cpp \ - MapLine.hpp \ - Matrix.cpp \ - Matrix.hpp \ + MapLine.hpp MapLine.cpp \ + Matrix.hpp Matrix.cpp \ MD5HashFunction.hpp \ - Message.cpp \ - Message.hpp \ + Message.hpp Message.cpp \ MessageException.hpp \ - MetafontWrapper.cpp \ - MetafontWrapper.hpp \ - NoPsSpecialHandler.cpp \ - NoPsSpecialHandler.hpp \ + MetafontWrapper.hpp MetafontWrapper.cpp \ + NoPsSpecialHandler.hpp NoPsSpecialHandler.cpp \ NumericRanges.hpp \ - PageRanges.cpp \ - PageRanges.hpp \ - PageSize.cpp \ - PageSize.hpp \ + PageRanges.hpp PageRanges.cpp \ + PageSize.hpp PageSize.cpp \ Pair.hpp \ - PapersizeSpecialHandler.cpp \ - PapersizeSpecialHandler.hpp \ - PathClipper.cpp \ - PathClipper.hpp \ - PDFParser.cpp \ - PDFParser.hpp \ + PapersizeSpecialHandler.hpp PapersizeSpecialHandler.cpp \ + PathClipper.hpp PathClipper.cpp \ + PDFParser.hpp PDFParser.cpp \ + PdfSpecialHandler.hpp PdfSpecialHandler.cpp \ PDFToSVG.hpp \ - PdfSpecialHandler.cpp \ - PdfSpecialHandler.hpp \ - PreScanDVIReader.cpp \ - PreScanDVIReader.hpp \ - Process.cpp \ - Process.hpp \ + PreScanDVIReader.hpp PreScanDVIReader.cpp \ + Process.hpp Process.cpp \ psdefs.cpp \ PSFilter.hpp \ - PSInterpreter.cpp \ - PSInterpreter.hpp \ - PSPattern.cpp \ - PSPattern.hpp \ - PSPreviewFilter.cpp \ - PSPreviewFilter.hpp \ - PsSpecialHandler.cpp \ - PsSpecialHandler.hpp \ - RangeMap.cpp \ - RangeMap.hpp \ - ShadingPatch.cpp \ - ShadingPatch.hpp \ - SignalHandler.cpp \ - SignalHandler.hpp \ - SourceInput.cpp \ - SourceInput.hpp \ + PSInterpreter.hpp PSInterpreter.cpp \ + PSPattern.hpp PSPattern.cpp \ + PSPreviewFilter.hpp PSPreviewFilter.cpp \ + PsSpecialHandler.hpp PsSpecialHandler.cpp \ + RangeMap.hpp RangeMap.cpp \ + ShadingPatch.hpp ShadingPatch.cpp \ + SignalHandler.hpp SignalHandler.cpp \ + SourceInput.hpp SourceInput.cpp \ SpecialActions.hpp \ SpecialHandler.hpp \ - SpecialManager.cpp \ - SpecialManager.hpp \ - StreamReader.cpp \ - StreamReader.hpp \ - StreamWriter.cpp \ - StreamWriter.hpp \ - Subfont.cpp \ - Subfont.hpp \ - SVGCharHandler.cpp \ - SVGCharHandler.hpp \ - SVGCharHandlerFactory.cpp \ - SVGCharHandlerFactory.hpp \ - SVGCharPathHandler.cpp \ - SVGCharPathHandler.hpp \ - SVGCharTspanTextHandler.cpp \ - SVGCharTspanTextHandler.hpp \ - SVGOutput.cpp \ - SVGOutput.hpp \ - SVGSingleCharTextHandler.cpp \ - SVGSingleCharTextHandler.hpp \ - SVGTree.cpp \ - SVGTree.hpp \ - System.cpp \ - System.hpp \ - TensorProductPatch.cpp \ - TensorProductPatch.hpp \ - Terminal.cpp \ - Terminal.hpp \ - TFM.cpp \ - TFM.hpp \ - ToUnicodeMap.cpp \ - ToUnicodeMap.hpp \ - TpicSpecialHandler.cpp \ - TpicSpecialHandler.hpp \ - TriangularPatch.cpp \ - TriangularPatch.hpp \ - TrueTypeFont.cpp \ - TrueTypeFont.hpp \ - TTFAutohint.cpp \ - TTFAutohint.hpp \ - Unicode.cpp \ - Unicode.hpp \ - utility.hpp \ - utility.cpp \ + SpecialManager.hpp SpecialManager.cpp \ + StreamReader.hpp StreamReader.cpp \ + StreamWriter.hpp StreamWriter.cpp \ + Subfont.hpp Subfont.cpp \ + SVGCharHandler.hpp SVGCharHandler.cpp \ + SVGCharHandlerFactory.hpp SVGCharHandlerFactory.cpp \ + SVGCharPathHandler.hpp SVGCharPathHandler.cpp \ + SVGCharTspanTextHandler.hpp SVGCharTspanTextHandler.cpp \ + SVGOutput.hpp SVGOutput.cpp \ + SVGSingleCharTextHandler.hpp SVGSingleCharTextHandler.cpp \ + SVGTree.hpp SVGTree.cpp \ + System.hpp System.cpp \ + TensorProductPatch.hpp TensorProductPatch.cpp \ + Terminal.hpp Terminal.cpp \ + TFM.hpp TFM.cpp \ + ToUnicodeMap.hpp ToUnicodeMap.cpp \ + TpicSpecialHandler.hpp TpicSpecialHandler.cpp \ + TriangularPatch.hpp TriangularPatch.cpp \ + TrueTypeFont.hpp TrueTypeFont.cpp \ + TTFAutohint.hpp TTFAutohint.cpp \ + Unicode.hpp Unicode.cpp \ + utility.hpp utility.cpp \ VectorIterator.hpp \ VectorStream.hpp \ - version.hpp \ VFActions.hpp \ - VFReader.cpp \ - VFReader.hpp \ + VFReader.hpp VFReader.cpp \ windows.hpp \ - XMLDocument.cpp \ - XMLDocument.hpp \ - XMLNode.cpp \ - XMLNode.hpp \ - XMLString.cpp \ - XMLString.hpp \ + XMLDocument.hpp XMLDocument.cpp \ + XMLNode.hpp XMLNode.cpp \ + XMLString.hpp XMLString.cpp \ XXHashFunction.hpp \ ZLibOutputStream.hpp @@ -273,7 +181,16 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) -Wnon-virtual-dtor \ AM_CXXFLAGS += \ $(POTRACE_CFLAGS) \ - $(XXHASH_CFLAGS) + $(XXHASH_CFLAGS) \ + $(KPATHSEA_INCLUDES) \ + $(POTRACE_INCLUDES) \ + $(FREETYPE2_INCLUDES) \ + $(LIBGS_INCLUDES) \ + $(CODE_COVERAGE_CFLAGS) + +if WIN32 +AM_CXXFLAGS += -DTEXLIVEWIN32 +endif WIN32 AM_LDFLAGS = \ $(KPSE_LIBS) \ @@ -284,8 +201,6 @@ AM_CFLAGS += \ -I$(dvisvgm_srcdir)/libs/ff-woff/fontforge \ -I$(dvisvgm_srcdir)/libs/ff-woff/inc -AM_CXXFLAGS += $(TTFAUTOHINT_CFLAGS) - AM_CXXFLAGS += \ $(BROTLI_CFLAGS) \ $(WOFF2_CFLAGS) @@ -296,23 +211,11 @@ else AM_CXXFLAGS += $(LIBCRYPTO_CFLAGS) endif -AM_LDFLAGS += $(TTFAUTOHINT_LIBS) endif -AM_CXXFLAGS += \ - $(KPATHSEA_INCLUDES) \ - $(POTRACE_INCLUDES) \ - $(FREETYPE2_INCLUDES) \ - $(ZLIB_INCLUDES) \ - $(LIBGS_INCLUDES) \ - $(CODE_COVERAGE_CFLAGS) - -if WIN32 -AM_CXXFLAGS += -DTEXLIVEWIN32 -endif WIN32 - -if ! TEXLIVE_BUILD # TL: do not try to rebuild these source files. +if ! TEXLIVE_BUILD + # the command-line parser class is generated from options.xml by opt2cpp $(srcdir)/CommandLine.hpp: options.xml rm -f $@ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in index 7da31007555..47584fce862 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in @@ -102,16 +102,17 @@ bin_PROGRAMS = dvisvgm$(EXEEXT) @USE_BUNDLED_MD5_TRUE@am__append_6 = ../libs/md5/libmd5.a @USE_BUNDLED_MD5_FALSE@am__append_7 = $(LIBCRYPTO_LIBS) @ENABLE_WOFF_TRUE@am__append_8 = ffwrapper.c ffwrapper.h -@ENABLE_WOFF_TRUE@am__append_9 = \ +@WIN32_TRUE@am__append_9 = -DTEXLIVEWIN32 +@ENABLE_WOFF_TRUE@am__append_10 = \ @ENABLE_WOFF_TRUE@ -I$(dvisvgm_srcdir)/libs/ff-woff/fontforge \ @ENABLE_WOFF_TRUE@ -I$(dvisvgm_srcdir)/libs/ff-woff/inc -@ENABLE_WOFF_TRUE@am__append_10 = $(TTFAUTOHINT_CFLAGS) \ -@ENABLE_WOFF_TRUE@ $(BROTLI_CFLAGS) $(WOFF2_CFLAGS) -@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_TRUE@am__append_11 = -I$(dvisvgm_srcdir)/libs/md5 -@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_FALSE@am__append_12 = $(LIBCRYPTO_CFLAGS) -@ENABLE_WOFF_TRUE@am__append_13 = $(TTFAUTOHINT_LIBS) -@WIN32_TRUE@am__append_14 = -DTEXLIVEWIN32 +@ENABLE_WOFF_TRUE@am__append_11 = \ +@ENABLE_WOFF_TRUE@ $(BROTLI_CFLAGS) \ +@ENABLE_WOFF_TRUE@ $(WOFF2_CFLAGS) + +@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_TRUE@am__append_12 = -I$(dvisvgm_srcdir)/libs/md5 +@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_FALSE@am__append_13 = $(LIBCRYPTO_CFLAGS) subdir = dvisvgm-src/src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \ @@ -145,83 +146,82 @@ am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libdvisvgm_a_AR = $(AR) $(ARFLAGS) libdvisvgm_a_LIBADD = -am__libdvisvgm_a_SOURCES_DIST = AGLTable.hpp BasicDVIReader.cpp \ - BasicDVIReader.hpp Bezier.cpp Bezier.hpp \ - BgColorSpecialHandler.cpp BgColorSpecialHandler.hpp Bitmap.cpp \ - Bitmap.hpp BoundingBox.cpp BoundingBox.hpp Calculator.cpp \ - Calculator.hpp Character.hpp CharMapID.cpp CharMapID.hpp \ - CLCommandLine.cpp CLCommandLine.hpp CLOption.hpp CMap.cpp \ - CMap.hpp CMapManager.cpp CMapManager.hpp CMapReader.cpp \ - CMapReader.hpp Color.cpp Color.hpp ColorSpecialHandler.cpp \ - ColorSpecialHandler.hpp CRC32.cpp CRC32.hpp \ - DependencyGraph.hpp Directory.cpp Directory.hpp DLLoader.cpp \ - DLLoader.hpp DVIActions.hpp DVIReader.cpp DVIReader.hpp \ - DvisvgmSpecialHandler.cpp DvisvgmSpecialHandler.hpp \ - DVIToSVG.cpp DVIToSVG.hpp DVIToSVGActions.cpp \ - DVIToSVGActions.hpp EmSpecialHandler.cpp EmSpecialHandler.hpp \ - EncFile.cpp EncFile.hpp EPSFile.cpp EPSFile.hpp EPSToSVG.hpp \ - FileFinder.cpp FileFinder.hpp FilePath.cpp FilePath.hpp \ - FileSystem.cpp FileSystem.hpp FixWord.hpp Font.cpp Font.hpp \ - FontCache.cpp FontCache.hpp FontEncoding.cpp FontEncoding.hpp \ - FontEngine.cpp FontEngine.hpp FontManager.cpp FontManager.hpp \ - FontMap.cpp FontMap.hpp FontMetrics.cpp FontMetrics.hpp \ - FontStyle.hpp FontWriter.cpp FontWriter.hpp GFGlyphTracer.cpp \ - GFGlyphTracer.hpp GFReader.cpp GFReader.hpp GFTracer.cpp \ - GFTracer.hpp Ghostscript.cpp Ghostscript.hpp Glyph.hpp \ - GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.cpp \ - HashFunction.hpp HtmlSpecialHandler.cpp HtmlSpecialHandler.hpp \ - HyperlinkManager.cpp HyperlinkManager.hpp ImageToSVG.cpp \ - ImageToSVG.hpp InputBuffer.cpp InputBuffer.hpp InputReader.cpp \ - InputReader.hpp JFM.cpp JFM.hpp Length.cpp Length.hpp \ - macros.hpp MapLine.cpp MapLine.hpp Matrix.cpp Matrix.hpp \ - MD5HashFunction.hpp Message.cpp Message.hpp \ - MessageException.hpp MetafontWrapper.cpp MetafontWrapper.hpp \ - NoPsSpecialHandler.cpp NoPsSpecialHandler.hpp \ - NumericRanges.hpp PageRanges.cpp PageRanges.hpp PageSize.cpp \ - PageSize.hpp Pair.hpp PapersizeSpecialHandler.cpp \ - PapersizeSpecialHandler.hpp PathClipper.cpp PathClipper.hpp \ - PDFParser.cpp PDFParser.hpp PDFToSVG.hpp PdfSpecialHandler.cpp \ - PdfSpecialHandler.hpp PreScanDVIReader.cpp \ - PreScanDVIReader.hpp Process.cpp Process.hpp psdefs.cpp \ - PSFilter.hpp PSInterpreter.cpp PSInterpreter.hpp PSPattern.cpp \ - PSPattern.hpp PSPreviewFilter.cpp PSPreviewFilter.hpp \ - PsSpecialHandler.cpp PsSpecialHandler.hpp RangeMap.cpp \ - RangeMap.hpp ShadingPatch.cpp ShadingPatch.hpp \ - SignalHandler.cpp SignalHandler.hpp SourceInput.cpp \ - SourceInput.hpp SpecialActions.hpp SpecialHandler.hpp \ - SpecialManager.cpp SpecialManager.hpp StreamReader.cpp \ - StreamReader.hpp StreamWriter.cpp StreamWriter.hpp Subfont.cpp \ - Subfont.hpp SVGCharHandler.cpp SVGCharHandler.hpp \ - SVGCharHandlerFactory.cpp SVGCharHandlerFactory.hpp \ - SVGCharPathHandler.cpp SVGCharPathHandler.hpp \ - SVGCharTspanTextHandler.cpp SVGCharTspanTextHandler.hpp \ - SVGOutput.cpp SVGOutput.hpp SVGSingleCharTextHandler.cpp \ - SVGSingleCharTextHandler.hpp SVGTree.cpp SVGTree.hpp \ - System.cpp System.hpp TensorProductPatch.cpp \ - TensorProductPatch.hpp Terminal.cpp Terminal.hpp TFM.cpp \ - TFM.hpp ToUnicodeMap.cpp ToUnicodeMap.hpp \ - TpicSpecialHandler.cpp TpicSpecialHandler.hpp \ - TriangularPatch.cpp TriangularPatch.hpp TrueTypeFont.cpp \ - TrueTypeFont.hpp TTFAutohint.cpp TTFAutohint.hpp Unicode.cpp \ - Unicode.hpp utility.hpp utility.cpp VectorIterator.hpp \ - VectorStream.hpp version.hpp VFActions.hpp VFReader.cpp \ - VFReader.hpp windows.hpp XMLDocument.cpp XMLDocument.hpp \ - XMLNode.cpp XMLNode.hpp XMLString.cpp XMLString.hpp \ - XXHashFunction.hpp ZLibOutputStream.hpp ffwrapper.c \ - ffwrapper.h +am__libdvisvgm_a_SOURCES_DIST = AGLTable.hpp BasicDVIReader.hpp \ + BasicDVIReader.cpp Bezier.hpp Bezier.cpp \ + BgColorSpecialHandler.hpp BgColorSpecialHandler.cpp Bitmap.hpp \ + Bitmap.cpp BoundingBox.hpp BoundingBox.cpp Calculator.hpp \ + Calculator.cpp Character.hpp CharMapID.hpp CharMapID.cpp \ + CLCommandLine.hpp CLCommandLine.cpp CMap.hpp CMap.cpp \ + CMapManager.hpp CMapManager.cpp CMapReader.hpp CMapReader.cpp \ + CLOption.hpp Color.hpp Color.cpp ColorSpecialHandler.hpp \ + ColorSpecialHandler.cpp CommandLine.hpp Directory.hpp \ + Directory.cpp DVIActions.hpp DLLoader.hpp DLLoader.cpp \ + DVIReader.hpp DVIReader.cpp DvisvgmSpecialHandler.hpp \ + DvisvgmSpecialHandler.cpp DVIToSVG.hpp DVIToSVG.cpp \ + DVIToSVGActions.hpp DVIToSVGActions.cpp EllipticalArc.hpp \ + EllipticalArc.cpp EmSpecialHandler.hpp EmSpecialHandler.cpp \ + EncFile.hpp EncFile.cpp EPSFile.hpp EPSFile.cpp EPSToSVG.hpp \ + FileFinder.hpp FileFinder.cpp FilePath.hpp FilePath.cpp \ + FileSystem.hpp FileSystem.cpp FixWord.hpp Font.hpp Font.cpp \ + FontCache.hpp FontCache.cpp FontEncoding.hpp FontEncoding.cpp \ + FontEngine.hpp FontEngine.cpp FontManager.hpp FontManager.cpp \ + FontMap.hpp FontMap.cpp FontMetrics.hpp FontMetrics.cpp \ + FontStyle.hpp FontWriter.hpp FontWriter.cpp GFGlyphTracer.hpp \ + GFGlyphTracer.cpp GFReader.hpp GFReader.cpp GFTracer.hpp \ + GFTracer.cpp Ghostscript.hpp Ghostscript.cpp Glyph.hpp \ + GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.hpp \ + HashFunction.cpp HtmlSpecialHandler.hpp HtmlSpecialHandler.cpp \ + HyperlinkManager.hpp HyperlinkManager.cpp ImageToSVG.hpp \ + ImageToSVG.cpp InputBuffer.hpp InputBuffer.cpp InputReader.hpp \ + InputReader.cpp JFM.hpp JFM.cpp Length.hpp Length.cpp \ + macros.hpp MapLine.hpp MapLine.cpp Matrix.hpp Matrix.cpp \ + MD5HashFunction.hpp Message.hpp Message.cpp \ + MessageException.hpp MetafontWrapper.hpp MetafontWrapper.cpp \ + NoPsSpecialHandler.hpp NoPsSpecialHandler.cpp \ + NumericRanges.hpp PageRanges.hpp PageRanges.cpp PageSize.hpp \ + PageSize.cpp Pair.hpp PapersizeSpecialHandler.hpp \ + PapersizeSpecialHandler.cpp PathClipper.hpp PathClipper.cpp \ + PDFParser.hpp PDFParser.cpp PdfSpecialHandler.hpp \ + PdfSpecialHandler.cpp PDFToSVG.hpp PreScanDVIReader.hpp \ + PreScanDVIReader.cpp Process.hpp Process.cpp psdefs.cpp \ + PSFilter.hpp PSInterpreter.hpp PSInterpreter.cpp PSPattern.hpp \ + PSPattern.cpp PSPreviewFilter.hpp PSPreviewFilter.cpp \ + PsSpecialHandler.hpp PsSpecialHandler.cpp RangeMap.hpp \ + RangeMap.cpp ShadingPatch.hpp ShadingPatch.cpp \ + SignalHandler.hpp SignalHandler.cpp SourceInput.hpp \ + SourceInput.cpp SpecialActions.hpp SpecialHandler.hpp \ + SpecialManager.hpp SpecialManager.cpp StreamReader.hpp \ + StreamReader.cpp StreamWriter.hpp StreamWriter.cpp Subfont.hpp \ + Subfont.cpp SVGCharHandler.hpp SVGCharHandler.cpp \ + SVGCharHandlerFactory.hpp SVGCharHandlerFactory.cpp \ + SVGCharPathHandler.hpp SVGCharPathHandler.cpp \ + SVGCharTspanTextHandler.hpp SVGCharTspanTextHandler.cpp \ + SVGOutput.hpp SVGOutput.cpp SVGSingleCharTextHandler.hpp \ + SVGSingleCharTextHandler.cpp SVGTree.hpp SVGTree.cpp \ + System.hpp System.cpp TensorProductPatch.hpp \ + TensorProductPatch.cpp Terminal.hpp Terminal.cpp TFM.hpp \ + TFM.cpp ToUnicodeMap.hpp ToUnicodeMap.cpp \ + TpicSpecialHandler.hpp TpicSpecialHandler.cpp \ + TriangularPatch.hpp TriangularPatch.cpp TrueTypeFont.hpp \ + TrueTypeFont.cpp TTFAutohint.hpp TTFAutohint.cpp Unicode.hpp \ + Unicode.cpp utility.hpp utility.cpp VectorIterator.hpp \ + VectorStream.hpp VFActions.hpp VFReader.hpp VFReader.cpp \ + windows.hpp XMLDocument.hpp XMLDocument.cpp XMLNode.hpp \ + XMLNode.cpp XMLString.hpp XMLString.cpp XXHashFunction.hpp \ + ZLibOutputStream.hpp ffwrapper.c ffwrapper.h @ENABLE_WOFF_TRUE@am__objects_1 = ffwrapper.$(OBJEXT) am_libdvisvgm_a_OBJECTS = BasicDVIReader.$(OBJEXT) Bezier.$(OBJEXT) \ BgColorSpecialHandler.$(OBJEXT) Bitmap.$(OBJEXT) \ BoundingBox.$(OBJEXT) Calculator.$(OBJEXT) CharMapID.$(OBJEXT) \ CLCommandLine.$(OBJEXT) CMap.$(OBJEXT) CMapManager.$(OBJEXT) \ CMapReader.$(OBJEXT) Color.$(OBJEXT) \ - ColorSpecialHandler.$(OBJEXT) CRC32.$(OBJEXT) \ - Directory.$(OBJEXT) DLLoader.$(OBJEXT) DVIReader.$(OBJEXT) \ + ColorSpecialHandler.$(OBJEXT) Directory.$(OBJEXT) \ + DLLoader.$(OBJEXT) DVIReader.$(OBJEXT) \ DvisvgmSpecialHandler.$(OBJEXT) DVIToSVG.$(OBJEXT) \ - DVIToSVGActions.$(OBJEXT) EmSpecialHandler.$(OBJEXT) \ - EncFile.$(OBJEXT) EPSFile.$(OBJEXT) FileFinder.$(OBJEXT) \ - FilePath.$(OBJEXT) FileSystem.$(OBJEXT) Font.$(OBJEXT) \ - FontCache.$(OBJEXT) FontEncoding.$(OBJEXT) \ + DVIToSVGActions.$(OBJEXT) EllipticalArc.$(OBJEXT) \ + EmSpecialHandler.$(OBJEXT) EncFile.$(OBJEXT) EPSFile.$(OBJEXT) \ + FileFinder.$(OBJEXT) FilePath.$(OBJEXT) FileSystem.$(OBJEXT) \ + Font.$(OBJEXT) FontCache.$(OBJEXT) FontEncoding.$(OBJEXT) \ FontEngine.$(OBJEXT) FontManager.$(OBJEXT) FontMap.$(OBJEXT) \ FontMetrics.$(OBJEXT) FontWriter.$(OBJEXT) \ GFGlyphTracer.$(OBJEXT) GFReader.$(OBJEXT) GFTracer.$(OBJEXT) \ @@ -283,12 +283,12 @@ am__depfiles_remade = ./$(DEPDIR)/BasicDVIReader.Po \ ./$(DEPDIR)/Bitmap.Po ./$(DEPDIR)/BoundingBox.Po \ ./$(DEPDIR)/CLCommandLine.Po ./$(DEPDIR)/CMap.Po \ ./$(DEPDIR)/CMapManager.Po ./$(DEPDIR)/CMapReader.Po \ - ./$(DEPDIR)/CRC32.Po ./$(DEPDIR)/Calculator.Po \ - ./$(DEPDIR)/CharMapID.Po ./$(DEPDIR)/Color.Po \ - ./$(DEPDIR)/ColorSpecialHandler.Po ./$(DEPDIR)/DLLoader.Po \ - ./$(DEPDIR)/DVIReader.Po ./$(DEPDIR)/DVIToSVG.Po \ - ./$(DEPDIR)/DVIToSVGActions.Po ./$(DEPDIR)/Directory.Po \ - ./$(DEPDIR)/DvisvgmSpecialHandler.Po ./$(DEPDIR)/EPSFile.Po \ + ./$(DEPDIR)/Calculator.Po ./$(DEPDIR)/CharMapID.Po \ + ./$(DEPDIR)/Color.Po ./$(DEPDIR)/ColorSpecialHandler.Po \ + ./$(DEPDIR)/DLLoader.Po ./$(DEPDIR)/DVIReader.Po \ + ./$(DEPDIR)/DVIToSVG.Po ./$(DEPDIR)/DVIToSVGActions.Po \ + ./$(DEPDIR)/Directory.Po ./$(DEPDIR)/DvisvgmSpecialHandler.Po \ + ./$(DEPDIR)/EPSFile.Po ./$(DEPDIR)/EllipticalArc.Po \ ./$(DEPDIR)/EmSpecialHandler.Po ./$(DEPDIR)/EncFile.Po \ ./$(DEPDIR)/FileFinder.Po ./$(DEPDIR)/FilePath.Po \ ./$(DEPDIR)/FileSystem.Po ./$(DEPDIR)/Font.Po \ @@ -368,11 +368,27 @@ am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libdvisvgm_a_SOURCES) $(dvisvgm_SOURCES) DIST_SOURCES = $(am__libdvisvgm_a_SOURCES_DIST) $(dvisvgm_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am 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 @@ -392,14 +408,43 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/../libs/defs.am $(srcdir)/Makefile.in \ $(srcdir)/version.hpp.in $(top_srcdir)/../../build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AM_LDFLAGS = $(KPSE_LIBS) $(CODE_COVERAGE_LDFLAGS) $(am__append_13) +AM_LDFLAGS = \ + $(KPSE_LIBS) \ + $(CODE_COVERAGE_LDFLAGS) + AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ @@ -545,6 +590,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LIBRARIES = libdvisvgm.a +SUBDIRS = optimizer dvisvgm_SOURCES = \ CommandLine.hpp \ dvisvgm.cpp @@ -553,87 +599,88 @@ dvisvgm_SOURCES = \ @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 -dvisvgm_LDADD = $(noinst_LIBRARIES) ../libs/clipper/libclipper.a \ - $(POTRACE_LIBS) $(XXHASH_LIBS) $(am__append_5) $(am__append_6) \ - $(am__append_7) $(KPATHSEA_LIBS) $(FREETYPE2_LIBS) \ - $(FONTFORGE_LIBS) $(ZLIB_LIBS) $(LIBGS_LIBS) +dvisvgm_LDADD = $(noinst_LIBRARIES) optimizer/liboptimizer.a \ + ../libs/clipper/libclipper.a $(POTRACE_LIBS) $(XXHASH_LIBS) \ + $(am__append_5) $(am__append_6) $(am__append_7) \ + $(KPATHSEA_LIBS) $(FREETYPE2_LIBS) $(FONTFORGE_LIBS) \ + $(ZLIB_LIBS) $(LIBGS_LIBS) dvisvgm_DEPENDENCIES = $(noinst_LIBRARIES) $(KPATHSEA_DEPEND) \ $(ZLIB_DEPEND) $(FREETYPE2_DEPEND) -libdvisvgm_a_SOURCES = AGLTable.hpp BasicDVIReader.cpp \ - BasicDVIReader.hpp Bezier.cpp Bezier.hpp \ - BgColorSpecialHandler.cpp BgColorSpecialHandler.hpp Bitmap.cpp \ - Bitmap.hpp BoundingBox.cpp BoundingBox.hpp Calculator.cpp \ - Calculator.hpp Character.hpp CharMapID.cpp CharMapID.hpp \ - CLCommandLine.cpp CLCommandLine.hpp CLOption.hpp CMap.cpp \ - CMap.hpp CMapManager.cpp CMapManager.hpp CMapReader.cpp \ - CMapReader.hpp Color.cpp Color.hpp ColorSpecialHandler.cpp \ - ColorSpecialHandler.hpp CRC32.cpp CRC32.hpp \ - DependencyGraph.hpp Directory.cpp Directory.hpp DLLoader.cpp \ - DLLoader.hpp DVIActions.hpp DVIReader.cpp DVIReader.hpp \ - DvisvgmSpecialHandler.cpp DvisvgmSpecialHandler.hpp \ - DVIToSVG.cpp DVIToSVG.hpp DVIToSVGActions.cpp \ - DVIToSVGActions.hpp EmSpecialHandler.cpp EmSpecialHandler.hpp \ - EncFile.cpp EncFile.hpp EPSFile.cpp EPSFile.hpp EPSToSVG.hpp \ - FileFinder.cpp FileFinder.hpp FilePath.cpp FilePath.hpp \ - FileSystem.cpp FileSystem.hpp FixWord.hpp Font.cpp Font.hpp \ - FontCache.cpp FontCache.hpp FontEncoding.cpp FontEncoding.hpp \ - FontEngine.cpp FontEngine.hpp FontManager.cpp FontManager.hpp \ - FontMap.cpp FontMap.hpp FontMetrics.cpp FontMetrics.hpp \ - FontStyle.hpp FontWriter.cpp FontWriter.hpp GFGlyphTracer.cpp \ - GFGlyphTracer.hpp GFReader.cpp GFReader.hpp GFTracer.cpp \ - GFTracer.hpp Ghostscript.cpp Ghostscript.hpp Glyph.hpp \ - GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.cpp \ - HashFunction.hpp HtmlSpecialHandler.cpp HtmlSpecialHandler.hpp \ - HyperlinkManager.cpp HyperlinkManager.hpp ImageToSVG.cpp \ - ImageToSVG.hpp InputBuffer.cpp InputBuffer.hpp InputReader.cpp \ - InputReader.hpp JFM.cpp JFM.hpp Length.cpp Length.hpp \ - macros.hpp MapLine.cpp MapLine.hpp Matrix.cpp Matrix.hpp \ - MD5HashFunction.hpp Message.cpp Message.hpp \ - MessageException.hpp MetafontWrapper.cpp MetafontWrapper.hpp \ - NoPsSpecialHandler.cpp NoPsSpecialHandler.hpp \ - NumericRanges.hpp PageRanges.cpp PageRanges.hpp PageSize.cpp \ - PageSize.hpp Pair.hpp PapersizeSpecialHandler.cpp \ - PapersizeSpecialHandler.hpp PathClipper.cpp PathClipper.hpp \ - PDFParser.cpp PDFParser.hpp PDFToSVG.hpp PdfSpecialHandler.cpp \ - PdfSpecialHandler.hpp PreScanDVIReader.cpp \ - PreScanDVIReader.hpp Process.cpp Process.hpp psdefs.cpp \ - PSFilter.hpp PSInterpreter.cpp PSInterpreter.hpp PSPattern.cpp \ - PSPattern.hpp PSPreviewFilter.cpp PSPreviewFilter.hpp \ - PsSpecialHandler.cpp PsSpecialHandler.hpp RangeMap.cpp \ - RangeMap.hpp ShadingPatch.cpp ShadingPatch.hpp \ - SignalHandler.cpp SignalHandler.hpp SourceInput.cpp \ - SourceInput.hpp SpecialActions.hpp SpecialHandler.hpp \ - SpecialManager.cpp SpecialManager.hpp StreamReader.cpp \ - StreamReader.hpp StreamWriter.cpp StreamWriter.hpp Subfont.cpp \ - Subfont.hpp SVGCharHandler.cpp SVGCharHandler.hpp \ - SVGCharHandlerFactory.cpp SVGCharHandlerFactory.hpp \ - SVGCharPathHandler.cpp SVGCharPathHandler.hpp \ - SVGCharTspanTextHandler.cpp SVGCharTspanTextHandler.hpp \ - SVGOutput.cpp SVGOutput.hpp SVGSingleCharTextHandler.cpp \ - SVGSingleCharTextHandler.hpp SVGTree.cpp SVGTree.hpp \ - System.cpp System.hpp TensorProductPatch.cpp \ - TensorProductPatch.hpp Terminal.cpp Terminal.hpp TFM.cpp \ - TFM.hpp ToUnicodeMap.cpp ToUnicodeMap.hpp \ - TpicSpecialHandler.cpp TpicSpecialHandler.hpp \ - TriangularPatch.cpp TriangularPatch.hpp TrueTypeFont.cpp \ - TrueTypeFont.hpp TTFAutohint.cpp TTFAutohint.hpp Unicode.cpp \ - Unicode.hpp utility.hpp utility.cpp VectorIterator.hpp \ - VectorStream.hpp version.hpp VFActions.hpp VFReader.cpp \ - VFReader.hpp windows.hpp XMLDocument.cpp XMLDocument.hpp \ - XMLNode.cpp XMLNode.hpp XMLString.cpp XMLString.hpp \ - XXHashFunction.hpp ZLibOutputStream.hpp $(am__append_8) +libdvisvgm_a_SOURCES = AGLTable.hpp BasicDVIReader.hpp \ + BasicDVIReader.cpp Bezier.hpp Bezier.cpp \ + BgColorSpecialHandler.hpp BgColorSpecialHandler.cpp Bitmap.hpp \ + Bitmap.cpp BoundingBox.hpp BoundingBox.cpp Calculator.hpp \ + Calculator.cpp Character.hpp CharMapID.hpp CharMapID.cpp \ + CLCommandLine.hpp CLCommandLine.cpp CMap.hpp CMap.cpp \ + CMapManager.hpp CMapManager.cpp CMapReader.hpp CMapReader.cpp \ + CLOption.hpp Color.hpp Color.cpp ColorSpecialHandler.hpp \ + ColorSpecialHandler.cpp CommandLine.hpp Directory.hpp \ + Directory.cpp DVIActions.hpp DLLoader.hpp DLLoader.cpp \ + DVIReader.hpp DVIReader.cpp DvisvgmSpecialHandler.hpp \ + DvisvgmSpecialHandler.cpp DVIToSVG.hpp DVIToSVG.cpp \ + DVIToSVGActions.hpp DVIToSVGActions.cpp EllipticalArc.hpp \ + EllipticalArc.cpp EmSpecialHandler.hpp EmSpecialHandler.cpp \ + EncFile.hpp EncFile.cpp EPSFile.hpp EPSFile.cpp EPSToSVG.hpp \ + FileFinder.hpp FileFinder.cpp FilePath.hpp FilePath.cpp \ + FileSystem.hpp FileSystem.cpp FixWord.hpp Font.hpp Font.cpp \ + FontCache.hpp FontCache.cpp FontEncoding.hpp FontEncoding.cpp \ + FontEngine.hpp FontEngine.cpp FontManager.hpp FontManager.cpp \ + FontMap.hpp FontMap.cpp FontMetrics.hpp FontMetrics.cpp \ + FontStyle.hpp FontWriter.hpp FontWriter.cpp GFGlyphTracer.hpp \ + GFGlyphTracer.cpp GFReader.hpp GFReader.cpp GFTracer.hpp \ + GFTracer.cpp Ghostscript.hpp Ghostscript.cpp Glyph.hpp \ + GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.hpp \ + HashFunction.cpp HtmlSpecialHandler.hpp HtmlSpecialHandler.cpp \ + HyperlinkManager.hpp HyperlinkManager.cpp ImageToSVG.hpp \ + ImageToSVG.cpp InputBuffer.hpp InputBuffer.cpp InputReader.hpp \ + InputReader.cpp JFM.hpp JFM.cpp Length.hpp Length.cpp \ + macros.hpp MapLine.hpp MapLine.cpp Matrix.hpp Matrix.cpp \ + MD5HashFunction.hpp Message.hpp Message.cpp \ + MessageException.hpp MetafontWrapper.hpp MetafontWrapper.cpp \ + NoPsSpecialHandler.hpp NoPsSpecialHandler.cpp \ + NumericRanges.hpp PageRanges.hpp PageRanges.cpp PageSize.hpp \ + PageSize.cpp Pair.hpp PapersizeSpecialHandler.hpp \ + PapersizeSpecialHandler.cpp PathClipper.hpp PathClipper.cpp \ + PDFParser.hpp PDFParser.cpp PdfSpecialHandler.hpp \ + PdfSpecialHandler.cpp PDFToSVG.hpp PreScanDVIReader.hpp \ + PreScanDVIReader.cpp Process.hpp Process.cpp psdefs.cpp \ + PSFilter.hpp PSInterpreter.hpp PSInterpreter.cpp PSPattern.hpp \ + PSPattern.cpp PSPreviewFilter.hpp PSPreviewFilter.cpp \ + PsSpecialHandler.hpp PsSpecialHandler.cpp RangeMap.hpp \ + RangeMap.cpp ShadingPatch.hpp ShadingPatch.cpp \ + SignalHandler.hpp SignalHandler.cpp SourceInput.hpp \ + SourceInput.cpp SpecialActions.hpp SpecialHandler.hpp \ + SpecialManager.hpp SpecialManager.cpp StreamReader.hpp \ + StreamReader.cpp StreamWriter.hpp StreamWriter.cpp Subfont.hpp \ + Subfont.cpp SVGCharHandler.hpp SVGCharHandler.cpp \ + SVGCharHandlerFactory.hpp SVGCharHandlerFactory.cpp \ + SVGCharPathHandler.hpp SVGCharPathHandler.cpp \ + SVGCharTspanTextHandler.hpp SVGCharTspanTextHandler.cpp \ + SVGOutput.hpp SVGOutput.cpp SVGSingleCharTextHandler.hpp \ + SVGSingleCharTextHandler.cpp SVGTree.hpp SVGTree.cpp \ + System.hpp System.cpp TensorProductPatch.hpp \ + TensorProductPatch.cpp Terminal.hpp Terminal.cpp TFM.hpp \ + TFM.cpp ToUnicodeMap.hpp ToUnicodeMap.cpp \ + TpicSpecialHandler.hpp TpicSpecialHandler.cpp \ + TriangularPatch.hpp TriangularPatch.cpp TrueTypeFont.hpp \ + TrueTypeFont.cpp TTFAutohint.hpp TTFAutohint.cpp Unicode.hpp \ + Unicode.cpp utility.hpp utility.cpp VectorIterator.hpp \ + VectorStream.hpp VFActions.hpp VFReader.hpp VFReader.cpp \ + windows.hpp XMLDocument.hpp XMLDocument.cpp XMLNode.hpp \ + XMLNode.cpp XMLString.hpp XMLString.cpp XXHashFunction.hpp \ + ZLibOutputStream.hpp $(am__append_8) EXTRA_DIST = options.xml options.dtd iapi.h ierrors.h MiKTeXCom.hpp MiKTeXCom.cpp AM_CFLAGS = $(WARNING_CFLAGS) $(ZLIB_INCLUDES) $(CODE_COVERAGE_CFLAGS) \ - $(am__append_9) + $(am__append_10) AM_CXXFLAGS = $(WARNING_CXXFLAGS) -Wnon-virtual-dtor \ -I$(dvisvgm_srcdir)/libs/clipper \ -I$(dvisvgm_srcdir)/libs/variant/include $(POTRACE_CFLAGS) \ - $(XXHASH_CFLAGS) $(am__append_10) $(am__append_11) \ - $(am__append_12) $(KPATHSEA_INCLUDES) $(POTRACE_INCLUDES) \ - $(FREETYPE2_INCLUDES) $(ZLIB_INCLUDES) $(LIBGS_INCLUDES) \ - $(CODE_COVERAGE_CFLAGS) $(am__append_14) + $(XXHASH_CFLAGS) $(KPATHSEA_INCLUDES) $(POTRACE_INCLUDES) \ + $(FREETYPE2_INCLUDES) $(LIBGS_INCLUDES) \ + $(CODE_COVERAGE_CFLAGS) $(am__append_9) $(am__append_11) \ + $(am__append_12) $(am__append_13) CLEANFILES = *.gcda *.gcno -all: all-am +all: all-recursive .SUFFIXES: .SUFFIXES: .c .cpp .lo .o .obj @@ -746,7 +793,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMapManager.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMapReader.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CRC32.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Calculator.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CharMapID.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Color.Po@am__quote@ # am--include-marker @@ -758,6 +804,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Directory.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DvisvgmSpecialHandler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EPSFile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EllipticalArc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EmSpecialHandler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EncFile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileFinder.Po@am__quote@ # am--include-marker @@ -894,14 +941,61 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am +tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ @@ -914,7 +1008,7 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $$unique; \ fi; \ fi -ctags: ctags-am +ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) @@ -927,7 +1021,7 @@ GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am +cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ @@ -979,22 +1073,48 @@ distdir-am: $(DISTFILES) || exit 1; \ fi; \ done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done check-am: all-am -check: check-am +check: check-recursive all-am: Makefile $(PROGRAMS) $(LIBRARIES) -installdirs: +installdirs: installdirs-recursive +installdirs-am: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -installcheck: installcheck-am +installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ @@ -1017,12 +1137,12 @@ distclean-generic: 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: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstLIBRARIES mostlyclean-am -distclean: distclean-am +distclean: distclean-recursive -rm -f ./$(DEPDIR)/BasicDVIReader.Po -rm -f ./$(DEPDIR)/Bezier.Po -rm -f ./$(DEPDIR)/BgColorSpecialHandler.Po @@ -1032,7 +1152,6 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/CMap.Po -rm -f ./$(DEPDIR)/CMapManager.Po -rm -f ./$(DEPDIR)/CMapReader.Po - -rm -f ./$(DEPDIR)/CRC32.Po -rm -f ./$(DEPDIR)/Calculator.Po -rm -f ./$(DEPDIR)/CharMapID.Po -rm -f ./$(DEPDIR)/Color.Po @@ -1044,6 +1163,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/Directory.Po -rm -f ./$(DEPDIR)/DvisvgmSpecialHandler.Po -rm -f ./$(DEPDIR)/EPSFile.Po + -rm -f ./$(DEPDIR)/EllipticalArc.Po -rm -f ./$(DEPDIR)/EmSpecialHandler.Po -rm -f ./$(DEPDIR)/EncFile.Po -rm -f ./$(DEPDIR)/FileFinder.Po @@ -1123,47 +1243,47 @@ distclean: distclean-am distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags -dvi: dvi-am +dvi: dvi-recursive dvi-am: -html: html-am +html: html-recursive html-am: -info: info-am +info: info-recursive info-am: install-data-am: -install-dvi: install-dvi-am +install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS -install-html: install-html-am +install-html: install-html-recursive install-html-am: -install-info: install-info-am +install-info: install-info-recursive install-info-am: install-man: -install-pdf: install-pdf-am +install-pdf: install-pdf-recursive install-pdf-am: -install-ps: install-ps-am +install-ps: install-ps-recursive install-ps-am: installcheck-am: -maintainer-clean: maintainer-clean-am +maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/BasicDVIReader.Po -rm -f ./$(DEPDIR)/Bezier.Po -rm -f ./$(DEPDIR)/BgColorSpecialHandler.Po @@ -1173,7 +1293,6 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/CMap.Po -rm -f ./$(DEPDIR)/CMapManager.Po -rm -f ./$(DEPDIR)/CMapReader.Po - -rm -f ./$(DEPDIR)/CRC32.Po -rm -f ./$(DEPDIR)/Calculator.Po -rm -f ./$(DEPDIR)/CharMapID.Po -rm -f ./$(DEPDIR)/Color.Po @@ -1185,6 +1304,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/Directory.Po -rm -f ./$(DEPDIR)/DvisvgmSpecialHandler.Po -rm -f ./$(DEPDIR)/EPSFile.Po + -rm -f ./$(DEPDIR)/EllipticalArc.Po -rm -f ./$(DEPDIR)/EmSpecialHandler.Po -rm -f ./$(DEPDIR)/EncFile.Po -rm -f ./$(DEPDIR)/FileFinder.Po @@ -1263,42 +1383,44 @@ maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic -mostlyclean: mostlyclean-am +mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool -pdf: pdf-am +pdf: pdf-recursive pdf-am: -ps: ps-am +ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ - clean-binPROGRAMS clean-generic clean-libtool \ - clean-noinstLIBRARIES 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-binPROGRAMS 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 uninstall-binPROGRAMS +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + 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-binPROGRAMS 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 \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile # TL: do not try to rebuild these source files. + # the command-line parser class is generated from options.xml by opt2cpp @TEXLIVE_BUILD_FALSE@$(srcdir)/CommandLine.hpp: options.xml @TEXLIVE_BUILD_FALSE@ rm -f $@ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp index eb82372ce58..57aa116f028 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp @@ -28,11 +28,6 @@ using namespace std; -MapLine::MapLine () : _sfd(0), _fontindex(0), _slant(0), _bold(0), _extend(1) -{ -} - - /** Constructs a MapLine object by parsing a single map line from the given stream. */ MapLine::MapLine (istream &is) : MapLine() { char buf[256]; @@ -226,9 +221,7 @@ void MapLine::parseDVIPDFMLine (InputReader &ir) { throw_number_expected('w', true); break; default: - ostringstream oss; - oss << "invalid option: -" << option; - throw MapLineException(oss.str()); + throw MapLineException("invalid option: -" + string(1, option)); } ir.skipSpace(); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp index 1620becd5e7..ea41fae0d02 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp @@ -31,17 +31,15 @@ class InputReader; class SubfontDefinition; -struct MapLineException : MessageException -{ - MapLineException (const std::string &msg) : MessageException(msg) {} +struct MapLineException : MessageException { + explicit MapLineException (const std::string &msg) : MessageException(msg) {} }; -class MapLine -{ +class MapLine { public: - MapLine (std::istream &is); - MapLine (std::string str); + explicit MapLine (std::istream &is); + explicit MapLine (std::string str); const std::string& texname () const {return _texname;} const std::string& psname () const {return _psname;} const std::string& fontfname () const {return _fontfname;} @@ -53,8 +51,7 @@ class MapLine SubfontDefinition* sfd () const {return _sfd;} protected: - MapLine (); - void init (); + MapLine () =default; bool isDVIPSFormat (const char *line) const; void parse (const char *line); void parseDVIPSLine (InputReader &ir); @@ -62,13 +59,13 @@ class MapLine void parseFilenameOptions (std::string opt); private: - std::string _texname; ///< TeX font name - std::string _psname; ///< PS font name - std::string _fontfname; ///< name of fontfile - std::string _encname; ///< name of encoding (without file suffix ".enc") - SubfontDefinition *_sfd; ///< subfont definition to be used - int _fontindex; ///< font index of file with multiple fonts (e.g. ttc files) - double _slant, _bold, _extend; + std::string _texname; ///< TeX font name + std::string _psname; ///< PS font name + std::string _fontfname; ///< name of fontfile + std::string _encname; ///< name of encoding (without file suffix ".enc") + SubfontDefinition *_sfd=nullptr; ///< subfont definition to be used + int _fontindex=0; ///< font index of file with multiple fonts (e.g. ttc files) + double _slant=0, _bold=0, _extend=1; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp index 1f9ff9ac0fa..f94e84809c1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp @@ -70,7 +70,7 @@ Matrix::Matrix (double d) { * remaining matrix components will be set to those of the identity matrix. * @param[in] v array containing the matrix components * @param[in] size size of array v */ -Matrix::Matrix (double v[], unsigned size) { +Matrix::Matrix (const double *v, unsigned size) { set(v, size); } @@ -86,7 +86,7 @@ Matrix::Matrix (const std::vector<double> &v, int start) { Matrix::Matrix (const string &cmds, Calculator &calc) { - parse(cmds, calc); + *this = parse(cmds, calc); } @@ -109,7 +109,7 @@ Matrix& Matrix::set (double d) { } -Matrix& Matrix::set (double v[], unsigned size) { +Matrix& Matrix::set (const double *v, unsigned size) { size = min(size, 9u); for (unsigned i=0; i < size; i++) _values[i/3][i%3] = v[i]; @@ -134,8 +134,8 @@ Matrix& Matrix::set (const vector<double> &v, int start) { } -Matrix& Matrix::set(const string &cmds, Calculator &calc) { - parse(cmds, calc); +Matrix& Matrix::set (const string &cmds, Calculator &calc) { + *this = parse(cmds, calc); return *this; } @@ -143,7 +143,7 @@ Matrix& Matrix::set(const string &cmds, Calculator &calc) { Matrix& Matrix::translate (double tx, double ty) { if (tx != 0 || ty != 0) { TranslationMatrix t(tx, ty); - rmultiply(t); + lmultiply(t); } return *this; } @@ -152,7 +152,7 @@ Matrix& Matrix::translate (double tx, double ty) { Matrix& Matrix::scale (double sx, double sy) { if (sx != 1 || sy != 1) { ScalingMatrix s(sx, sy); - rmultiply(s); + lmultiply(s); } return *this; } @@ -163,7 +163,7 @@ Matrix& Matrix::scale (double sx, double sy) { * @param[in] deg rotation angle in degrees */ Matrix& Matrix::rotate (double deg) { RotationMatrix r(deg); - rmultiply(r); + lmultiply(r); return *this; } @@ -179,7 +179,7 @@ Matrix& Matrix::xskewByRatio (double xyratio) { if (xyratio != 0) { double v[] = {1, xyratio}; Matrix t(v, 2); - rmultiply(t); + lmultiply(t); } return *this; } @@ -196,7 +196,7 @@ Matrix& Matrix::yskewByRatio (double xyratio) { if (xyratio != 0) { double v[] = {1, 0, 0, xyratio}; Matrix t(v, 4); - rmultiply(t); + lmultiply(t); } return *this; } @@ -208,7 +208,7 @@ Matrix& Matrix::flip (bool haxis, double a) { s = -1; double v[] = {-s, 0, (haxis ? 0 : 2*a), 0, s, (haxis ? 2*a : 0), 0, 0, 1}; Matrix t(v); - rmultiply(t); + lmultiply(t); return *this; } @@ -222,8 +222,8 @@ Matrix& Matrix::transpose () { } -/** Multiplies this matrix M with matrix tm (tm is the factor on the left side): M := tm * M */ -Matrix& Matrix::lmultiply (const Matrix &tm) { +/** Multiplies this matrix M with matrix tm (tm is the factor on the right side): M := M * tm */ +Matrix& Matrix::rmultiply (const Matrix &tm) { Matrix ret; for (int i=0; i < 3; i++) for (int j=0; j < 3; j++) @@ -233,8 +233,8 @@ Matrix& Matrix::lmultiply (const Matrix &tm) { } -/** Multiplies this matrix M with matrix tm (tm is the factor on the right side): M := M * tm */ -Matrix& Matrix::rmultiply (const Matrix &tm) { +/** Multiplies this matrix M with matrix tm (tm is the factor on the left side): M := tm * M */ +Matrix& Matrix::lmultiply (const Matrix &tm) { Matrix ret; for (int i=0; i < 3; i++) for (int j=0; j < 3; j++) @@ -356,8 +356,8 @@ static double getArgument (istream &is, Calculator &calc, double def, bool optio } -Matrix& Matrix::parse (istream &is, Calculator &calc) { - *this = Matrix(1); +Matrix Matrix::parse (istream &is, Calculator &calc) { + Matrix ret(1); while (is) { is >> ws; int cmd = is.get(); @@ -365,22 +365,22 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { case 'T': { double tx = getArgument(is, calc, 0, false, false); double ty = getArgument(is, calc, 0, true, true); - translate(tx, ty); + ret.translate(tx, ty); break; } case 'S': { double sx = getArgument(is, calc, 1, false, false); double sy = getArgument(is, calc, sx, true, true ); - scale(sx, sy); + ret.scale(sx, sy); break; } case 'R': { double a = getArgument(is, calc, 0, false, false); double x = getArgument(is, calc, calc.getVariable("ux")+calc.getVariable("w")/2, true, true); double y = getArgument(is, calc, calc.getVariable("uy")+calc.getVariable("h")/2, true, true); - translate(-x, -y); - rotate(a); - translate(x, y); + ret.translate(-x, -y); + ret.rotate(a); + ret.translate(x, y); break; } case 'F': { @@ -388,7 +388,7 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { if (c != 'H' && c != 'V') throw ParserException("'H' or 'V' expected"); double a = getArgument(is, calc, 0, false, false); - flip(c == 'H', a); + ret.flip(c == 'H', a); break; } case 'K': { @@ -396,15 +396,12 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { if (c != 'X' && c != 'Y') throw ParserException("transformation command 'K' must be followed by 'X' or 'Y'"); double a = getArgument(is, calc, 0, false, false); - if (std::abs(cos(deg2rad(a))) < numeric_limits<double>::epsilon()) { - ostringstream oss; - oss << "illegal skewing angle: " << a << " degrees"; - throw ParserException(oss.str()); - } + if (std::abs(cos(deg2rad(a))) < numeric_limits<double>::epsilon()) + throw ParserException("illegal skewing angle: " + util::to_string(a) + " degrees"); if (c == 'X') - xskewByAngle(a); + ret.xskewByAngle(a); else - yskewByAngle(a); + ret.yskewByAngle(a); break; } case 'M': { @@ -415,20 +412,18 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { v[6] = v[7] = 0; v[8] = 1; Matrix tm(v); - rmultiply(tm); + ret.lmultiply(tm); break; } default: - ostringstream oss; - oss << "transformation command expected (found '" << char(cmd) << "' instead)"; - throw ParserException(oss.str()); + throw ParserException("transformation command expected (found '" + string(1, cmd) + "' instead)"); } } - return *this; + return ret; } -Matrix& Matrix::parse (const string &cmds, Calculator &calc) { +Matrix Matrix::parse (const string &cmds, Calculator &calc) { istringstream iss; iss.str(cmds); return parse(iss, calc); @@ -437,17 +432,14 @@ Matrix& Matrix::parse (const string &cmds, Calculator &calc) { /** Returns an SVG matrix expression that can be used in transform attributes. * ((a,b,c),(d,e,f),(0,0,1)) => matrix(a d b e c f) */ -string Matrix::getSVG () const { +string Matrix::toSVG () const { ostringstream oss; oss << "matrix("; for (int i=0; i < 3; i++) { - for (int j=0; j < 2; j++) { - if (i > 0 || j > 0) - oss << ' '; - oss << XMLString(_values[j][i]); - } + for (int j=0; j < 2; j++) + oss << XMLString(_values[j][i]) << ' '; } - oss << ')'; + oss.seekp(-1, ios::cur) << ')'; // overwrite trailing space character return oss.str(); } @@ -467,9 +459,118 @@ ostream& Matrix::write (ostream &os) const { } -////////////////////////////////////////////////////////////////// +static const char* ord_suffix (int n) { + static const char *suffixes[] = {"th", "st", "nd", "rd"}; + if (abs(n) < 4) + return suffixes[n]; + return suffixes[0]; +} + + +static void skip_comma_wsp (istream &is) { + is >> ws; + if (is.peek() == ',') is.ignore(1); + is >> ws; +} + + +static size_t parse_transform_cmd (istream &is, string cmd, size_t minparams, size_t maxparams, vector<double> ¶ms) { + for (int i=0; i < int(cmd.length()); i++) { + if (is.get() != cmd[i]) { + is.seekg(-i-1, ios::cur); + return 0; + } + } + params.clear(); + is >> ws; + if (is.get() != '(') + throw ParserException("missing '(' after command '"+cmd+"'"); + for (size_t i=1; i <= maxparams; i++) { + is >> ws; + double val; + if (is.fail()) + throw ParserException(to_string(i)+ord_suffix(i)+" parameter of '"+cmd+"' must be a number"); + is >> val; + params.push_back(val); + is >> ws; + if (i == minparams && is.peek() == ')') { + is.ignore(1); + return i; + } + if (i == maxparams) { + if (is.peek() != ')') + throw ParserException("missing ')' at end of command '"+cmd+"'"); + is.ignore(1); + } + skip_comma_wsp(is); + } + return maxparams; +} +static bool ne (double x, double y) {return abs(x-y) >= 1e-6;} +static bool ne_angle (double x, double y) {return abs(x-y) >= 1e-3;} + + +Matrix Matrix::parseSVGTransform (const string &transform) { + istringstream iss(transform); + Matrix matrix(1); + iss >> ws; + while (iss) { + vector<double> params; + if (parse_transform_cmd(iss, "matrix", 6, 6, params)) { + if (ne(params[0], 1) || ne(params[1], 0) || ne(params[2], 0) || ne(params[3], 1) || ne(params[4], 0) || ne(params[5], 0)) + matrix.rmultiply({params[0], params[2], params[4], params[1], params[3], params[5]}); + } + else if (parse_transform_cmd(iss, "rotate", 1, 3, params)) { + if (params.size() == 1) { + params.push_back(0); + params.push_back(0); + } + if (ne_angle(fmod(params[0], 360), 0)) { + bool translate = ne(params[1], 0) || ne(params[2], 0); + if (translate) + matrix.rmultiply(TranslationMatrix(params[1], params[2])); + matrix.rmultiply(RotationMatrix(params[0])); + if (translate) + matrix.rmultiply(TranslationMatrix(-params[1], -params[2])); + } + } + else if (parse_transform_cmd(iss, "scale", 1, 2, params)) { + if (params.size() == 1) + params.push_back(1); + if (ne(params[0], 1) || ne(params[1], 1)) + matrix.rmultiply(ScalingMatrix(params[0], params[1])); + } + else if (parse_transform_cmd(iss, "skewX", 1, 1, params)) { + if (ne_angle(fmod(abs(params[0])-90, 180), 0)) + matrix.rmultiply(XSkewingMatrix(params[0])); + } + else if (parse_transform_cmd(iss, "skewY", 1, 1, params)) { + if (ne_angle(fmod(abs(params[0])-90, 180), 0)) + matrix.rmultiply(YSkewingMatrix(params[0])); + } + else if (parse_transform_cmd(iss, "translate", 1, 2, params)) { + if (params.size() == 1) + params.push_back(0); + if (ne(params[0], 0) || ne(params[1], 0)) + matrix.rmultiply(TranslationMatrix(params[0], params[1])); + } + else { // invalid command + string cmd; + while (isalpha(iss.peek())) + cmd += char(iss.get()); + if (cmd.empty()) + throw ParserException("unexpected character in transform attribute: "+to_string(char(iss.get()))); + throw ParserException("invalid command in transform attribute: "+cmd); + } + skip_comma_wsp(iss); + } + return matrix; +} + +////////////////////////////////////////////////////////////////// + TranslationMatrix::TranslationMatrix (double tx, double ty) { double v[] = {1, 0, tx, 0, 1, ty}; set(v, 6); @@ -490,3 +591,14 @@ RotationMatrix::RotationMatrix (double deg) { set(v, 5); } + +XSkewingMatrix::XSkewingMatrix (double deg) { + double xyratio = tan(deg2rad(deg)); + lmultiply(Matrix({1, xyratio})); +} + + +YSkewingMatrix::YSkewingMatrix (double deg) { + double xyratio = tan(deg2rad(deg)); + lmultiply(Matrix({1, 0, 0, xyratio})); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp index 73b443a619c..733ff71fad8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp @@ -30,7 +30,7 @@ struct ParserException : public MessageException { - ParserException (const std::string &msg) : MessageException(msg) {} + explicit ParserException (const std::string &msg) : MessageException(msg) {} }; class Calculator; @@ -42,20 +42,18 @@ class Matrix { public: Matrix (const std::string &cmds, Calculator &calc); Matrix (double d=0); - Matrix (double v[], unsigned size=9); - Matrix (const std::vector<double> &v, int start=0); + explicit Matrix (const double *v, unsigned size=9); + explicit Matrix (const std::vector<double> &v, int start=0); Matrix (std::initializer_list<double> initlist); Matrix& set (double d); - Matrix& set (double v[], unsigned size); + Matrix& set (const double *v, unsigned size); Matrix& set (const std::vector<double> &v, int start=0); Matrix& set (const std::string &cmds, Calculator &calc); double get (int row, int col) const {return _values[row][col];} Matrix& transpose (); Matrix& invert (); - Matrix& parse (std::istream &is, Calculator &c); - Matrix& parse (const std::string &cmds, Calculator &c); - Matrix& lmultiply (const Matrix &tm); Matrix& rmultiply (const Matrix &tm); + Matrix& lmultiply (const Matrix &tm); Matrix& translate (double tx, double ty); Matrix& translate (const DPair &p) {return translate(p.x(), p.y());} Matrix& scale (double sx, double sy); @@ -72,9 +70,13 @@ class Matrix { bool operator != (const Matrix &m) const; bool isIdentity() const; bool isTranslation (double &tx, double &ty) const; - std::string getSVG () const; + std::string toSVG () const; std::ostream& write (std::ostream &os) const; + static Matrix parse (std::istream &is, Calculator &c); + static Matrix parse (const std::string &cmds, Calculator &c); + static Matrix parseSVGTransform (const std::string &transform); + private: double _values[3][3]; // row x col }; @@ -91,7 +93,17 @@ struct ScalingMatrix : public Matrix { struct RotationMatrix : public Matrix { - RotationMatrix (double deg); + explicit RotationMatrix (double deg); +}; + + +struct XSkewingMatrix : public Matrix { + explicit XSkewingMatrix (double deg); +}; + + +struct YSkewingMatrix : public Matrix { + explicit YSkewingMatrix (double deg); }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp index 4ab9fc89a7d..85ed204cb43 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp @@ -28,12 +28,8 @@ using namespace std; -MessageStream::MessageStream () : _os(0), _nl(false), _col(1), _indent(0) { -} - - -MessageStream::MessageStream (std::ostream &os) - : _os(&os), _nl(true), _col(1), _indent(0) +MessageStream::MessageStream (std::ostream &os) noexcept + : _os(&os), _nl(true) { Terminal::init(os); } @@ -45,7 +41,7 @@ MessageStream::~MessageStream () { } -void MessageStream::putChar (const char c, ostream &os) { +void MessageStream::putChar (char c, ostream &os) { switch (c) { case '\r': os << '\r'; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp index 95a96555637..a7e60340218 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp @@ -31,13 +31,12 @@ class Message; -class MessageStream -{ +class MessageStream { friend class Message; public: - MessageStream (); - MessageStream (std::ostream &os); + MessageStream () =default; + explicit MessageStream (std::ostream &os) noexcept; ~MessageStream (); template <typename T> @@ -58,26 +57,25 @@ class MessageStream void clearline (); protected: - void putChar (const char c, std::ostream &os); + void putChar (char c, std::ostream &os); std::ostream* os () {return _os;} private: - std::ostream *_os; - bool _nl; ///< true if previous character was a newline - int _col; ///< current terminal column - int _indent; ///< indentation width (number of columns/characters) + std::ostream *_os=nullptr; + bool _nl=false; ///< true if previous character was a newline + int _col=1; ///< current terminal column + int _indent=0; ///< indentation width (number of columns/characters) }; -class Message -{ +class Message { struct Color { - Color () : foreground(-1), background(-1) {} - Color (int8_t fgcolor) : foreground(fgcolor), background(-1) {} - Color (int8_t fgcolor, bool light) : foreground(fgcolor + (light ? 8 : 0)), background(-1) {} - Color (int8_t fgcolor, int8_t bgcolor) : foreground(fgcolor), background(bgcolor) {} - int8_t foreground; - int8_t background; + Color () =default; + explicit Color (int8_t fgcolor) noexcept : foreground(fgcolor) {} + Color (int8_t fgcolor, bool light) noexcept: foreground(fgcolor + (light ? 8 : 0)) {} + Color (int8_t fgcolor, int8_t bgcolor) noexcept : foreground(fgcolor), background(bgcolor) {} + int8_t foreground = -1; + int8_t background = -1; }; public: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp index ccd6567d3d2..c7aa342860e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp @@ -25,12 +25,10 @@ #include <string> -class MessageException : public std::exception -{ +class MessageException : public std::exception { public: - MessageException (const std::string &msg) : _message(msg) {} - virtual ~MessageException () throw() =default; - const char* what () const throw() override {return _message.c_str();} + explicit MessageException (std::string msg) : _message(std::move(msg)) {} + const char* what () const noexcept override {return _message.c_str();} private: std::string _message; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp index a5f8538c319..5807d7254ef 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp @@ -18,7 +18,6 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#include <cstdlib> #include <cctype> #include <fstream> #include <sstream> @@ -32,12 +31,13 @@ using namespace std; -MetafontWrapper::MetafontWrapper (const string &fname, const string &dir) : _fontname(fname), _dir(dir) +MetafontWrapper::MetafontWrapper (string fname, string dir) + : _fontname(std::move(fname)), _dir(std::move(dir)) { // ensure that folder paths ends with slash if (_dir.empty()) _dir = "./"; - else if (_dir != "/" && dir[dir.length()-1] != '/') + else if (_dir != "/" && _dir.back() != '/') _dir += '/'; } @@ -87,7 +87,7 @@ bool MetafontWrapper::call (const string &mode, double mag) { iss.getline(buf, sizeof(buf)); string line = buf; if (line.substr(0, 3) == ">> ") { - resolution = atoi(line.substr(3).c_str()); + resolution = stoi(line.substr(3)); break; } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp index e1107afe9ba..031eb01ebd1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp @@ -29,7 +29,7 @@ class FileFinder; class MetafontWrapper { public: - MetafontWrapper (const std::string &fontname, const std::string &dir); + MetafontWrapper (std::string fname, std::string dir); bool call (const std::string &mode, double mag); bool make (const std::string &mode, double mag); bool success () const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp index c87d0e3d862..5bf19811674 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp @@ -25,10 +25,10 @@ #include "windows.hpp" #ifdef _MSC_VER -#import <MiKTeX209-session.tlb> +#import <miktex-session.tlb> using namespace MiKTeXSession2_9; #else -#include "miktex209-session.h" +#include "miktex-session.h" #endif class MiKTeXCom { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp index 5f97cfdb27a..f4f04218856 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp @@ -27,8 +27,8 @@ class NoPsSpecialHandler : public SpecialHandler { public: NoPsSpecialHandler () : _count(0) {} bool process (const std::string &prefix, std::istream &is, SpecialActions &actions) override; - const char* name () const override {return 0;} - const char* info () const override {return 0;} + const char* name () const override {return nullptr;} + const char* info () const override {return nullptr;} std::vector<const char*> prefixes() const override; protected: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp index 10dd9b1577c..1ecd40cba82 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp @@ -119,7 +119,7 @@ static pair<bool,int> parse_escape_seq (InputReader &ir) { string str; for (int i=0; i < 3 && isoctaldigit(ir.peek()); i++) str += static_cast<char>(ir.get()); - return pair<bool,int>{true, stoi(str, 0, 8)}; + return pair<bool,int>{true, stoi(str, nullptr, 8)}; } char c = static_cast<char>(ir.get()); switch (c) { @@ -168,10 +168,8 @@ static string parse_literal_string (InputReader &ir) { static char get_hex_digit (InputReader &ir) { int c = ir.get(); if (isxdigit(c)) - return static_cast<char>(c); - ostringstream oss; - oss << "invalid hexadecimal digit '" << static_cast<char>(c) << "'"; - throw PDFException(oss.str()); + return char(c); + throw PDFException("invalid hexadecimal digit '" + string(1, char(c)) + "'"); } @@ -190,7 +188,7 @@ static string parse_hex_string (InputReader &ir) { else if (ir.peek() == '>') hexpair += '0'; ir.skipSpace(); - str += static_cast<char>(stoi(hexpair, 0, 16)); + str += static_cast<char>(stoi(hexpair, nullptr, 16)); } if (ir.peek() != '>') throw PDFException("missing '>' at end of hexadecimal string"); @@ -316,7 +314,7 @@ static string& subst_numeric_chars (string &str) { if (pos > str.length()-3) throw PDFException("sign character # must be followed by two hexadecimal digits"); if (isxdigit(str[pos+1]) && isxdigit(str[pos+2])) { - int c = stoi(str.substr(pos+1, 2), 0, 16); + int c = stoi(str.substr(pos+1, 2), nullptr, 16); if (c == 0) throw PDFException("null character not permitted in name"); str.replace(pos, 3, 1, static_cast<char>(c)); @@ -458,7 +456,7 @@ static ostream& operator << (ostream &os, const unique_ptr<Dictionary<string,PDF struct WriteVisitor { - WriteVisitor (ostream &os) : _os(os) {} + explicit WriteVisitor (ostream &os) : _os(os) {} template <typename T> void operator () (const T &val) {_os << val;} ostream &_os; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp index f4595ce4de0..64716683077 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp @@ -79,12 +79,12 @@ struct PDFObjectRef { }; struct PDFOperator { - PDFOperator (const std::string &name) : opname(name) {} + explicit PDFOperator (std::string name) : opname(std::move(name)) {} std::string opname; }; struct PDFName { - PDFName (const std::string &val) : str(val) {} + explicit PDFName (std::string val) : str(std::move(val)) {} bool operator == (const PDFName &name) const {return str == name.str;} std::string str; }; @@ -134,14 +134,14 @@ class PDFObject { template<> inline const PDFArray* PDFObject::get() const { - if (auto *p = mpark::get_if<std::unique_ptr<PDFArray>>(&_value)) + if (auto p = mpark::get_if<std::unique_ptr<PDFArray>>(&_value)) return &(**p); return nullptr; } template<> inline const PDFDict* PDFObject::get() const { - if (auto *p = mpark::get_if<std::unique_ptr<PDFDict>>(&_value)) + if (auto p = mpark::get_if<std::unique_ptr<PDFDict>>(&_value)) return &(**p); return nullptr; } @@ -179,7 +179,7 @@ class PDFParser { /** If errors occur while parsing a sequence of PDF objects, an instance of this exception is thrown. */ struct PDFException : public MessageException { - PDFException (const std::string &msg) : MessageException(msg) {} + explicit PDFException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp index f999de88e8d..d1871d0bb1e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp @@ -60,4 +60,3 @@ class PDFToSVG : public ImageToSVG { }; #endif - diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp index c27dcfea4bb..aa9cab21077 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp @@ -51,8 +51,15 @@ void PSInterpreter::init () { "-dWRITESYSTEMDICT", // leave systemdict writable as some operators must be replaced "-dNOPROMPT" }; - if (int gsrev = _gs.revision()) + if (int gsrev = _gs.revision()) { gsargs.emplace_back(gsrev == 922 ? "-dREALLYDELAYBIND" : "-dDELAYBIND"); + // As of GS 9.50, -dSAFER is active by default which leads to warnings + // in conjunction with -dDELAYBIND and -dWRITESYSTEMDICT. + // Thus, -dDELAYSAFER (or -dNOSAFER) must be added. + // https://www.ghostscript.com/doc/9.50/Use.htm#Safer + if (gsrev >= 950) + gsargs.emplace_back("-dDELAYSAFER"); + } _gs.init(gsargs.size(), gsargs.data(), this); _gs.set_stdio(input, output, error); _initialized = true; @@ -111,7 +118,7 @@ bool PSInterpreter::execute (const char *str, size_t len, bool flush) { if (_filter && _filter->active()) { PSFilter *filter = _filter; - _filter = 0; // prevent recursion when filter calls execute() + _filter = nullptr; // prevent recursion when filter calls execute() filter->execute(str, len); if (filter->active()) // filter still active after execution? _filter = filter; @@ -189,7 +196,7 @@ int GSDLLCALL PSInterpreter::input (void *inst, char *buf, int len) { * @param[in] len number of characters in buf * @return number of processed characters (equals 'len') */ int GSDLLCALL PSInterpreter::output (void *inst, const char *buf, int len) { - PSInterpreter *self = static_cast<PSInterpreter*>(inst); + auto self = static_cast<PSInterpreter*>(inst); if (self && self->_actions) { const size_t MAXLEN = 512; // maximal line length (longer lines are of no interest) const char *end = buf+len-1; // last position of buf @@ -204,7 +211,7 @@ int GSDLLCALL PSInterpreter::output (void *inst, const char *buf, int len) { vector<char> &linebuf = self->_linebuf; // just a shorter name... if ((*last == '\n' || !self->active()) || self->_inError) { if (linelength + linebuf.size() > 1) { // prefix "dvi." plus final newline - SplittedCharInputBuffer ib(linebuf.empty() ? 0 : &linebuf[0], linebuf.size(), first, linelength); + SplittedCharInputBuffer ib(linebuf.empty() ? nullptr : &linebuf[0], linebuf.size(), first, linelength); BufferInputReader in(ib); if (self->_inError) self->_errorMessage += string(first, linelength); @@ -213,7 +220,7 @@ int GSDLLCALL PSInterpreter::output (void *inst, const char *buf, int len) { if (in.check("Unrecoverable error: ")) { self->_errorMessage.clear(); while (!in.eof()) - self->_errorMessage += in.get(); + self->_errorMessage += char(in.get()); self->_inError = true; } else if (in.check("dvi.")) @@ -279,6 +286,7 @@ void PSInterpreter::callActions (InputReader &in) { {"setlinewidth", { 1, &PSActions::setlinewidth}}, {"setmatrix", { 6, &PSActions::setmatrix}}, {"setmiterlimit", { 1, &PSActions::setmiterlimit}}, + {"setnulldevice", { 1, &PSActions::setnulldevice}}, {"setopacityalpha",{ 1, &PSActions::setopacityalpha}}, {"setshapealpha", { 1, &PSActions::setshapealpha}}, {"setpagedevice", { 0, &PSActions::setpagedevice}}, diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp index 6a64351889b..8e75e3c5f1a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp @@ -32,7 +32,7 @@ struct PSException : public MessageException { - PSException (const std::string &msg) : MessageException(msg) {} + explicit PSException (const std::string &msg) : MessageException(msg) {} }; @@ -71,6 +71,7 @@ struct PSActions { virtual void setlinewidth (std::vector<double> &p) =0; virtual void setmatrix (std::vector<double> &p) =0; virtual void setmiterlimit (std::vector<double> &p) =0; + virtual void setnulldevice (std::vector<double> &p) =0; virtual void setopacityalpha (std::vector<double> &p) =0; virtual void setshapealpha (std::vector<double> &p) =0; virtual void setpagedevice (std::vector<double> &p) =0; @@ -90,7 +91,7 @@ class PSInterpreter { enum Mode {PS_NONE, PS_RUNNING, PS_QUIT}; public: - explicit PSInterpreter (PSActions *actions=0); + explicit PSInterpreter (PSActions *actions=nullptr); PSInterpreter (const PSInterpreter &psi) =delete; bool execute (const char *str, size_t len, bool flush=true); bool execute (const char *str, bool flush=true) {return execute(str, std::strlen(str), flush);} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp index 43b45c56596..90ff6a56852 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp @@ -39,7 +39,7 @@ string PSPattern::svgID () const { /** Appends the definition of this pattern to the "def" section of the SVG tree. */ void PSPattern::apply (SpecialActions &actions) { if (auto pattern = createPatternNode()) - actions.appendToDefs(std::move(pattern)); + actions.svgTree().appendToDefs(std::move(pattern)); } @@ -54,18 +54,18 @@ PSTilingPattern::PSTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, dou /** Assigns a new group element. */ -void PSTilingPattern::setGroupNode (unique_ptr<XMLElementNode> &&node) { +void PSTilingPattern::setGroupNode (unique_ptr<XMLElement> node) { _groupNode = std::move(node); _groupNodePtr = _groupNode.get(); } /** Creates a new pattern element representing the pattern defined in the PS code. */ -unique_ptr<XMLElementNode> PSTilingPattern::createPatternNode () const { +unique_ptr<XMLElement> PSTilingPattern::createPatternNode () const { if (!_groupNode) return nullptr; BoundingBox box(_bbox.minX(), _bbox.minY(), _bbox.minX()+_xstep, _bbox.minY()+_ystep); - auto pattern = util::make_unique<XMLElementNode>("pattern"); + auto pattern = util::make_unique<XMLElement>("pattern"); pattern->addAttribute("id", svgID()); pattern->addAttribute("x", box.minX()); pattern->addAttribute("y", box.minY()); @@ -74,7 +74,7 @@ unique_ptr<XMLElementNode> PSTilingPattern::createPatternNode () const { pattern->addAttribute("viewBox", box.toSVGViewBox()); pattern->addAttribute("patternUnits", "userSpaceOnUse"); if (!_matrix.isIdentity()) - pattern->addAttribute("patternTransform", _matrix.getSVG()); + pattern->addAttribute("patternTransform", _matrix.toSVG()); if (_xstep < _bbox.width() || _ystep < _bbox.height()) { // overlapping tiles? // disable clipping at the tile borders => tiles become "transparent" pattern->addAttribute("overflow", "visible"); @@ -89,10 +89,10 @@ unique_ptr<XMLElementNode> PSTilingPattern::createPatternNode () const { /** Creates a new clip element restricting the drawing area to the * dimensions given in the definition of the pattern. */ -unique_ptr<XMLElementNode> PSTilingPattern::createClipNode() const { - auto clip = util::make_unique<XMLElementNode>("clipPath"); +unique_ptr<XMLElement> PSTilingPattern::createClipNode() const { + auto clip = util::make_unique<XMLElement>("clipPath"); clip->addAttribute("id", "pc"+XMLString(psID())); - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", _bbox.minX()); rect->addAttribute("y", _bbox.minY()); rect->addAttribute("width", _bbox.width()); @@ -104,9 +104,9 @@ unique_ptr<XMLElementNode> PSTilingPattern::createClipNode() const { /** Creates a new group element that contains all "drawing" elements that * define the pattern graphic. */ -unique_ptr<XMLElementNode> PSTilingPattern::createGroupNode () const { +unique_ptr<XMLElement> PSTilingPattern::createGroupNode () const { // add all succeeding path elements to this group - auto group = util::make_unique<XMLElementNode>("g"); + auto group = util::make_unique<XMLElement>("g"); group->addAttribute("clip-path", XMLString("url(#pc")+XMLString(psID())+")"); return group; } @@ -145,16 +145,16 @@ string PSUncoloredTilingPattern::svgID () const { /** Appends the definition of this pattern with the current color applied * to the "def" section of the SVG tree. */ void PSUncoloredTilingPattern::apply (SpecialActions &actions) { - set<Color>::iterator it=_colors.find(_currentColor); + auto it=_colors.find(_currentColor); if (it == _colors.end()) { if (_applied) - setGroupNode(util::static_unique_ptr_cast<XMLElementNode>(getGroupNode()->clone())); + setGroupNode(util::static_unique_ptr_cast<XMLElement>(getGroupNode()->clone())); // assign current color to the pattern graphic - vector<XMLElementNode*> colored_elems; + vector<XMLElement*> colored_elems; const array<const char*, 2> attribs = {{"fill", "stroke"}}; for (const char *attrib : attribs) { getGroupNode()->getDescendants(nullptr, attrib, colored_elems); - for (XMLElementNode *elem : colored_elems) { + for (XMLElement *elem : colored_elems) { if (string(elem->getAttributeValue(attrib)) != "none") elem->addAttribute(attrib, _currentColor.svgColorString()); } @@ -167,7 +167,7 @@ void PSUncoloredTilingPattern::apply (SpecialActions &actions) { } -unique_ptr<XMLElementNode> PSUncoloredTilingPattern::createClipNode() const { +unique_ptr<XMLElement> PSUncoloredTilingPattern::createClipNode() const { // only the first instance of this patterns get a clip element if (_colors.empty()) return PSTilingPattern::createClipNode(); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp index 818e08fc87b..7dde27827d6 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp @@ -32,7 +32,7 @@ class SpecialActions; class SVGTree; -class XMLElementNode; +class XMLElement; class PSPattern { public: @@ -42,8 +42,8 @@ class PSPattern { virtual void apply (SpecialActions &actions); protected: - PSPattern (int id) : _id(id) {} - virtual std::unique_ptr<XMLElementNode> createPatternNode () const =0; + explicit PSPattern (int id) : _id(id) {} + virtual std::unique_ptr<XMLElement> createPatternNode () const =0; private: int _id; ///< PostSCript ID of this pattern @@ -52,23 +52,23 @@ class PSPattern { class PSTilingPattern : public PSPattern { public: - virtual XMLElementNode* getContainerNode () {return _groupNode.get();} + virtual XMLElement* getContainerNode () {return _groupNode.get();} void apply (SpecialActions &actions) override; protected: PSTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, double xstep, double ystep); - std::unique_ptr<XMLElementNode> createPatternNode () const override; - virtual std::unique_ptr<XMLElementNode> createClipNode () const; - virtual std::unique_ptr<XMLElementNode> createGroupNode () const; - virtual XMLElementNode* getGroupNode () const {return _groupNodePtr;} - virtual void setGroupNode (std::unique_ptr<XMLElementNode> &&node); + std::unique_ptr<XMLElement> createPatternNode () const override; + virtual std::unique_ptr<XMLElement> createClipNode () const; + virtual std::unique_ptr<XMLElement> createGroupNode () const; + virtual XMLElement* getGroupNode () const {return _groupNodePtr;} + virtual void setGroupNode (std::unique_ptr<XMLElement> node); private: BoundingBox _bbox; ///< bounding box of the tile graphics Matrix _matrix; ///< tile transformation double _xstep, _ystep; ///< horizontal and vertical distance between neighboured tiles - mutable std::unique_ptr<XMLElementNode> _groupNode; ///< group containing the drawing elements - XMLElementNode *_groupNodePtr; ///< keeps a pointer to the group node even after moving _groupNode to the SVGTree + mutable std::unique_ptr<XMLElement> _groupNode; ///< group containing the drawing elements + XMLElement *_groupNodePtr; ///< keeps a pointer to the group node even after moving _groupNode to the SVGTree }; @@ -86,7 +86,7 @@ class PSUncoloredTilingPattern final : public PSTilingPattern { void apply (SpecialActions &actions) override; protected: - std::unique_ptr<XMLElementNode> createClipNode () const override; + std::unique_ptr<XMLElement> createClipNode () const override; private: std::set<Color> _colors; ///< colors this pattern has already been drawn with diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp index 5f58d931d56..7de5a2e2a8b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp @@ -30,7 +30,7 @@ class SpecialActions; class PSPreviewFilter : public PSFilter { public: - PSPreviewFilter (PSInterpreter &psi); + explicit PSPreviewFilter (PSInterpreter &psi); void activate (); void execute (const char *code, size_t len) override; bool active () const override {return _active;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp index dc82151fff9..e6c1a8287bd 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp @@ -78,7 +78,7 @@ bool PageRanges::parse (const string &str, int max_page) { /** Returns the number of pages. */ size_t PageRanges::numberOfPages () const { size_t sum=0; - for (NumericRanges<int>::ConstIterator it=begin(); it != end(); ++it) - sum += it->second - it->first + 1; + for (const auto &entry : *this) + sum += entry.second - entry.first + 1; return sum; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp index 3831f5d49bc..2f0a48aeb94 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp @@ -96,7 +96,7 @@ void PageSize::resize (string name) { name = util::tolower(name); // extract optional suffix - size_t pos = name.rfind("-"); + size_t pos = name.rfind('-'); bool landscape = false; if (pos != string::npos) { string suffix = name.substr(pos); @@ -117,14 +117,14 @@ void PageSize::resize (string name) { } else if (name == "legal") { _width = 216_mm; - _height = 356_mm;; + _height = 356_mm; } else if (name == "letter") { _width = 216_mm; _height = 279_mm; } else if (name == "ledger") { - _width = 279_mm;; + _width = 279_mm; _height = 432_mm; } else if (isdigit(name[1]) && name.length() < 5) { // limit length of number to prevent arithmetic errors diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp index b5a0836162d..c785a89564e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp @@ -25,14 +25,14 @@ #include "MessageException.hpp" struct PageSizeException : public MessageException { - PageSizeException (const std::string &msg) : MessageException(msg) {} + explicit PageSizeException (const std::string &msg) : MessageException(msg) {} }; class PageSize { public: PageSize () =default; PageSize (Length w, Length h) : _width(w), _height(h) {} - PageSize (const std::string &name); + explicit PageSize (const std::string &name); void resize (std:: string name); void resize (Length w, Length h); Length width () const {return _width;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp index 2ca2a9466d7..5dd7c68a932 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp @@ -26,17 +26,21 @@ #include "macros.hpp" template <typename T> -class Pair -{ +class Pair { public: - Pair (T x=0, T y=0) : _x(x), _y(y) {} + explicit Pair (T x=0, T y=0) : _x(x), _y(y) {} + template <typename U> Pair (const Pair<U> &p) : _x(U(p.x())), _y(U(p.y())) {} + Pair (const Pair &p) =default; + Pair (Pair &&p) =default; + Pair& operator = (const Pair &p) =default; + Pair& operator = (Pair &&p) =default; Pair operator += (const Pair &p) {_x += p._x; _y += p._y; return *this;} Pair operator -= (const Pair &p) {_x -= p._x; _y -= p._y; return *this;} Pair operator *= (T c) {_x *= c; _y *= c; return *this;} Pair operator /= (T c) {_x /= c; _y /= c; return *this;} Pair operator - () const {return Pair(-_x, -_y);} Pair ortho () const {return Pair(-_y, _x);} - double length () const {return std::sqrt(_x*_x + _y*_y);} + double length () const {return std::hypot(_x, _y);} bool operator == (const Pair &p) const {return _x == p._x && _y == p._y;} bool operator != (const Pair &p) const {return _x != p._x || _y != p._y;} T x () const {return _x;} @@ -54,15 +58,30 @@ inline Pair<T> abs (const Pair<T> &p) { return Pair<T>(std::abs(p.x()), std::abs(p.y())); } -struct Pair32 : public Pair<int32_t> -{ - Pair32 (int32_t x=0, int32_t y=0) : Pair<int32_t>(x, y) {} - explicit Pair32 (double x, double y) : Pair<int32_t>(int32_t(x+0.5), int32_t(y+0.5)) {} +/** Returns the dot product of two 2D vectors. */ +template <typename T> +inline T dot (const Pair<T> &p1, const Pair<T> &p2) { + return p1.x()*p1.y() + p1.y()*p2.y(); +} + +/** Returns the determinant of two 2D vectors. */ +template <typename T> +inline T det (const Pair<T> &p1, const Pair<T> &p2) { + return p1.x()*p2.y() - p1.y()*p2.x(); +} + +struct Pair32 : public Pair<int32_t> { + explicit Pair32 (int32_t x=0, int32_t y=0) : Pair<int32_t>(x, y) {} + explicit Pair32 (double x, double y) : Pair<int32_t>(lround(x), lround(y)) {} Pair32 (const Pair<int32_t> &p) : Pair<int32_t>(p) {} }; typedef Pair<double> DPair; +inline DPair round (const DPair &p) { + return DPair(std::lround(p.x()), std::lround(p.y())); +} + template <typename T> IMPLEMENT_ARITHMETIC_OPERATOR(Pair<T>, +) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp index a08b74a1aad..f646289d25e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <cmath> #include "Bezier.hpp" #include "PathClipper.hpp" @@ -31,9 +32,7 @@ using CurvedPath = PathClipper::CurvedPath; const int SCALE_FACTOR = 1000; inline cInt to_cInt (double x) { - if (x < 0) - return static_cast<cInt>(x*SCALE_FACTOR - 0.5); - return static_cast<cInt>(x*SCALE_FACTOR + 0.5); + return static_cast<cInt>(lround(x*SCALE_FACTOR)); } @@ -50,7 +49,7 @@ inline DPair to_DPair (const IntPoint &p) { /** In order to flatten a curved path, all path segements are processed sequentially. * Depending on the type of the segment, one of the methods provided by this class * is called. */ -class FlattenActions : public CurvedPath::Actions { +class FlattenActions : public CurvedPath::IterationActions { public: FlattenActions (vector<Bezier> &curves, Polygons &polygons, int &numLines) : _polygons(polygons), _curves(curves), _numLines(numLines) {} @@ -74,7 +73,7 @@ class FlattenActions : public CurvedPath::Actions { _currentPoint = p; } - void conicto (const CurvedPath::Point &p1, const CurvedPath::Point &p2) override { + void quadto (const CurvedPath::Point &p1, const CurvedPath::Point &p2) override { Bezier bezier(_currentPoint, p1, p2); addCurvePoints(bezier); } @@ -130,9 +129,9 @@ class FlattenActions : public CurvedPath::Actions { /** Removes adjacent polygon vertices that equal their predecessor. */ static void remove_redundant_vertices (Polygon &polygon) { - Polygon::iterator it1=polygon.begin(); + auto it1=polygon.begin(); while (it1 != polygon.end()) { - Polygon::iterator it2 = it1+1; + auto it2 = it1+1; if (it2 == polygon.end()) it2 = polygon.begin(); if (it1 == it2) @@ -159,8 +158,8 @@ static void remove_redundant_vertices (Polygon &polygon) { void PathClipper::flatten (const CurvedPath &curvedPath, Polygons &polygons) { FlattenActions flattenActions(_curves, polygons, _numLines); curvedPath.iterate(flattenActions, false); - for (size_t i=0; i < polygons.size(); i++) - remove_redundant_vertices(polygons[i]); + for (Polygon &poly : polygons) + remove_redundant_vertices(poly); } @@ -207,7 +206,7 @@ static double division_ratio (const IntPoint &p1, const IntPoint &p2, const IntP /** Returns the label of point q that lies on the line between points p1 and p2. */ inline ZLabel division_label (const IntPoint &p1, const IntPoint &p2, const IntPoint &q) { - double t1, t2; + double t1=0, t2=0; double s=0; int32_t id = segment_id(p1, p2, t1, t2); if (id > 0) @@ -237,7 +236,7 @@ void PathClipper::callback (IntPoint &e1bot, IntPoint &e1top, IntPoint &e2bot, I * @param[out] label if not 0, retrieves the label of the endpoint * @param[in] startLabel if true, the found endpoint is treated as start point and * parameter 'label' gets the corresponding value */ -static size_t find_segment_endpoint (const Polygon &polygon, size_t start, ZLabel *label=0, bool startLabel=false) { +static size_t find_segment_endpoint (const Polygon &polygon, size_t start, ZLabel *label=nullptr, bool startLabel=false) { if (polygon.empty()) return 0; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp index 43edd96569e..70174b0fe10 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp @@ -95,7 +95,7 @@ static char prepare_mode (InputReader &ir) { void PdfSpecialHandler::preprocessPagesize (StreamInputReader &ir, SpecialActions &actions) { // add page sizes to collection of paper sizes in order to handle them equally SpecialHandler *handler = SpecialManager::instance().findHandlerByName("papersize"); - if (auto *papersizeHandler = dynamic_cast<PapersizeSpecialHandler*>(handler)) { + if (auto papersizeHandler = dynamic_cast<PapersizeSpecialHandler*>(handler)) { try { Length width, height; // parse parameter sequence of the form (name length)+ @@ -152,8 +152,8 @@ void PdfSpecialHandler::preprocessDest (StreamInputReader &ir, SpecialActions &a }); if (objects.size() < 2) return; - auto *name = objects[0].get<string>(); - auto *dest = objects[1].get<PDFArray>(); + auto name = objects[0].get<string>(); + auto dest = objects[1].get<PDFArray>(); // get target info from array [pageno /XYZ xpos ypos zpos] if (name && dest && dest->size() >= 4 && dest->at(0).get<int>()) { int pageno = *dest->at(0).get<int>(); @@ -210,7 +210,7 @@ static Color to_color (const PDFObject &obj) { Color color; if (obj.get<int>() || obj.get<double>()) color.setGray(double(obj)); - else if (auto *colorArray = obj.get<PDFArray>()) { + else if (auto colorArray = obj.get<PDFArray>()) { size_t size = min(size_t(4), colorArray->size()); valarray<double> colorComps(size); for (size_t i=0; i < size; i++) @@ -262,7 +262,7 @@ void PdfSpecialHandler::processDest (StreamInputReader &ir, SpecialActions &acti PDFParser parser; vector<PDFObject> objects = parser.parse(ir); if (!objects.empty()) { - if (auto *name = objects[0].get<string>()) + if (auto name = objects[0].get<string>()) HyperlinkManager::instance().setActiveNameAnchor(*name, actions); } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp index f8ede292a2a..ff73cb53366 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp @@ -21,9 +21,9 @@ #ifdef _WIN32 #include "windows.hpp" #else + #include <csignal> #include <fcntl.h> #include <sys/wait.h> - #include <signal.h> #include <unistd.h> #endif @@ -61,8 +61,8 @@ class Subprocess { }; -Process::Process (const string &cmd, const string ¶mstr) - : _cmd(cmd), _paramstr(paramstr) +Process::Process (string cmd, string paramstr) + : _cmd(std::move(cmd)), _paramstr(std::move(paramstr)) { } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp index 3333e24df1d..70eeafb9d8b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp @@ -25,11 +25,11 @@ class Process { public: - Process (const std::string &cmd, const std::string ¶mstr); + Process (std::string cmd, std::string paramstr); Process (const Process &orig) =delete; Process (Process &&orig) =delete; - bool run (std::string *out=0); - bool run (const std::string &dir, std::string *out=0); + bool run (std::string *out=nullptr); + bool run (const std::string &dir, std::string *out=nullptr); private: std::string _cmd; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp index 4b503d34bee..405da48434b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp @@ -25,6 +25,7 @@ #include <sstream> #include "EPSFile.hpp" #include "FileFinder.hpp" +#include "FilePath.hpp" #include "FileSystem.hpp" #include "Message.hpp" #include "PathClipper.hpp" @@ -183,6 +184,15 @@ void PsSpecialHandler::preprocess (const string &prefix, istream &is, SpecialAct } +static string filename_suffix (const string &fname) { + string ret; + size_t pos = fname.rfind('.'); + if (pos != string::npos) + ret = util::tolower(fname.substr(pos+1)); + return ret; +} + + bool PsSpecialHandler::process (const string &prefix, istream &is, SpecialActions &actions) { // process PS headers only once (in prescan) if (prefix == "!" || prefix == "header=") @@ -203,10 +213,24 @@ bool PsSpecialHandler::process (const string &prefix, istream &is, SpecialAction else if (prefix == "psfile=" || prefix == "PSfile=" || prefix == "pdffile=") { if (_actions) { StreamInputReader in(is); - const string fname = in.getQuotedString(in.peek() == '"' ? "\"" : nullptr); + string fname = in.getQuotedString(in.peek() == '"' ? "\"" : nullptr); + fname = FileSystem::adaptPathSeperators(fname); + FileType fileType = FileType::EPS; + if (prefix == "pdffile") + fileType = FileType::PDF; + else { + // accept selected non-PS files in psfile special + string ext = filename_suffix(fname); + if (ext == "pdf") + fileType = FileType::PDF; + else if (ext == "svg") + fileType = FileType::SVG; + else if (ext == "jpg" || ext == "jpeg" || ext == "png") + fileType = FileType::BITMAP; + } map<string,string> attr; - in.parseAttributes(attr); - imgfile(prefix == "pdffile=" ? FileType::PDF : FileType::EPS, fname, attr); + in.parseAttributes(attr, false); + imgfile(fileType, fname, attr); } } else if (prefix == "ps::") { @@ -216,9 +240,9 @@ bool PsSpecialHandler::process (const string &prefix, istream &is, SpecialAction // collect characters inside the brackets string code; for (int i=0; i < 9 && is.peek() != ']' && !is.eof(); ++i) - code += is.get(); + code += char(is.get()); if (is.peek() == ']') - code += is.get(); + code += char(is.get()); if (code == "[begin]" || code == "[nobreak]") { moveToDVIPos(); @@ -272,15 +296,6 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma if (fname == "/dev/null") return; - string filepath; - if (const char *path = FileFinder::instance().lookup(fname, false)) - filepath = FileSystem::adaptPathSeperators(path); - if ((filepath.empty() || !FileSystem::exists(filepath)) && FileSystem::exists(fname)) - filepath = fname; - if (filepath.empty()) { - Message::wstream(true) << "file '" << fname << "' not found\n"; - return; - } map<string,string>::const_iterator it; // bounding box of EPS figure in PS point units (lower left and upper right corner) @@ -290,7 +305,9 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma double ury = (it = attr.find("ury")) != attr.end() ? stod(it->second) : 0; int pageno = (it = attr.find("page")) != attr.end() ? stoi(it->second, nullptr, 10) : 1; - if (filetype == FileType::PDF && llx == 0 && lly == 0 && urx == 0 && ury == 0) { + if (filetype == FileType::BITMAP || filetype == FileType::SVG) + swap(lly, ury); + else if (filetype == FileType::PDF && llx == 0 && lly == 0 && urx == 0 && ury == 0) { BoundingBox pagebox = _psi.pdfPageBox(fname, pageno); if (pagebox.valid()) { llx = pagebox.minX(); @@ -316,6 +333,8 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma double vscale = (it = attr.find("vscale")) != attr.end() ? stod(it->second) : 100; double angle = (it = attr.find("angle")) != attr.end() ? stod(it->second) : 0; + bool clipToBbox = (attr.find("clip") != attr.end()); + // compute factors to scale the bounding box to width rwi and height rhi double sx = rwi/abs(llx-urx); double sy = rhi/abs(lly-ury); @@ -335,36 +354,26 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma _actions->setY(0); moveToDVIPos(); - auto groupNode = util::make_unique<XMLElementNode>("g"); // put SVG nodes created from the EPS/PDF file in this group - _xmlnode = groupNode.get(); - _psi.execute( - "\n@beginspecial @setspecial" // enter special environment - "/setpagedevice{@setpagedevice}def " // activate processing of operator "setpagedevice" - "matrix setmatrix" // don't apply outer PS transformations - "/FirstPage "+to_string(pageno)+" def" // set number of fisrt page to convert (PDF only) - "/LastPage "+to_string(pageno)+" def" // set number of last page to convert (PDF only) - "("+ filepath + ")run " // execute file content - "@endspecial " // leave special environment - ); - if (!groupNode->empty()) { // has anything been drawn? + auto imgNode = createImageNode(filetype, fname, pageno, BoundingBox(llx, lly, urx, ury), clipToBbox); + if (imgNode) { // has anything been drawn? Matrix matrix(1); - matrix.scale(sx, -sy).rotate(-angle).scale(hscale/100, vscale/100); // apply transformation attributes + if (filetype == FileType::EPS || filetype == FileType::PDF) + sy = -sy; // adapt orientation of y-coordinates + matrix.scale(sx, sy).rotate(-angle).scale(hscale/100, vscale/100); // apply transformation attributes matrix.translate(x+hoffset, y-voffset); // move image to current DVI position - matrix.rmultiply(_actions->getMatrix()); + matrix.lmultiply(_actions->getMatrix()); // update bounding box BoundingBox bbox(0, 0, urx-llx, ury-lly); bbox.transform(matrix); _actions->embed(bbox); - // insert group containing SVG nodes created from image - matrix.lmultiply(TranslationMatrix(-llx, -lly)); // move lower left corner of image to origin + // insert element containing the image data + matrix.rmultiply(TranslationMatrix(-llx, -lly)); // move lower left corner of image to origin if (!matrix.isIdentity()) - groupNode->addAttribute("transform", matrix.getSVG()); - _actions->appendToPage(std::move(groupNode)); + imgNode->addAttribute("transform", matrix.toSVG()); + _actions->svgTree().appendToPage(std::move(imgNode)); } - _xmlnode = nullptr; // append following elements to page group again - // restore DVI position _actions->setX(x); _actions->setY(y); @@ -372,6 +381,63 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma } +/** Creates an XML element containing the image data depending on the file type. + * @param[in] type file type of the image + * @param[in] fname file name/path of image file + * @param[in] pageno number of page to process (PDF only) + * @param[in] bbox bounding box of the image + * @param[in] clip if true, the image is clipped to its bounding box + * @return pointer to the element or nullptr if there's no image data */ +unique_ptr<XMLElement> PsSpecialHandler::createImageNode (FileType type, const string &fname, int pageno, BoundingBox bbox, bool clip) { + unique_ptr<XMLElement> node; + string pathstr; + if (const char *path = FileFinder::instance().lookup(fname, false)) + pathstr = FileSystem::adaptPathSeperators(path); + if ((pathstr.empty() || !FileSystem::exists(pathstr)) && FileSystem::exists(fname)) + pathstr = fname; + if (pathstr.empty()) + Message::wstream(true) << "file '" << fname << "' not found\n"; + else if (type == FileType::BITMAP || type == FileType::SVG) { + node = util::make_unique<XMLElement>("image"); + node->addAttribute("x", 0); + node->addAttribute("y", 0); + node->addAttribute("width", bbox.width()); + node->addAttribute("height", bbox.height()); + + // Only reference the image with an absolute path if either an absolute path was given by the user + // or a given plain filename is not present in the current working directory but was found through + // the FileFinder, i.e. it's usually located somewhere in the texmf tree. + string href = pathstr; + if (!FilePath::isAbsolute(fname) && (fname.find('/') != string::npos || FilePath(fname).exists())) + href = FilePath(pathstr).relative(FilePath(_actions->getSVGFilePath(pageno))); + node->addAttribute("xlink:href", href); + } + else { // PostScript or PDF + // clip image to its bounding box if flag 'clip' is given + string rectclip; + if (clip) + rectclip = to_string(bbox.minX())+" "+to_string(bbox.minY())+" "+to_string(bbox.width())+" "+to_string(bbox.height())+" rectclip"; + + node = util::make_unique<XMLElement>("g"); // put SVG nodes created from the EPS/PDF file in this group + _xmlnode = node.get(); + _psi.execute( + "\n@beginspecial @setspecial" // enter special environment + "/setpagedevice{@setpagedevice}def " // activate processing of operator "setpagedevice" + "matrix setmatrix" // don't apply outer PS transformations + "/FirstPage "+to_string(pageno)+" def" // set number of first page to convert (PDF only) + "/LastPage "+to_string(pageno)+" def " // set number of last page to convert (PDF only) + +rectclip+ // clip to bounding box (if requexted by attribute 'clip') + "(" + pathstr + ")run " // execute file content + "@endspecial " // leave special environment + ); + if (node->empty()) + node.reset(nullptr); + _xmlnode = nullptr; // append following elements to page group again + } + return node; +} + + /** Apply transformation to width, height, and depth set by preview package. * @param[in] matrix transformation matrix to apply * @param[out] w width @@ -386,15 +452,17 @@ static bool transform_box_extents (const Matrix &matrix, double &w, double &h, d return false; // => non-horizontal baseline, can't compute meaningful extents if (ex.y() == 0) // horizontal scaling or skewing? - w *= fabs(ex.x()); + w *= abs(ex.x()); if (ey.x()==0 || ex.y()==0) { // vertical scaling? - if (ey.y() < 0) swap(h, d); - if (double sy = fabs(ey.y())/ey.length()) { - h *= fabs(ey.y()/sy); - d *= fabs(ey.y()/sy); - } - else + if (ey.y() < 0) + swap(h, d); + double sy = abs(ey.y())/ey.length(); + if (sy < 1e-8) h = d = 0; + else { + h *= abs(ey.y()/sy); + d *= abs(ey.y()/sy); + } } return true; } @@ -435,7 +503,7 @@ void PsSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) { "depth=" << XMLString(d*bp2pt) << "pt\n"; } #if 0 - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", actions.bbox().minX()); rect->addAttribute("y", actions.bbox().minY()); rect->addAttribute("width", w); @@ -445,7 +513,7 @@ void PsSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) { rect->addAttribute("stroke-width", "0.1"); actions.appendToPage(std::move(rect)); if (d > 0) { - auto line = util::make_unique<XMLElementNode>("line"); + auto line = util::make_unique<XMLElement>("line"); line->addAttribute("x1", actions.bbox().minX()); line->addAttribute("y1", actions.bbox().minY()+h); line->addAttribute("x2", actions.bbox().maxX()); @@ -553,14 +621,14 @@ void PsSpecialHandler::stroke (vector<double> &p) { } if (_clipStack.prependedPath()) _path.prepend(*_clipStack.prependedPath()); - unique_ptr<XMLElementNode> path; + unique_ptr<XMLElement> path; Pair<double> point; if (_path.isDot(point)) { // zero-length path? if (_linecap == 1) { // round line ends? => draw dot double x = point.x(); double y = point.y(); double r = _linewidth/2.0; - path = util::make_unique<XMLElementNode>("circle"); + path = util::make_unique<XMLElement>("circle"); path->addAttribute("cx", x); path->addAttribute("cy", y); path->addAttribute("r", r); @@ -575,7 +643,7 @@ void PsSpecialHandler::stroke (vector<double> &p) { ostringstream oss; _path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - path = util::make_unique<XMLElementNode>("path"); + path = util::make_unique<XMLElement>("path"); path->addAttribute("d", oss.str()); path->addAttribute("stroke", _actions->getColor().svgColorString()); path->addAttribute("fill", "none"); @@ -592,13 +660,11 @@ void PsSpecialHandler::stroke (vector<double> &p) { if (_blendmode > 0 && _blendmode < 16) path->addAttribute("style", "mix-blend-mode:"+css_blendmode_name(_blendmode)); if (!_dashpattern.empty()) { - ostringstream oss; - for (size_t i=0; i < _dashpattern.size(); i++) { - if (i > 0) - oss << ','; - oss << XMLString(_dashpattern[i]); - } - path->addAttribute("stroke-dasharray", oss.str()); + string patternStr; + for (double dashValue : _dashpattern) + patternStr += XMLString(dashValue)+","; + patternStr.pop_back(); + path->addAttribute("stroke-dasharray", patternStr); if (_dashoffset != 0) path->addAttribute("stroke-dashoffset", _dashoffset); } @@ -614,7 +680,7 @@ void PsSpecialHandler::stroke (vector<double> &p) { if (_xmlnode) _xmlnode->append(std::move(path)); else { - _actions->appendToPage(std::move(path)); + _actions->svgTree().appendToPage(std::move(path)); _actions->embed(bbox); } _path.clear(); @@ -642,7 +708,7 @@ void PsSpecialHandler::fill (vector<double> &p, bool evenodd) { ostringstream oss; _path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - unique_ptr<XMLElementNode> path = util::make_unique<XMLElementNode>("path"); + unique_ptr<XMLElement> path = util::make_unique<XMLElement>("path"); path->addAttribute("d", oss.str()); if (_pattern) path->addAttribute("fill", XMLString("url(#")+_pattern->svgID()+")"); @@ -665,7 +731,7 @@ void PsSpecialHandler::fill (vector<double> &p, bool evenodd) { if (_xmlnode) _xmlnode->append(std::move(path)); else { - _actions->appendToPage(std::move(path)); + _actions->svgTree().appendToPage(std::move(path)); _actions->embed(bbox); } _path.clear(); @@ -682,7 +748,7 @@ static void create_matrix (vector<double> &v, int startindex, Matrix &matrix) { // using corresponding values of the identity matrix. if (v.size()-startindex < 6) { v.resize(6+startindex); - for (int i=v.size()-startindex; i < 6; ++i) + for (size_t i=v.size()-startindex; i < 6; ++i) v[i+startindex] = (i%3 ? 0 : 1); } // PS matrix [a b c d e f] equals ((a,b,0),(c,d,0),(e,f,1)). @@ -724,7 +790,7 @@ void PsSpecialHandler::makepattern (vector<double> &p) { Matrix matrix; // transformation matrix given together with pattern definition create_matrix(p, 9, matrix); - matrix.rmultiply(_actions->getMatrix()); + matrix.lmultiply(_actions->getMatrix()); unique_ptr<PSTilingPattern> pattern; if (paint_type == 1) @@ -756,10 +822,10 @@ void PsSpecialHandler::setpattern (vector<double> &p) { if (it == _patterns.end()) _pattern = nullptr; else { - if (auto *pattern = dynamic_cast<PSUncoloredTilingPattern*>(it->second.get())) + if (auto pattern = dynamic_cast<PSUncoloredTilingPattern*>(it->second.get())) pattern->setColor(color); it->second->apply(*_actions); - if (auto *pattern = dynamic_cast<PSTilingPattern*>(it->second.get())) + if (auto pattern = dynamic_cast<PSTilingPattern*>(it->second.get())) _pattern = pattern; else _pattern = nullptr; @@ -828,19 +894,19 @@ void PsSpecialHandler::clip (Path path, bool evenodd) { intersectedPath.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); } if (pathReplaced) { - auto pathElem = util::make_unique<XMLElementNode>("path"); + auto pathElem = util::make_unique<XMLElement>("path"); pathElem->addAttribute("d", oss.str()); if (evenodd) pathElem->addAttribute("clip-rule", "evenodd"); int newID = _clipStack.topID(); - auto clipElem = util::make_unique<XMLElementNode>("clipPath"); + auto clipElem = util::make_unique<XMLElement>("clipPath"); clipElem->addAttribute("id", XMLString("clip")+XMLString(newID)); if (!COMPUTE_CLIPPATHS_INTERSECTIONS && oldID) clipElem->addAttribute("clip-path", XMLString("url(#clip")+XMLString(oldID)+")"); clipElem->append(std::move(pathElem)); - _actions->appendToDefs(std::move(clipElem)); + _actions->svgTree().appendToDefs(std::move(clipElem)); } } @@ -864,7 +930,7 @@ void PsSpecialHandler::shfill (vector<double> ¶ms) { case 3: colorSpace = Color::ColorSpace::RGB; break; case 4: colorSpace = Color::ColorSpace::CMYK; break; } - VectorIterator<double> it = params; + VectorIterator<double> it(params); it += 2; // skip shading type and color space // Get color to fill the whole mesh area before drawing the gradient colors on top of that background. // This is an optional parameter to shfill. @@ -951,15 +1017,15 @@ static void read_patch_data (ShadingPatch &patch, int edgeflag, class ShadingCallback : public ShadingPatch::Callback { public: - ShadingCallback (SpecialActions &actions, XMLElementNode *parent, int clippathID) + ShadingCallback (SpecialActions &actions, XMLElement *parent, int clippathID) : _actions(actions) { - auto group = util::make_unique<XMLElementNode>("g"); + auto group = util::make_unique<XMLElement>("g"); _group = group.get(); if (parent) parent->append(std::move(group)); else - actions.appendToPage(std::move(group)); + actions.svgTree().appendToPage(std::move(group)); if (clippathID > 0) _group->addAttribute("clip-path", XMLString("url(#clip")+XMLString(clippathID)+")"); } @@ -971,7 +1037,7 @@ class ShadingCallback : public ShadingPatch::Callback { // draw a single patch segment ostringstream oss; path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - auto pathElem = util::make_unique<XMLElementNode>("path"); + auto pathElem = util::make_unique<XMLElement>("path"); pathElem->addAttribute("d", oss.str()); pathElem->addAttribute("fill", color.svgColorString()); _group->append(std::move(pathElem)); @@ -979,7 +1045,7 @@ class ShadingCallback : public ShadingPatch::Callback { private: SpecialActions &_actions; - XMLElementNode *_group; + XMLElement *_group; }; @@ -999,16 +1065,14 @@ void PsSpecialHandler::processSequentialPatchMesh (int shadingTypeID, ColorSpace #if 0 if (bgcolorGiven) { // fill whole patch area with given background color - GraphicsPath<double> outline; - patch->getBoundaryPath(outline); + GraphicsPath<double> outline = patch->getBoundaryPath(); callback.patchSegment(outline, bgcolor); } #endif patch->approximate(SHADING_SEGMENT_SIZE, SHADING_SEGMENT_OVERLAP, SHADING_SIMPLIFY_DELTA, callback); if (!_xmlnode) { // update bounding box - BoundingBox bbox; - patch->getBBox(bbox); + BoundingBox bbox = patch->getBBox(); bbox.transform(_actions->getMatrix()); _actions->embed(bbox); } @@ -1093,7 +1157,7 @@ void PsSpecialHandler::scale (vector<double> &p) { if (_actions) { Matrix m = _actions->getMatrix(); ScalingMatrix s(p[0], p[1]); - m.lmultiply(s); + m.rmultiply(s); _actions->setMatrix(m); } } @@ -1103,7 +1167,7 @@ void PsSpecialHandler::translate (vector<double> &p) { if (_actions) { Matrix m = _actions->getMatrix(); TranslationMatrix t(p[0], p[1]); - m.lmultiply(t); + m.rmultiply(t); _actions->setMatrix(m); } } @@ -1113,7 +1177,7 @@ void PsSpecialHandler::rotate (vector<double> &p) { if (_actions) { Matrix m = _actions->getMatrix(); RotationMatrix r(p[0]); - m.lmultiply(r); + m.rmultiply(r); _actions->setMatrix(m); } } @@ -1167,6 +1231,18 @@ void PsSpecialHandler::executed () { _actions->progress("ps"); } + +/** This method is called by PSInterpreter if the status of the output devices has changed. + * @param[in] p 1 if output device is the nulldevice, 1 otherwise */ +void PsSpecialHandler::setnulldevice (vector<double> &p) { + if (_actions) { + if (p[0] != 0) + _actions->lockOutput(); // prevent further SVG output + else + _actions->unlockOutput(); // enable SVG output again + } +} + //////////////////////////////////////////// void PsSpecialHandler::ClippingStack::pushEmptyPath () { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp index 188c4527189..c7a8a978150 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp @@ -34,7 +34,7 @@ class PSPattern; -class XMLElementNode; +class XMLElement; class PsSpecialHandler : public SpecialHandler, protected PSActions { using Path = GraphicsPath<double>; @@ -68,7 +68,7 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { int saveID; ///< if >=0, path was pushed by 'save', and saveID holds the ID of the PS memory object Entry () : Entry(-1) {} Entry (const Path &p, int pid, int sid) : path(std::make_shared<Path>(p)), pathID(pid), saveID(sid) {} - Entry (int sid) : path(nullptr), pathID(0), saveID(sid) {} + explicit Entry (int sid) : path(nullptr), pathID(0), saveID(sid) {} Entry (const Entry &entry) =default; Entry (Entry &&entry) =default; }; @@ -77,11 +77,11 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { }; enum PsSection {PS_NONE, PS_HEADERS, PS_BODY}; - enum class FileType {EPS, PDF}; + enum class FileType {EPS, PDF, SVG, BITMAP}; public: PsSpecialHandler (); - ~PsSpecialHandler (); + ~PsSpecialHandler () override; const char* name () const override {return "ps";} const char* info () const override {return "dvips PostScript specials";} std::vector<const char*> prefixes() const override; @@ -104,6 +104,7 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { void executeAndSync (std::istream &is, bool updatePos); void processHeaderFile (const char *fname); void imgfile (FileType type, const std::string &fname, const std::map<std::string,std::string> &attr); + std::unique_ptr<XMLElement> createImageNode (FileType type, const std::string &fname, int pageno, BoundingBox bbox, bool clip); void dviEndPage (unsigned pageno, SpecialActions &actions) override; void clip (Path path, bool evenodd); void processSequentialPatchMesh (int shadingTypeID, ColorSpace cspace, VectorIterator<double> &it); @@ -145,6 +146,7 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { void setlinewidth (std::vector<double> &p) override {_linewidth = scale(p[0] ? p[0] : 0.5);} void setmatrix (std::vector<double> &p) override; void setmiterlimit (std::vector<double> &p) override {_miterlimit = p[0];} + void setnulldevice (std::vector<double> &p) override; void setopacityalpha (std::vector<double> &p) override {_opacityalpha = p[0];} void setshapealpha (std::vector<double> &p) override {_shapealpha = p[0];} void setpagedevice (std::vector<double> &p) override; @@ -160,8 +162,8 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { SpecialActions *_actions; PSPreviewFilter _previewFilter; ///< filter to extract information generated by the preview package PsSection _psSection=PS_NONE; ///< current section processed (nothing yet, headers, or body specials) - XMLElementNode *_xmlnode; ///< if != 0, created SVG elements are appended to this node - XMLElementNode *_savenode; ///< pointer to temporaryly store _xmlnode + XMLElement *_xmlnode; ///< if != 0, created SVG elements are appended to this node + XMLElement *_savenode; ///< pointer to temporaryly store _xmlnode std::string _headerCode; ///< collected literal PS header code Path _path; DPair _currentpoint; ///< current PS position in bp units diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp index dd9eb88462c..5fa2bb10ab1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <numeric> #include "RangeMap.hpp" using namespace std; @@ -96,7 +97,7 @@ void RangeMap::addRange (uint32_t cmin, uint32_t cmax, uint32_t vmin) { } else { // ranges overlap and/or must be inserted somewhere inside the vector - Ranges::iterator it = lower_bound(_ranges.begin(), _ranges.end(), range); + auto it = lower_bound(_ranges.begin(), _ranges.end(), range); const bool at_end = (it == _ranges.end()); if (at_end) --it; @@ -125,16 +126,16 @@ void RangeMap::addRange (uint32_t cmin, uint32_t cmax, uint32_t vmin) { void RangeMap::adaptNeighbors (Ranges::iterator it) { if (it != _ranges.end()) { // adapt left neighbor - Ranges::iterator lit = it-1; // points to left neighbor - if (it != _ranges.begin() && it->min() <= lit->max()) { + if (it != _ranges.begin() && it->min() <= (it-1)->max()) { + auto lit = it-1; // points to left neighbor bool left_neighbor_valid = (it->min() > 0 && it->min()-1 >= lit->min()); - if (left_neighbor_valid) // is adapted left neighbor valid? - lit->max(it->min()-1); // => assign new max value + if (left_neighbor_valid) // is adapted left neighbor valid? + lit->max(it->min()-1); // => assign new max value if (!left_neighbor_valid || it->join(*lit)) it = _ranges.erase(lit); } // remove right neighbors completely overlapped by *it - Ranges::iterator rit = it+1; // points to right neighbor + auto rit = it+1; // points to right neighbor while (rit != _ranges.end() && it->max() >= rit->max()) { // complete overlap? _ranges.erase(rit); rit = it+1; @@ -178,10 +179,9 @@ uint32_t RangeMap::valueAt (uint32_t c) const { /** Returns the number of values mapped. */ size_t RangeMap::numValues () const { - size_t count=0; - for (const Range &range : _ranges) - count += range.max()-range.min()+1; - return count; + return std::accumulate(_ranges.begin(), _ranges.end(), 0, [](size_t sum, const Range &range) { + return sum+range.max()-range.min()+1; + }); } @@ -191,7 +191,7 @@ ostream& RangeMap::Range::write (ostream& os) const { ostream& RangeMap::write (ostream& os) const { - for (size_t i=0; i < _ranges.size(); i++) - _ranges[i].write(os) << '\n'; + for (const Range &range : _ranges) + range.write(os) << '\n'; return os; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp index 70fc6836e9c..3733053e4d0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp @@ -25,7 +25,7 @@ using namespace std; -void SVGCharHandler::setInitialContextNode (XMLElementNode *node) { +void SVGCharHandler::setInitialContextNode (XMLElement *node) { resetContextNode(); _initialContextNode = node; } @@ -34,9 +34,9 @@ void SVGCharHandler::setInitialContextNode (XMLElementNode *node) { /** Changes the context element. All following nodes will be appended to this node. * @param[in] node the new context node * @return bare pointer to the new context node or 0 if context hasn't changed */ -XMLElementNode* SVGCharHandler::pushContextNode (unique_ptr<XMLElementNode> &&node) { +XMLElement* SVGCharHandler::pushContextNode (unique_ptr<XMLElement> node) { if (node && (_contextNodeStack.empty() || node.get() != _contextNodeStack.top())) { - XMLElementNode *nodeptr = node.get(); + XMLElement *nodeptr = node.get(); contextNode()->append(std::move(node)); _contextNodeStack.push(nodeptr); return nodeptr; @@ -61,11 +61,11 @@ void SVGCharHandler::resetContextNode () { /** Creates and returns a new SVG text element. * @param[in] x current x coordinate * @param[in] y current y coordinate */ -unique_ptr<XMLElementNode> SVGCharTextHandler::createTextNode (double x, double y) const { +unique_ptr<XMLElement> SVGCharTextHandler::createTextNode (double x, double y) const { const Font *font = _font.get(); if (!font) return nullptr; - auto textNode = util::make_unique<XMLElementNode>("text"); + auto textNode = util::make_unique<XMLElement>("text"); if (_selectFontByClass) textNode->addAttribute("class", string("f")+XMLString(_fontnum)); else { @@ -77,7 +77,7 @@ unique_ptr<XMLElementNode> SVGCharTextHandler::createTextNode (double x, double if (_vertical) { textNode->addAttribute("writing-mode", "tb"); // align glyphs designed for horizontal layout properly - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(font)) { + if (auto pf = dynamic_cast<const PhysicalFont*>(font)) { if (!pf->getMetrics()->verticalLayout()) { // alphabetic text designed for horizontal layout? x += pf->scaledAscent()/2.5; // move vertical baseline to the right by strikethrough offset textNode->addAttribute("glyph-orientation-vertical", 90); // ensure rotation @@ -87,6 +87,6 @@ unique_ptr<XMLElementNode> SVGCharTextHandler::createTextNode (double x, double textNode->addAttribute("x", x); textNode->addAttribute("y", y); if (!_matrix.get().isIdentity()) - textNode->addAttribute("transform", _matrix.get().getSVG()); + textNode->addAttribute("transform", _matrix.get().toSVG()); return textNode; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp index c527ee26655..48d24496fab 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp @@ -31,7 +31,7 @@ template <typename T> class CharProperty { public: - CharProperty (const T &v) : _value(v), _changed(false) {} + CharProperty (const T &v) : _value(v) {} void set (const T &v) { if (v != _value) { @@ -47,20 +47,20 @@ class CharProperty { private: T _value; - bool _changed; + bool _changed=false; }; -class XMLElementNode; +class XMLElement; /** Base class for all character handlers. These handlers create SVG representations * for the added characters and append them to the SVG tree. */ class SVGCharHandler { public: - SVGCharHandler () : _color(Color::BLACK), _font(0), _fontnum(0), _matrix(1), _vertical(false), _initialContextNode(0) {} + SVGCharHandler () : _matrix(1) {} virtual ~SVGCharHandler() =default; - virtual void setInitialContextNode (XMLElementNode *node); + virtual void setInitialContextNode (XMLElement *node); virtual void appendChar (uint32_t c, double x, double y) =0; virtual void notifyXAdjusted () {} virtual void notifyYAdjusted () {} @@ -74,32 +74,32 @@ class SVGCharHandler { protected: virtual void resetContextNode (); - XMLElementNode* pushContextNode (std::unique_ptr<XMLElementNode> &&node); + XMLElement* pushContextNode (std::unique_ptr<XMLElement> node); void popContextNode (); - XMLElementNode* contextNode () const { + XMLElement* contextNode () const { return _contextNodeStack.empty() ? _initialContextNode : _contextNodeStack.top(); } - CharProperty<Color> _color; ///< current color - CharProperty<const Font*> _font; ///< current font - int _fontnum; ///< current font ID - CharProperty<Matrix> _matrix; ///< current transformation - CharProperty<bool> _vertical; ///< current writing mode + CharProperty<Color> _color=Color::BLACK; ///< current color + CharProperty<const Font*> _font=0; ///< current font + int _fontnum=0; ///< current font ID + CharProperty<Matrix> _matrix; ///< current transformation + CharProperty<bool> _vertical=false; ///< current writing mode private: - XMLElementNode *_initialContextNode; ///< SVG element the generated character nodes are attached to - std::stack<XMLElementNode*> _contextNodeStack; + XMLElement *_initialContextNode= nullptr; ///< SVG element the generated character nodes are attached to + std::stack<XMLElement*> _contextNodeStack; }; /** Base class for all character handlers that create SVG <text> elements. */ class SVGCharTextHandler : public SVGCharHandler { public: - SVGCharTextHandler (bool selectFontByClass) : _selectFontByClass(selectFontByClass) {} + explicit SVGCharTextHandler (bool selectFontByClass) : _selectFontByClass(selectFontByClass) {} protected: - std::unique_ptr<XMLElementNode> createTextNode (double x, double y) const; + std::unique_ptr<XMLElement> createTextNode (double x, double y) const; private: bool _selectFontByClass; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp index 1b2316926d0..3962168ae2f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp @@ -31,7 +31,7 @@ using namespace std; * @param[in] createUseElements determines whether to create "use" elements to reference previous paths or not * @param[in] relativePathCommands determines whether to create relative or absolute SVG path commands */ SVGCharPathHandler::SVGCharPathHandler (bool createUseElements, bool relativePathCommands) - : _relativePathCommands(relativePathCommands), _groupNode(0), _fontColor(Color::BLACK) + : _relativePathCommands(relativePathCommands) { if (createUseElements) _appendChar = &SVGCharPathHandler::appendUseElement; @@ -42,7 +42,7 @@ SVGCharPathHandler::SVGCharPathHandler (bool createUseElements, bool relativePat void SVGCharPathHandler::resetContextNode () { SVGCharHandler::resetContextNode(); - _groupNode = 0; + _groupNode = nullptr; } @@ -69,11 +69,11 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { if (color.changed() || _matrix.changed()) { resetContextNode(); if (applyColor || applyMatrix) { - _groupNode = pushContextNode(util::make_unique<XMLElementNode>("g")); + _groupNode = pushContextNode(util::make_unique<XMLElement>("g")); if (applyColor) contextNode()->addAttribute("fill", color.get().svgColorString()); if (applyMatrix) - contextNode()->addAttribute("transform", _matrix.get().getSVG()); + contextNode()->addAttribute("transform", _matrix.get().toSVG()); } color.changed(false); _matrix.changed(false); @@ -84,7 +84,7 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { GlyphMetrics metrics; font->getGlyphMetrics(c, _vertical, metrics); x -= metrics.wl; - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(font)) { + if (auto pf = dynamic_cast<const PhysicalFont*>(font)) { // Center glyph between top and bottom border of the TFM box. // This is just an approximation used until I find a way to compute // the exact location in vertical mode. @@ -109,28 +109,28 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { void SVGCharPathHandler::appendUseElement (uint32_t c, double x, double y, const Matrix &matrix) { string id = "#g" + to_string(FontManager::instance().fontID(_font)) + "-" + to_string(c); - auto useNode = util::make_unique<XMLElementNode>("use"); + auto useNode = util::make_unique<XMLElement>("use"); useNode->addAttribute("x", XMLString(x)); useNode->addAttribute("y", XMLString(y)); useNode->addAttribute("xlink:href", id); if (!matrix.isIdentity()) - useNode->addAttribute("transform", matrix.getSVG()); + useNode->addAttribute("transform", matrix.toSVG()); contextNode()->append(std::move(useNode)); } void SVGCharPathHandler::appendPathElement (uint32_t c, double x, double y, const Matrix &matrix) { Glyph glyph; - const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(_font.get()); + auto pf = dynamic_cast<const PhysicalFont*>(_font.get()); if (pf && pf->getGlyph(c, glyph)) { double sx = pf->scaledSize()/pf->unitsPerEm(); double sy = -sx; ostringstream oss; glyph.writeSVG(oss, _relativePathCommands, sx, sy, x, y); - auto glyphNode = util::make_unique<XMLElementNode>("path"); + auto glyphNode = util::make_unique<XMLElement>("path"); glyphNode->addAttribute("d", oss.str()); if (!matrix.isIdentity()) - glyphNode->addAttribute("transform", matrix.getSVG()); + glyphNode->addAttribute("transform", matrix.toSVG()); contextNode()->append(std::move(glyphNode)); } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp index 944e554a9e6..ba172de340d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp @@ -37,10 +37,10 @@ class SVGCharPathHandler : public SVGCharHandler { void resetContextNode () override; private: - AppendMethod _appendChar; ///< method called to append a single character - bool _relativePathCommands; ///< if true, create relative rather than absolute SVG path commands - XMLElementNode *_groupNode; ///< current group node taking the path elements - CharProperty<Color> _fontColor; ///< color of current font + AppendMethod _appendChar; ///< method called to append a single character + bool _relativePathCommands; ///< if true, create relative rather than absolute SVG path commands + XMLElement *_groupNode=nullptr; ///< current group node taking the path elements + CharProperty<Color> _fontColor=Color::BLACK; ///< color of current font }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp index eb47f493085..a48f5f9a931 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp @@ -41,20 +41,20 @@ void SVGCharTspanTextHandler::appendChar (uint32_t c, double x, double y) { if (_tspanNode && (_xchanged || _ychanged || _color.changed())) { // if drawing position or color was explicitly changed, finish current tspan element popContextNode(); - _tspanNode = 0; + _tspanNode = nullptr; } // Apply text color changes only if the color of the entire font is black. // Glyphs of non-black fonts (e.g. defined in a XeTeX document) can't change their color. bool applyColor = _color.get() != Color::BLACK && _font.get()->color() == Color::BLACK; if (_xchanged || _ychanged || (_color.changed() && applyColor)) { - _tspanNode = pushContextNode(util::make_unique<XMLElementNode>("tspan")); + _tspanNode = pushContextNode(util::make_unique<XMLElement>("tspan")); if (applyColor) _tspanNode->addAttribute("fill", _color.get().svgColorString()); _color.changed(false); if (_xchanged) { if (_vertical) { // align glyphs designed for horizontal layout properly - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(_font.get())) + if (auto pf = dynamic_cast<const PhysicalFont*>(_font.get())) if (!pf->getMetrics()->verticalLayout()) x += pf->scaledAscent()/2.5; // move vertical baseline to the right by strikethrough offset } @@ -70,16 +70,16 @@ void SVGCharTspanTextHandler::appendChar (uint32_t c, double x, double y) { } -void SVGCharTspanTextHandler::setInitialContextNode (XMLElementNode *node) { +void SVGCharTspanTextHandler::setInitialContextNode (XMLElement *node) { SVGCharHandler::setInitialContextNode(node); - _textNode = _tspanNode = 0; + _textNode = _tspanNode = nullptr; _xchanged = _ychanged = false; } void SVGCharTspanTextHandler::resetContextNode () { SVGCharHandler::resetContextNode(); - _textNode = _tspanNode = 0; + _textNode = _tspanNode = nullptr; _xchanged = _ychanged = false; _font.changed(false); _matrix.changed(false); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp index c88e97bfe52..01567997b63 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp @@ -25,19 +25,19 @@ class SVGCharTspanTextHandler : public SVGCharTextHandler { public: - SVGCharTspanTextHandler (bool selectFontByClass); + explicit SVGCharTspanTextHandler (bool selectFontByClass); void notifyXAdjusted () override {_xchanged = true;} void notifyYAdjusted() override {_ychanged = true;} void appendChar (uint32_t c, double x, double y) override; - void setInitialContextNode (XMLElementNode *node) override; + void setInitialContextNode (XMLElement *node) override; protected: void resetContextNode () override; private: bool _xchanged, _ychanged; - XMLElementNode *_textNode; - XMLElementNode *_tspanNode; + XMLElement *_textNode; + XMLElement *_tspanNode; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp index 6256acdeba1..7c4108c8769 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp @@ -34,8 +34,8 @@ using namespace std; -SVGOutput::SVGOutput (const string &base, const string &pattern, int zipLevel) - : _path(base), _pattern(pattern), _stdout(base.empty()), _zipLevel(zipLevel), _page(-1) +SVGOutput::SVGOutput (const string &base, string pattern, int zipLevel) + : _path(base), _pattern(std::move(pattern)), _stdout(base.empty()), _zipLevel(zipLevel), _page(-1) { } @@ -46,8 +46,8 @@ SVGOutput::SVGOutput (const string &base, const string &pattern, int zipLevel) * @param[in] hash hash value of the current page * @return output stream for the given page */ ostream& SVGOutput::getPageStream (int page, int numPages, const HashTriple &hashes) const { - string fname = filename(page, numPages, hashes); - if (fname.empty()) { + FilePath path = filepath(page, numPages, hashes); + if (path.empty()) { if (_zipLevel == 0) { _osptr.reset(); return cout; @@ -63,52 +63,35 @@ ostream& SVGOutput::getPageStream (int page, int numPages, const HashTriple &has _page = page; if (_zipLevel > 0) - _osptr = util::make_unique<ZLibOutputFileStream>(fname, ZLIB_GZIP, _zipLevel); + _osptr = util::make_unique<ZLibOutputFileStream>(path.absolute(), ZLIB_GZIP, _zipLevel); else - _osptr = util::make_unique<ofstream>(fname); + _osptr = util::make_unique<ofstream>(path.absolute()); if (!_osptr) - throw MessageException("can't open file "+fname+" for writing"); + throw MessageException("can't open file "+path.shorterAbsoluteOrRelative()+" for writing"); return *_osptr; } -/** Returns the name of the SVG file containing the given page. +/** Returns the path of the SVG file containing the given page number. * @param[in] page number of current page * @param[in] numPages total number of pages * @param[in] hash hash value of current page */ -string SVGOutput::filename (int page, int numPages, const HashTriple &hashes) const { - if (_stdout) - return ""; - - string expanded_pattern = util::trim(expandFormatString(_pattern, page, numPages, hashes)); - // set and expand default pattern if necessary - if (expanded_pattern.empty()) { - string pattern = hashes.empty() ? (numPages > 1 ? "%f-%p" : "%f") : "%f-%hd"; - expanded_pattern = expandFormatString(pattern, page, numPages, hashes); +FilePath SVGOutput::filepath (int page, int numPages, const HashTriple &hashes) const { + FilePath outpath; + if (!_stdout) { + string expanded_pattern = util::trim(expandFormatString(_pattern, page, numPages, hashes)); + // set and expand default pattern if necessary + if (expanded_pattern.empty()) { + string pattern = hashes.empty() ? (numPages > 1 ? "%f-%p" : "%f") : "%f-%hd"; + expanded_pattern = expandFormatString(pattern, page, numPages, hashes); + } + // append suffix if necessary + outpath.set(expanded_pattern, true); + if (outpath.suffix().empty()) + outpath.suffix(_zipLevel > 0 ? "svgz" : "svg"); } - // append suffix if necessary - FilePath outpath(expanded_pattern, true); - if (outpath.suffix().empty()) - outpath.suffix(_zipLevel > 0 ? "svgz" : "svg"); - string abspath = outpath.absolute(); - string relpath = outpath.relative(); - return abspath.length() < relpath.length() ? abspath : relpath; -} - - -#if 0 -string SVGOutput::outpath (int page, int numPages) const { - string path = filename(page, numPages); - if (path.empty()) - return ""; - size_t pos = path.rfind('/'); - if (pos == string::npos) - return "."; - if (pos == 0) - return "/"; - return path.substr(0, pos); + return outpath; } -#endif /** Replaces expressions in a given string by the corresponding values and returns the result. @@ -174,9 +157,7 @@ string SVGOutput::expandFormatString (string str, int page, int numPages, const result += oss.str(); } catch (CalculatorException &e) { - oss.str(""); - oss << "error in filename pattern (" << e.what() << ")"; - throw MessageException(oss.str()); + throw MessageException("error in filename pattern (" + string(e.what()) + ")"); } pos = endpos; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp index 6fb4ee6abf1..3c382f0b7fe 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp @@ -31,8 +31,8 @@ struct SVGOutputBase { class HashTriple { public: HashTriple () =default; - HashTriple (const std::string &dviHash, const std::string &optHash, const std::string &cmbHash) - : _dviHash(dviHash), _optHash(optHash), _cmbHash(cmbHash) {} + HashTriple (std::string dviHash, std::string optHash, std::string cmbHash) + : _dviHash(std::move(dviHash)), _optHash(std::move(optHash)), _cmbHash(std::move(cmbHash)) {} std::string dviHash () const {return _dviHash;} std::string optHash () const {return _optHash;} std::string cmbHash () const {return _cmbHash;} @@ -46,7 +46,7 @@ struct SVGOutputBase { virtual ~SVGOutputBase () =default; virtual std::ostream& getPageStream (int page, int numPages, const HashTriple &hashes=HashTriple()) const =0; - virtual std::string filename (int page, int numPages, const HashTriple &hashes=HashTriple()) const =0; + virtual FilePath filepath (int page, int numPages, const HashTriple &hashes= HashTriple()) const =0; virtual bool ignoresHashes () const {return true;} }; @@ -54,11 +54,11 @@ struct SVGOutputBase { class SVGOutput : public SVGOutputBase { public: SVGOutput () : SVGOutput("", "", 0) {} - SVGOutput (const std::string &base) : SVGOutput(base, "", 0) {} + explicit SVGOutput (const std::string &base) : SVGOutput(base, "", 0) {} SVGOutput (const std::string &base, const std::string &pattern) : SVGOutput(base, pattern, 0) {} - SVGOutput (const std::string &base, const std::string &pattern, int zipLevel); + SVGOutput (const std::string &base, std::string pattern, int zipLevel); std::ostream& getPageStream (int page, int numPages, const HashTriple &hash=HashTriple()) const override; - std::string filename (int page, int numPages, const HashTriple &hash=HashTriple()) const override; + FilePath filepath (int page, int numPages, const HashTriple &hash=HashTriple()) const override; bool ignoresHashes () const override; protected: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp index 9729bafabac..7fd2174f127 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp @@ -26,7 +26,7 @@ class SVGSingleCharTextHandler : public SVGCharTextHandler { public: - SVGSingleCharTextHandler (bool createStyleElements) : SVGCharTextHandler(createStyleElements) {} + explicit SVGSingleCharTextHandler (bool createStyleElements) : SVGCharTextHandler(createStyleElements) {} void appendChar (uint32_t c, double x, double y) override; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp index 3c891219e14..57b5fd5a4fa 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp @@ -20,9 +20,9 @@ #include <algorithm> #include <array> +#include <cstring> #include <sstream> #include "BoundingBox.hpp" -#include "DependencyGraph.hpp" #include "DVIToSVG.hpp" #include "FileSystem.hpp" #include "Font.hpp" @@ -36,7 +36,6 @@ using namespace std; - // static class variables bool SVGTree::CREATE_CSS=true; bool SVGTree::USE_FONTS=true; @@ -56,7 +55,7 @@ SVGTree::SVGTree () : _charHandler(SVGCharHandlerFactory::createHandler()) { /** Clears the SVG tree and initializes the root element. */ void SVGTree::reset () { _doc.clear(); - auto rootNode = util::make_unique<XMLElementNode>("svg"); + auto rootNode = util::make_unique<XMLElement>("svg"); rootNode->addAttribute("version", "1.1"); rootNode->addAttribute("xmlns", "http://www.w3.org/2000/svg"); rootNode->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); @@ -112,45 +111,46 @@ bool SVGTree::setFontFormat (string formatstr) { /** Starts a new page. * @param[in] pageno number of new page */ void SVGTree::newPage (int pageno) { - auto pageNode = util::make_unique<XMLElementNode>("g"); + auto pageNode = util::make_unique<XMLElement>("g"); if (pageno >= 0) pageNode->addAttribute("id", string("page")+XMLString(pageno)); _charHandler->setInitialContextNode(pageNode.get()); _page = pageNode.get(); _root->append(std::move(pageNode)); - while (!_contextElementStack.empty()) - _contextElementStack.pop(); + _defsContextStack = stack<XMLElement*>(); + _pageContextStack = stack<XMLElement*>(); } -void SVGTree::appendToDefs (unique_ptr<XMLNode> &&node) { +void SVGTree::appendToDefs (unique_ptr<XMLNode> node) { if (!_defs) { - auto defsNode = util::make_unique<XMLElementNode>("defs"); + auto defsNode = util::make_unique<XMLElement>("defs"); _defs = defsNode.get(); _root->prepend(std::move(defsNode)); } - _defs->append(std::move(node)); + XMLElement *parent = _defsContextStack.empty() ? _defs : _defsContextStack.top(); + parent->append(std::move(node)); } -void SVGTree::appendToPage (unique_ptr<XMLNode> &&node) { - XMLElementNode *parent = _contextElementStack.empty() ? _page : _contextElementStack.top(); +void SVGTree::appendToPage (unique_ptr<XMLNode> node) { + XMLElement *parent = _pageContextStack.empty() ? _page : _pageContextStack.top(); parent->append(std::move(node)); _charHandler->setInitialContextNode(parent); } -void SVGTree::prependToPage (unique_ptr<XMLNode> &&node) { - if (_contextElementStack.empty()) +void SVGTree::prependToPage (unique_ptr<XMLNode> node) { + if (_pageContextStack.empty()) _page->prepend(std::move(node)); else - _contextElementStack.top()->prepend(std::move(node)); + _pageContextStack.top()->prepend(std::move(node)); } void SVGTree::transformPage (const Matrix &usermatrix) { if (!usermatrix.isIdentity()) - _page->addAttribute("transform", usermatrix.getSVG()); + _page->addAttribute("transform", usermatrix.toSVG()); } @@ -159,17 +159,17 @@ void SVGTree::transformPage (const Matrix &usermatrix) { * @param[in] font font to extract the glyph from * @param[in] cb pointer to callback object for sending feedback to the glyph tracer (may be 0) * @return pointer to element node if glyph exists, 0 otherwise */ -static unique_ptr<XMLElementNode> createGlyphNode (int c, const PhysicalFont &font, GFGlyphTracer::Callback *cb) { +static unique_ptr<XMLElement> createGlyphNode (int c, const PhysicalFont &font, GFGlyphTracer::Callback *cb) { Glyph glyph; if (!font.getGlyph(c, glyph, cb) || (!SVGTree::USE_FONTS && !SVGTree::CREATE_USE_ELEMENTS)) return nullptr; double sx=1.0, sy=1.0; double upem = font.unitsPerEm(); - unique_ptr<XMLElementNode> glyphNode; + unique_ptr<XMLElement> glyphNode; if (SVGTree::USE_FONTS) { double extend = font.style() ? font.style()->extend : 1; - glyphNode = util::make_unique<XMLElementNode>("glyph"); + glyphNode = util::make_unique<XMLElement>("glyph"); glyphNode->addAttribute("unicode", XMLString(font.unicode(c), false)); glyphNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance(c)*extend)); glyphNode->addAttribute("vert-adv-y", XMLString(font.vAdvance(c))); @@ -178,7 +178,7 @@ static unique_ptr<XMLElementNode> createGlyphNode (int c, const PhysicalFont &fo glyphNode->addAttribute("glyph-name", name); } else { - glyphNode = util::make_unique<XMLElementNode>("path"); + glyphNode = util::make_unique<XMLElement>("path"); glyphNode->addAttribute("id", "g"+to_string(FontManager::instance().fontID(&font))+"-"+to_string(c)); sx = font.scaledSize()/upem; sy = -sx; @@ -192,7 +192,7 @@ static unique_ptr<XMLElementNode> createGlyphNode (int c, const PhysicalFont &fo static string font_info (const Font &font) { ostringstream oss; - if (const NativeFont *nf = dynamic_cast<const NativeFont*>(&font)) { + if (auto nf = dynamic_cast<const NativeFont*>(&font)) { oss << nf->familyName() << ' ' << nf->styleName() << "; " << nf->filename(); if (nf->style()) { if (nf->style()->bold != 0) @@ -255,14 +255,14 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr if (ADD_COMMENTS) { string info = font_info(font); if (!info.empty()) - appendToDefs(util::make_unique<XMLCommentNode>(string(" font: ")+info+" ")); + appendToDefs(util::make_unique<XMLComment>(string(" font: ")+info+" ")); } - auto fontNode = util::make_unique<XMLElementNode>("font"); + auto fontNode = util::make_unique<XMLElement>("font"); string fontname = font.name(); fontNode->addAttribute("id", fontname); fontNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance())); - auto faceNode = util::make_unique<XMLElementNode>("font-face"); + auto faceNode = util::make_unique<XMLElement>("font-face"); faceNode->addAttribute("font-family", fontname); faceNode->addAttribute("units-per-em", XMLString(font.unitsPerEm())); if (!font.verticalLayout()) { @@ -281,7 +281,7 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr // reference the already embedded path together with a transformation attribute and let the SVG renderer // scale the glyphs properly. This is only necessary if we don't want to use font but path elements. for (int c : chars) { - auto useNode = util::make_unique<XMLElementNode>("use"); + auto useNode = util::make_unique<XMLElement>("use"); useNode->addAttribute("id", "g"+to_string(FontManager::instance().fontID(&font))+"-"+to_string(c)); useNode->addAttribute("xlink:href", "#g"+to_string(FontManager::instance().fontID(font.uniqueFont()))+"-"+to_string(c)); double scale = font.scaledSize()/font.uniqueFont()->scaledSize(); @@ -297,70 +297,47 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr } -/** Pushes a new context element that will take all following nodes added to the page. */ -void SVGTree::pushContextElement (unique_ptr<XMLElementNode> &&node) { - XMLElementNode *nodePtr = node.get(); - if (_contextElementStack.empty()) - _page->append(std::move(node)); +void SVGTree::pushDefsContext (unique_ptr<XMLElement> node) { + XMLElement *nodePtr = node.get(); + if (_defsContextStack.empty()) + appendToDefs(std::move(node)); else - _contextElementStack.top()->append(std::move(node)); - _contextElementStack.push(nodePtr); - _charHandler->setInitialContextNode(nodePtr); + _defsContextStack.top()->append(std::move(node)); + _defsContextStack.push(nodePtr); } -/** Pops the current context element and restored the previous one. */ -void SVGTree::popContextElement () { - if (!_contextElementStack.empty()) - _contextElementStack.pop(); - _charHandler->setInitialContextNode(_page); +void SVGTree::popDefsContext () { + if (!_defsContextStack.empty()) + _defsContextStack.pop(); } -/** Extracts the ID from a local URL reference like url(#abcde) */ -static inline string extract_id_from_url (const string &url) { - return url.substr(5, url.length()-6); +/** Pushes a new context element that will take all following nodes added to the page. */ +void SVGTree::pushPageContext (unique_ptr<XMLElement> node) { + XMLElement *nodePtr = node.get(); + if (_pageContextStack.empty()) + _page->append(std::move(node)); + else + _pageContextStack.top()->append(std::move(node)); + _pageContextStack.push(nodePtr); + _charHandler->setInitialContextNode(nodePtr); } -/** Removes elements present in the SVG tree that are not required. - * For now, only clipPath elements are removed. */ -void SVGTree::removeRedundantElements () { - vector<XMLElementNode*> clipPathElements; - if (!_defs || !_defs->getDescendants("clipPath", nullptr, clipPathElements)) - return; - - // collect dependencies between clipPath elements in the defs section of the SVG tree - DependencyGraph<string> idTree; - for (const XMLElementNode *clip : clipPathElements) { - if (const char *id = clip->getAttributeValue("id")) { - if (const char *url = clip->getAttributeValue("clip-path")) - idTree.insert(extract_id_from_url(url), id); - else - idTree.insert(id); - } - } - // collect elements that reference a clipPath, i.e. have a clip-path attribute - vector<XMLElementNode*> descendants; - _page->getDescendants(nullptr, "clip-path", descendants); - // remove referenced IDs and their dependencies from the dependency graph - for (const XMLElementNode *elem : descendants) { - string idref = extract_id_from_url(elem->getAttributeValue("clip-path")); - idTree.removeDependencyPath(idref); - } - descendants.clear(); - for (const string &str : idTree.getKeys()) { - XMLElementNode *node = _defs->getFirstDescendant("clipPath", "id", str.c_str()); - _defs->remove(node); - } +/** Pops the current context element and restored the previous one. */ +void SVGTree::popPageContext () { + if (!_pageContextStack.empty()) + _pageContextStack.pop(); + _charHandler->setInitialContextNode(_page); } -XMLCDataNode* SVGTree::styleCDataNode () { +XMLCData* SVGTree::styleCDataNode () { if (!_styleCDataNode) { - auto styleNode = util::make_unique<XMLElementNode>("style"); + auto styleNode = util::make_unique<XMLElement>("style"); styleNode->addAttribute("type", "text/css"); - auto cdataNode = util::make_unique<XMLCDataNode>(); + auto cdataNode = util::make_unique<XMLCData>(); _styleCDataNode = cdataNode.get(); styleNode->append(std::move(cdataNode)); _root->insertBefore(std::move(styleNode), _page); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp index 62891e76fa3..d351ec97991 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp @@ -46,17 +46,18 @@ class SVGTree { void reset (); bool write (std::ostream &os) const {return bool(_doc.write(os));} void newPage (int pageno); - void appendToDefs (std::unique_ptr<XMLNode> &&node); - void appendToPage (std::unique_ptr<XMLNode> &&node); - void prependToPage (std::unique_ptr<XMLNode> &&node); - void appendToDoc (std::unique_ptr<XMLNode> &&node) {_doc.append(std::move(node));} - void appendToRoot (std::unique_ptr<XMLNode> &&node) {_root->append(std::move(node));} + void appendToDefs (std::unique_ptr<XMLNode> node); + void appendToPage (std::unique_ptr<XMLNode> node); + void prependToPage (std::unique_ptr<XMLNode> node); + void appendToDoc (std::unique_ptr<XMLNode> node) {_doc.append(std::move(node));} + void appendToRoot (std::unique_ptr<XMLNode> node) {_root->append(std::move(node));} void appendChar (int c, double x, double y) {_charHandler->appendChar(c, x, y);} void appendFontStyles (const std::unordered_set<const Font*> &fonts); - void append (const PhysicalFont &font, const std::set<int> &chars, GFGlyphTracer::Callback *callback=0); - void pushContextElement (std::unique_ptr<XMLElementNode> &&node); - void popContextElement (); - void removeRedundantElements (); + void append (const PhysicalFont &font, const std::set<int> &chars, GFGlyphTracer::Callback *callback=nullptr); + void pushDefsContext (std::unique_ptr<XMLElement> node); + void popDefsContext (); + void pushPageContext (std::unique_ptr<XMLElement> node); + void popPageContext (); void setBBox (const BoundingBox &bbox); void setFont (int id, const Font &font); static bool setFontFormat (std::string formatstr); @@ -68,10 +69,12 @@ class SVGTree { void transformPage (const Matrix &m); Color getColor () const {return _charHandler->getColor();} const Matrix& getMatrix () const {return _charHandler->getMatrix();} - XMLElementNode* rootNode () const {return _root;} + XMLElement* rootNode () const {return _root;} + XMLElement* defsNode () const {return _defs;} + XMLElement* pageNode () const {return _page;} protected: - XMLCDataNode* styleCDataNode (); + XMLCData* styleCDataNode (); public: static bool USE_FONTS; ///< if true, create font references and don't draw paths directly @@ -85,10 +88,11 @@ class SVGTree { private: XMLDocument _doc; - XMLElementNode *_root, *_page, *_defs; - XMLCDataNode *_styleCDataNode; + XMLElement *_root, *_page, *_defs; + XMLCData *_styleCDataNode; std::unique_ptr<SVGCharHandler> _charHandler; - std::stack<XMLElementNode*> _contextElementStack; + std::stack<XMLElement*> _defsContextStack; + std::stack<XMLElement*> _pageContextStack; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp index 2c430ac58bf..4346301e7bf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp @@ -38,12 +38,12 @@ class ShadingPatch { using ColorVec = std::vector<Color>; public: - ShadingPatch (Color::ColorSpace colorSpace) : _colorspace(colorSpace) {} + explicit ShadingPatch (Color::ColorSpace colorSpace) : _colorspace(colorSpace) {} virtual ~ShadingPatch () =default; virtual int psShadingType () const =0; virtual void approximate (int gridsize, bool overlap, double delta, Callback &callback) const =0; - virtual void getBBox (BoundingBox &bbox) const =0; - virtual void getBoundaryPath (GraphicsPath<double> &path) const =0; + virtual BoundingBox getBBox () const =0; + virtual GraphicsPath<double> getBoundaryPath () const =0; virtual void setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) =0; virtual void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) =0; virtual int numPoints (int edgeflag) const =0; @@ -63,7 +63,7 @@ class ShadingPatch { struct ShadingException : public MessageException { - ShadingException (const std::string &msg) : MessageException(msg) {} + explicit ShadingException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp index aa2a5dde55e..886c9281bbc 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp @@ -129,7 +129,7 @@ bool SignalHandler::Impl::setSigintHandler (HandlerFunc handler) { bool SignalHandler::Impl::restoreSigintHandler () { if (_origSigaction.sa_handler == nullptr) return false; - return (sigaction(SIGINT, &_origSigaction, 0) == 0); + return (sigaction(SIGINT, &_origSigaction, nullptr) == 0); } #else // !HAVE_SIGACTION diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp index 05df49ee84a..3b0f7b3c62c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp @@ -43,7 +43,7 @@ class TemporaryFile { class SourceInput { public: - SourceInput (const std::string &fname) : _fname(fname) {} + explicit SourceInput (const std::string &fname) : _fname(fname) {} std::istream& getInputStream (bool showMessages=false); std::string getFileName () const; std::string getMessageFileName () const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp index 5e32f84413b..7e53303792b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp @@ -25,10 +25,12 @@ #include <memory> #include "BoundingBox.hpp" #include "Color.hpp" +#include "FilePath.hpp" #include "Matrix.hpp" +#include "SVGTree.hpp" +class XMLElement; class XMLNode; -class XMLElementNode; class SpecialActions { public: @@ -44,20 +46,20 @@ class SpecialActions { virtual const Matrix& getMatrix () const =0; virtual Matrix getPageTransformation () const {return Matrix(1);} virtual void setBgColor (const Color &color) =0; - virtual void appendToPage(std::unique_ptr<XMLNode> &&node) =0; - virtual void appendToDefs(std::unique_ptr<XMLNode> &&node) =0; - virtual void prependToPage(std::unique_ptr<XMLNode> &&node) =0; - virtual void pushContextElement (std::unique_ptr<XMLElementNode> &&node) =0; - virtual void popContextElement () =0; + virtual const SVGTree& svgTree () const =0; + SVGTree& svgTree () {return const_cast<SVGTree&>(const_cast<const SpecialActions*>(this)->svgTree());} virtual BoundingBox& bbox () =0; virtual BoundingBox& bbox (const std::string &name, bool reset=false) =0; virtual void embed (const BoundingBox &bbox) =0; virtual void embed (const DPair &p, double r=0) =0; virtual unsigned getCurrentPageNumber () const =0; - virtual std::string getSVGFilename (unsigned pageno) const =0; + virtual FilePath getSVGFilePath (unsigned pageno) const =0; virtual std::string getBBoxFormatString () const =0; virtual void progress (const char *id) {} virtual int getDVIStackDepth () const {return 0;} + virtual void lockOutput () {} + virtual void unlockOutput () {} + virtual bool outputLocked () const {return false;} static double PROGRESSBAR_DELAY; ///< progress bar doesn't appear before this time has elapsed (in sec) }; @@ -65,6 +67,7 @@ class SpecialActions { class EmptySpecialActions : public SpecialActions { public: + EmptySpecialActions () : _matrix(1) {_svg.newPage(1);} double getX () const override {return 0;} double getY () const override {return 0;} void setX (double x) override {} @@ -75,22 +78,19 @@ class EmptySpecialActions : public SpecialActions { Color getColor () const override {return Color::BLACK;} void setMatrix (const Matrix &m) override {} const Matrix& getMatrix () const override {return _matrix;} - void appendToPage(std::unique_ptr<XMLNode> &&node) override {} - void appendToDefs(std::unique_ptr<XMLNode> &&node) override {} - void prependToPage(std::unique_ptr<XMLNode> &&node) override {} - void pushContextElement (std::unique_ptr<XMLElementNode> &&node) override {} - void popContextElement () override {} + const SVGTree& svgTree () const override {return _svg;} BoundingBox& bbox () override {return _bbox;} BoundingBox& bbox (const std::string &name, bool reset=false) override {return _bbox;} void embed (const BoundingBox &bbox) override {} void embed (const DPair &p, double r=0) override {} unsigned getCurrentPageNumber() const override {return 0;} - std::string getSVGFilename (unsigned pageno) const override {return "";} + FilePath getSVGFilePath (unsigned pageno) const override {return FilePath();} std::string getBBoxFormatString () const override {return "";} private: BoundingBox _bbox; Matrix _matrix; + SVGTree _svg; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp index 35b4caf44a0..4a3439bb246 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp @@ -32,7 +32,7 @@ class SpecialManager; struct SpecialException : public MessageException { - SpecialException (const std::string &msg) : MessageException(msg) {} + explicit SpecialException (const std::string &msg) : MessageException(msg) {} }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp index 5b8646879f0..4838cbdf47b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp @@ -46,7 +46,7 @@ void SpecialManager::unregisterHandlers () { /** Registers a single special handler. This method doesn't check if a * handler of the same class is already registered. * @param[in] handler pointer to handler to be registered */ -void SpecialManager::registerHandler (unique_ptr<SpecialHandler> &&handler) { +void SpecialManager::registerHandler (unique_ptr<SpecialHandler> handler) { if (handler) { // get array of prefixes this handler is responsible for for (const char *prefix : handler->prefixes()) @@ -104,11 +104,11 @@ static string extract_prefix (istream &is) { int c; string prefix; while (isalnum(c=is.get())) - prefix += c; + prefix += char(c); if (ispunct(c)) // also add separation character to identifying prefix - prefix += c; + prefix += char(c); if (prefix == "ps:" && is.peek() == ':') - prefix += is.get(); + prefix += char(is.get()); return prefix; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp index 671078baa6b..fe88eaf58eb 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp @@ -36,8 +36,9 @@ class SpecialManager { using HandlerMap = std::unordered_map<std::string,SpecialHandler*>; public: + SpecialManager (const SpecialManager &) =delete; static SpecialManager& instance (); - void registerHandler (std::unique_ptr<SpecialHandler> &&handler); + void registerHandler (std::unique_ptr<SpecialHandler> handler); void registerHandlers (std::vector<std::unique_ptr<SpecialHandler>> &handlers, const char *ignorelist); void unregisterHandlers (); void preprocess (const std::string &special, SpecialActions &actions) const; @@ -51,7 +52,6 @@ class SpecialManager { protected: SpecialManager () =default; - SpecialManager (const SpecialManager &) =delete; SpecialHandler* findHandlerByPrefix (const std::string &prefix) const; private: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp index 08067566075..ccfb176abee 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp @@ -20,8 +20,9 @@ #include <algorithm> #include <vector> -#include "CRC32.hpp" +#include "HashFunction.hpp" #include "StreamReader.hpp" +#include "utility.hpp" using namespace std; @@ -46,13 +47,13 @@ uint32_t StreamReader::readUnsigned (int bytes) { } -/** Reads an unsigned integer from assigned input stream and updates the CRC32 checksum. - * @param[in] bytes number of bytes to read (max. 4) - * @param[in,out] crc32 checksum to be updated +/** Reads an unsigned integer from assigned input stream and updates the hash value. + * @param[in] n number of bytes to read (max. 4) + * @param[in,out] hashfunc hash to update * @return read integer */ -uint32_t StreamReader::readUnsigned (int bytes, CRC32 &crc32) { - uint32_t ret = readUnsigned(bytes); - crc32.update(ret, bytes); +uint32_t StreamReader::readUnsigned (int n, HashFunction &hashfunc) { + uint32_t ret = readUnsigned(n); + hashfunc.update(util::bytes(ret, n)); return ret; } @@ -70,13 +71,13 @@ int32_t StreamReader::readSigned (int bytes) { } -/** Reads an signed integer from assigned input stream and updates the CRC32 checksum. +/** Reads an signed integer from assigned input stream and updates the hash value. * @param[in] bytes number of bytes to read (max. 4) - * @param[in,out] crc32 checksum to be updated + * @param[in,out] hashfunc hash to update * @return read integer */ -int32_t StreamReader::readSigned (int bytes, CRC32 &crc32) { - int32_t ret = readSigned(bytes); - crc32.update(uint32_t(ret), bytes); +int32_t StreamReader::readSigned (int n, HashFunction &hashfunc) { + int32_t ret = readSigned(n); + hashfunc.update(util::bytes(ret, n)); return ret; } @@ -87,21 +88,21 @@ string StreamReader::readString () { throw StreamReaderException("no stream assigned"); string ret; while (!_is->eof() && _is->peek() > 0) - ret += _is->get(); + ret += char(_is->get()); _is->get(); // skip 0-byte return ret; } -/** Reads a string terminated by a 0-byte and updates the CRC32 checksum. - * @param[in,out] crc32 checksum to be updated +/** Reads a string terminated by a 0-byte and updates the hash value. + * @param[in,out] hashfunc hash to update * @param[in] finalZero consider final 0-byte in checksum * @return the string read */ -string StreamReader::readString (CRC32 &crc32, bool finalZero) { +string StreamReader::readString (HashFunction &hashfunc, bool finalZero) { string ret = readString(); - crc32.update(reinterpret_cast<const uint8_t*>(ret.data()), ret.length()); + hashfunc.update(ret.data(), ret.length()); if (finalZero) - crc32.update(0, 1); + hashfunc.update(0, 1); return ret; } @@ -119,36 +120,37 @@ string StreamReader::readString (int length) { } -/** Reads a string of a given length and updates the CRC32 checksum. +/** Reads a string of a given length and updates the hash value. * @param[in] length number of characters to read - * @param[in,out] crc32 checksum to be updated + * @param[in,out] hashfunc hash to update * @return the string read */ -string StreamReader::readString (int length, CRC32 &crc32) { +string StreamReader::readString (int length, HashFunction &hashfunc) { string ret = readString(length); - crc32.update(reinterpret_cast<const uint8_t*>(ret.data()), length); + hashfunc.update(ret.data(), length); return ret; } -vector<uint8_t>& StreamReader::readBytes (int n, vector<uint8_t> &bytes) { +vector<uint8_t> StreamReader::readBytes (int n) { + vector<uint8_t> bytes(n); if (n > 0) - _is->read((char*)&bytes[0], n); + _is->read(reinterpret_cast<char*>(bytes.data()), n); return bytes; } -vector<uint8_t>& StreamReader::readBytes (int n, vector<uint8_t> &bytes, CRC32 &crc32) { - readBytes(n, bytes); - crc32.update(&bytes[0], bytes.size()); +vector<uint8_t> StreamReader::readBytes (int n, HashFunction &hashfunc) { + vector<uint8_t> bytes = readBytes(n); + hashfunc.update(bytes); return bytes; } -int StreamReader::readByte (CRC32 &crc32) { +int StreamReader::readByte (HashFunction &hashfunc) { int ret = readByte(); if (ret >= 0) { - const uint8_t c = uint8_t(ret & 0xff); - crc32.update(&c, 1); + char c = ret & 0xff; + hashfunc.update(&c, 1); } return ret; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp index bf38b2cbf76..05c4e1e701b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp @@ -26,28 +26,28 @@ #include <vector> #include "MessageException.hpp" -class CRC32; +class HashFunction; class StreamReader { public: - StreamReader (std::istream &is) : _is(&is) {} + explicit StreamReader (std::istream &is) : _is(&is) {} virtual ~StreamReader () =default; bool isStreamValid () const {return _is;} bool eof () const {return _is->eof();} void clearStream () {_is->clear();} std::istream& replaceStream (std::istream &s); uint32_t readUnsigned (int n); - uint32_t readUnsigned (int n, CRC32 &crc32); + uint32_t readUnsigned (int n, HashFunction &hashfunc); int32_t readSigned (int n); - int32_t readSigned (int n, CRC32 &crc32); + int32_t readSigned (int n, HashFunction &hashfunc); std::string readString (); - std::string readString (CRC32 &crc32, bool finalZero=false); + std::string readString (HashFunction &hashfunc, bool finalZero=false); std::string readString (int length); - std::string readString (int length, CRC32 &crc32); - std::vector<uint8_t>& readBytes (int n, std::vector<uint8_t> &bytes); - std::vector<uint8_t>& readBytes (int n, std::vector<uint8_t> &bytes, CRC32 &crc32); + std::string readString (int length, HashFunction &hashfunc); + std::vector<uint8_t> readBytes (int n); + std::vector<uint8_t> readBytes (int n, HashFunction &hash); int readByte () {return _is->get();} - int readByte (CRC32 &crc32); + int readByte (HashFunction &hashfunc); void seek (std::streampos pos, std::ios::seekdir dir) {_is->seekg(pos, dir);} void seek (std::streampos pos) {_is->seekg(pos);} std::streampos tell () const {return _is->tellg();} @@ -62,7 +62,7 @@ class StreamReader { struct StreamReaderException : public MessageException { - StreamReaderException (const std::string &msg) : MessageException(msg) {} + explicit StreamReaderException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp index c5630f56ba2..62164686952 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp @@ -18,8 +18,9 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#include "CRC32.hpp" +#include "HashFunction.hpp" #include "StreamWriter.hpp" +#include "utility.hpp" using namespace std; @@ -37,7 +38,7 @@ void StreamWriter::writeUnsigned (uint32_t val, int n) { * @param[in] val the value to write * @param[in] n number of bytes to be considered */ void StreamWriter::writeSigned (int32_t val, int n) { - writeUnsigned((uint32_t)val, n); + writeUnsigned(uint32_t(val), n); } @@ -71,27 +72,27 @@ void StreamWriter::writeString (const string &str, bool finalZero) { /** Writes an unsigned integer to the output stream. * @param[in] val the value to write * @param[in] n number of bytes to be considered - * @param[in,out] crc32 checksum to be updated */ -void StreamWriter::writeUnsigned (uint32_t val, int n, CRC32 &crc32) { + * @param[in,out] hashfunc hash to update */ +void StreamWriter::writeUnsigned (uint32_t val, int n, HashFunction &hashfunc) { writeUnsigned(val, n); - crc32.update(val, n); + hashfunc.update(util::bytes(val, n)); } -/** Writes a signed integer to the output stream and updates the CRC32 checksum. +/** Writes a signed integer to the output stream and updates the hash value. * @param[in] val the value to write * @param[in] n number of bytes to be considered - * @param[in,out] crc32 checksum to be updated */ -void StreamWriter::writeSigned (int32_t val, int n, CRC32 &crc32) { - writeUnsigned((uint32_t)val, n, crc32); + * @param[in,out] hashfunc hash to update */ +void StreamWriter::writeSigned (int32_t val, int n, HashFunction &hashfunc) { + writeUnsigned(uint32_t(val), n, hashfunc); } -/** Writes a string to the output stream and updates the CRC32 checksum. +/** Writes a string to the output stream and updates the hash value. * @param[in] str the string to write - * @param[in,out] crc32 checksum to be updated + * @param[in,out] hashfunc hash to update * @param[in] finalZero if true, a final 0-byte is appended */ -void StreamWriter::writeString (const std::string &str, CRC32 &crc32, bool finalZero) { +void StreamWriter::writeString (const std::string &str, HashFunction &hashfunc, bool finalZero) { writeString(str, finalZero); - crc32.update((const uint8_t*)str.c_str(), str.length() + (finalZero ? 1 : 0)); + hashfunc.update(str.data(), str.length() + (finalZero ? 1 : 0)); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp index b60e61811e9..441a9a7e7ff 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp @@ -24,21 +24,20 @@ #include <ostream> #include <vector> -class CRC32; +class HashFunction; class StreamWriter { public: - StreamWriter (std::ostream &os) : _os(os) {} - virtual ~StreamWriter () =default; + explicit StreamWriter (std::ostream &os) : _os(os) {} void writeUnsigned (uint32_t val, int n); void writeSigned (int32_t val, int n); void writeBytes (const std::vector<uint8_t> &bytes); void writeBytes (const uint8_t *buf, size_t bufsize); void writeBytes (int byte, size_t count); void writeString (const std::string &str, bool finalZero=false); - void writeUnsigned (uint32_t val, int n, CRC32 &crc32); - void writeSigned (int32_t val, int n, CRC32 &crc32); - void writeString (const std::string &str, CRC32 &crc32, bool finalZero=false); + void writeUnsigned (uint32_t val, int n, HashFunction &hashfunc); + void writeSigned (int32_t val, int n, HashFunction &hashfunc); + void writeString (const std::string &str, HashFunction &hashfunc, bool finalZero=false); private: std::ostream &_os; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp index 3f246c0dd8d..e0b2570d8c7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp @@ -34,13 +34,13 @@ using namespace std; // helper functions static int skip_mapping_data (istream &is); -static bool scan_line (const char *line, int lineno, vector<uint16_t> &mapping, const string &fname, long &pos); +static bool scan_line (const char *line, int lineno, vector<uint16_t> &mapping, const string &fname, long &offset); /** Constructs a new SubfontDefinition object. * @param[in] name name of subfont definition * @param[in] fpath path to corresponding .sfd file*/ -SubfontDefinition::SubfontDefinition (const string &name, const char *fpath) : _sfname(name) { +SubfontDefinition::SubfontDefinition (string name, const char *fpath) : _sfname(std::move(name)) { // read all subfont IDs from the .sfd file but skip the mapping data ifstream is(fpath); while (is) { @@ -51,7 +51,7 @@ SubfontDefinition::SubfontDefinition (const string &name, const char *fpath) : _ else { string id; while (is && !isspace(is.peek())) - id += is.get(); + id += char(is.get()); if (!id.empty()) { auto state = _subfonts.emplace(pair<string,unique_ptr<Subfont>>(id, unique_ptr<Subfont>())); if (state.second) // id was not present in map already @@ -136,7 +136,7 @@ bool Subfont::read () { else { string id; while (is && !isspace(is.peek())) - id += is.get(); + id += char(is.get()); if (id != _id) lineno += skip_mapping_data(is); else { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp index c452aaeaccf..ca88520ea2f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp @@ -37,6 +37,7 @@ class Subfont; class SubfontDefinition { using Subfonts = std::map<std::string, std::unique_ptr<Subfont>>; public: + SubfontDefinition (const SubfontDefinition &sfd) =delete; static SubfontDefinition* lookup (const std::string &name); // int getIDs (std::vector<std::string> &ids) const; const std::string& name() const {return _sfname;} @@ -46,8 +47,7 @@ class SubfontDefinition { const char* path () const; protected: - SubfontDefinition (const std::string &name, const char *fpath); - SubfontDefinition (const SubfontDefinition &sfd) =delete; + SubfontDefinition (std::string name, const char *fpath); private: std::string _sfname; ///< name of subfont @@ -59,12 +59,12 @@ class SubfontDefinition { class Subfont { friend class SubfontDefinition; public: + Subfont (const Subfont &sf) =delete; const std::string& id () const {return _id;} uint16_t decode (unsigned char c); protected: Subfont (SubfontDefinition &sfd, const std::string &id) : _sfd(sfd), _id(id), _mapping(0) {} - Subfont (const Subfont &sf) =delete; bool read (); private: @@ -76,8 +76,8 @@ class Subfont { class SubfontException : public MessageException { public: - SubfontException (const std::string &msg, const std::string &fname, int lineno=0) - : MessageException(msg), _fname(fname), _lineno(lineno) {} + SubfontException (const std::string &msg, std::string fname, int lineno=0) + : MessageException(msg), _fname(std::move(fname)), _lineno(lineno) {} const char* filename () const {return _fname.c_str();} int lineno () const {return _lineno;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp index c63e5e02dcd..b2724bdcab2 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp @@ -36,7 +36,7 @@ using namespace std; double System::time () { #if defined (HAVE_SYS_TIME_H) struct timeval tv; - gettimeofday(&tv, NULL); + gettimeofday(&tv, nullptr); return tv.tv_sec + tv.tv_usec/1000000.0; #elif defined (HAVE_SYS_TIMEB_H) struct timeb tb; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp index 36cb462b6f3..668ff390833 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp @@ -33,7 +33,7 @@ class StreamReader; class TFM : public FontMetrics { public: - TFM (std::istream &is); + explicit TFM (std::istream &is); double getCharWidth (int c) const override; double getCharHeight (int c) const override; double getCharDepth (int c) const override; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp index e9e0ef4b192..52acd63179a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp @@ -63,7 +63,7 @@ void TensorProductPatch::setFirstMatrixColumn (DPair source[4][4], int col, bool * @param[in] edgeflag defines how to connect this patch with another one * @param[in] patch reference patch required if edgeflag > 0 */ void TensorProductPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - TensorProductPatch *tpPatch = dynamic_cast<TensorProductPatch*>(patch); + auto tpPatch = dynamic_cast<TensorProductPatch*>(patch); if (edgeflag > 0 && !tpPatch) throw ShadingException("missing preceding data in definition of tensor-product patch"); if ((edgeflag == 0 && points.size() != 16) || (edgeflag > 0 && points.size() != 12)) @@ -107,7 +107,7 @@ void TensorProductPatch::setPoints (const PointVec &points, int edgeflag, Shadin * @param[in] edgeflag defines how to connect this patch with another one * @param[in] patch reference patch required if edgeflag > 0 */ void TensorProductPatch::setColors(const ColorVec &colors, int edgeflag, ShadingPatch* patch) { - TensorProductPatch *tpPatch = dynamic_cast<TensorProductPatch*>(patch); + auto tpPatch = dynamic_cast<TensorProductPatch*>(patch); if (edgeflag > 0 && !tpPatch) throw ShadingException("missing preceding data in definition of tensor-product patch"); if ((edgeflag == 0 && colors.size() != 4) || (edgeflag > 0 && colors.size() != 2)) @@ -201,16 +201,18 @@ Color TensorProductPatch::averageColor (const Color &c1, const Color &c2, const } -void TensorProductPatch::getBoundaryPath (GraphicsPath<double> &path) const { +GraphicsPath<double> TensorProductPatch::getBoundaryPath () const { // Simple approach: Use the outer curves as boundary path. This doesn't always lead // to correct results since, depending on the control points, P(u,v) might exceed // the simple boundary. + GraphicsPath<double> path; path.moveto(_points[0][0]); path.cubicto(_points[0][1], _points[0][2], _points[0][3]); path.cubicto(_points[1][3], _points[2][3], _points[3][3]); path.cubicto(_points[3][2], _points[3][1], _points[3][0]); path.cubicto(_points[2][0], _points[1][0], _points[0][0]); path.closepath(); + return path; } @@ -354,8 +356,7 @@ void TensorProductPatch::approximateRow (double v1, double inc, bool overlap, do void TensorProductPatch::approximate (int gridsize, bool overlap, double delta, Callback &callback) const { if (_colors[0] == _colors[1] && _colors[1] == _colors[2] && _colors[2] == _colors[3]) { // simple case: monochromatic patch - GraphicsPath<double> path; - getBoundaryPath(path); + GraphicsPath<double> path = getBoundaryPath(); callback.patchSegment(path, _colors[0]); } else { @@ -377,17 +378,16 @@ void TensorProductPatch::approximate (int gridsize, bool overlap, double delta, } -void TensorProductPatch::getBBox (BoundingBox &bbox) const { +BoundingBox TensorProductPatch::getBBox () const { + BoundingBox bbox; Bezier bezier; - BoundingBox bezierBox; for (int i=0; i <= 1; i++) { horizontalCurve(i, bezier); - bezier.getBBox(bezierBox); - bbox.embed(bezierBox); + bbox.embed(bezier.getBBox()); verticalCurve(i, bezier); - bezier.getBBox(bezierBox); - bbox.embed(bezierBox); + bbox.embed(bezier.getBBox()); } + return bbox; } @@ -492,7 +492,7 @@ DPair CoonsPatch::valueAt (double u, double v) const { * @param[in] edgeflag defines how to connect this patch to another one * @param[in] patch reference patch required if edgeflag > 0 */ void CoonsPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - CoonsPatch *coonsPatch = dynamic_cast<CoonsPatch*>(patch); + auto coonsPatch = dynamic_cast<CoonsPatch*>(patch); if (edgeflag > 0 && !coonsPatch) throw ShadingException("missing preceding data in definition of relative Coons patch"); if ((edgeflag == 0 && points.size() != 12) || (edgeflag > 0 && points.size() != 8)) @@ -529,7 +529,7 @@ void CoonsPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch * void CoonsPatch::setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) { - CoonsPatch *coonsPatch = dynamic_cast<CoonsPatch*>(patch); + auto coonsPatch = dynamic_cast<CoonsPatch*>(patch); if (edgeflag > 0 && !coonsPatch) throw ShadingException("missing preceding data in definition of relative Coons patch"); if ((edgeflag == 0 && colors.size() != 4) || (edgeflag > 0 && colors.size() != 2)) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp index ca5071d2eb4..711feefc2d8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp @@ -36,13 +36,11 @@ * \f[P(u,v):=\sum_{i=0}^3\sum_{j=0}^3 p_{ij} B_i(u) B_j(v)\f] * where \f$B_k(t)={3\choose k}(1-t)^k t^k\f$ and \f$u,v \in [0,1]\f$. The four colors assigned * to the vertices are interpolated bilinearily over the unit square. */ -class TensorProductPatch : public ShadingPatch -{ +class TensorProductPatch : public ShadingPatch { friend class CoonsPatch; - public: TensorProductPatch () : ShadingPatch(Color::ColorSpace::RGB) {} - TensorProductPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} + explicit TensorProductPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} TensorProductPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, TensorProductPatch *patch); int psShadingType() const override {return 7;} void setPoints (const DPair points[4][4], int edgeflag, TensorProductPatch *patch); @@ -53,12 +51,12 @@ class TensorProductPatch : public ShadingPatch Color averageColor () const override; void horizontalCurve (double v, Bezier &bezier) const; void verticalCurve (double u, Bezier &bezier) const; - void getBoundaryPath (GraphicsPath<double> &path) const override; + GraphicsPath<double> getBoundaryPath () const override; void subpatch (double u1, double u2, double v1, double v2, TensorProductPatch &patch) const; DPair blossomValue (double u1, double u2, double u3, double v1, double v2, double v3) const; DPair blossomValue (double u[3], double v[3]) const {return blossomValue(u[0], u[1], u[2], v[0], v[1], v[2]);} void approximate (int gridsize, bool overlap, double delta, Callback &callback) const override; - void getBBox (BoundingBox &bbox) const override; + BoundingBox getBBox () const override; int numPoints (int edgeflag) const override {return edgeflag == 0 ? 16 : 12;} int numColors (int edgeflag) const override {return edgeflag == 0 ? 4 : 2;} @@ -78,16 +76,15 @@ class TensorProductPatch : public ShadingPatch * depend on the outer ones, i.e. they are computed automatically and can't be set by the user. * Thus, a Coons patch is defined by 12 control points, 4 vertex colors and a corresponding * color space. */ -class CoonsPatch : public TensorProductPatch -{ +class CoonsPatch : public TensorProductPatch { public: - CoonsPatch () {} - CoonsPatch (Color::ColorSpace cspace) : TensorProductPatch(cspace) {} + CoonsPatch () =default; + explicit CoonsPatch (Color::ColorSpace cspace) : TensorProductPatch(cspace) {} CoonsPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, CoonsPatch *patch); int psShadingType() const override {return 6;} - virtual void setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) override; - virtual void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) override; - virtual DPair valueAt (double u, double v) const override; + void setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) override; + void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) override; + DPair valueAt (double u, double v) const override; int numPoints (int edgeflag) const override {return edgeflag == 0 ? 12 : 8;} int numColors (int edgeflag) const override {return edgeflag == 0 ? 4 : 2;} }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp index ae940d2d8ea..b97fa439afe 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp @@ -23,6 +23,7 @@ #include <sstream> #include <string> #include "Color.hpp" +#include "EllipticalArc.hpp" #include "InputBuffer.hpp" #include "InputReader.hpp" #include "GraphicsPath.hpp" @@ -69,7 +70,7 @@ Color TpicSpecialHandler::fillColor (bool grayOnly) const { * @param[in] penwidth pen with used to compute the stroke parameters * @param[in] pencolor the drawing color * @param[in] ddist dash/dot distance of line in PS point units (0:solid line, >0:dashed line, <0:dotted line) */ -static void add_stroke_attribs (XMLElementNode *elem, double penwidth, Color pencolor, double ddist) { +static void add_stroke_attribs (XMLElement *elem, double penwidth, Color pencolor, double ddist) { if (penwidth > 0) { // attributes actually required? elem->addAttribute("stroke", pencolor.svgColorString()); elem->addAttribute("stroke-width", XMLString(penwidth)); @@ -81,9 +82,9 @@ static void add_stroke_attribs (XMLElementNode *elem, double penwidth, Color pen } -static unique_ptr<XMLElementNode> create_ellipse_element (double cx, double cy, double rx, double ry) { +static unique_ptr<XMLElement> create_ellipse_element (double cx, double cy, double rx, double ry) { bool is_circle = (rx == ry); - auto elem = util::make_unique<XMLElementNode>(is_circle ? "circle" : "ellipse"); + auto elem = util::make_unique<XMLElement>(is_circle ? "circle" : "ellipse"); elem->addAttribute("cx", XMLString(cx)); elem->addAttribute("cy", XMLString(cy)); if (is_circle) @@ -100,8 +101,8 @@ static unique_ptr<XMLElementNode> create_ellipse_element (double cx, double cy, * @param[in] ddist dash/dot distance of line in PS point units (0:solid line, >0:dashed line, <0:dotted line) * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { - if (!_points.empty() && (_penwidth > 0 || _grayLevel >= 0)) { - unique_ptr<XMLElementNode> elem; + if (!_points.empty() && (_penwidth > 0 || _grayLevel >= 0) && !actions.outputLocked()) { + unique_ptr<XMLElement> elem; if (_points.size() == 1) { const DPair &p = _points.back(); elem = create_ellipse_element(p.x()+actions.getX(), p.y()+actions.getY(), _penwidth/2.0, _penwidth/2.0); @@ -109,14 +110,14 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { } else { if (_points.size() == 2 || (_grayLevel < 0 && _points.front() != _points.back())) { - elem = util::make_unique<XMLElementNode>("polyline"); + elem = util::make_unique<XMLElement>("polyline"); elem->addAttribute("fill", "none"); elem->addAttribute("stroke-linecap", "round"); } else { while (_points.front() == _points.back()) _points.pop_back(); - elem = util::make_unique<XMLElementNode>("polygon"); + elem = util::make_unique<XMLElement>("polygon"); elem->addAttribute("fill", _grayLevel < 0 ? "none" : fillColor(false).svgColorString()); } ostringstream oss; @@ -131,7 +132,7 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { elem->addAttribute("points", oss.str()); add_stroke_attribs(elem.get(), _penwidth, Color::BLACK, ddist); } - actions.appendToPage(std::move(elem)); + actions.svgTree().appendToPage(std::move(elem)); } reset(); } @@ -146,7 +147,7 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { * @param[in] ddist length of dashes and gaps * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ void TpicSpecialHandler::drawSplines (double ddist, SpecialActions &actions) { - if (!_points.empty() && _penwidth > 0) { + if (!_points.empty() && _penwidth > 0 && !actions.outputLocked()) { const size_t numPoints = _points.size(); if (numPoints < 3) { _grayLevel = -1; @@ -164,7 +165,7 @@ void TpicSpecialHandler::drawSplines (double ddist, SpecialActions &actions) { const DPair p1 = p+_points[i]; const DPair p2 = p+_points[i+1]; mid = p1+(p2-p1)/2.0; - path.conicto(p1, mid); + path.quadto(p1, mid); actions.embed(mid); actions.embed((p0+p1*6.0+p2)/8.0, _penwidth); } @@ -174,27 +175,19 @@ void TpicSpecialHandler::drawSplines (double ddist, SpecialActions &actions) { path.lineto(p+_points[numPoints-1]); actions.embed(p+_points[numPoints-1]); } - auto pathElem = util::make_unique<XMLElementNode>("path"); + auto pathElem = util::make_unique<XMLElement>("path"); pathElem->addAttribute("fill", "none"); ostringstream oss; path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); pathElem->addAttribute("d", oss.str()); add_stroke_attribs(pathElem.get(), _penwidth, _dviColor, ddist); - actions.appendToPage(std::move(pathElem)); + actions.svgTree().appendToPage(std::move(pathElem)); } } reset(); } -static double normalized_angle (double rad) { - rad = fmod(rad, math::TWO_PI); - if (rad < 0) - rad += math::TWO_PI; - return rad; -} - - /** Draws an elliptical arc. * @param[in] cx x-coordinate of arc center relative to current DVI position * @param[in] cy y-coordinate of arc center relative to current DVI position @@ -204,31 +197,25 @@ static double normalized_angle (double rad) { * @param[in] angle2 ending angle (clockwise) relative to x-axis * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ void TpicSpecialHandler::drawArc (double cx, double cy, double rx, double ry, double angle1, double angle2, SpecialActions &actions) { - if (_penwidth > 0 || _grayLevel >= 0) { - angle1 = -angle1; - angle2 = -angle2; + if ((_penwidth > 0 || _grayLevel >= 0) && !actions.outputLocked()) { cx += actions.getX(); cy += actions.getY(); - unique_ptr<XMLElementNode> elem; + unique_ptr<XMLElement> elem; bool closed=true; if (abs(angle2-angle1) >= math::TWO_PI) // closed ellipse? elem = create_ellipse_element(cx, cy, rx, ry); else { - angle1 = normalized_angle(angle1); - angle2 = normalized_angle(angle2); - double delta = normalized_angle(angle2-angle1); - int large_arg = (delta < math::PI) ? 1 : 0; - ostringstream oss; - oss << 'M' << XMLString(cx+rx*cos(angle1)) << ' ' << XMLString(cy+ry*sin(-angle1)) - << 'A' << XMLString(rx) << ' ' << XMLString(ry) - << " 0 " // no rotation of x-axis - << large_arg << " 1 " // always draw arc clockwise (sweep flag == 1) - << XMLString(cx+rx*cos(angle2)) << ' ' << XMLString(cy-ry*sin(angle2)); + EllipticalArc arc(DPair(cx, cy), rx, ry, 0, -angle1, math::normalize_0_2pi(angle2-angle1)); + GraphicsPath<double> path; + path.moveto(arc.startPoint()); + path.arcto(rx, ry, 0, arc.largeArc(), arc.sweepPositive(), arc.endPoint()); if (_grayLevel >= 0) - oss << 'Z'; + path.closepath(); else closed = false; - elem = util::make_unique<XMLElementNode>("path"); + elem = util::make_unique<XMLElement>("path"); + ostringstream oss; + path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); elem->addAttribute("d", oss.str()); } if (_penwidth > 0) { @@ -238,7 +225,7 @@ void TpicSpecialHandler::drawArc (double cx, double cy, double rx, double ry, do elem->addAttribute("stroke-linecap", "round"); } elem->addAttribute("fill", _grayLevel < 0 ? "none" : fillColor(true).svgColorString()); - actions.appendToPage(std::move(elem)); + actions.svgTree().appendToPage(std::move(elem)); double pw = _penwidth/2.0; actions.embed(BoundingBox(cx-rx-pw, cy-ry-pw, cx+rx+pw, cy+ry+pw)); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp index 4f9a4a1f58e..01efe2e8f0d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp @@ -31,7 +31,7 @@ TriangularPatch::TriangularPatch (const PointVec &points, const ColorVec &colors void TriangularPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - TriangularPatch *triangularPatch = dynamic_cast<TriangularPatch*>(patch); + auto triangularPatch = dynamic_cast<TriangularPatch*>(patch); if (edgeflag > 0 && !triangularPatch) throw ShadingException("missing preceding data in definition of triangular patch"); if ((edgeflag == 0 && points.size() != 3) || (edgeflag > 0 && points.size() != 1)) @@ -62,7 +62,7 @@ void TriangularPatch::setPoints (const DPair &p1, const DPair &p2, const DPair & void TriangularPatch::setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) { - TriangularPatch *triangularPatch = dynamic_cast<TriangularPatch*>(patch); + auto triangularPatch = dynamic_cast<TriangularPatch*>(patch); if (edgeflag > 0 && !triangularPatch) throw ShadingException("missing preceding data in definition of triangular patch"); if ((edgeflag == 0 && colors.size() != 3) || (edgeflag > 0 && colors.size() != 1)) @@ -161,8 +161,7 @@ static inline double snap (double x) { * @param[in] callback object notified */ void TriangularPatch::approximate (int gridsize, bool overlap, double delta, Callback &callback) const { if (_colors[0] == _colors[1] && _colors[1] == _colors[2]) { - GraphicsPath<double> path; - getBoundaryPath(path); + GraphicsPath<double> path = getBoundaryPath(); callback.patchSegment(path, _colors[0]); } else { @@ -197,18 +196,21 @@ void TriangularPatch::approximate (int gridsize, bool overlap, double delta, Cal } -void TriangularPatch::getBoundaryPath(GraphicsPath<double> &path) const { +GraphicsPath<double> TriangularPatch::getBoundaryPath () const { + GraphicsPath<double> path; path.clear(); path.moveto(_points[0]); path.lineto(_points[1]); path.lineto(_points[2]); path.closepath(); + return path; } -void TriangularPatch::getBBox (BoundingBox &bbox) const { - bbox.invalidate(); +BoundingBox TriangularPatch::getBBox () const { + BoundingBox bbox; bbox.embed(_points[0]); bbox.embed(_points[1]); bbox.embed(_points[2]); + return bbox; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp index 3ad189aff88..d329e43fa1a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp @@ -25,11 +25,10 @@ #include "Pair.hpp" #include "ShadingPatch.hpp" -class TriangularPatch : public ShadingPatch -{ +class TriangularPatch : public ShadingPatch { public: TriangularPatch (); - TriangularPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} + explicit TriangularPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} TriangularPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, TriangularPatch *patch); int psShadingType() const override {return 4;} DPair valueAt (double u, double v) const; @@ -40,8 +39,8 @@ class TriangularPatch : public ShadingPatch void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) override; void setColors (const Color &c1, const Color &c2, const Color &c3); void approximate (int gridsize, bool overlap, double delta, Callback &listener) const override; - void getBBox (BoundingBox &bbox) const override; - void getBoundaryPath(GraphicsPath<double> &path) const override; + BoundingBox getBBox () const override; + GraphicsPath<double> getBoundaryPath () const override; int numPoints (int edgeflag) const override {return edgeflag == 0 ? 3 : 1;} int numColors (int edgeflag) const override {return edgeflag == 0 ? 3 : 1;} @@ -54,10 +53,9 @@ class TriangularPatch : public ShadingPatch }; -class LatticeTriangularPatch : public TriangularPatch -{ +class LatticeTriangularPatch : public TriangularPatch { public: - LatticeTriangularPatch (Color::ColorSpace cspace) : TriangularPatch(cspace) {} + explicit LatticeTriangularPatch (Color::ColorSpace cspace) : TriangularPatch(cspace) {} int psShadingType() const override {return 5;} }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp index 2cbb77bac51..408a00eede2 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp @@ -127,7 +127,7 @@ void TrueTypeFont::writeWOFF (ostream &os) const { void TrueTypeFont::writeWOFF (const string &fname) const { - ofstream ofs(fname.c_str(), ios::binary); + ofstream ofs(fname, ios::binary); writeWOFF(ofs); } @@ -136,10 +136,10 @@ void TrueTypeFont::writeWOFF (const string &fname) const { * @param[out] os stream to write the WOFF2 data to * @return true on success */ bool TrueTypeFont::writeWOFF2 (ostream &os) const { - const uint8_t* input_data = reinterpret_cast<const uint8_t*>(_buffer.data()); + auto input_data = reinterpret_cast<const uint8_t*>(_buffer.data()); size_t output_size = woff2::MaxWOFF2CompressedSize(input_data, _buffer.size()); string output(output_size, 0); - uint8_t* output_data = reinterpret_cast<uint8_t*>(&output[0]); + auto output_data = reinterpret_cast<uint8_t*>(&output[0]); woff2::WOFF2Params params; if (woff2::ConvertTTFToWOFF2(input_data, _buffer.size(), output_data, &output_size, params)) { output.resize(output_size); @@ -151,7 +151,7 @@ bool TrueTypeFont::writeWOFF2 (ostream &os) const { bool TrueTypeFont::writeWOFF2 (const string &fname) const { - ofstream ofs(fname.c_str(), ios::binary); + ofstream ofs(fname, ios::binary); return writeWOFF2(ofs); } @@ -167,9 +167,9 @@ string TrueTypeFont::TTFTableRecord::name () const { uint32_t TrueTypeFont::TTFTableRecord::computeChecksum () const { uint32_t sum=0; - const uint32_t *startptr = reinterpret_cast<const uint32_t*>(data); - const uint32_t *endptr = startptr + paddedSize()/sizeof(uint32_t); + auto startptr = reinterpret_cast<const uint32_t*>(data); + auto endptr = startptr + paddedSize()/sizeof(uint32_t); while (startptr < endptr) sum += *startptr++; return sum; -}
\ No newline at end of file +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp index 67a90be3ffb..d2e5b6e98d4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp @@ -53,7 +53,7 @@ class TrueTypeFont { public: TrueTypeFont () : _version(0) {} - TrueTypeFont (const std::string &fname) {read(fname);} + explicit TrueTypeFont (const std::string &fname) {read(fname);} bool read (const std::string &fname); void writeWOFF (std::ostream &os) const; void writeWOFF (const std::string &fname) const; @@ -68,7 +68,7 @@ class TrueTypeFont { struct TrueTypeFontException : public MessageException { - TrueTypeFontException (const std::string &msg) : MessageException(msg) {} + explicit TrueTypeFontException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp index ab17d48fa90..d4a18a7bb96 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp @@ -92,21 +92,21 @@ string Unicode::utf8 (int32_t cp) { string utf8; if (cp >= 0) { if (cp < 0x80) - utf8 += cp; + utf8 += char(cp); else if (cp < 0x800) { - utf8 += 0xC0 + (cp >> 6); - utf8 += 0x80 + (cp & 0x3F); + utf8 += char(0xC0 + (cp >> 6)); + utf8 += char(0x80 + (cp & 0x3F)); } else if (cp < 0x10000) { - utf8 += 0xE0 + (cp >> 12); - utf8 += 0x80 + ((cp >> 6) & 0x3F); - utf8 += 0x80 + (cp & 0x3F); + utf8 += char(0xE0 + (cp >> 12)); + utf8 += char(0x80 + ((cp >> 6) & 0x3F)); + utf8 += char(0x80 + (cp & 0x3F)); } else if (cp < 0x110000) { - utf8 += 0xF0 + (cp >> 18); - utf8 += 0x80 + ((cp >> 12) & 0x3F); - utf8 += 0x80 + ((cp >> 6) & 0x3F); - utf8 += 0x80 + (cp & 0x3F); + utf8 += char(0xF0 + (cp >> 18)); + utf8 += char(0x80 + ((cp >> 12) & 0x3F)); + utf8 += char(0x80 + ((cp >> 6) & 0x3F)); + utf8 += char(0x80 + (cp & 0x3F)); } // UTF-8 does not support codepoints >= 0x110000 } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp index df150d0a511..cff67c919c1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp @@ -28,12 +28,8 @@ using namespace std; -VFReader::VFReader (istream &is) - : StreamReader(is), _actions(0), _designSize(0) { -} - - -VFReader::~VFReader () { +VFReader::VFReader (istream &is) : StreamReader(is) +{ } @@ -57,7 +53,7 @@ int VFReader::executeCommand (ApproveAction approve) { bool approved = !approve || approve(opcode); VFActions *actions = _actions; if (!approved) - replaceActions(0); // disable actions + replaceActions(nullptr); // disable actions if (opcode <= 241) // short character definition? cmdShortChar(opcode); @@ -70,9 +66,7 @@ int VFReader::executeCommand (ApproveAction approve) { case 248: cmdPost(); break; // postamble default : { // invalid opcode replaceActions(actions); // reenable actions - ostringstream oss; - oss << "undefined VF command (opcode " << opcode << ')'; - throw VFException(oss.str()); + throw VFException("undefined VF command (opcode " + std::to_string(opcode) + ")"); } } } @@ -143,8 +137,7 @@ void VFReader::cmdLongChar () { else { uint32_t cc = readUnsigned(4); // character code readUnsigned(4); // equals character width from corresponding TFM file - vector<uint8_t> dvi(pl); // DVI subroutine - readBytes(pl, dvi); + auto dvi = readBytes(pl); // DVI subroutine _actions->defineVFChar(cc, std::move(dvi)); // call template method for user actions } } @@ -158,8 +151,7 @@ void VFReader::cmdShortChar (int pl) { else { uint32_t cc = readUnsigned(1); // character code readUnsigned(3); // character width from corresponding TFM file - vector<uint8_t> dvi(pl); // DVI subroutine - readBytes(pl, dvi); + auto dvi = readBytes(pl); // DVI subroutine _actions->defineVFChar(cc, std::move(dvi)); // call template method for user actions } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp index 00da32bbfdc..8ddba805e8f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp @@ -25,28 +25,23 @@ #include "StreamReader.hpp" -struct VFException : public MessageException -{ - VFException (const std::string &msg) : MessageException(msg) {} +struct VFException : public MessageException { + explicit VFException (const std::string &msg) : MessageException(msg) {} }; - struct VFActions; - -class VFReader : public StreamReader -{ +class VFReader : public StreamReader{ using ApproveAction = bool (*)(int); public: - VFReader (std::istream &is); - virtual ~VFReader (); + explicit VFReader (std::istream &is); VFActions* replaceActions (VFActions *a); bool executeAll (); bool executePreambleAndFontDefs (); bool executeCharDefs (); protected: - int executeCommand (ApproveAction approve=0); + int executeCommand (ApproveAction approve=nullptr); // the following methods represent the VF commands // they are called by executeCommand and should not be used directly @@ -57,8 +52,8 @@ class VFReader : public StreamReader void cmdFontDef (int len); private: - VFActions *_actions; ///< actions to execute when reading a VF command - double _designSize; ///< design size of currently read VF in PS points + VFActions *_actions=nullptr; ///< actions to execute when reading a VF command + double _designSize=0; ///< design size of currently read VF in PS points }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp index d5615eafb35..17707fbc965 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp @@ -25,17 +25,15 @@ #include "MessageException.hpp" -struct IteratorException : public MessageException -{ - IteratorException (const std::string &msg) : MessageException(msg) {} +struct IteratorException : public MessageException { + explicit IteratorException (const std::string &msg) : MessageException(msg) {} }; template <typename T> -class VectorIterator -{ +class VectorIterator { public: - VectorIterator (std::vector<T> &vec) : _vector(vec), _pos(0) {} + explicit VectorIterator (std::vector<T> &vec) : _vector(vec), _pos(0) {} VectorIterator operator ++ () { _pos++; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp index ddf9aa5985a..c74388e076b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp @@ -25,10 +25,9 @@ #include <vector> template <typename T> -class VectorStreamBuffer : public std::streambuf -{ +class VectorStreamBuffer : public std::streambuf { public: - VectorStreamBuffer (const std::vector<T> &v) { + explicit VectorStreamBuffer (const std::vector<T> &v) { if (v.empty()) _begin = _end = _curr = nullptr; else { @@ -76,10 +75,9 @@ class VectorStreamBuffer : public std::streambuf template <typename T> -class VectorInputStream : public std::istream -{ +class VectorInputStream : public std::istream { public: - VectorInputStream (const std::vector<T> &source) : std::istream(&_buf), _buf(source) {} + explicit VectorInputStream (const std::vector<T> &source) : std::istream(&_buf), _buf(source) {} private: VectorStreamBuffer<T> _buf; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp index 66ef7e612c9..be14eaf6786 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp @@ -22,7 +22,7 @@ using namespace std; -XMLDocument::XMLDocument (unique_ptr<XMLElementNode> &&root) +XMLDocument::XMLDocument (unique_ptr<XMLElement> root) : _rootElement(std::move(root)) { } @@ -34,17 +34,17 @@ void XMLDocument::clear () { } -void XMLDocument::append (unique_ptr<XMLNode> &&node) { +void XMLDocument::append (unique_ptr<XMLNode> node) { if (node) { - if (dynamic_cast<XMLElementNode*>(node.get())) - _rootElement = util::static_unique_ptr_cast<XMLElementNode>(std::move(node)); + if (node->toElement()) + _rootElement = util::static_unique_ptr_cast<XMLElement>(std::move(node)); else _nodes.emplace_back(std::move(node)); } } -void XMLDocument::setRootNode (unique_ptr<XMLElementNode> &&root) { +void XMLDocument::setRootNode (unique_ptr<XMLElement> root) { _rootElement = std::move(root); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp index 0e5dc6a6ee3..e9132c44d8f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp @@ -28,17 +28,17 @@ class XMLDocument { public: XMLDocument () =default; - XMLDocument (std::unique_ptr<XMLElementNode> &&root); + explicit XMLDocument(std::unique_ptr<XMLElement> root); void clear (); - void append (std::unique_ptr<XMLElementNode> &&node); - void append (std::unique_ptr<XMLNode> &&node); - void setRootNode (std::unique_ptr<XMLElementNode> &&root); - const XMLElementNode* getRootElement () const {return _rootElement.get();} + void append (std::unique_ptr<XMLElement> node); + void append (std::unique_ptr<XMLNode> node); + void setRootNode (std::unique_ptr<XMLElement> root); + const XMLElement* getRootElement () const {return _rootElement.get();} std::ostream& write (std::ostream &os) const; private: std::vector<std::unique_ptr<XMLNode>> _nodes; - std::unique_ptr<XMLElementNode> _rootElement; + std::unique_ptr<XMLElement> _rootElement; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp index e0598c4956a..128be5b9e51 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp @@ -28,32 +28,71 @@ using namespace std; +bool XMLElement::WRITE_NEWLINES=true; -XMLElementNode::XMLElementNode (const string &n) : _name(n) { + +/** Inserts a sibling node after this one. + * @param[in] node node to insert + * @return raw pointer to inserted node */ +XMLNode* XMLNode::insertNext (unique_ptr<XMLNode> node) { + if (_next) { + _next->_prev = node.get(); + node->_next = std::move(_next); + } + node->_prev = this; + node->_parent = _parent; + _next = std::move(node); + return _next.get(); } -XMLElementNode::XMLElementNode (const XMLElementNode &node) - : _name(node._name), _attributes(node._attributes) +/** Removes the following sibling node of this one. + * @return pointer to the removed node */ +unique_ptr<XMLNode> XMLNode::removeNext () { + unique_ptr<XMLNode> oldnext = std::move(_next); + if (oldnext) { + oldnext->_parent = oldnext->_prev = nullptr; + if ((_next = std::move(oldnext->_next))) { + _next->_prev = this; + oldnext->_next.reset(); + } + } + return oldnext; +} + +///////////////////////////////////////////////////////////////////// + +XMLElement::XMLElement (string name) : _name(std::move(name)) { +} + + +XMLElement::XMLElement (const XMLElement &node) + : XMLNode(node), _name(node._name), _attributes(node._attributes) { - for (const auto &child : node._children) - _children.emplace_back(unique_ptr<XMLNode>(child->clone())); + for (XMLNode *child=_firstChild.get(); child; child = child->next()) + insertLast(child->clone()); } -XMLElementNode::XMLElementNode (XMLElementNode &&node) - : _name(std::move(node._name)), _attributes(std::move(node._attributes)), _children(std::move(node._children)) +XMLElement::XMLElement (XMLElement &&node) noexcept + : XMLNode(std::move(node)), + _name(std::move(node._name)), + _attributes(std::move(node._attributes)), + _firstChild(std::move(node._firstChild)), + _lastChild(node._lastChild) { } -void XMLElementNode::clear () { +/** Removes all attributes and children. */ +void XMLElement::clear () { _attributes.clear(); - _children.clear(); + _firstChild.reset(); + _lastChild = nullptr; } -void XMLElementNode::addAttribute (const string &name, const string &value) { +void XMLElement::addAttribute (const string &name, const string &value) { if (Attribute *attr = getAttribute(name)) attr->value = value; else @@ -61,27 +100,66 @@ void XMLElementNode::addAttribute (const string &name, const string &value) { } -void XMLElementNode::addAttribute (const string &name, double value) { +void XMLElement::addAttribute (const string &name, double value) { addAttribute(name, XMLString(value)); } +void XMLElement::removeAttribute (const std::string &name) { + _attributes.erase(find_if(_attributes.begin(), _attributes.end(), [&](const Attribute &attr) { + return attr.name == name; + })); +} + + +/** Inserts a new last child node and returns a raw pointer to it. */ +XMLNode* XMLElement::insertLast (unique_ptr<XMLNode> child) { + if (!child) + return nullptr; + child->parent(this); + if (!empty()) + _lastChild = _lastChild->insertNext(std::move(child)); + else { + _firstChild = std::move(child); + _lastChild = _firstChild.get(); + } + return _lastChild; +} + + +/** Inserts a new first child node and returns a raw pointer to it. */ +XMLNode* XMLElement::insertFirst (unique_ptr<XMLNode> child) { + if (!child) + return nullptr; + child->parent(this); + if (empty()) { + _firstChild = std::move(child); + _lastChild = _firstChild.get(); + } + else { + child->insertNext(std::move(_firstChild)); + _firstChild = std::move(child); + } + return _firstChild.get(); +} + + /** Appends a child node to this element. The element also takes the ownership of the child. * @param[in] child node to be appended * @return raw pointer to the appended child node */ -XMLNode* XMLElementNode::append (unique_ptr<XMLNode> &&child) { +XMLNode* XMLElement::append (unique_ptr<XMLNode> child) { if (!child) return nullptr; - XMLTextNode *textNode1 = dynamic_cast<XMLTextNode*>(child.get()); - if (!textNode1 || _children.empty()) - _children.emplace_back(std::move(child)); + XMLText *textNode1 = child->toText(); + if (!textNode1 || empty()) + insertLast(std::move(child)); else { - if (XMLTextNode *textNode2 = dynamic_cast<XMLTextNode*>(_children.back().get())) - textNode2->append(util::static_unique_ptr_cast<XMLTextNode>(std::move(child))); // merge two consecutive text nodes + if (XMLText *textNode2 = _lastChild->toText()) + textNode2->append(util::static_unique_ptr_cast<XMLText>(std::move(child))); // merge two consecutive text nodes else - _children.emplace_back(std::move(child)); + insertLast(std::move(child)); } - return _children.back().get(); + return _lastChild; } @@ -89,30 +167,31 @@ XMLNode* XMLElementNode::append (unique_ptr<XMLNode> &&child) { * appended there, otherwise a new text node is created. * @param[in] str string to be appended * @return raw pointer to the text node the string was appended to */ -XMLNode* XMLElementNode::append (const string &str) { - if (_children.empty() || !dynamic_cast<XMLTextNode*>(_children.back().get())) - _children.emplace_back(util::make_unique<XMLTextNode>(str)); +XMLNode* XMLElement::append (const string &str) { + XMLText *last; + if (!empty() && (last = _lastChild->toText())) + last->append(str); else - static_cast<XMLTextNode*>(_children.back().get())->append(str); - return _children.back().get(); + insertLast(util::make_unique<XMLText>(str)); + return _lastChild; } /** Prepends a child node to this element. The element also takes the ownership of the child. * @param[in] child node to be prepended * @return raw pointer to the prepended child node */ -XMLNode* XMLElementNode::prepend (unique_ptr<XMLNode> &&child) { +XMLNode* XMLElement::prepend (unique_ptr<XMLNode> child) { if (!child) return nullptr; - XMLTextNode *textNode1 = dynamic_cast<XMLTextNode*>(child.get()); - if (textNode1 && !_children.empty()) { - if (XMLTextNode *textNode2 = dynamic_cast<XMLTextNode*>(_children.front().get())) { - textNode2->prepend(util::static_unique_ptr_cast<XMLTextNode>(std::move(child))); // merge two consecutive text nodes + XMLText *textNode1 = child->toText(); + if (textNode1 && !empty()) { + if (XMLText *textNode2 = _firstChild->toText()) { + textNode2->prepend(util::static_unique_ptr_cast<XMLText>(std::move(child))); // merge two consecutive text nodes return textNode2; } } - _children.emplace_front(std::move(child)); - return _children.front().get(); + insertFirst(std::move(child)); + return _firstChild.get(); } @@ -121,15 +200,15 @@ XMLNode* XMLElementNode::prepend (unique_ptr<XMLNode> &&child) { * node present, nothing is inserted. * @param[in] child node to be inserted * @param[in] sibling following sibling of 'child' - * @return true on success */ -bool XMLElementNode::insertBefore (unique_ptr<XMLNode> &&child, XMLNode *sibling) { - auto it = _children.begin(); - while (it != _children.end() && it->get() != sibling) - ++it; - if (it == _children.end()) - return false; - _children.emplace(it, std::move(child)); - return true; + * @return raw pointer to inserted node */ +XMLNode* XMLElement::insertBefore (unique_ptr<XMLNode> child, XMLNode *sibling) { + if (!child || (sibling && sibling->parent() != this)) + return nullptr; + if (!sibling) + return insertLast(std::move(child)); + if (sibling == _firstChild.get()) + return insertFirst(std::move(child)); + return sibling->prev()->insertNext(std::move(child)); } @@ -138,25 +217,93 @@ bool XMLElementNode::insertBefore (unique_ptr<XMLNode> &&child, XMLNode *sibling * node present, nothing is inserted. * @param[in] child node to be inserted * @param[in] sibling preceding sibling of 'child' - * @return true on success */ -bool XMLElementNode::insertAfter (unique_ptr<XMLNode> &&child, XMLNode *sibling) { - auto it = _children.begin(); - while (it != _children.end() && it->get() != sibling) - ++it; - if (it == _children.end()) - return false; - _children.emplace(++it, std::move(child)); - return true; -} - - -/** Removes a given child from the element. */ -void XMLElementNode::remove (const XMLNode *child) { - auto it = find_if(_children.begin(), _children.end(), [=](const unique_ptr<XMLNode> &ptr) { - return ptr.get() == child; - }); - if (it != _children.end()) - _children.erase(it); + * @return raw pointer to inserted node */ +XMLNode* XMLElement::insertAfter (unique_ptr<XMLNode> child, XMLNode *sibling) { + if (!child || (sibling && sibling->parent() != this)) + return nullptr; + if (!sibling) + return insertFirst(std::move(child)); + if (sibling == _lastChild) + return insertLast(std::move(child)); + return sibling->insertNext(std::move(child)); +} + + +/** Moves a sequence of child nodes to a new element of a given name and inserts + * this (wrapper) element at the former position of the first node of the sequence. + * Example: wrap 3 child nodes of element a with b: + * <a>text1<c/>text2<d/></a> => <a>text1<b><c/>text2<d/></b></a> + * @param[in] first first node to wrap + * @param[in] last last node to wrap (or nullptr if all following siblings of 'first' are to be wrapped) + * @param[in] name name of the wrapper element to be created + * @return raw pointer to the new wrapper element */ +XMLElement* XMLElement::wrap (XMLNode *first, XMLNode *last, const string &name) { + if (!first || !first->parent() || (last && first->parent() != last->parent())) + return nullptr; + XMLElement *parent = first->parent()->toElement(); + XMLNode *prev = first->prev(); + auto wrapper = util::make_unique<XMLElement>(name); + if (last) + last = last->next(); + XMLNode *child = first; + while (child && child != last) { + XMLNode *next = child->next(); + wrapper->insertLast(remove(child)); + child = next; + } + XMLElement *ret = wrapper.get(); + if (prev) + parent->insertAfter(std::move(wrapper), prev); + else + parent->insertFirst(std::move(wrapper)); + return ret; +} + + +/** Moves all child nodes C1,...,Cn of a given element E to its parent and + * removes E afterwards, so that C1 is located at the former position of E + * followed by C2,...,Cn. + * Example: unwrap a child element b of a: + * <a>text1<b><c/>text2<d/></b></a> => <a>text1<c/>text2<d/></a> + * @param[in] child child element to unwrap + * @return raw pointer to the first node C1 of the unwrapped sequence */ +XMLNode* XMLElement::unwrap (XMLElement *child) { + if (!child || !child->parent()) + return nullptr; + XMLElement *parent = child->parent()->toElement(); + auto removedChild = remove(child); + if (child->empty()) + return child->next(); + XMLNode *firstGrandchild = child->firstChild(); + XMLNode *prev = child->prev(); + unique_ptr<XMLNode> grandchild = std::move(child->_firstChild); + while (grandchild) { + prev = parent->insertAfter(std::move(grandchild), prev); + grandchild = std::move(prev->_next); + } + return firstGrandchild; +} + + +/** Removes a child node from the element. + * @param[in] child pointer to child to remove + * @return pointer to removed child or nullptr if given child doesn't belong to this element */ +unique_ptr<XMLNode> XMLElement::remove (XMLNode *child) { + unique_ptr<XMLNode> node; + if (child && child->parent()) { + XMLElement *parent = child->parent()->toElement(); + if (child == parent->_lastChild) + parent->_lastChild = child->prev(); + if (child != parent->firstChild()) + node = child->prev()->removeNext(); + else { + node = std::move(parent->_firstChild); + if ((parent->_firstChild = std::move(node->_next))) + parent->_firstChild->prev(nullptr); + } + child->parent(nullptr); + } + return node; } @@ -165,10 +312,10 @@ void XMLElementNode::remove (const XMLNode *child) { * @param[in] attrName name of attribute to find * @param[out] descendants all elements found * @return true if at least one element was found */ -bool XMLElementNode::getDescendants (const char *name, const char *attrName, vector<XMLElementNode*> &descendants) const { - for (auto &child : _children) { - if (XMLElementNode *elem = dynamic_cast<XMLElementNode*>(child.get())) { - if ((!name || elem->getName() == name) && (!attrName || elem->hasAttribute(attrName))) +bool XMLElement::getDescendants (const char *name, const char *attrName, vector<XMLElement*> &descendants) const { + for (XMLNode *child = _firstChild.get(); child; child = child->next()) { + if (XMLElement *elem = child->toElement()) { + if ((!name || elem->name() == name) && (!attrName || elem->hasAttribute(attrName))) descendants.push_back(elem); elem->getDescendants(name, attrName, descendants); } @@ -182,15 +329,15 @@ bool XMLElementNode::getDescendants (const char *name, const char *attrName, vec * @param[in] attrName if not 0, only elements with an attribute of this name are considered * @param[in] attrValue if not 0, only elements with attribute attrName="attrValue" are considered * @return pointer to the found element or 0 */ -XMLElementNode* XMLElementNode::getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const { - for (auto &child : _children) { - if (XMLElementNode *elem = dynamic_cast<XMLElementNode*>(child.get())) { - if (!name || elem->getName() == name) { +XMLElement* XMLElement::getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const { + for (XMLNode *child = _firstChild.get(); child; child = child->next()) { + if (XMLElement *elem = child->toElement()) { + if (!name || elem->name() == name) { const char *value; - if (!attrName || (((value = elem->getAttributeValue(attrName)) != 0) && (!attrValue || string(value) == attrValue))) + if (!attrName || (((value = elem->getAttributeValue(attrName)) != nullptr) && (!attrValue || string(value) == attrValue))) return elem; } - if (XMLElementNode *descendant = elem->getFirstDescendant(name, attrName, attrValue)) + if (XMLElement *descendant = elem->getFirstDescendant(name, attrName, attrValue)) return descendant; } } @@ -198,23 +345,22 @@ XMLElementNode* XMLElementNode::getFirstDescendant (const char *name, const char } -ostream& XMLElementNode::write (ostream &os) const { +ostream& XMLElement::write (ostream &os) const { os << '<' << _name; for (const auto &attrib : _attributes) os << ' ' << attrib.name << "='" << attrib.value << '\''; - if (_children.empty()) + if (empty()) os << "/>"; else { os << '>'; // Insert newlines around children except text nodes. According to the // SVG specification, pure whitespace nodes are ignored by the SVG renderer. - if (!dynamic_cast<XMLTextNode*>(_children.front().get())) + if (WRITE_NEWLINES && !_firstChild->toText()) os << '\n'; - for (auto it=_children.begin(); it != _children.end(); ++it) { - (*it)->write(os); - if (!dynamic_cast<XMLTextNode*>(it->get())) { - auto next=it; - if (++next == _children.end() || !dynamic_cast<XMLTextNode*>(next->get())) + for (XMLNode *child = _firstChild.get(); child; child = child->next()) { + child->write(os); + if (!child->toText()) { + if (WRITE_NEWLINES && (!child->next() || !child->next()->toText())) os << '\n'; } } @@ -225,7 +371,7 @@ ostream& XMLElementNode::write (ostream &os) const { /** Returns true if this element has an attribute of given name. */ -bool XMLElementNode::hasAttribute (const string &name) const { +bool XMLElement::hasAttribute (const string &name) const { return getAttribute(name) != nullptr; } @@ -233,14 +379,14 @@ bool XMLElementNode::hasAttribute (const string &name) const { /** Returns the value of an attribute. * @param[in] name name of attribute * @return attribute value or 0 if attribute doesn't exist */ -const char* XMLElementNode::getAttributeValue (const std::string& name) const { +const char* XMLElement::getAttributeValue (const std::string& name) const { if (const Attribute *attr = getAttribute(name)) return attr->value.c_str(); return nullptr; } -XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &name) { +XMLElement::Attribute* XMLElement::getAttribute (const string &name) { auto it = find_if(_attributes.begin(), _attributes.end(), [&](const Attribute &attr) { return attr.name == name; }); @@ -248,7 +394,7 @@ XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &name) { } -const XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &name) const { +const XMLElement::Attribute* XMLElement::getAttribute (const string &name) const { auto it = find_if(_attributes.begin(), _attributes.end(), [&](const Attribute &attr) { return attr.name == name; }); @@ -258,11 +404,11 @@ const XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &nam ////////////////////// -void XMLTextNode::append (unique_ptr<XMLNode> &&node) { +void XMLText::append (unique_ptr<XMLNode> node) { if (!node) return; - if (dynamic_cast<XMLTextNode*>(node.get())) - append(util::static_unique_ptr_cast<XMLTextNode>(std::move(node))); + if (node->toText()) + append(util::static_unique_ptr_cast<XMLText>(std::move(node))); else { // append text representation of the node ostringstream oss; @@ -272,32 +418,37 @@ void XMLTextNode::append (unique_ptr<XMLNode> &&node) { } -void XMLTextNode::append (unique_ptr<XMLTextNode> &&node) { +void XMLText::append (unique_ptr<XMLText> node) { if (node) _text += node->_text; } -void XMLTextNode::append (const string &str) { +void XMLText::append (const string &str) { _text += str; } -void XMLTextNode::prepend (unique_ptr<XMLNode> &&node) { - if (XMLTextNode *textNode = dynamic_cast<XMLTextNode*>(node.get())) +void XMLText::prepend (unique_ptr<XMLNode> node) { + if (XMLText *textNode = node->toText()) _text = textNode->_text + _text; } + +const XMLText* XMLText::toWSNode () const { + return _text.find_first_not_of(" \t\n\r") == string::npos ? this : nullptr; +} + ///////////////////////////////////////////////////////////////////// -ostream& XMLCDataNode::write (ostream &os) const { +ostream& XMLCData::write (ostream &os) const { if (!_data.empty()) - os << "<![CDATA[\n" << _data << "]]>"; + os << "<![CDATA[" << _data << "]]>"; return os; } -void XMLCDataNode::append (string &&str) { +void XMLCData::append (string &&str) { if (_data.empty()) _data = move(str); else diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp index b9a75fa0588..b4e5ed6f2b4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp @@ -29,107 +29,198 @@ #include <vector> #include "utility.hpp" +class XMLCData; +class XMLComment; +class XMLElement; +class XMLText; class XMLNode { + friend class XMLElement; + + template <typename T> + T* cast (const T* (XMLNode::*func)() const) { + return const_cast<T*>((const_cast<const XMLNode*>(this)->*func)()); + } + public: + XMLNode () =default; + XMLNode (const XMLNode &node) : _next(nullptr) {} + XMLNode (XMLNode &&node) noexcept : _parent(node._parent), _prev(node._prev), _next(std::move(node._next)) {} virtual ~XMLNode () =default; virtual std::unique_ptr<XMLNode> clone () const =0; virtual void clear () =0; virtual std::ostream& write (std::ostream &os) const =0; + virtual const XMLElement* toElement () const {return nullptr;} + virtual const XMLText* toText () const {return nullptr;} + virtual const XMLText* toWSNode () const {return nullptr;} + virtual const XMLComment* toComment () const {return nullptr;} + virtual const XMLCData* toCData () const {return nullptr;} + XMLElement* toElement () {return cast<XMLElement>(&XMLNode::toElement);} + XMLText* toText () {return cast<XMLText>(&XMLNode::toText);} + XMLComment* toComment () {return cast<XMLComment>(&XMLNode::toComment);} + XMLCData* toCData () {return cast<XMLCData>(&XMLNode::toCData);} + XMLNode* parent () const {return _parent;} + XMLNode* prev () const {return _prev;} + XMLNode* next () const {return _next.get();} + + protected: + XMLNode* insertNext (std::unique_ptr<XMLNode> node); + std::unique_ptr<XMLNode> removeNext (); + void parent (XMLNode *p) {_parent = p;} + void prev (XMLNode *p) {_prev = p;} + + private: + XMLNode *_parent=nullptr; ///< pointer to parent node + XMLNode *_prev=nullptr; ///< pointer to preceding sibling + std::unique_ptr<XMLNode> _next; ///< pointer to next sibling (incl. ownership) +}; + + +class XMLNodeIterator { + public: + XMLNodeIterator () =default; + explicit XMLNodeIterator (XMLNode *curr) : _curr(curr) {} + XMLNodeIterator& operator ++ () {_curr = _curr->next(); return *this;} + XMLNodeIterator& operator -- () {_curr = _curr->prev(); return *this;} + XMLNodeIterator operator ++ (int) {auto p=_curr; _curr = _curr->next(); return XMLNodeIterator(p);} + XMLNodeIterator operator -- (int) {auto p=_curr; _curr = _curr->prev(); return XMLNodeIterator(p);} + XMLNode* operator * () {return _curr;} + XMLNode& operator -> () {return *_curr;} + bool operator == (const XMLNodeIterator &it) const {return _curr == it._curr;} + bool operator != (const XMLNodeIterator &it) const {return _curr != it._curr;} + + private: + XMLNode *_curr=nullptr; }; -class XMLElementNode : public XMLNode { +class ConstXMLNodeIterator { + public: + ConstXMLNodeIterator () =default; + explicit ConstXMLNodeIterator (const XMLNode *curr) : _curr(curr) {} + ConstXMLNodeIterator& operator ++ () {_curr = _curr->next(); return *this;} + ConstXMLNodeIterator& operator -- () {_curr = _curr->prev(); return *this;} + ConstXMLNodeIterator operator ++ (int) {auto p=_curr; _curr = _curr->next(); return ConstXMLNodeIterator(p);} + ConstXMLNodeIterator operator -- (int) {auto p=_curr; _curr = _curr->prev(); return ConstXMLNodeIterator(p);} + const XMLNode* operator * () {return _curr;} + const XMLNode& operator -> () {return *_curr;} + bool operator == (const ConstXMLNodeIterator &it) const {return _curr == it._curr;} + bool operator != (const ConstXMLNodeIterator &it) const {return _curr != it._curr;} + + private: + const XMLNode *_curr=nullptr; +}; + + +class XMLElement : public XMLNode { public: struct Attribute { - Attribute (const std::string &nam, const std::string &val) : name(nam), value(val) {} + Attribute (std::string nam, std::string val) : name(std::move(nam)), value(std::move(val)) {} std::string name; std::string value; }; - using ChildList = std::deque<std::unique_ptr<XMLNode>>; + using Attributes = std::vector<Attribute>; + static bool WRITE_NEWLINES; ///< insert line breaks after element tags? public: - XMLElementNode (const std::string &name); - XMLElementNode (const XMLElementNode &node); - XMLElementNode (XMLElementNode &&node); - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLElementNode>(*this);} + explicit XMLElement (std::string name); + XMLElement (const XMLElement &node); + XMLElement (XMLElement &&node) noexcept; + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLElement>(*this);} void clear () override; void addAttribute (const std::string &name, const std::string &value); void addAttribute (const std::string &name, double value); - XMLNode* append (std::unique_ptr<XMLNode> &&child); + void removeAttribute (const std::string &name); + XMLNode* append (std::unique_ptr<XMLNode> child); XMLNode* append (const std::string &str); - XMLNode* prepend (std::unique_ptr<XMLNode> &&child); - void remove (const XMLNode *child); - bool insertAfter (std::unique_ptr<XMLNode> &&child, XMLNode *sibling); - bool insertBefore (std::unique_ptr<XMLNode> &&child, XMLNode *sibling); + XMLNode* prepend (std::unique_ptr<XMLNode> child); + XMLNode* insertAfter (std::unique_ptr<XMLNode> child, XMLNode *sibling); + XMLNode* insertBefore (std::unique_ptr<XMLNode> child, XMLNode *sibling); bool hasAttribute (const std::string &name) const; const char* getAttributeValue (const std::string &name) const; - bool getDescendants (const char *name, const char *attrName, std::vector<XMLElementNode*> &descendants) const; - XMLElementNode* getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const; + bool getDescendants (const char *name, const char *attrName, std::vector<XMLElement*> &descendants) const; + XMLElement* getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const; + XMLNode* firstChild () const {return _firstChild.get();} + XMLNode* lastChild () const {return _lastChild;} std::ostream& write (std::ostream &os) const override; - bool empty () const {return _children.empty();} - const ChildList& children () const {return _children;} - const std::string& getName () const {return _name;} + bool empty () const {return !_firstChild;} + Attributes& attributes () {return _attributes;} + const Attributes& attributes () const {return _attributes;} + XMLNodeIterator begin () {return XMLNodeIterator(_firstChild.get());} + XMLNodeIterator end () {return XMLNodeIterator(nullptr);} + ConstXMLNodeIterator begin () const {return ConstXMLNodeIterator(_firstChild.get());} + ConstXMLNodeIterator end () const {return ConstXMLNodeIterator(nullptr);} + const std::string& name () const {return _name;} + const XMLElement* toElement () const override {return this;} + const Attribute* getAttribute (const std::string &name) const; + + static std::unique_ptr<XMLNode> remove (XMLNode *child); + static XMLElement* wrap (XMLNode *first, XMLNode *last, const std::string &name); + static XMLNode* unwrap (XMLElement *child); + protected: Attribute* getAttribute (const std::string &name); - const Attribute* getAttribute (const std::string &name) const; + XMLNode* insertFirst (std::unique_ptr<XMLNode> child); + XMLNode* insertLast (std::unique_ptr<XMLNode> child); private: std::string _name; // element name (<name a1="v1" .. an="vn">...</name>) std::vector<Attribute> _attributes; - ChildList _children; // child nodes + std::unique_ptr<XMLNode> _firstChild; ///< pointer to first child node (incl. ownership) + XMLNode *_lastChild=nullptr; ///< pointer to last child node }; -class XMLTextNode : public XMLNode { +class XMLText : public XMLNode { public: - XMLTextNode (const std::string &str) : _text(str) {} - XMLTextNode (std::string &&str) : _text(std::move(str)) {} - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLTextNode>(*this);} + explicit XMLText (std::string str) : _text(std::move(str)) {} + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLText>(*this);} void clear () override {_text.clear();} - void append (std::unique_ptr<XMLNode> &&node); - void append (std::unique_ptr<XMLTextNode> &&node); + void append (std::unique_ptr<XMLNode> node); + void append (std::unique_ptr<XMLText> node); void append (const std::string &str); - void prepend (std::unique_ptr<XMLNode> &&node); + void prepend (std::unique_ptr<XMLNode> node); std::ostream& write (std::ostream &os) const override {return os << _text;} const std::string& getText () const {return _text;} + const XMLText* toText () const override {return this;} + const XMLText* toWSNode () const override; private: std::string _text; }; -class XMLCommentNode : public XMLNode { +class XMLComment : public XMLNode { public: - XMLCommentNode (const std::string &str) : _text(str) {} - XMLCommentNode (std::string &&str) : _text(std::move(str)) {} - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLCommentNode>(*this);} + explicit XMLComment (std::string str) : _text(std::move(str)) {} + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLComment>(*this);} void clear () override {_text.clear();} std::ostream& write (std::ostream &os) const override {return os << "<!--" << _text << "-->";} + const XMLComment* toComment () const override {return this;} private: std::string _text; }; -class XMLCDataNode : public XMLNode { +class XMLCData : public XMLNode { public: - XMLCDataNode () =default; - XMLCDataNode (const std::string &d) : _data(d) {} - XMLCDataNode (std::string &&d) : _data(std::move(d)) {} - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLCDataNode>(*this);} + XMLCData () =default; + explicit XMLCData (std::string data) : _data(std::move(data)) {} + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLCData>(*this);} void clear () override {_data.clear();} void append (std::string &&str); std::ostream& write (std::ostream &os) const override; + const XMLCData* toCData () const override {return this;} private: std::string _data; }; -inline std::ostream& operator << (std::ostream &os, const XMLElementNode &node) {return node.write(os);} -inline std::ostream& operator << (std::ostream &os, const XMLTextNode &node) {return node.write(os);} -inline std::ostream& operator << (std::ostream &os, const XMLCommentNode &node) {return node.write(os);} -inline std::ostream& operator << (std::ostream &os, const XMLCDataNode &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLElement &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLText &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLComment &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLCData &node) {return node.write(os);} #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp index 734cc7ff8cd..fcafb8d1ee0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp @@ -21,6 +21,7 @@ #include <cmath> #include <cstdlib> #include "Unicode.hpp" +#include "utility.hpp" #include "XMLString.hpp" using namespace std; @@ -89,14 +90,8 @@ XMLString::XMLString (double x) { } if (std::abs(x) < 1e-6) x = 0; - assign(to_string(x)); - size_t pos = find('.'); - if (pos != string::npos) { - pos = find_last_not_of('0'); - if (pos != string::npos) { - erase(pos+1); // remove trailing zeros - if (at(length()-1) == '.') - pop_back(); // remove trailing dot - } - } + assign(util::to_string(x)); + size_t pos = find("0."); + if (pos != string::npos && (pos == 0 || at(pos-1) == '-')) + erase(pos, 1); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp index efc88d1a25a..fa9cf15f9ea 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp @@ -24,14 +24,13 @@ #include <string> -class XMLString : public std::string -{ +class XMLString : public std::string { public: XMLString () : std::string() {} - XMLString (const char *str, bool plain=false); - XMLString (const std::string &str, bool plain=false); - XMLString (int n, bool cast=true); - XMLString (double x); + explicit XMLString (const char *str, bool plain=false); + explicit XMLString (const std::string &str, bool plain=false); + explicit XMLString (int n, bool cast=true); + explicit XMLString (double x); static int DECIMAL_PLACES; ///< number of decimal places applied to floating point values (0-6) }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp index 62f10db3792..f81deddbd46 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp @@ -23,7 +23,11 @@ #include <xxhash.h> #include "HashFunction.hpp" +#include "utility.hpp" +#if (XXH_VERSION_NUMBER >= 701) && defined(XXH3_SECRET_SIZE_MIN) +#define ENABLE_XXH128 +#endif template <int HASH_SIZE> struct XXHInterface { @@ -49,6 +53,17 @@ struct XXHInterface<8> { static constexpr auto digest = &XXH64_digest; }; +#ifdef ENABLE_XXH128 +template<> +struct XXHInterface<16> { + using State = XXH3_state_t; + static constexpr auto createState = &XXH3_createState; + static constexpr auto freeState = &XXH3_freeState; + static constexpr auto reset = &XXH3_128bits_reset_withSeed; + static constexpr auto update = &XXH3_128bits_update; + static constexpr auto digest = &XXH3_128bits_digest; +}; +#endif /** Implements the HashFunction class for the xxHash algorithms. */ template <int HASH_BYTES> @@ -57,23 +72,19 @@ class XXHashFunction : public HashFunction { public: XXHashFunction () : _state(Interface::createState()) {Interface::reset(_state, 0);} XXHashFunction(const char *data, size_t length) : XXHashFunction() {update(data, length);} - XXHashFunction(const std::string &data) : XXHashFunction() {update(data);} - XXHashFunction(const std::vector<uint8_t> &data) : XXHashFunction() {update(data);} - ~XXHashFunction () {Interface::freeState(_state);} + explicit XXHashFunction(const std::string &data) : XXHashFunction() {update(data);} + explicit XXHashFunction(const std::vector<uint8_t> &data) : XXHashFunction() {update(data);} + ~XXHashFunction () override {Interface::freeState(_state);} int digestSize () const override {return HASH_BYTES;} void reset () override {Interface::reset(_state, 0);} void update (const char *data, size_t length) override {Interface::update(_state, data, length);} void update (const std::string &data) override {update(data.data(), data.length());} void update (const std::vector<uint8_t> &data) override {update(reinterpret_cast<const char*>(data.data()), data.size());} + using HashFunction::update; // unhide update(istream &is) defined in base class + std::vector<uint8_t> digestValue () const override { - std::vector<uint8_t> hash(HASH_BYTES); - auto digest = Interface::digest(_state); - for (int i=HASH_BYTES-1; i >= 0; i--) { - hash[i] = digest & 0xff; - digest >>= 8; - } - return hash; + return util::bytes(Interface::digest(_state), HASH_BYTES); } static unsigned version () {return XXH_versionNumber();} @@ -85,4 +96,19 @@ class XXHashFunction : public HashFunction { using XXH32HashFunction = XXHashFunction<4>; using XXH64HashFunction = XXHashFunction<8>; +#ifdef ENABLE_XXH128 +using XXH128HashFunction = XXHashFunction<16>; + +template<> +inline std::vector<uint8_t> XXHashFunction<16>::digestValue () const { + std::vector<uint8_t> hash; + auto digest = Interface::digest(_state); + for (auto chunk : {digest.high64, digest.low64}) { + auto bytes = util::bytes(chunk); + hash.insert(hash.end(), bytes.begin(), bytes.end()); + } + return hash; +} +#endif + #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp index 4e882813550..8331cb9eed3 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp @@ -33,20 +33,20 @@ #endif struct ZLibException : public MessageException { - ZLibException (const std::string &msg) : MessageException(msg) {} + explicit ZLibException (const std::string &msg) : MessageException(msg) {} }; enum ZLibCompressionFormat {ZLIB_DEFLATE=0, ZLIB_GZIP=16}; class ZLibOutputBuffer : public std::streambuf { public: - ZLibOutputBuffer () {} + ZLibOutputBuffer () =default; ZLibOutputBuffer (std::streambuf *sbuf, ZLibCompressionFormat format, int zipLevel) { open(sbuf, format, zipLevel); } - ~ZLibOutputBuffer () { + ~ZLibOutputBuffer () override { close(); } @@ -84,7 +84,7 @@ class ZLibOutputBuffer : public std::streambuf { else { if (_inbuf.size() == _inbuf.capacity()) flush(Z_NO_FLUSH); - _inbuf.push_back(c); + _inbuf.push_back(static_cast<unsigned char>(c)); } return c; } @@ -101,10 +101,10 @@ class ZLibOutputBuffer : public std::streambuf { * @throws ZLibException if compression failed */ void flush (int flushmode) { if (_opened) { - _zstream.avail_in = _inbuf.size(); + _zstream.avail_in = static_cast<uInt>(_inbuf.size()); _zstream.next_in = _inbuf.data(); do { - _zstream.avail_out = _zbuf.size(); + _zstream.avail_out = static_cast<uInt>(_zbuf.size()); _zstream.next_out = _zbuf.data(); int ret = deflate(&_zstream, flushmode); if (ret == Z_STREAM_ERROR) { @@ -146,7 +146,7 @@ class ZLibOutputStream : private ZLibOutputBuffer, public std::ostream { ZLibOutputStream (std::ostream &os, ZLibCompressionFormat format, int zipLevel) : ZLibOutputBuffer(os.rdbuf(), format, zipLevel), std::ostream(this) {} - ~ZLibOutputStream () {close();} + ~ZLibOutputStream () override {close();} bool open (std::ostream &os, ZLibCompressionFormat format, int zipLevel) { ZLibOutputBuffer::close(); @@ -172,7 +172,7 @@ class ZLibOutputFileStream : public ZLibOutputStream { } } - ~ZLibOutputFileStream () {close();} + ~ZLibOutputFileStream () override {close();} private: std::ofstream _ofs; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp index b82709f1f55..37584d5ddbd 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp @@ -45,6 +45,7 @@ #include "PsSpecialHandler.hpp" #include "SignalHandler.hpp" #include "SourceInput.hpp" +#include "optimizer/SVGOptimizer.hpp" #include "SVGOutput.hpp" #include "System.hpp" #include "XXHashFunction.hpp" @@ -108,27 +109,36 @@ static void set_libgs (CommandLine &args) { static bool set_cache_dir (const CommandLine &args) { if (args.cacheOpt.given() && !args.cacheOpt.value().empty()) { if (args.cacheOpt.value() == "none") - PhysicalFont::CACHE_PATH = 0; + PhysicalFont::CACHE_PATH.clear(); else if (FileSystem::exists(args.cacheOpt.value())) - PhysicalFont::CACHE_PATH = args.cacheOpt.value().c_str(); + PhysicalFont::CACHE_PATH = args.cacheOpt.value(); else Message::wstream(true) << "cache directory '" << args.cacheOpt.value() << "' does not exist (caching disabled)\n"; } - else if (const char *userdir = FileSystem::userdir()) { + else { + string &cachepath = PhysicalFont::CACHE_PATH; + const char *cachehome = getenv("XDG_CACHE_HOME"); + if (!cachehome || util::trim(cachehome).empty()) { #ifdef _WIN32 - string cachedir = "\\.dvisvgm\\cache"; + cachehome = "~\\.cache"; #else - string cachedir = "/.dvisvgm/cache"; + cachehome = "~/.cache"; #endif - static string cachepath = userdir + cachedir; + } + cachepath = util::trim(cachehome) + FileSystem::PATHSEP + "dvisvgm"; + if (cachepath[0] == '~' && cachepath[1] == FileSystem::PATHSEP) { + if (FileSystem::userdir()) + cachepath.replace(0, 1, FileSystem::userdir()); + else + cachepath.erase(0, 2); // strip leading "~/" + } if (!FileSystem::exists(cachepath)) FileSystem::mkdir(cachepath); - PhysicalFont::CACHE_PATH = cachepath.c_str(); } if (args.cacheOpt.given() && args.cacheOpt.value().empty()) { - cout << "cache directory: " << (PhysicalFont::CACHE_PATH ? PhysicalFont::CACHE_PATH : "(none)") << '\n'; + cout << "cache directory: " << (PhysicalFont::CACHE_PATH.empty() ? "(none)" : PhysicalFont::CACHE_PATH) << '\n'; try { - if (PhysicalFont::CACHE_PATH) + if (!PhysicalFont::CACHE_PATH.empty()) FontCache::fontinfo(PhysicalFont::CACHE_PATH, cout, true); } catch (StreamReaderException &e) { @@ -143,7 +153,7 @@ static bool set_cache_dir (const CommandLine &args) { static bool set_temp_dir (const CommandLine &args) { if (args.tmpdirOpt.given()) { if (!args.tmpdirOpt.value().empty()) - FileSystem::TMPDIR = args.tmpdirOpt.value().c_str(); + FileSystem::TMPDIR = args.tmpdirOpt.value(); else { cout << "temporary folder: " << FileSystem::tmpdir() << '\n'; return false; @@ -299,14 +309,14 @@ static string svg_options_hash (const CommandLine &cmdline) { // options affecting the SVG output vector<const CL::Option*> svg_options = { &cmdline.bboxOpt, &cmdline.clipjoinOpt, &cmdline.colornamesOpt, &cmdline.commentsOpt, - &cmdline.exactOpt, &cmdline.fontFormatOpt, &cmdline.fontmapOpt, &cmdline.gradOverlapOpt, + &cmdline.exactBboxOpt, &cmdline.fontFormatOpt, &cmdline.fontmapOpt, &cmdline.gradOverlapOpt, &cmdline.gradSegmentsOpt, &cmdline.gradSimplifyOpt, &cmdline.linkmarkOpt, &cmdline.magOpt, - &cmdline.noFontsOpt, &cmdline.noMergeOpt, &cmdline.noSpecialsOpt, &cmdline.noStylesOpt, - &cmdline.precisionOpt, &cmdline.relativeOpt, &cmdline.zoomOpt + &cmdline.noFontsOpt, &cmdline.noMergeOpt, &cmdline.noSpecialsOpt, &cmdline.noStylesOpt, + &cmdline.optimizeOpt, &cmdline.precisionOpt, &cmdline.relativeOpt, &cmdline.zoomOpt }; string idString = get_transformation_string(cmdline); for (const CL::Option *opt : svg_options) { - idString += opt->given(); + idString += char(opt->given()); idString += opt->valueString(); } return XXH64HashFunction(idString).digestString(); @@ -337,10 +347,9 @@ static void set_variables (const CommandLine &cmdline) { SVGTree::USE_FONTS = !cmdline.noFontsOpt.given(); if (!SVGTree::setFontFormat(cmdline.fontFormatOpt.value())) { string msg = "unknown font format '"+cmdline.fontFormatOpt.value()+"' (supported formats: "; - ostringstream oss; for (const string &format : FontWriter::supportedFormats()) - oss << ", " << format; - msg += oss.str().substr(2) + ')'; + msg += format + ", "; + msg.erase(msg.end()-2); throw CL::CommandLineException(msg); } SVGTree::CREATE_USE_ELEMENTS = cmdline.noFontsOpt.value() < 1; @@ -350,7 +359,7 @@ static void set_variables (const CommandLine &cmdline) { SVGTree::ADD_COMMENTS = cmdline.commentsOpt.given(); DVIToSVG::TRACE_MODE = cmdline.traceAllOpt.given() ? (cmdline.traceAllOpt.value() ? 'a' : 'm') : 0; Message::LEVEL = cmdline.verbosityOpt.value(); - PhysicalFont::EXACT_BBOX = cmdline.exactOpt.given(); + PhysicalFont::EXACT_BBOX = cmdline.exactBboxOpt.given(); PhysicalFont::KEEP_TEMP_FILES = cmdline.keepOpt.given(); PhysicalFont::METAFONT_MAG = max(1.0, cmdline.magOpt.value()); XMLString::DECIMAL_PLACES = max(0, min(6, cmdline.precisionOpt.value())); @@ -358,6 +367,19 @@ static void set_variables (const CommandLine &cmdline) { PsSpecialHandler::SHADING_SEGMENT_OVERLAP = cmdline.gradOverlapOpt.given(); PsSpecialHandler::SHADING_SEGMENT_SIZE = max(1, cmdline.gradSegmentsOpt.value()); PsSpecialHandler::SHADING_SIMPLIFY_DELTA = cmdline.gradSimplifyOpt.value(); + if (cmdline.optimizeOpt.given()) { + SVGOptimizer::MODULE_SEQUENCE = cmdline.optimizeOpt.value(); + vector<string> modnames; + if (!SVGOptimizer().checkModuleString(SVGOptimizer::MODULE_SEQUENCE, modnames)) { + string msg = "invalid optimizer module"; + if (modnames.size() > 1) msg += 's'; + msg += ": "; + for (const string &modname : modnames) + msg += modname + ", "; + msg.erase(msg.end()-2); + throw CL::CommandLineException(msg); + } + } } @@ -393,6 +415,10 @@ int main (int argc, char *argv[]) { SpecialManager::instance().writeHandlerInfo(cout); return 0; } + if (cmdline.optimizeOpt.value() == "list") { + SVGOptimizer().listModules(cout); + return 0; + } if (!set_cache_dir(cmdline) || !set_temp_dir(cmdline)) return 0; check_bbox(cmdline.bboxOpt.value()); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp new file mode 100644 index 00000000000..e26018253d6 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp @@ -0,0 +1,176 @@ +/************************************************************************* +** AttributeExtractor.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 <array> +#include "AttributeExtractor.hpp" + +using namespace std; + +/** Constructs a new run object for an attribute and a sequence of sibling nodes. + * @param[in] attr attribute to look for + * @param[in] first first element of node sequence to scan */ +AttributeExtractor::AttributeRun::AttributeRun (const Attribute &attr, XMLElement *first) { + _length = 1; + _first = first; + for (_last=_first->next(); _last; _last=_last->next()) { + if (_last->toText() || _last->toCData()) // don't include text/CDATA nodes + break; + if (XMLElement *childElem = _last->toElement()) { + if (!groupable(*childElem)) + break; + const char *val = childElem->getAttributeValue(attr.name); + if (val && val == attr.value) + ++_length; + else + break; + } + } + if (_first != _last && _last) + _last = _last->prev(); +} + + +const char* AttributeExtractor::info () const { + return "move common attributes from a sequence of elements to enclosing groups"; +} + + +/** Performs the attribute extraction on a given context node. Each extracted + * attribute gets its own group, i.e. the extraction of multiple attributes + * of the same elements leads to nested groups. + * @param[in] context attributes of all children in this element are extracted + * @param[in] recurse if true, the algorithm is recursively performed on all descendant elements */ +void AttributeExtractor::execute (XMLElement *context, bool recurse) { + if (!context || context->empty()) + return; + if (recurse) { + for (auto node : *context) { + if (XMLElement *elem = node->toElement()) + execute(elem, true); + } + } + for (XMLNode *child=context->firstChild(); child; child=child->next()) { + if (XMLElement *elem = child->toElement()) + child = extractAttribute(elem); + } +} + + +/** Looks for the first attribute not yet processed and tries to group it. If + * there is a sequence of adjacent sibling nodes N1,...,Nn with an identical inheritable + * attribute, the function creates a group element with this attribute and moves the + * nodes N1,...,Nn into that group. The group is inserted at the former position of N1. + * @param[in] elem first element of a node sequence with potentially identical attributes + * @return the new group element if attributes could be grouped, 'elem' otherwise */ +XMLNode* AttributeExtractor::extractAttribute (XMLElement *elem) { + for (const auto ¤tAttribute : elem->attributes()) { + if (!inheritable(currentAttribute) || extracted(currentAttribute)) + continue; + AttributeRun run(currentAttribute, elem); + if (run.length() >= MIN_RUN_LENGTH) { + XMLElement::Attribute attrib = currentAttribute; + XMLElement *group = XMLElement::wrap(run.first(), run.last(), "g"); + group->addAttribute(attrib.name, attrib.value); + // remove attribute from the grouped elements but keep it on elements with 'id' attribute + // since they can be referenced, and keep 'fill' attribute on animation elements + for (XMLNode *node : *group) { + XMLElement *elem = node->toElement(); + if (elem && extractable(attrib, *elem)) + elem->removeAttribute(attrib.name); + } + // continue with children of the new group but ignore the just extracted attribute + _extractedAttributes.insert(attrib.name); + execute(group, false); + _extractedAttributes.erase(attrib.name); + return group; + } + } + return elem; +} + + +/** Checks whether an element type is allowed to be put in a group element (<g>...</g>). + * For now we only consider a subset of the actually allowed set of elements. + * @param[in] elem name of element to check + * @return true if the element is groupable */ +bool AttributeExtractor::groupable (const XMLElement &elem) { + // https://www.w3.org/TR/SVG/struct.html#GElement + static const char *names[] = { + "a", "altGlyphDef", "animate", "animateColor", "animateMotion", "animateTransform", + "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "ellipse", "filter", + "font", "font-face", "foreignObject", "g", "image", "line", "linearGradient", "marker", + "mask", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "set", + "style", "switch", "symbol", "text", "title", "use", "view" + }; + return binary_search(begin(names), end(names), elem.name(), [](const string &name1, const string &name2) { + return name1 < name2; + }); +} + + +/** Checks whether an SVG attribute A of an element E implicitly propagates its properties + * to all child elements of E that don't specify A. For now we only consider a subset of + * the inheritable properties. + * @param[in] attrib name of attribute to check + * @return true if the attribute is inheritable */ +bool AttributeExtractor::inheritable (const Attribute &attrib) { + // subset of inheritable properties listed on https://www.w3.org/TR/SVG11/propidx.html + // clip-path is not inheritable but can be moved to the parent element as long as + // no child gets an different clip-path attribute + // https://www.w3.org/TR/SVG11/styling.html#Inheritance + static const char *names[] = { + "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", + "color-rendering", "direction", "fill", "fill-opacity", "fill-rule", "font", "font-family", "font-size", + "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "letter-spacing", "paint-order", "stroke", "stroke-dasharray", "stroke-dashoffset", + "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "transform", + "visibility", "word-spacing", "writing-mode" + }; + return binary_search(begin(names), end(names), attrib.name, [](const string &name1, const string &name2) { + return name1 < name2; + }); +} + + +/** Checks whether an attribute is allowed to be removed from a given element. */ +bool AttributeExtractor::extractable (const Attribute &attrib, XMLElement &element) { + if (element.hasAttribute("id")) + return false; + if (attrib.name != "fill") + return true; + // the 'fill' attribute of animation elements has different semantics than + // that of graphics elements => don't extract it from animation nodes + // https://www.w3.org/TR/SVG11/animate.html#TimingAttributes + static const char *names[] = { + "animate", "animateColor", "animateMotion", "animateTransform", "set" + }; + auto it = find_if(begin(names), end(names), [&](const string &name) { + return element.name() == name; + }); + return it == end(names); +} + + +/** Returns true if a given attribute was already extracted from the + * current run of elements. */ +bool AttributeExtractor::extracted (const Attribute &attr) const { + return _extractedAttributes.find(attr.name) != _extractedAttributes.end(); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp new file mode 100644 index 00000000000..c882e8b4c8f --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp @@ -0,0 +1,61 @@ +/************************************************************************* +** AttributeExtractor.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +#include <set> +#include <string> +#include "OptimizerModule.hpp" +#include "../XMLNode.hpp" + +/** Moves common attributes of adjacent elements to enclosing groups. */ +class AttributeExtractor : public OptimizerModule { + using Attribute = XMLElement::Attribute; + + /** Represents a range of adjacent nodes where all elements have a common attribute. */ + struct AttributeRun { + public: + AttributeRun (const Attribute &attr, XMLElement *first); + XMLNode* first () {return _first;} + XMLNode* last () {return _last;} + int length () const {return _length;} + + private: + int _length; ///< run length excluding non-element nodes + XMLNode *_first, *_last; ///< first and last node in run + }; + + public: + void execute (XMLElement*, XMLElement *context) override {execute(context, true);}; + const char* info () const override; + static bool groupable (const XMLElement &elem); + static bool inheritable (const Attribute &attrib); + static bool extractable (const Attribute &attr, XMLElement &element); + + protected: + void execute (XMLElement *context, bool recurse); + XMLNode* extractAttribute (XMLElement *elem); + bool extracted (const Attribute &attr) const; + + private: + std::set<std::string> _extractedAttributes; + static constexpr int MIN_RUN_LENGTH = 3; +}; + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp index c9738d3f030..c9111b43d56 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp @@ -25,12 +25,12 @@ #include <memory> #include <set> #include <vector> -#include "utility.hpp" +#include "../utility.hpp" template <typename T> class DependencyGraph { struct GraphNode { - GraphNode (const T &k) : key(k), dependent() {} + explicit GraphNode (const T &k) : key(k), dependent() {} void addDependee (GraphNode *node) { if (node) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp new file mode 100644 index 00000000000..36bf3a8cd5a --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp @@ -0,0 +1,165 @@ +/************************************************************************* +** GroupCollapser.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 <array> +#include <string> +#include <vector> +#include "AttributeExtractor.hpp" +#include "GroupCollapser.hpp" +#include "../XMLNode.hpp" + +using namespace std; + + +const char* GroupCollapser::info () const { + return "join nested group elements"; +} + + +/** Checks if there's only a single child element and optional whitespace + * siblings in a given element. + * @param[in] elem element to check + * @return pointer to the only child element or nullptr */ +static XMLElement* only_child_element (XMLElement *elem) { + XMLElement *firstChildElement=nullptr; + for (XMLNode *child : *elem) { + if (XMLElement *childElement = child->toElement()) { + if (firstChildElement) + return nullptr; + firstChildElement = childElement; + } + else if (!child->toWSNode()) + return nullptr; + } + return firstChildElement; +} + + +/** Removes all whitespace child nodes from a given element. */ +static void remove_ws_nodes (XMLElement *elem) { + XMLNode *node = elem->firstChild(); + while (node) { + if (!node->toWSNode()) + node = node->next(); + else { + XMLNode *next = node->next(); + XMLElement::remove(node); + node = next; + } + } +} + + +/** Recursively removes all redundant group elements from the given context element + * and moves their attributes to the corresponding parent element. + * @param[in] context root of the subtree to process */ +void GroupCollapser::execute (XMLElement *context) { + if (!context) + return; + XMLNode *node=context->firstChild(); + while (node) { + XMLNode *next = node->next(); // keep safe pointer to next node + if (XMLElement *elem = node->toElement()) + execute(elem); + node = next; + } + if (context->name() == "g" && context->attributes().empty()) { + // unwrap group without attributes + remove_ws_nodes(context); + XMLElement::unwrap(context); + } + else { + XMLElement *child = only_child_element(context); + if (child && collapsible(*context)) { + if (child->name() == "g" && unwrappable(*child, *context) && moveAttributes(*child, *context)) { + remove_ws_nodes(context); + XMLElement::unwrap(child); + } + } + } +} + + +/** Moves all attributes from an element to another one. Attributes already + * present in the destination element are overwritten or combined. + * @param[in] source element the attributes are taken from + * @param[in] dest element that receives the attributes + * @return true if all attributes have been moved */ +bool GroupCollapser::moveAttributes (XMLElement &source, XMLElement &dest) { + vector<string> movedAttributes; + for (const XMLElement::Attribute &attr : source.attributes()) { + if (attr.name == "transform") { + string transform; + if (const char *destvalue = dest.getAttributeValue("transform")) + transform = destvalue+attr.value; + else + transform = attr.value; + dest.addAttribute("transform", transform); + movedAttributes.emplace_back("transform"); + } + else if (AttributeExtractor::inheritable(attr)) { + dest.addAttribute(attr.name, attr.value); + movedAttributes.emplace_back(attr.name); + } + } + for (const string &attrname : movedAttributes) + source.removeAttribute(attrname); + return source.attributes().empty(); +} + + +/** Returns true if a given element is allowed to take the inheritable attributes + * and children of a child group without changing the semantics. + * @param[in] element group element to check */ +bool GroupCollapser::collapsible (const XMLElement &element) { + // the 'fill' attribute of animation elements has different semantics than + // that of graphics elements => don't collapse them + static const char *names[] = { + "animate", "animateColor", "animateMotion", "animateTransform", "set" + }; + auto it = find_if(begin(names), end(names), [&](const string &name) { + return element.name() == name; + }); + return it == end(names); +} + + +/** Returns true if a given group element is allowed to be unwrapped, i.e. its + * attributes and children can be moved to the parent without changing the semantics. + * @param[in] source element whose children and attributes should be moved + * @param[in] dest element that should receive the children and attributes */ +bool GroupCollapser::unwrappable (const XMLElement &source, const XMLElement &dest) { + // check for colliding clip-path attributes + if (const char *cp1 = source.getAttributeValue("clip-path")) { + if (const char *cp2 = dest.getAttributeValue("clip-path")) { + if (string(cp1) != cp2) + return false; + } + } + // these attributes prevent a group from being unwrapped + static const char *attribs[] = { + "class", "id", "filter", "mask", "style" + }; + auto it = find_if(begin(attribs), end(attribs), [&](const string &name) { + return source.hasAttribute(name) || dest.hasAttribute(name); + }); + return it == end(attribs); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp new file mode 100644 index 00000000000..9b5eb018293 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp @@ -0,0 +1,36 @@ +/************************************************************************* +** GroupCollapser.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +/** Joins the attributes of nested groups and removes groups without attributes. */ +class GroupCollapser : public OptimizerModule { + public: + void execute (XMLElement*, XMLElement *context) override {execute(context);}; + void execute (XMLElement *context); + const char* info () const override; + + protected: + static bool moveAttributes (XMLElement &source, XMLElement &dest); + static bool collapsible (const XMLElement &elem); + static bool unwrappable (const XMLElement &source, const XMLElement &dest); +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am new file mode 100644 index 00000000000..10232c273d3 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am @@ -0,0 +1,14 @@ +noinst_LIBRARIES = liboptimizer.a + +liboptimizer_a_SOURCES = \ + AttributeExtractor.hpp AttributeExtractor.cpp \ + DependencyGraph.hpp \ + GroupCollapser.hpp GroupCollapser.cpp \ + OptimizerModule.hpp \ + RedundantElementRemover.hpp RedundantElementRemover.cpp \ + SVGOptimizer.hpp SVGOptimizer.cpp \ + TextSimplifier.hpp TextSimplifier.cpp \ + TransformSimplifier.hpp TransformSimplifier.cpp \ + WSNodeRemover.hpp WSNodeRemover.cpp + +AM_CXXFLAGS = -I$(dvisvgm_srcdir)/libs/variant/include diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in new file mode 100644 index 00000000000..103e6bc0e36 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in @@ -0,0 +1,694 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +subdir = dvisvgm-src/src/optimizer +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/../../m4/kpse-common.m4 \ + $(top_srcdir)/../../m4/kpse-cxx-hack.m4 \ + $(top_srcdir)/../../m4/kpse-freetype2-flags.m4 \ + $(top_srcdir)/../../m4/kpse-kpathsea-flags.m4 \ + $(top_srcdir)/../../m4/kpse-warnings.m4 \ + $(top_srcdir)/../../m4/kpse-win32.m4 \ + $(top_srcdir)/../../m4/kpse-zlib-flags.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)/version.ac \ + $(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 = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +liboptimizer_a_AR = $(AR) $(ARFLAGS) +liboptimizer_a_LIBADD = +am_liboptimizer_a_OBJECTS = AttributeExtractor.$(OBJEXT) \ + GroupCollapser.$(OBJEXT) RedundantElementRemover.$(OBJEXT) \ + SVGOptimizer.$(OBJEXT) TextSimplifier.$(OBJEXT) \ + TransformSimplifier.$(OBJEXT) WSNodeRemover.$(OBJEXT) +liboptimizer_a_OBJECTS = $(am_liboptimizer_a_OBJECTS) +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)/../../build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/AttributeExtractor.Po \ + ./$(DEPDIR)/GroupCollapser.Po \ + ./$(DEPDIR)/RedundantElementRemover.Po \ + ./$(DEPDIR)/SVGOptimizer.Po ./$(DEPDIR)/TextSimplifier.Po \ + ./$(DEPDIR)/TransformSimplifier.Po \ + ./$(DEPDIR)/WSNodeRemover.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +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 = +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 = +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 = $(liboptimizer_a_SOURCES) +DIST_SOURCES = $(liboptimizer_a_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)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/../../build-aux/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@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BROTLI_CFLAGS = @BROTLI_CFLAGS@ +BROTLI_LIBS = @BROTLI_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CODE_COVERAGE_RULES = @CODE_COVERAGE_RULES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXLD = @CXXLD@ +CYGPATH_W = @CYGPATH_W@ +DATE = @DATE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DVISVGM_TREE = @DVISVGM_TREE@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FREETYPE2_DEPEND = @FREETYPE2_DEPEND@ +FREETYPE2_INCLUDES = @FREETYPE2_INCLUDES@ +FREETYPE2_LIBS = @FREETYPE2_LIBS@ +FT2_CONFIG = @FT2_CONFIG@ +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@ +KPATHSEA_DEPEND = @KPATHSEA_DEPEND@ +KPATHSEA_INCLUDES = @KPATHSEA_INCLUDES@ +KPATHSEA_LIBS = @KPATHSEA_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGS_INCLUDES = @LIBGS_INCLUDES@ +LIBGS_LIBS = @LIBGS_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +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@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARNING_CFLAGS = @WARNING_CFLAGS@ +WARNING_CXXFLAGS = @WARNING_CXXFLAGS@ +WOFF2_CFLAGS = @WOFF2_CFLAGS@ +WOFF2_LIBS = @WOFF2_LIBS@ +ZLIB_DEPEND = @ZLIB_DEPEND@ +ZLIB_INCLUDES = @ZLIB_INCLUDES@ +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@ +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@ +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_LIBRARIES = liboptimizer.a +liboptimizer_a_SOURCES = \ + AttributeExtractor.hpp AttributeExtractor.cpp \ + DependencyGraph.hpp \ + GroupCollapser.hpp GroupCollapser.cpp \ + OptimizerModule.hpp \ + RedundantElementRemover.hpp RedundantElementRemover.cpp \ + SVGOptimizer.hpp SVGOptimizer.cpp \ + TextSimplifier.hpp TextSimplifier.cpp \ + TransformSimplifier.hpp TransformSimplifier.cpp \ + WSNodeRemover.hpp WSNodeRemover.cpp + +AM_CXXFLAGS = -I$(dvisvgm_srcdir)/libs/variant/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.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 dvisvgm-src/src/optimizer/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign dvisvgm-src/src/optimizer/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; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +liboptimizer.a: $(liboptimizer_a_OBJECTS) $(liboptimizer_a_DEPENDENCIES) $(EXTRA_liboptimizer_a_DEPENDENCIES) + $(AM_V_at)-rm -f liboptimizer.a + $(AM_V_AR)$(liboptimizer_a_AR) liboptimizer.a $(liboptimizer_a_OBJECTS) $(liboptimizer_a_LIBADD) + $(AM_V_at)$(RANLIB) liboptimizer.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AttributeExtractor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GroupCollapser.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RedundantElementRemover.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SVGOptimizer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TextSimplifier.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransformSimplifier.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WSNodeRemover.Po@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 $(LIBRARIES) +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-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/AttributeExtractor.Po + -rm -f ./$(DEPDIR)/GroupCollapser.Po + -rm -f ./$(DEPDIR)/RedundantElementRemover.Po + -rm -f ./$(DEPDIR)/SVGOptimizer.Po + -rm -f ./$(DEPDIR)/TextSimplifier.Po + -rm -f ./$(DEPDIR)/TransformSimplifier.Po + -rm -f ./$(DEPDIR)/WSNodeRemover.Po + -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)/AttributeExtractor.Po + -rm -f ./$(DEPDIR)/GroupCollapser.Po + -rm -f ./$(DEPDIR)/RedundantElementRemover.Po + -rm -f ./$(DEPDIR)/SVGOptimizer.Po + -rm -f ./$(DEPDIR)/TextSimplifier.Po + -rm -f ./$(DEPDIR)/TransformSimplifier.Po + -rm -f ./$(DEPDIR)/WSNodeRemover.Po + -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-noinstLIBRARIES \ + 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/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp new file mode 100644 index 00000000000..ff4fec1b4dc --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp @@ -0,0 +1,30 @@ +/************************************************************************* +** OptimizerModule.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +class XMLElement; + +class OptimizerModule { + public: + virtual ~OptimizerModule () =default; + virtual void execute (XMLElement *defs, XMLElement *context) =0; + virtual const char* info () const =0; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp new file mode 100644 index 00000000000..85d8e5b1fa8 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp @@ -0,0 +1,68 @@ +/************************************************************************* +** RedundantElementRemover.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 "DependencyGraph.hpp" +#include "RedundantElementRemover.hpp" +#include "../XMLNode.hpp" + +using namespace std; + +const char* RedundantElementRemover::info () const { + return "remove redundant 'clipPath' elements"; +} + + +/** Extracts the ID from a local URL reference like url(#abcde) */ +static inline string extract_id_from_url (const string &url) { + return url.substr(5, url.length()-6); +} + + +/** Removes elements present in the SVG tree that are not required. + * For now, only clipPath elements are removed. */ +void RedundantElementRemover::execute (XMLElement *defs, XMLElement *context) { + vector<XMLElement*> clipPathElements; + if (!defs || !context || !defs->getDescendants("clipPath", nullptr, clipPathElements)) + return; + + // collect dependencies between clipPath elements in the defs section of the SVG tree + DependencyGraph<string> idTree; + for (const XMLElement *clip : clipPathElements) { + if (const char *id = clip->getAttributeValue("id")) { + if (const char *url = clip->getAttributeValue("clip-path")) + idTree.insert(extract_id_from_url(url), id); + else + idTree.insert(id); + } + } + // collect elements that reference a clipPath, i.e. have a clip-path attribute + vector<XMLElement*> descendants; + context->getDescendants(nullptr, "clip-path", descendants); + // remove referenced IDs and their dependencies from the dependency graph + for (const XMLElement *elem : descendants) { + string idref = extract_id_from_url(elem->getAttributeValue("clip-path")); + idTree.removeDependencyPath(idref); + } + descendants.clear(); + for (const string &str : idTree.getKeys()) { + XMLElement *node = defs->getFirstDescendant("clipPath", "id", str.c_str()); + XMLElement::remove(node); + } +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp new file mode 100644 index 00000000000..dd46cfeba5d --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp @@ -0,0 +1,29 @@ +/************************************************************************* +** RedundantElementRemover.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +class RedundantElementRemover : public OptimizerModule { + public: + void execute (XMLElement *defs, XMLElement *context) override; + const char* info () const override; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp new file mode 100644 index 00000000000..0320f8b565e --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp @@ -0,0 +1,107 @@ +/************************************************************************* +** SVGOptimizer.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 <array> +#include <map> +#include "SVGOptimizer.hpp" +#include "../SVGTree.hpp" + +#include "AttributeExtractor.hpp" +#include "GroupCollapser.hpp" +#include "RedundantElementRemover.hpp" +#include "TextSimplifier.hpp" +#include "TransformSimplifier.hpp" +#include "WSNodeRemover.hpp" + +using namespace std; + +string SVGOptimizer::MODULE_SEQUENCE; + +SVGOptimizer::SVGOptimizer (SVGTree *svg) : _svg(svg) { + // optimizer modules available to the user; must be listed in default order +// _moduleEntries.emplace_back(ModuleEntry("remove-ws", util::make_unique<WSNodeRemover>())); + _moduleEntries.emplace_back(ModuleEntry("simplify-text", util::make_unique<TextSimplifier>())); + _moduleEntries.emplace_back(ModuleEntry("group-attributes", util::make_unique<AttributeExtractor>())); + _moduleEntries.emplace_back(ModuleEntry("collapse-groups", util::make_unique<GroupCollapser>())); + _moduleEntries.emplace_back(ModuleEntry("simplify-transform", util::make_unique<TransformSimplifier>())); + _moduleEntries.emplace_back(ModuleEntry("remove-clippath", util::make_unique<RedundantElementRemover>())); +} + + +void SVGOptimizer::execute () { + if (!_svg || MODULE_SEQUENCE == "none") + return; + if (MODULE_SEQUENCE.empty()) + MODULE_SEQUENCE = "remove-clippath"; // default behaviour of previous dvisvgm releases + if (MODULE_SEQUENCE == "all") { + for (const auto &entry : _moduleEntries) + entry.module->execute(_svg->defsNode(), _svg->pageNode()); + } + else { + vector<string> names = util::split(MODULE_SEQUENCE, ","); + for (const string &name : names) { + if (OptimizerModule *module = getModule(name)) + module->execute(_svg->defsNode(), _svg->pageNode()); + } + } +} + + +void SVGOptimizer::listModules (ostream &os) const { + size_t maxlen=0; + map<string, const char*> infos; + for (const auto &entry : _moduleEntries) { + maxlen = max(maxlen, entry.modname.length()); + infos.emplace(entry.modname, entry.module->info()); + } + for (const auto &infopair : infos) { + os << setw(maxlen) << left << infopair.first; + os << " | " << infopair.second << '\n'; + } +} + + +/** Checks if all module names given in a comma-separated list are known. + * @param[in] namestr comma-separated list of module names + * @param[out] unknownNames names not recognized + * @return true if all names are known */ +bool SVGOptimizer::checkModuleString (string &namestr, vector<string> &unknownNames) const { + unknownNames.clear(); + if (namestr.empty() || namestr == "all" || namestr == "none") + return true; + vector<string> givenNames = util::split(namestr, ","); + for (const string &name : givenNames) { + if (!getModule(name)) + unknownNames.emplace_back(name); + } + return unknownNames.empty(); +} + + +OptimizerModule* SVGOptimizer::getModule (const string &name) const { + auto it = find_if(_moduleEntries.begin(), _moduleEntries.end(), [&](const ModuleEntry &entry) { + return entry.modname == name; + }); + if (it != _moduleEntries.end()) + return (*it).module.get(); + return nullptr; +} + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp new file mode 100644 index 00000000000..809f1f497c2 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp @@ -0,0 +1,59 @@ +/************************************************************************* +** SVGOptimizer.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +#include <memory> +#include <ostream> +#include <set> +#include <vector> +#include "OptimizerModule.hpp" +#include "../XMLNode.hpp" + +class SVGTree; + +class SVGOptimizer { + struct ModuleEntry { + ModuleEntry (std::string name, std::unique_ptr<OptimizerModule> mod) + : modname(std::move(name)), module(std::move(mod)) {} + + std::string modname; + std::unique_ptr<OptimizerModule> module; + }; + public: + explicit SVGOptimizer (SVGTree *svg=nullptr); + explicit SVGOptimizer (SVGTree &svg) : SVGOptimizer(&svg) {} + void execute (); + void listModules (std::ostream &os) const; + bool checkModuleString (std::string &namestr, std::vector<std::string> &unknownNames) const; + + static std::string MODULE_SEQUENCE; + + protected: + OptimizerModule* getModule (const std::string &name) const; + + private: + SVGTree *_svg; + std::vector<ModuleEntry> _moduleEntries; +}; + + + + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp new file mode 100644 index 00000000000..23e0e386dfe --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp @@ -0,0 +1,118 @@ +/************************************************************************* +** TextSimplifier.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 <vector> +#include "AttributeExtractor.hpp" +#include "TextSimplifier.hpp" +#include "../XMLNode.hpp" + +using namespace std; + + +const char* TextSimplifier::info () const { + return "merge data of tspans into enclosing text elements"; +} + + +/** Returns all common inheritable attributes of multiple elements. */ +static XMLElement::Attributes common_inheritable_attributes (const vector<XMLElement*> &elements) { + bool intersected=false; + XMLElement::Attributes commonAttribs; + for (const XMLElement *elem : elements) { + if (commonAttribs.empty()) { + if (intersected) + break; + for (const auto attrib : elem->attributes()) { + if (AttributeExtractor::inheritable(attrib)) + commonAttribs.push_back(attrib); + } + } + else { + for (auto it = commonAttribs.begin(); it != commonAttribs.end();) { + auto *attrib = elem->getAttribute(it->name); + if (!attrib || attrib->value != it->value) + it = commonAttribs.erase(it); + else + ++it; + } + } + intersected = true; + } + return commonAttribs; +} + + +/** Returns all tspan elements of a text element if the latter doesn't contain + * any non-whitespace text nodes. Otherwise, the returned vector is empty. + * @param[in] textElement text element to check + * @return the tspan children of the text element */ +static vector<XMLElement*> get_tspans (XMLElement *textElement) { + vector<XMLElement*> tspans; + bool failed=false; + for (XMLNode *child : *textElement) { + if (child->toWSNode() || child->toComment()) + continue; + if (child->toText()) + failed = true; + else if (XMLElement *childElement = child->toElement()) { + if (childElement->name() != "tspan") + failed = true; + else + tspans.push_back(childElement); + } + if (failed) { + tspans.clear(); + break; + } + } + return tspans; +} + + +void TextSimplifier::execute (XMLElement *context) { + if (!context) + return; + if (context->name() == "text") { + vector<XMLElement*> tspans = get_tspans(context); + vector<XMLElement::Attribute> attribs = common_inheritable_attributes(tspans); + if (!tspans.empty() && !attribs.empty()) { + // move all common tspan attributes to the parent text element + for (const XMLElement::Attribute &attr : attribs) + context->addAttribute(attr.name, attr.value); + // remove all common attributes from the tspan elements + for (XMLElement *tspan : tspans) { + for (const XMLElement::Attribute &attr : attribs) + tspan->removeAttribute(attr.name); + // unwrap the tspan if there are no remaining attributes + if (tspan->attributes().empty()) + XMLElement::unwrap(tspan); + } + } + } + else { + XMLNode *node = context->firstChild(); + while (node) { + XMLNode *next = node->next(); // keep safe pointer to next node + if (XMLElement *elem = node->toElement()) + execute(elem); + node = next; + } + } +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp new file mode 100644 index 00000000000..86f44e50518 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp @@ -0,0 +1,30 @@ +/************************************************************************* +** TextSimplifier.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +class TextSimplifier : public OptimizerModule { + public: + void execute (XMLElement *defs, XMLElement *context) override {execute(context);} + static void execute (XMLElement *context); + const char *info () const override; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp new file mode 100644 index 00000000000..b9d4c3db596 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp @@ -0,0 +1,182 @@ +/************************************************************************* +** TransformSimplifier.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 <cmath> +#include <cstdlib> +#include "TransformSimplifier.hpp" +#include "../Matrix.hpp" +#include "../utility.hpp" +#include "../XMLNode.hpp" +#include "../XMLString.hpp" + +using namespace std; + +const char* TransformSimplifier::info () const { + return "try to simplify and shorten the values of 'transform' attributes"; +} + + +/** Tries to simplify the transform attributes of the context node and all its descendants. */ +void TransformSimplifier::execute (XMLElement *context) { + if (!context) + return; + if (const char *transform = context->getAttributeValue("transform")) { + Matrix matrix = Matrix::parseSVGTransform(transform); + if (!incorporateTransform(context, matrix)) { + string decomp = decompose(matrix); + if (decomp.length() > matrix.toSVG().length()) + context->addAttribute("transform", matrix.toSVG()); + else { + if (decomp.empty()) + context->removeAttribute("transform"); + else + context->addAttribute("transform", decomp); + } + } + } + // continue with child elements + for (XMLNode *child : *context) { + if (XMLElement *elem = child->toElement()) + execute(elem); + } +} + + +/** Tries to incorporate the translation and scaling components of the 'transform' attribute + * of a given element into the positional and/or size attributes of that element. If successful, + * the 'transform' attribute is removed. + * Currently, only 'image' and 'rect' elements are considered. + * @param[in] elem element to check + * @param[in] matrix matrix representing the 'transform' attribute of the element + * @return true on success */ +bool TransformSimplifier::incorporateTransform (XMLElement *elem, const Matrix &matrix) { + if ((elem->name() == "image" || elem->name() == "rect") && matrix.get(0, 1) == 0 && matrix.get(1, 0) == 0) { + double tx = matrix.get(0, 2); + double ty = matrix.get(1, 2); + double sx = matrix.get(0, 0); + double sy = matrix.get(1, 1); + if (const char *xstr = elem->getAttributeValue("x")) + tx += sx*strtod(xstr, nullptr); + if (const char *ystr = elem->getAttributeValue("y")) + ty += sy*strtod(ystr, nullptr); + if (const char *wstr = elem->getAttributeValue("width")) + elem->addAttribute("width", sx*strtod(wstr, nullptr)); + if (const char *hstr = elem->getAttributeValue("height")) + elem->addAttribute("height", sy*strtod(hstr, nullptr)); + elem->addAttribute("x", tx); // update x attribute + elem->addAttribute("y", ty); // update x attribute + elem->removeAttribute("transform"); + return true; + } + return false; +} + + +static string translate_cmd (double dx, double dy) { + string ret; + XMLString dxstr(dx), dystr(dy); + if (dxstr != "0" || dystr != "0") { + ret = "translate("+dxstr; + if (dystr != "0") + ret += " "+dystr; + ret += ')'; + } + return ret; +} + + +static string scale_cmd (double sx, double sy) { + string ret; + XMLString sxstr(sx), systr(sy); + if (sxstr != "1" || systr != "1") { + ret = "scale("+sxstr; + if (systr != "1") + ret += " "+systr; + ret += ')'; + } + return ret; +} + + +static string rotate_cmd (double rad) { + string ret; + XMLString degstr(math::rad2deg(fmod(rad, math::TWO_PI))); + if (degstr != "0") + ret = "rotate("+degstr+")"; + return ret; +} + + +static string skewx_cmd (double rad) { + string ret; + XMLString degstr(math::rad2deg(fmod(rad, math::PI))); + if (degstr != "0") + ret = "skewX("+degstr+")"; + return ret; +} + + +static string skewy_cmd (double rad) { + string ret; + XMLString degstr(math::rad2deg(fmod(rad, math::PI))); + if (degstr != "0") + ret = "skewY("+degstr+")"; + return ret; +} + + +static bool not_equal (double x, double y) { + return abs(x-y) >= 1e-6; +} + + +/** Decomposes a transformation matrix into a sequence of basic SVG transformations, i.e. + * translation, rotation, scaling, and skewing. The algorithm (QR-based decomposition) + * is taken from http://frederic-wang.fr/decomposition-of-2d-transform-matrices.html. + * @param[in] matrix matrix to decompose + * @return string containing the SVG transformation commands */ +string TransformSimplifier::decompose (const Matrix &matrix) { + // transformation matrix [a b c d e f] according to + // https://www.w3.org/TR/SVG11/coords.html#EstablishingANewUserSpace + double a = matrix.get(0, 0); + double b = matrix.get(1, 0); + double c = matrix.get(0, 1); + double d = matrix.get(1, 1); + double e = matrix.get(0, 2); + double f = matrix.get(1, 2); + string ret = translate_cmd(e, f); + double delta = a*d - b*c; + if (not_equal(a, 0) || not_equal(b, 0)) { + double r = sqrt(a*a + b*b); + ret += rotate_cmd(b > 0 ? acos(a/r) : -acos(a/r)); + ret += scale_cmd(r, delta/r); + ret += skewx_cmd(atan((a*c + b*d)/(r*r))); + } + else if (not_equal(c, 0) || not_equal(d, 0)) { + double s = sqrt(c*c + d*d); + ret += rotate_cmd(math::HALF_PI - (d > 0 ? acos(-c/s) : -acos(c/s))); + ret += scale_cmd(delta/s, s); + ret += skewy_cmd(atan((a*c + b*d)/(s*s))); + } + else + ret += scale_cmd(0, 0); + return ret; +} + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp index 880f8b737ef..c4b6d9ee16e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp @@ -1,5 +1,5 @@ /************************************************************************* -** CRC32.hpp ** +** TransformSimplifier.hpp ** ** ** ** This file is part of dvisvgm -- a fast DVI to SVG converter ** ** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** @@ -18,30 +18,20 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#ifndef CRC32_HPP -#define CRC32_HPP +#pragma once -#include <cstdlib> -#include <istream> +#include <string> +#include "OptimizerModule.hpp" -class CRC32 { +class Matrix; + +class TransformSimplifier : public OptimizerModule { public: - CRC32 (); - CRC32 (const CRC32 &crc32) =delete; - void update (const uint8_t *bytes, size_t len); - void update (uint32_t n, int bytes=4); - void update (const char *str); - void update (std::istream &is); - uint32_t get () const; - void reset (); - static uint32_t compute (const uint8_t *bytes, size_t len); - static uint32_t compute (const char *str); - static uint32_t compute (std::istream &is); + void execute (XMLElement*, XMLElement *context) override {execute(context);} + void execute (XMLElement *context); + const char* info () const override; - private: - uint32_t _crc32; - uint32_t _tab[256]; + protected: + bool incorporateTransform (XMLElement *elem, const Matrix &matrix); + std::string decompose (const Matrix &matrix); }; - - -#endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp new file mode 100644 index 00000000000..2135e285bb6 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp @@ -0,0 +1,45 @@ +/************************************************************************* +** WSNodeRemover.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 "WSNodeRemover.hpp" +#include "../XMLNode.hpp" + +const char* WSNodeRemover::info () const { + return "remove redundant whitespace nodes"; +} + + +void WSNodeRemover::execute (XMLElement *context) { + if (!context) + return; + bool removeWS = context->name() != "text" && context->name() != "tspan"; + XMLNode *child = context->firstChild(); + while (child) { + if (removeWS && child->toWSNode()) { + XMLNode *next = child->next(); + XMLElement::remove(child); + child = next; + continue; + } + if (XMLElement *elem = child->toElement()) + execute(elem); + child = child->next(); + } +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp new file mode 100644 index 00000000000..c4fe7f989e1 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp @@ -0,0 +1,30 @@ +/************************************************************************* +** WSNodeRemover.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +class WSNodeRemover : public OptimizerModule { + public: + void execute (XMLElement*, XMLElement *context) override {execute(context);}; + void execute (XMLElement *context); + const char* info () const override; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml b/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml index 0764db3e5b8..27975f15910 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml @@ -81,6 +81,10 @@ <arg type="string" name="style" default="box"/> <description>select how to mark hyperlinked areas</description> </option> + <option long="optimize" short="O"> + <arg name="modules" type="string" default="all" optional="yes"/> + <description>perform several SVG optimizations</description> + </option> <option long="output" short="o"> <arg type="string" name="pattern"/> <description>set name pattern of output files</description> @@ -141,8 +145,8 @@ <arg type="string" name="dir" optional="yes"/> <description>set/print path of cache directory</description> </option> - <option long="exact" short="e"> - <description>compute exact glyph boxes</description> + <option long="exact-bbox" short="e"> + <description>compute exact glyph bounding boxes</description> </option> <option long="keep"> <description>keep temporary files</description> diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp index 5baf1a0bc0a..d38e2354e0a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp @@ -22,93 +22,103 @@ const char *PSInterpreter::PSDEFS = "<</Install{matrix setmatrix}/HWResolution[72 72]/PageSize[10000 10000]/Imaging" -"BBox null>>setpagedevice/@dodraw true store/@patcnt 0 store/@SD systemdict def" -"/@UD userdict def true setglobal @SD/:save @SD/save get put @SD/:restore @SD/r" -"estore get put @SD/:gsave @SD/gsave get put @SD/:grestore @SD/grestore get put" -" @SD/:grestoreall @SD/grestoreall get put @SD/:newpath @SD/newpath get put @SD" -"/:stroke @SD/stroke get put @SD/:fill @SD/fill get put @SD/:eofill @SD/eofill " -"get put @SD/:clip @SD/clip get put @SD/:eoclip @SD/eoclip get put @SD/:charpat" -"h @SD/charpath get put @SD/:show @SD/show get put @SD/:stringwidth @SD/stringw" -"idth get put @SD/.setopacityalpha known not{@SD/.setopacityalpha{pop}put}if @S" -"D/.setshapealpha known not{@SD/.setshapealpha{pop}put}if @SD/.setblendmode kno" -"wn not{@SD/.setblendmode{pop}put}if @SD/prseq{-1 1{-1 roll =only( )print}for(\\" -"n)print}put @SD/prcmd{( )exch(\\ndvi.)3{print}repeat prseq}put @SD/cvxall{{cvx" -"}forall}put @SD/defpr{[exch[/copy @SD]cvxall 5 -1 roll dup 6 1 roll[/get/exec]" -"cvxall 6 -1 roll dup 7 1 roll 4 -1 roll dup 5 1 roll dup length string cvs/prc" -"md cvx]cvx def}put @SD/querypos{{currentpoint}stopped{$error/newerror false pu" -"t}{2(querypos)prcmd}ifelse}put @SD/applyscalevals{1 0 dtransform exch dup mul " -"exch dup mul add sqrt 0 1 dtransform exch dup mul exch dup mul add sqrt 1 0 dt" -"ransform dup mul exch dup dup mul 3 -1 roll add dup 0 eq{pop}{sqrt div}ifelse " -"3(applyscalevals)prcmd}put @SD/prpath{{2(moveto)prcmd}{2(lineto)prcmd}{6(curve" -"to)prcmd}{0(closepath)prcmd}pathforall}put @SD/charpath{/@dodraw false store :" -"charpath/@dodraw true store}put @SD/stringwidth{/@dodraw false store :stringwi" -"dth/@dodraw true store}put @SD/show{@dodraw{dup :gsave currentpoint 2{50 mul e" -"xch}repeat :newpath moveto 50 50/scale sysexec true charpath fill :grestore/@d" -"odraw false store :show/@dodraw true store}{:show}ifelse}put @SD/awidthshow{{1" -" string dup 0 5 index put :gsave show :grestore pop 0 rmoveto 3 index eq{4 ind" -"ex 4 index rmoveto}if 1 index 1 index rmoveto}exch cshow 5{pop}repeat}put @SD/" -"widthshow{0 0 3 -1 roll pstack awidthshow}put @SD/ashow{0 0 0 6 3 roll awidths" -"how}put @SD/newpath{:newpath 1 1(newpath)prcmd}put @SD/stroke{@dodraw{prcolor " -"0 1(newpath)prcmd prpath 0(stroke)prcmd :newpath}{:stroke}ifelse}put @SD/fill{" -"@dodraw{prcolor 0 1(newpath)prcmd prpath 0(fill)prcmd :newpath}{:fill}ifelse}p" -"ut @SD/eofill{@dodraw{prcolor 0 1(newpath)prcmd prpath 0(eofill)prcmd :newpath" -"}{:eofill}ifelse}put @SD/clip{:clip 0 1(newpath)prcmd prpath 0(clip)prcmd}put " -"@SD/eoclip{:eoclip 0 1(newpath)prcmd prpath 0(eoclip)prcmd}put @SD/shfill{begi" -"n currentdict/ShadingType known currentdict/ColorSpace known and currentdict/D" -"ataSource known and currentdict/Function known not and ShadingType 4 ge and Da" -"taSource type/arraytype eq and{<</DeviceGray 1/DeviceRGB 3/DeviceCMYK 4/bgknow" -"n currentdict/Background known/bbknown currentdict/BBox known>>begin currentdi" -"ct ColorSpace known{ShadingType ColorSpace load bgknown{1 Background aload pop" -"}{0}ifelse bbknown{1 BBox aload pop}{0}ifelse ShadingType 5 eq{VerticesPerRow}" -"if DataSource aload length 4 add bgknown{ColorSpace load add}if bbknown{4 add}" -"if ShadingType 5 eq{1 add}if(shfill)prcmd}if end}if end}put/@rect{4 -2 roll mo" -"veto exch dup 0 rlineto exch 0 exch rlineto neg 0 rlineto closepath}bind def/@" -"rectcc{4 -2 roll moveto 2 copy 0 lt exch 0 lt xor{dup 0 exch rlineto exch 0 rl" -"ineto neg 0 exch rlineto}{exch dup 0 rlineto exch 0 exch rlineto neg 0 rlineto" -"}ifelse closepath}bind def @SD/rectclip{:newpath dup type/arraytype eq{aload l" -"ength 4 idiv{@rectcc}repeat}{@rectcc}ifelse clip :newpath}put @SD/rectfill{gsa" -"ve :newpath dup type/arraytype eq{aload length 4 idiv{@rectcc}repeat}{@rectcc}" -"ifelse fill grestore}put @SD/rectstroke{gsave :newpath dup type/arraytype eq{a" -"load length 4 idiv{@rect}repeat}{@rect}ifelse stroke grestore}put false setglo" -"bal @SD readonly pop/initclip 0 defpr/clippath 0 defpr/sysexec{@SD exch get ex" -"ec}def/adddot{dup length 1 add string dup 0 46 put dup 3 -1 roll 1 exch putint" -"erval}def/setlinewidth{dup/setlinewidth sysexec 1(setlinewidth)prcmd}def/setli" -"necap 1 defpr/setlinejoin 1 defpr/setmiterlimit 1 defpr/setdash{mark 3 1 roll " -"2 copy/setdash sysexec exch aload length 1 add -1 roll counttomark(setdash)prc" -"md pop}def/@setpagedevice{pop<<>>/setpagedevice sysexec matrix setmatrix newpa" -"th 0(setpagedevice)prcmd}def/prcolor{currentrgbcolor 3(setrgbcolor)prcmd}def/p" -"rintgstate{@dodraw{matrix currentmatrix aload pop 6(setmatrix)prcmd applyscale" -"vals currentlinewidth 1(setlinewidth)prcmd currentlinecap 1(setlinecap)prcmd c" -"urrentlinejoin 1(setlinejoin)prcmd currentmiterlimit 1(setmiterlimit)prcmd cur" -"rentrgbcolor 3(setrgbcolor)prcmd currentdash mark 3 1 roll exch aload length 1" -" add -1 roll counttomark(setdash)prcmd pop}if}def/setgstate{/setgstate sysexec" -" printgstate}def/save{@UD begin/@saveID vmstatus pop pop def end :save @saveID" -" 1(save)prcmd}def/restore{:restore printgstate @UD/@saveID known{@UD begin @sa" -"veID end}{0}ifelse 1(restore)prcmd}def/gsave 0 defpr/grestore{:grestore printg" -"state 0(grestore)prcmd}def/grestoreall{:grestoreall setstate 0(grestoreall)prc" -"md}def/rotate{dup type/arraytype ne @dodraw and{dup 1(rotate)prcmd}if/rotate s" -"ysexec applyscalevals}def/scale{dup type/arraytype ne @dodraw and{2 copy 2(sca" -"le)prcmd}if/scale sysexec applyscalevals}def/translate{dup type/arraytype ne @" -"dodraw and{2 copy 2(translate)prcmd}if/translate sysexec}def/setmatrix{dup/set" -"matrix sysexec @dodraw{aload pop 6(setmatrix)prcmd applyscalevals}if}def/initm" -"atrix{matrix setmatrix}def/concat{matrix currentmatrix matrix concatmatrix set" -"matrix}def/makepattern{gsave<</mx 3 -1 roll>>begin dup/XUID[1000000 @patcnt]pu" -"t mx/makepattern sysexec dup dup begin PatternType @patcnt BBox aload pop XSte" -"p YStep PaintType mx aload pop 15(makepattern)prcmd :newpath matrix setmatrix " -"PaintProc 0 1(makepattern)prcmd end/@patcnt @patcnt 1 add store end grestore}d" -"ef/setpattern{begin PatternType 1 eq{PaintType 1 eq{XUID aload pop exch pop 1}" -"{:gsave[currentcolorspace aload length -1 roll pop]setcolorspace/setcolor syse" -"xec XUID aload pop exch pop currentrgbcolor :grestore 4}ifelse(setpattern)prcm" -"d}{/setpattern sysexec}ifelse end}def/setcolor{dup type/dicttype eq{setpattern" -"}{/setcolor sysexec/currentrgbcolor sysexec setrgbcolor}ifelse}def/setgray 1 d" -"efpr/setcmykcolor 4 defpr/sethsbcolor 3 defpr/setrgbcolor 3 defpr/.setopacitya" -"lpha{dup/.setopacityalpha sysexec 1(setopacityalpha)prcmd}def/.setshapealpha{d" -"up/.setshapealpha sysexec 1(setshapealpha)prcmd}def/.setblendmode{dup/.setblen" -"dmode sysexec<</Normal 0/Compatible 0/Multiply 1/Screen 2/Overlay 3/SoftLight " -"4/HardLight 5/ColorDodge 6/ColorBurn 7/Darken 8/Lighten 9/Difference 10/Exclus" -"ion 11/Hue 12/Saturation 13/Color 14/Luminosity 15/CompatibleOverprint 16>>exc" -"h get 1(setblendmode)prcmd}def/@pdfpagecount{GS_PDF_ProcSet begin pdfdict begi" -"n(r)file pdfopen begin pdfpagecount currentdict pdfclose end end end}def/@pdfp" -"agebox{GS_PDF_ProcSet begin pdfdict begin(r)file pdfopen begin dup dup 1 lt ex" -"ch pdfpagecount gt or{pop}{pdfgetpage/MediaBox pget pop aload pop}ifelse curre" -"ntdict pdfclose end end end}def DELAYBIND{.bindnow}if "; +"BBox null>>setpagedevice/@dodraw true store/@nulldev false store/@patcnt 0 sto" +"re/@SD systemdict def/@UD userdict def true setglobal @SD/:save @SD/save get p" +"ut @SD/:restore @SD/restore get put @SD/:gsave @SD/gsave get put @SD/:grestore" +" @SD/grestore get put @SD/:grestoreall @SD/grestoreall get put @SD/:newpath @S" +"D/newpath get put @SD/:stroke @SD/stroke get put @SD/:fill @SD/fill get put @S" +"D/:eofill @SD/eofill get put @SD/:clip @SD/clip get put @SD/:eoclip @SD/eoclip" +" get put @SD/:charpath @SD/charpath get put @SD/:show @SD/show get put @SD/:st" +"ringwidth @SD/stringwidth get put @SD/:nulldevice @SD/nulldevice get put @SD/." +"setopacityalpha known not{@SD/.setopacityalpha{pop}put}if @SD/.setshapealpha k" +"nown not{@SD/.setshapealpha{pop}put}if @SD/.setblendmode known not{@SD/.setble" +"ndmode{pop}put}if @SD/prseq{-1 1{-1 roll =only( )print}for(\\n)print}put @SD/p" +"rcmd{( )exch(\\ndvi.)3{print}repeat prseq}put @SD/cvxall{{cvx}forall}put @SD/d" +"efpr{[exch[/copy @SD]cvxall 5 -1 roll dup 6 1 roll[/get/exec]cvxall 6 -1 roll " +"dup 7 1 roll 4 -1 roll dup 5 1 roll dup length string cvs/prcmd cvx]cvx def}pu" +"t @SD/querypos{{currentpoint}stopped{$error/newerror false put}{2(querypos)prc" +"md}ifelse}put @SD/applyscalevals{1 0 dtransform exch dup mul exch dup mul add " +"sqrt 0 1 dtransform exch dup mul exch dup mul add sqrt 1 0 dtransform dup mul " +"exch dup dup mul 3 -1 roll add dup 0 eq{pop}{sqrt div}ifelse 3(applyscalevals)" +"prcmd}put @SD/prpath{{2(moveto)prcmd}{2(lineto)prcmd}{6(curveto)prcmd}{0(close" +"path)prcmd}pathforall}put @SD/nulldevice{/@nulldev true store :nulldevice 1 1(" +"setnulldevice)prcmd}put @SD/charpath{/@dodraw false store :charpath/@dodraw tr" +"ue store}put @SD/stringwidth{/@dodraw false store :stringwidth/@dodraw true st" +"ore}put @SD/show{@dodraw @nulldev not and{dup :gsave currentpoint 2{50 mul exc" +"h}repeat :newpath moveto 50 50/scale sysexec true charpath fill :grestore/@dod" +"raw false store :show/@dodraw true store}{:show}ifelse}put @SD/varxyshow{exch " +"dup type/arraytype eq{<</arr 3 -1 roll/prc 5 -1 roll/chr 1 string/idx 0>>begin" +"{chr 0 3 -1 roll put :gsave chr show :grestore currentpoint prc moveto/idx idx" +" 1 add store}forall end}{pop show}ifelse}put @SD/xyshow{{exch arr idx 2 mul ge" +"t add exch arr idx 2 mul 1 add get add}varxyshow}put @SD/xshow{{exch arr idx g" +"et add exch}varxyshow}put @SD/yshow{{arr idx get add}varxyshow}put @SD/awidths" +"how{{1 string dup 0 5 index put :gsave show :grestore pop 0 rmoveto 3 index eq" +"{4 index 4 index rmoveto}if 1 index 1 index rmoveto}exch cshow 5{pop}repeat}pu" +"t @SD/widthshow{0 0 3 -1 roll pstack awidthshow}put @SD/ashow{0 0 0 6 3 roll a" +"widthshow}put @SD/newpath{:newpath 1 1(newpath)prcmd}put @SD/stroke{@dodraw @n" +"ulldev not and{prcolor 0 1(newpath)prcmd prpath 0(stroke)prcmd :newpath}{:stro" +"ke}ifelse}put @SD/fill{@dodraw @nulldev not and{prcolor 0 1(newpath)prcmd prpa" +"th 0(fill)prcmd :newpath}{:fill}ifelse}put @SD/eofill{@dodraw @nulldev not and" +"{prcolor 0 1(newpath)prcmd prpath 0(eofill)prcmd :newpath}{:eofill}ifelse}put " +"@SD/clip{:clip @nulldev not{0 1(newpath)prcmd prpath 0(clip)prcmd}if}put @SD/e" +"oclip{:eoclip @nulldev not{0 1(newpath)prcmd prpath 0(eoclip)prcmd}}put @SD/sh" +"fill{begin currentdict/ShadingType known currentdict/ColorSpace known and curr" +"entdict/DataSource known and currentdict/Function known not and ShadingType 4 " +"ge and DataSource type/arraytype eq and{<</DeviceGray 1/DeviceRGB 3/DeviceCMYK" +" 4/bgknown currentdict/Background known/bbknown currentdict/BBox known>>begin " +"currentdict ColorSpace known{ShadingType ColorSpace load bgknown{1 Background " +"aload pop}{0}ifelse bbknown{1 BBox aload pop}{0}ifelse ShadingType 5 eq{Vertic" +"esPerRow}if DataSource aload length 4 add bgknown{ColorSpace load add}if bbkno" +"wn{4 add}if ShadingType 5 eq{1 add}if(shfill)prcmd}if end}if end}put/@rect{4 -" +"2 roll moveto exch dup 0 rlineto exch 0 exch rlineto neg 0 rlineto closepath}b" +"ind def/@rectcc{4 -2 roll moveto 2 copy 0 lt exch 0 lt xor{dup 0 exch rlineto " +"exch 0 rlineto neg 0 exch rlineto}{exch dup 0 rlineto exch 0 exch rlineto neg " +"0 rlineto}ifelse closepath}bind def @SD/rectclip{:newpath dup type/arraytype e" +"q{aload length 4 idiv{@rectcc}repeat}{@rectcc}ifelse clip :newpath}put @SD/rec" +"tfill{gsave :newpath dup type/arraytype eq{aload length 4 idiv{@rectcc}repeat}" +"{@rectcc}ifelse fill grestore}put @SD/rectstroke{gsave :newpath dup type/array" +"type eq{aload length 4 idiv{@rect}repeat}{@rect}ifelse stroke grestore}put fal" +"se setglobal @SD readonly pop/initclip 0 defpr/clippath 0 defpr/sysexec{@SD ex" +"ch get exec}def/adddot{dup length 1 add string dup 0 46 put dup 3 -1 roll 1 ex" +"ch putinterval}def/setlinewidth{dup/setlinewidth sysexec 1(setlinewidth)prcmd}" +"def/setlinecap 1 defpr/setlinejoin 1 defpr/setmiterlimit 1 defpr/setdash{mark " +"3 1 roll 2 copy/setdash sysexec exch aload length 1 add -1 roll counttomark(se" +"tdash)prcmd pop}def/@setpagedevice{pop<<>>/setpagedevice sysexec matrix setmat" +"rix newpath 0(setpagedevice)prcmd}def/@checknulldev{@nulldev{currentpagedevice" +" maxlength 0 ne{/@nulldev false store 0 1(setnulldevice)prcmd}if}if}def/prcolo" +"r{currentrgbcolor 3(setrgbcolor)prcmd}def/printgstate{@dodraw @nulldev not and" +"{matrix currentmatrix aload pop 6(setmatrix)prcmd applyscalevals currentlinewi" +"dth 1(setlinewidth)prcmd currentlinecap 1(setlinecap)prcmd currentlinejoin 1(s" +"etlinejoin)prcmd currentmiterlimit 1(setmiterlimit)prcmd currentrgbcolor 3(set" +"rgbcolor)prcmd currentdash mark 3 1 roll exch aload length 1 add -1 roll count" +"tomark(setdash)prcmd pop}if}def/setgstate{/setgstate sysexec printgstate}def/s" +"ave{@UD begin/@saveID vmstatus pop pop def end :save @saveID 1(save)prcmd}def/" +"restore{:restore @checknulldev printgstate @UD/@saveID known{@UD begin @saveID" +" end}{0}ifelse 1(restore)prcmd}def/gsave 0 defpr/grestore{:grestore @checknull" +"dev printgstate 0(grestore)prcmd}def/grestoreall{:grestoreall @checknulldev se" +"tstate 0(grestoreall)prcmd}def/rotate{dup type/arraytype ne @dodraw and{dup 1(" +"rotate)prcmd}if/rotate sysexec applyscalevals}def/scale{dup type/arraytype ne " +"@dodraw and{2 copy 2(scale)prcmd}if/scale sysexec applyscalevals}def/translate" +"{dup type/arraytype ne @dodraw and{2 copy 2(translate)prcmd}if/translate sysex" +"ec}def/setmatrix{dup/setmatrix sysexec @dodraw{aload pop 6(setmatrix)prcmd app" +"lyscalevals}{pop}ifelse}def/initmatrix{matrix setmatrix}def/concat{matrix curr" +"entmatrix matrix concatmatrix setmatrix}def/makepattern{gsave<</mx 3 -1 roll>>" +"begin dup/XUID[1000000 @patcnt]put mx/makepattern sysexec dup dup begin Patter" +"nType @patcnt BBox aload pop XStep YStep PaintType mx aload pop 15(makepattern" +")prcmd :newpath matrix setmatrix PaintProc 0 1(makepattern)prcmd end/@patcnt @" +"patcnt 1 add store end grestore}def/setpattern{begin PatternType 1 eq{PaintTyp" +"e 1 eq{XUID aload pop exch pop 1}{:gsave[currentcolorspace aload length -1 rol" +"l pop]setcolorspace/setcolor sysexec XUID aload pop exch pop currentrgbcolor :" +"grestore 4}ifelse(setpattern)prcmd}{/setpattern sysexec}ifelse end}def/setcolo" +"r{dup type/dicttype eq{setpattern}{/setcolor sysexec/currentrgbcolor sysexec s" +"etrgbcolor}ifelse}def/setgray 1 defpr/setcmykcolor 4 defpr/sethsbcolor 3 defpr" +"/setrgbcolor 3 defpr/.setopacityalpha{dup/.setopacityalpha sysexec 1(setopacit" +"yalpha)prcmd}def/.setshapealpha{dup/.setshapealpha sysexec 1(setshapealpha)prc" +"md}def/.setblendmode{dup/.setblendmode sysexec<</Normal 0/Compatible 0/Multipl" +"y 1/Screen 2/Overlay 3/SoftLight 4/HardLight 5/ColorDodge 6/ColorBurn 7/Darken" +" 8/Lighten 9/Difference 10/Exclusion 11/Hue 12/Saturation 13/Color 14/Luminosi" +"ty 15/CompatibleOverprint 16>>exch get 1(setblendmode)prcmd}def/@pdfpagecount{" +"(r)file runpdfbegin pdfpagecount runpdfend}def/@pdfpagebox{(r)file runpdfbegin" +" dup dup 1 lt exch pdfpagecount gt or{pop}{pdfgetpage/MediaBox pget pop aload " +"pop}ifelse runpdfend}def DELAYBIND{.bindnow}if "; + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp index 99e8e194a02..f1ae59ec08e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp @@ -20,6 +20,7 @@ #include <algorithm> #include <cctype> +#include <cmath> #include <fstream> #include <functional> #include <iterator> @@ -27,6 +28,56 @@ using namespace std; +/** Computes the singular value decomposition of a given 2x2 matrix M + * so that M = rotate(phi)*scale(sx,sy)*rotate(theta), where + * rotate(t):={{cos t, -sin t}, {sin t, cos t}} and scale(sx, sy):={{sx, 0}, {0, sy}}. + * The corresponding math can be found in Jim Blinn: "Consider the Lowly 2x2 Matrix" + * https://ieeexplore.ieee.org/document/486688 + * Also published in "Jim Blinn's Corner: Notation, Notation, Notation", pp. 69--95. + * @param[in] m matrix {{m00, m01}, {m10, m11}} where the inner pairs denote the rows + * @return vector {phi, sx, sy, theta} */ +vector<double> math::svd (const double (&m)[2][2]) { + double phi=0, theta=0, sx=0, sy=0; + if (m[0][0] != 0 || m[0][1] != 0 || m[1][0] != 0 || m[1][1] != 0) { + double e = (m[0][0] + m[1][1])/2; // = cos(phi+theta)*(sx+sy)/2 + double f = (m[0][0] - m[1][1])/2; // = cos(phi-theta)*(sx-sy)/2 + double g = (m[1][0] + m[0][1])/2; // = sin(phi-theta)*(sx-sy)/2 + double h = (m[1][0] - m[0][1])/2; // = sin(phi+theta)*(sx+sy)/2 + double hyp1 = hypot(e, h); // = (sx+sy)/2 + double hyp2 = hypot(f, g); // = (sx-sy)/2 + sx = hyp1+hyp2; + sy = hyp1-hyp2; + if (hyp2 == 0) // uniformly scaled rotation? + theta = atan2(h, e); + else if (hyp1 == 0) // uniformly scaled reflection? + theta = -atan2(g, f); + else { + double a1 = atan2(g, f); // = phi-theta (g/f = tan(phi-theta)) + double a2 = atan2(h, e); // = phi+theta (h/e = tan(phi+theta)) + phi = (a2+a1)/2; + theta = (a2-a1)/2; + } + } + return vector<double>{phi, sx, sy, theta}; +} + + +/** Normalizes an angle to the interval [-mod, mod). */ +double math::normalize_angle (double angle, double mod) { + angle = fmod(angle+mod, 2.0*mod); + if (angle < 0) + angle += 2.0*mod; + return angle-mod; +} + + +double math::normalize_0_2pi (double rad) { + rad = fmod(rad, TWO_PI); + if (rad < 0) + rad += TWO_PI; + return rad; +} + /** Returns a given string with leading and trailing whitespace removed. * @param[in] str the string to process @@ -109,6 +160,20 @@ string util::tolower (const string &str) { } +/** Converts a double to a string and strips redundant trailing digits/dots. */ +string util::to_string (double val) { + string str = std::to_string(val); + if (str.find('.') != string::npos) { // double value and not an integer? + size_t pos = str.find_last_not_of('0'); + if (pos != string::npos) // trailing zeros + str.erase(pos+1, string::npos); + if (str.back() == '.') // trailing dot? + str.pop_back(); + } + return str; +} + + /** Returns the integer part of log10 of a given integer \f$n>0\f$. * If \f$n<0\f$, the result is 0. */ int util::ilog10 (int n) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp index 905e4150dd5..7127280284a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp @@ -35,6 +35,14 @@ constexpr const double TWO_PI = 6.283185307179586476925286766559005768; constexpr const double SQRT2 = 1.414213562373095048801688724209698079; inline double deg2rad (double deg) {return PI*deg/180.0;} +inline double rad2deg (double rad) {return 180.0*rad/PI;} +double normalize_angle (double angle, double mod); +double normalize_0_2pi (double rad); +std::vector<double> svd (const double (&m)[2][2]); + +/** Signum function (returns x/abs(x) if x != 0, and 0 otherwise). */ +template <typename T> +inline int sgn (T x) {return (x > T(0)) - (x < T(0));} } // namespace math @@ -51,12 +59,31 @@ std::string trim (const std::string &str, const char *ws=" \t\n\r\f"); std::string normalize_space (std::string str, const char *ws=" \t\n\r\f"); std::string tolower (const std::string &str); std::string replace (std::string str, const std::string &find, const std::string &repl); +std::string to_string (double val); std::vector<std::string> split (const std::string &str, const std::string &sep); int ilog10 (int n); std::string read_file_contents (const std::string &fname); void write_file_contents (const std::string &fname, std::string::iterator start, std::string::iterator end); + +/** Returns a sequence of bytes of a given integral value. + * @param[in] val get bytes of this value + * @param[in] n number of bytes to extract (from LSB to MSB), all if n == 0 + * @return vector of bytes in big-endian order */ +template <typename T> +std::vector<uint8_t> bytes (T val, int n=0) { + if (n <= 0) + n = sizeof(T); + std::vector<uint8_t> ret(n); + for (int i=0; i < n; i++) { + ret[n-i-1] = val & 0xff; + val >>= 8; + } + return ret; +} + + /** Encodes the bytes in the half-open range [first,last) to Base64 and writes * the result to the range starting at 'dest'. * @param[in] first initial position of the range to be encoded diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp index 22305f75f2b..59320fa6d2d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp @@ -22,7 +22,7 @@ #define VERSION_HPP constexpr const char *PROGRAM_NAME = "dvisvgm"; -constexpr const char *PROGRAM_VERSION = "2.6.3"; +constexpr const char *PROGRAM_VERSION = "2.8.1"; #endif |