summaryrefslogtreecommitdiff
path: root/dviware/dvisvgm/src
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-08-14 03:00:41 +0000
committerNorbert Preining <norbert@preining.info>2022-08-14 03:00:41 +0000
commite874d39878309e456c7ffe8d5fc6a91be571b50c (patch)
tree818c806809254f29f08c3e436a764cbdc566d59a /dviware/dvisvgm/src
parentb229ca426d9d7fee0e3c48c58a00ffcf3da66cb0 (diff)
CTAN sync 202208140300
Diffstat (limited to 'dviware/dvisvgm/src')
-rw-r--r--dviware/dvisvgm/src/CLCommandLine.cpp6
-rw-r--r--dviware/dvisvgm/src/CMap.cpp2
-rw-r--r--dviware/dvisvgm/src/DVIReader.cpp2
-rw-r--r--dviware/dvisvgm/src/DvisvgmSpecialHandler.cpp174
-rw-r--r--dviware/dvisvgm/src/DvisvgmSpecialHandler.hpp27
-rw-r--r--dviware/dvisvgm/src/FileFinder.cpp25
-rw-r--r--dviware/dvisvgm/src/FilePath.cpp10
-rw-r--r--dviware/dvisvgm/src/Font.cpp2
-rw-r--r--dviware/dvisvgm/src/FontManager.cpp11
-rw-r--r--dviware/dvisvgm/src/FontMap.cpp4
-rw-r--r--dviware/dvisvgm/src/FontWriter.cpp10
-rw-r--r--dviware/dvisvgm/src/GraphicsPathParser.hpp299
-rw-r--r--dviware/dvisvgm/src/HashFunction.hpp2
-rw-r--r--dviware/dvisvgm/src/HyperlinkManager.cpp2
-rw-r--r--dviware/dvisvgm/src/HyperlinkManager.hpp4
-rw-r--r--dviware/dvisvgm/src/Makefile.am2
-rw-r--r--dviware/dvisvgm/src/Makefile.in54
-rw-r--r--dviware/dvisvgm/src/MapLine.cpp6
-rw-r--r--dviware/dvisvgm/src/MetafontWrapper.cpp2
-rw-r--r--dviware/dvisvgm/src/MiKTeXCom.cpp5
-rw-r--r--dviware/dvisvgm/src/Opacity.hpp6
-rw-r--r--dviware/dvisvgm/src/PDFParser.cpp6
-rw-r--r--dviware/dvisvgm/src/PageSize.cpp2
-rw-r--r--dviware/dvisvgm/src/PapersizeSpecialHandler.cpp2
-rw-r--r--dviware/dvisvgm/src/PsSpecialHandler.cpp2
-rw-r--r--dviware/dvisvgm/src/SVGElement.hpp2
-rw-r--r--dviware/dvisvgm/src/SVGOutput.cpp4
-rw-r--r--dviware/dvisvgm/src/SVGTree.cpp2
-rw-r--r--dviware/dvisvgm/src/TFM.cpp4
-rw-r--r--dviware/dvisvgm/src/Unicode.cpp2
-rw-r--r--dviware/dvisvgm/src/XMLNode.cpp38
-rw-r--r--dviware/dvisvgm/src/XMLNode.hpp3
-rw-r--r--dviware/dvisvgm/src/XMLParser.cpp182
-rw-r--r--dviware/dvisvgm/src/XMLParser.hpp58
-rw-r--r--dviware/dvisvgm/src/XMLString.cpp2
-rw-r--r--dviware/dvisvgm/src/dvisvgm.cpp9
-rw-r--r--dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp26
-rw-r--r--dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp1
-rw-r--r--dviware/dvisvgm/src/optimizer/GroupCollapser.cpp7
-rw-r--r--dviware/dvisvgm/src/optimizer/Makefile.am2
-rw-r--r--dviware/dvisvgm/src/optimizer/Makefile.in24
-rw-r--r--dviware/dvisvgm/src/optimizer/TextSimplifier.cpp2
-rw-r--r--dviware/dvisvgm/src/utility.cpp16
-rw-r--r--dviware/dvisvgm/src/utility.hpp8
44 files changed, 733 insertions, 326 deletions
diff --git a/dviware/dvisvgm/src/CLCommandLine.cpp b/dviware/dvisvgm/src/CLCommandLine.cpp
index 17ba2c2d1f..e8b538e783 100644
--- a/dviware/dvisvgm/src/CLCommandLine.cpp
+++ b/dviware/dvisvgm/src/CLCommandLine.cpp
@@ -154,7 +154,7 @@ void CommandLine::parseLongOption (istream &is) {
/** Returns all options that match the given long name. */
vector<Option*> CommandLine::lookupOption (const string &optname) const {
vector<Option*> matches;
- int len = optname.length();
+ auto len = optname.length();
for (OptSectPair optsect : options()) {
if (optsect.first->longName() == optname) { // exact match?
matches.clear();
@@ -187,7 +187,7 @@ void CommandLine::help (ostream &os, int mode) const {
string usage = _usage;
int count=0;
while (!usage.empty()) {
- size_t pos = usage.find('\n');
+ auto pos = usage.find('\n');
os << (count++ == 0 ? "Usage: " : " ") << PROGRAM_NAME << ' ' << usage.substr(0, pos) << '\n';
if (pos != string::npos)
usage = usage.substr(pos+1);
@@ -201,7 +201,7 @@ void CommandLine::help (ostream &os, int mode) const {
unordered_map<Option*, pair<string,string>> linecols;
size_t col1width=0;
for (const OptSectPair &ospair : options()) {
- size_t pos;
+ string::size_type pos;
string line = ospair.first->helpline();
if ((pos = line.find('\t')) != string::npos) {
linecols.emplace(ospair.first, pair<string,string>(line.substr(0, pos), line.substr(pos+1)));
diff --git a/dviware/dvisvgm/src/CMap.cpp b/dviware/dvisvgm/src/CMap.cpp
index 5979745e4c..cedc1a7c57 100644
--- a/dviware/dvisvgm/src/CMap.cpp
+++ b/dviware/dvisvgm/src/CMap.cpp
@@ -66,7 +66,7 @@ string SegmentedCMap::getROString() const {
bool SegmentedCMap::mapsToUnicode () const {
vector<string> encstrings = {"UTF8", "UTF16", "UCS2", "UCS4", "UCS32"};
for (const string &encstr : encstrings) {
- size_t pos = _filename.find(encstr);
+ auto pos = _filename.find(encstr);
if (pos != string::npos && (pos == 0 || _filename[pos-1] == '-'))
return true;
}
diff --git a/dviware/dvisvgm/src/DVIReader.cpp b/dviware/dvisvgm/src/DVIReader.cpp
index 094dd6e499..b8c5bc449e 100644
--- a/dviware/dvisvgm/src/DVIReader.cpp
+++ b/dviware/dvisvgm/src/DVIReader.cpp
@@ -460,7 +460,7 @@ const Font* DVIReader::defineFont (uint32_t fontnum, const string &name, uint32_
Font *font = fm.getFont(fontnum);
if (!font && !name.empty()) { // font not registered yet?
if (name[0] == '[') { // LuaTeX native font reference?
- size_t last = name.rfind(']');
+ auto last = name.rfind(']');
if (last != string::npos) {
string path = name.substr(1, last-1);
FontStyle style;
diff --git a/dviware/dvisvgm/src/DvisvgmSpecialHandler.cpp b/dviware/dvisvgm/src/DvisvgmSpecialHandler.cpp
index 077e030776..1acef64f0e 100644
--- a/dviware/dvisvgm/src/DvisvgmSpecialHandler.cpp
+++ b/dviware/dvisvgm/src/DvisvgmSpecialHandler.cpp
@@ -153,19 +153,19 @@ bool DvisvgmSpecialHandler::process (const string &prefix, istream &is, SpecialA
static void expand_constants (string &str, SpecialActions &actions) {
bool repl_bbox = true;
while (repl_bbox) {
- size_t pos = str.find("{?bbox ");
+ const auto pos = str.find("{?bbox ");
if (pos == string::npos)
repl_bbox = false;
else {
- size_t endpos = pos+7;
+ auto endpos = pos+7;
while (endpos < str.length() && isalnum(str[endpos]))
++endpos;
- if (str[endpos] == '}') {
- BoundingBox &box=actions.bbox(str.substr(pos+7, endpos-pos-7));
+ if (str[endpos] != '}')
+ repl_bbox = false;
+ else {
+ BoundingBox &box = actions.bbox(str.substr(pos+7, endpos-pos-7));
str.replace(pos, endpos-pos+1, box.svgViewBoxString());
}
- else
- repl_bbox = false;
}
}
struct Constant {
@@ -181,7 +181,7 @@ static void expand_constants (string &str, SpecialActions &actions) {
}};
for (const Constant &constant : constants) {
const string pattern = string("{?")+constant.name+"}";
- size_t pos = str.find(pattern);
+ auto pos = str.find(pattern);
while (pos != string::npos) {
str.replace(pos, strlen(constant.name)+3, constant.val);
pos = str.find(pattern, pos+constant.val.length()); // look for further matches
@@ -194,9 +194,9 @@ static void expand_constants (string &str, SpecialActions &actions) {
* and replaces the substring by the computed value.
* @param[in,out] str string to scan for expressions */
static void evaluate_expressions (string &str, const SpecialActions &actions) {
- size_t left = str.find("{?("); // start position of expression macro
+ auto left = str.find("{?("); // start position of expression macro
while (left != string::npos) {
- size_t right = str.find(")}", left+2); // end position of expression macro
+ auto right = str.find(")}", left+2); // end position of expression macro
if (right == string::npos)
break;
Calculator calc;
@@ -232,7 +232,7 @@ void DvisvgmSpecialHandler::processRaw (InputReader &ir, SpecialActions &actions
if (!xml.empty()) {
evaluate_expressions(xml, actions);
expand_constants(xml, actions);
- _pageParser.parse(xml, actions);
+ _pageParser.parse(xml, actions.svgTree());
}
}
}
@@ -244,7 +244,7 @@ void DvisvgmSpecialHandler::processRawDef (InputReader &ir, SpecialActions &acti
if (!xml.empty()) {
evaluate_expressions(xml, actions);
expand_constants(xml, actions);
- _defsParser.parse(xml, actions);
+ _defsParser.parse(xml, actions.svgTree());
}
}
}
@@ -276,9 +276,9 @@ void DvisvgmSpecialHandler::processRawPut (InputReader &ir, SpecialActions &acti
if ((type == 'P' || type == 'D') && !def.empty()) {
expand_constants(def, actions);
if (type == 'P')
- _pageParser.parse(def, actions);
+ _pageParser.parse(def, actions.svgTree());
else { // type == 'D'
- _defsParser.parse(def, actions);
+ _defsParser.parse(def, actions.svgTree());
type = 'L'; // locked
}
}
@@ -414,8 +414,8 @@ void DvisvgmSpecialHandler::dviPreprocessingFinished () {
void DvisvgmSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) {
- _defsParser.finish(actions);
- _pageParser.finish(actions);
+ _defsParser.finish(actions.svgTree());
+ _pageParser.finish(actions.svgTree());
actions.bbox().unlock();
for (auto &strvecpair : _macros) {
StringVector &vec = strvecpair.second;
@@ -432,147 +432,3 @@ 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 a call of this function
- * is supposed to finish the parsing of an XML subtree, 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;
- try {
- while (left != string::npos) {
- size_t 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++;
- }
- }
- catch (const SpecialException &e) {
- _error = true;
- throw;
- }
- 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<SVGElement>(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 </" + _nameStack.back() + "> but found </" + name + ">");
- (actions.svgTree().*_popContext)();
- _nameStack.pop_back();
-}
-
-
-/** Processes any remaining XML fragments, checks for missing closing tags,
- * and resets the parser state. */
-void DvisvgmSpecialHandler::XMLParser::finish (SpecialActions &actions) {
- if (!_xmlbuf.empty()) {
- if (!_error)
- parse("", actions, true);
- _xmlbuf.clear();
- }
- string tags;
- while (!_nameStack.empty()) {
- tags += "</"+_nameStack.back()+">, ";
- _nameStack.pop_back();
- }
- if (!tags.empty() && !_error) {
- tags.resize(tags.length()-2);
- throw SpecialException("missing closing tag(s): "+tags);
- }
-}
diff --git a/dviware/dvisvgm/src/DvisvgmSpecialHandler.hpp b/dviware/dvisvgm/src/DvisvgmSpecialHandler.hpp
index f5ae43f411..7d1ad20cfe 100644
--- a/dviware/dvisvgm/src/DvisvgmSpecialHandler.hpp
+++ b/dviware/dvisvgm/src/DvisvgmSpecialHandler.hpp
@@ -26,6 +26,7 @@
#include <unordered_map>
#include <vector>
#include "SpecialHandler.hpp"
+#include "XMLParser.hpp"
class InputReader;
class SpecialActions;
@@ -43,32 +44,6 @@ class XMLNode;
#endif
class DvisvgmSpecialHandler : public SpecialHandler {
- class XMLParser {
- using AppendFunc = void (SVGTree::*)(std::unique_ptr<XMLNode>);
- using PushFunc = void (SVGTree::*)(std::unique_ptr<SVGElement>);
- 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 finish (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
- bool _error=false;
- };
-
using StringVector = std::vector<std::string>;
using MacroMap = std::unordered_map<std::string, StringVector>;
diff --git a/dviware/dvisvgm/src/FileFinder.cpp b/dviware/dvisvgm/src/FileFinder.cpp
index e7efe2786f..c95ab1023f 100644
--- a/dviware/dvisvgm/src/FileFinder.cpp
+++ b/dviware/dvisvgm/src/FileFinder.cpp
@@ -21,7 +21,6 @@
#include <config.h>
#ifdef MIKTEX
#include "MiKTeXCom.hpp"
- #include "utility.hpp"
#else
#ifdef KPSE_CXX_UNSAFE
extern "C" {
@@ -43,6 +42,7 @@
#include "Message.hpp"
#include "MessageException.hpp"
#include "Process.hpp"
+#include "utility.hpp"
std::string FileFinder::_argv0;
std::string FileFinder::_progname;
@@ -120,12 +120,12 @@ const char* FileFinder::findFile (const std::string &fname, const char *ftype) c
if (ftype)
ext = ftype;
else {
- size_t pos = fname.rfind('.');
+ auto pos = fname.rfind('.');
if (pos == std::string::npos)
return nullptr; // no extension and no file type => no search
ext = fname.substr(pos+1);
}
-
+ ext = util::tolower(ext);
#ifdef _WIN32
if (ext == "dll" || ext == "exe")
return lookupExecutable(fname);
@@ -140,7 +140,18 @@ const char* FileFinder::findFile (const std::string &fname, const char *ftype) c
return _pathbuf.empty() ? nullptr : _pathbuf.c_str();
}
try {
- return _miktex->findFile(fname.c_str());
+ if (!ftype) // no file type given?
+ return _miktex->findFile(fname.c_str()); // lookup given filename
+ // handle file type "ttf" similar to kpathsea and look for .ttf, .ttc, and .dfont
+ std::vector<std::string> suffixes{ext};
+ if (ext == "ttf") {
+ suffixes.emplace_back("ttc");
+ suffixes.emplace_back("dfont");
+ }
+ for (const auto &suffix : suffixes) {
+ if (const char *path = _miktex->findFile((fname+"."+suffix).c_str()))
+ return path;
+ }
}
catch (const MessageException &e) {
return nullptr;
@@ -181,8 +192,8 @@ const char* FileFinder::findFile (const std::string &fname, const char *ftype) c
std::free(path);
return _pathbuf.c_str();
}
- return nullptr;
#endif // !MIKTEX
+ return nullptr;
}
@@ -191,7 +202,7 @@ const char* FileFinder::findFile (const std::string &fname, const char *ftype) c
* @param[in] fname name of file to look up
* @return file path on success, 0 otherwise */
const char* FileFinder::findMappedFile (std::string fname) const {
- size_t pos = fname.rfind('.');
+ auto pos = fname.rfind('.');
if (pos == std::string::npos)
return nullptr;
const std::string ext = fname.substr(pos+1); // file extension
@@ -214,7 +225,7 @@ const char* FileFinder::findMappedFile (std::string fname) const {
* @param[in] fname name of file to build
* @return file path on success, 0 otherwise */
const char* FileFinder::mktex (const std::string &fname) const {
- size_t pos = fname.rfind('.');
+ auto pos = fname.rfind('.');
if (!_enableMktex || pos == std::string::npos)
return nullptr;
diff --git a/dviware/dvisvgm/src/FilePath.cpp b/dviware/dvisvgm/src/FilePath.cpp
index 998204b684..3c89c2c3ea 100644
--- a/dviware/dvisvgm/src/FilePath.cpp
+++ b/dviware/dvisvgm/src/FilePath.cpp
@@ -29,7 +29,7 @@ using namespace std;
/** Removes redundant slashes from a given path. */
static string& single_slashes (string &str) {
- size_t pos=0;
+ string::size_type pos=0;
while ((pos = str.find("//", pos)) != string::npos)
str.replace(pos, 2, "/");
return str;
@@ -124,7 +124,7 @@ void FilePath::init (string path, bool isfile, string current_dir) {
path = FileSystem::ensureForwardSlashes(path);
#endif
if (isfile) {
- size_t pos = path.rfind('/');
+ auto pos = path.rfind('/');
_fname = path.substr((pos == string::npos) ? 0 : pos+1);
// remove filename from path
if (pos == 0 && _fname.length() > 1) // file in root directory?
@@ -163,12 +163,12 @@ void FilePath::add (const string &dir) {
* location of a directory (and not of a file) an empty string
* is returned. */
string FilePath::suffix () const {
- size_t start = 0;
+ string::size_type start = 0;
// ignore leading dots
while (start < _fname.length() && _fname[start] == '.')
start++;
string sub = _fname.substr(start);
- size_t pos = sub.rfind('.');
+ auto pos = sub.rfind('.');
if (pos != string::npos && pos < sub.length()-1)
return sub.substr(pos+1);
return "";
@@ -194,7 +194,7 @@ void FilePath::suffix (const string &newSuffix) {
* Example: FilePath("/a/b/c.def", true) == "c" */
string FilePath::basename () const {
if (!_fname.empty()) {
- size_t len = suffix().length();
+ auto len = suffix().length();
if (len > 0)
len++; // strip dot too
return _fname.substr(0, _fname.length()-len);
diff --git a/dviware/dvisvgm/src/Font.cpp b/dviware/dvisvgm/src/Font.cpp
index 9627c421e2..2fa4ce5be9 100644
--- a/dviware/dvisvgm/src/Font.cpp
+++ b/dviware/dvisvgm/src/Font.cpp
@@ -54,7 +54,7 @@ const FontEncoding* Font::encoding () const {
const FontMap::Entry* Font::fontMapEntry () const {
string fontname = name();
- size_t pos = fontname.rfind('.');
+ auto pos = fontname.rfind('.');
if (pos != string::npos)
fontname = fontname.substr(0, pos); // strip extension
return FontMap::instance().lookup(fontname);
diff --git a/dviware/dvisvgm/src/FontManager.cpp b/dviware/dvisvgm/src/FontManager.cpp
index 2262346c60..e85a9dc528 100644
--- a/dviware/dvisvgm/src/FontManager.cpp
+++ b/dviware/dvisvgm/src/FontManager.cpp
@@ -145,7 +145,7 @@ const VirtualFont* FontManager::getVF () const {
static unique_ptr<Font> create_font (const string &filename, const string &fontname, int fontindex, uint32_t checksum, double dsize, double ssize) {
string ext;
if (const char *dot = strrchr(filename.c_str(), '.'))
- ext = dot+1;
+ ext = util::tolower(dot+1);
if (!ext.empty() && FileFinder::instance().lookup(filename)) {
if (ext == "pfb")
return PhysicalFont::create(fontname, checksum, dsize, ssize, PhysicalFont::Type::PFB);
@@ -271,8 +271,13 @@ int FontManager::registerFont (uint32_t fontnum, string filename, int fontIndex,
newfont = font->clone(ptsize, style, color);
}
else {
- if (!FileSystem::exists(path))
- path = FileFinder::instance().lookup(filename, false);
+ if (!FileSystem::exists(path)) {
+ const char *fontFormats[] = {nullptr, "otf", "ttf"};
+ for (const char *format : fontFormats) {
+ if ((path = FileFinder::instance().lookup(filename, format, false)) != nullptr)
+ break;
+ }
+ }
if (path) {
newfont.reset(new NativeFontImpl(path, fontIndex, ptsize, style, color));
newfont->findAndAssignBaseFontMap();
diff --git a/dviware/dvisvgm/src/FontMap.cpp b/dviware/dvisvgm/src/FontMap.cpp
index e5c0caef5d..c9e2f8912c 100644
--- a/dviware/dvisvgm/src/FontMap.cpp
+++ b/dviware/dvisvgm/src/FontMap.cpp
@@ -125,13 +125,13 @@ bool FontMap::apply (const MapLine& mapline, char modechar) {
* @return true if at least one of the given map files was found */
bool FontMap::read (const string &fname_seq) {
bool found = false;
- size_t left=0;
+ string::size_type left=0;
while (left < fname_seq.length()) {
const char modechar = fname_seq[left];
if (strchr("+-=", modechar))
left++;
string fname;
- size_t right = fname_seq.find(',', left);
+ auto right = fname_seq.find(',', left);
if (right != string::npos)
fname = fname_seq.substr(left, right-left);
else {
diff --git a/dviware/dvisvgm/src/FontWriter.cpp b/dviware/dvisvgm/src/FontWriter.cpp
index b05f63c3df..0f7946f567 100644
--- a/dviware/dvisvgm/src/FontWriter.cpp
+++ b/dviware/dvisvgm/src/FontWriter.cpp
@@ -128,7 +128,7 @@ struct SFDActions : Glyph::IterationActions {
}
ostream &_os;
- Glyph::Point _startPoint, _currentPoint;
+ Glyph::Point _startPoint, _currentPoint;
};
@@ -174,8 +174,12 @@ static void writeSFD (const string &sfdname, const PhysicalFont &font, const set
"SplineSet\n";
Glyph glyph;
if (font.getGlyph(c, glyph, cb)) {
- SFDActions actions(sfd);
- glyph.iterate(actions, false);
+ if (glyph.empty())
+ sfd << "0 0 m 0\n";
+ else {
+ SFDActions actions(sfd);
+ glyph.iterate(actions, false);
+ }
}
sfd <<
"EndSplineSet\n"
diff --git a/dviware/dvisvgm/src/GraphicsPathParser.hpp b/dviware/dvisvgm/src/GraphicsPathParser.hpp
new file mode 100644
index 0000000000..0106f21a52
--- /dev/null
+++ b/dviware/dvisvgm/src/GraphicsPathParser.hpp
@@ -0,0 +1,299 @@
+/*************************************************************************
+** GraphicsPathParser.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2022 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 <cctype>
+#include <cstring>
+#include <istream>
+#include <sstream>
+#include "GraphicsPath.hpp"
+#include "MessageException.hpp"
+
+
+struct GraphicsPathParserException : public MessageException {
+ explicit GraphicsPathParserException (const std::string &msg) : MessageException(msg) {}
+};
+
+
+template <typename T>
+class GraphicsPathParser {
+ public:
+ GraphicsPath<T> parse (std::istream &is);
+
+ GraphicsPath<T> parse (const std::string &str) {
+ std::istringstream iss(str);
+ return parse(iss);
+ }
+
+ protected:
+ template <typename NumType>
+ NumType parseNumberOfType (std::istream &is) const {
+ is >> std::ws;
+ NumType number;
+ is >> number;
+ if (is.fail())
+ error("number expected", is);
+ is >> std::ws;
+ return number;
+ }
+
+ T parseNumber (std::istream &is) const {
+ return parseNumberOfType<T>(is);
+ }
+
+ Pair<T> parsePair (std::istream &is) {
+ T x = parseNumber(is);
+ skipCommaAndWhitespace(is);
+ T y = parseNumber(is);
+ return Pair<T>(x, y);
+ }
+
+ void skipCommaAndWhitespace (std::istream &is) {
+ is >> std::ws;
+ if (is.peek() == ',') {
+ is.get();
+ is >> std::ws;
+ }
+ }
+
+ void parseMoveTo (std::istream &is, bool relative);
+ void parseClosePath ();
+ void parseLineTo (std::istream &is, bool relative);
+ void parseHorizontalLineTo (std::istream &is, bool relative);
+ void parseVerticalLineTo (std::istream &is, bool relative);
+ void parseCubicTo (std::istream &is, bool relative);
+ void parseShortCubicTo (std::istream &is, bool relative);
+ void parseQuadraticTo (std::istream &is, bool relative);
+ void parseShortQuadraticTo (std::istream &is, bool relative);
+ void parseArcTo (std::istream &is, bool relative);
+
+ void error (const std::string &msg, std::istream &is) const {
+ std::string postext;
+ if (_startpos >= 0) { // valid start position?
+ if (is)
+ postext = " at position "+ std::to_string(is.tellg()-_startpos);
+ else
+ postext = " (premature end of data)";
+ }
+ throw GraphicsPathParserException(msg + postext);
+ }
+
+ private:
+ std::istream::pos_type _startpos=0; ///< stream position where the parsing started
+ GraphicsPath<T> *_path=nullptr; ///< path being parsed
+ Pair<T> _startPoint; ///< start point of current subpath
+ Pair<T> _currentPoint; ///< current point reached by last path command
+ Pair<T> _prevCtrlPoint; ///< last control point of preceding curve command
+};
+
+
+/** Creates a GraphicsPath object from a SVG path data string read from a given input stream.
+ * @param[in] is stream to read from
+ * @return GraphicsPath object created from the SVG path description
+ * @throw GraphicsPathParserException if the path data contains syntax error */
+template <typename T>
+GraphicsPath<T> GraphicsPathParser<T>::parse (std::istream &is) {
+ GraphicsPath<T> path;
+ _path = &path;
+ _startpos = is.tellg();
+ _currentPoint = _startPoint = _prevCtrlPoint = Pair<T>(0, 0);
+ int cmd=0;
+ while (!is.eof()) {
+ is >> std::ws;
+ if (is.peek() < 0)
+ break;
+ if (isalpha(is.peek()))
+ cmd = is.get();
+ else {
+ // further set of parameters appended to preceding command (command letter omitted)
+ skipCommaAndWhitespace(is);
+ // subsequent coordinate pairs of a "moveto" command lead to implicit "lineto" commands
+ // https://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
+ if (cmd == 'M')
+ cmd = 'L';
+ else if (cmd == 'm')
+ cmd = 'l';
+ }
+ int lower_cmd = std::tolower(cmd);
+ bool relative = (cmd == lower_cmd);
+ switch (lower_cmd) {
+ case 'm': parseMoveTo(is, relative); break;
+ case 'z': parseClosePath(); break;
+ case 'l': parseLineTo(is, relative); break;
+ case 'h': parseHorizontalLineTo(is, relative); break;
+ case 'v': parseVerticalLineTo(is, relative); break;
+ case 'c': parseCubicTo(is, relative); break;
+ case 's': parseShortCubicTo(is, relative); break;
+ case 'q': parseQuadraticTo(is, relative); break;
+ case 't': parseShortQuadraticTo(is, relative); break;
+ case 'a': parseArcTo(is, relative); break;
+ case 0 : error("missing command at beginning of SVG path", is);
+ default : error("invalid SVG path command '"+std::string(1, char(cmd))+"'", is);
+ }
+ if (strchr("csqt", lower_cmd) == nullptr) // not a Bézier curve command?
+ _prevCtrlPoint = _currentPoint; // => no control point, use current point
+ }
+ _path = nullptr;
+ return path;
+}
+
+
+/** Parses a single parameter pair of a "moveto" command. */
+template <typename T>
+void GraphicsPathParser<T>::parseMoveTo (std::istream &is, bool relative) {
+ Pair<T> p = parsePair(is);
+ if (!relative || _path->empty())
+ _currentPoint = p;
+ else
+ _currentPoint += p;
+ _path->moveto(_currentPoint);
+ _startPoint = _currentPoint;
+}
+
+
+/** Handles a "closepath" command. */
+template <typename T>
+void GraphicsPathParser<T>::parseClosePath () {
+ _path->closepath();
+ _currentPoint = _startPoint;
+}
+
+
+/** Parses a single parameter pair of a "lineto" command. */
+template <typename T>
+void GraphicsPathParser<T>::parseLineTo (std::istream &is, bool relative) {
+ Pair<T> p = parsePair(is);
+ if (relative)
+ _currentPoint += p;
+ else
+ _currentPoint = p;
+ _path->lineto(_currentPoint);
+}
+
+
+/** Parses a single parameter of a horizontal "lineto" command. */
+template <typename T>
+void GraphicsPathParser<T>::parseHorizontalLineTo (std::istream &is, bool relative) {
+ T x = parseNumber(is);
+ if (relative)
+ _currentPoint += Pair<T>(x, 0);
+ else
+ _currentPoint = Pair<T>(x, _currentPoint.y());
+ _path->lineto(_currentPoint);
+}
+
+
+/** Parses a single parameter of a vertical "lineto" command. */
+template <typename T>
+void GraphicsPathParser<T>::parseVerticalLineTo (std::istream &is, bool relative) {
+ T y = parseNumber(is);
+ if (relative)
+ _currentPoint += Pair<T>(0, y);
+ else
+ _currentPoint = Pair<T>(_currentPoint.x(), y);
+ _path->lineto(_currentPoint);
+}
+
+
+/** Parses a single parameter set a "cubicto" (cubic Bézier curve) command. */
+template <typename T>
+void GraphicsPathParser<T>::parseCubicTo (std::istream &is, bool relative) {
+ Pair<T> p1 = parsePair(is);
+ Pair<T> p2 = parsePair(is);
+ Pair<T> pe = parsePair(is);
+ if (!relative)
+ _currentPoint = pe;
+ else {
+ p1 += _currentPoint;
+ p2 += _currentPoint;
+ _currentPoint += pe;
+ }
+ _path->cubicto(p1, p2, _currentPoint);
+ _prevCtrlPoint = p2;
+}
+
+
+/** Parses a single parameter set a shorthand "cubicto" (cubic Bézier curve) command. */
+template <typename T>
+void GraphicsPathParser<T>::parseShortCubicTo (std::istream &is, bool relative) {
+ Pair<T> p1 = _prevCtrlPoint + (_currentPoint-_prevCtrlPoint)*T(2);
+ Pair<T> p2 = parsePair(is);
+ Pair<T> pe = parsePair(is);
+ if (!relative)
+ _currentPoint = pe;
+ else {
+ p2 += _currentPoint;
+ _currentPoint += pe;
+ }
+ _path->cubicto(p1, p2, _currentPoint);
+ _prevCtrlPoint = p2;
+}
+
+
+/** Parses a single parameter set a "quadto" (quadratic Bézier curve) command. */
+template <typename T>
+void GraphicsPathParser<T>::parseQuadraticTo (std::istream &is, bool relative) {
+ Pair<T> p1 = parsePair(is);
+ Pair<T> pe = parsePair(is);
+ if (!relative)
+ _currentPoint = pe;
+ else {
+ p1 += _currentPoint;
+ _currentPoint += pe;
+ }
+ _path->quadto(p1, _currentPoint);
+ _prevCtrlPoint = p1;
+}
+
+
+/** Parses a single parameter set a shorthand "quadto" (quadratic Bézier curve) command. */
+template <typename T>
+void GraphicsPathParser<T>::parseShortQuadraticTo (std::istream &is, bool relative) {
+ Pair<T> p1 = _prevCtrlPoint + (_currentPoint-_prevCtrlPoint)*T(2);
+ Pair<T> pe = parsePair(is);
+ if (relative)
+ _currentPoint += pe;
+ else
+ _currentPoint = pe;
+ _path->quadto(p1, _currentPoint);
+ _prevCtrlPoint = p1;
+}
+
+
+/** Parses a single parameter set an "arcto" command. */
+template <typename T>
+void GraphicsPathParser<T>::parseArcTo (std::istream &is, bool relative) {
+ Pair<T> r = parsePair(is);
+ double xrot = parseNumberOfType<double>(is);
+ int largeArgFlag = parseNumberOfType<int>(is);
+ if (largeArgFlag != 0 && largeArgFlag != 1)
+ error("large-arc-flag must be 0 or 1", is);
+ int sweepFlag = parseNumberOfType<int>(is);
+ if (sweepFlag != 0 && sweepFlag != 1)
+ error("sweep-flag must be 0 or 1", is);
+ T x = parseNumber(is);
+ T y = parseNumber(is);
+ Pair<T> p(x, y);
+ if (relative)
+ p += _currentPoint;
+ _currentPoint = p;
+ _path->arcto(r.x(), r.y(), xrot, bool(largeArgFlag), bool(sweepFlag), _currentPoint);
+}
diff --git a/dviware/dvisvgm/src/HashFunction.hpp b/dviware/dvisvgm/src/HashFunction.hpp
index 15f7725543..ecd938bcbb 100644
--- a/dviware/dvisvgm/src/HashFunction.hpp
+++ b/dviware/dvisvgm/src/HashFunction.hpp
@@ -28,7 +28,7 @@
/** Common base class for all hash functions. */
class HashFunction {
- public:
+ public:
virtual ~HashFunction () =default;
virtual int digestSize () const =0;
virtual void reset () =0;
diff --git a/dviware/dvisvgm/src/HyperlinkManager.cpp b/dviware/dvisvgm/src/HyperlinkManager.cpp
index 2371234499..65ee534a32 100644
--- a/dviware/dvisvgm/src/HyperlinkManager.cpp
+++ b/dviware/dvisvgm/src/HyperlinkManager.cpp
@@ -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(':');
+ auto seppos = marker.find(':');
if (seppos == string::npos)
type = marker;
else {
diff --git a/dviware/dvisvgm/src/HyperlinkManager.hpp b/dviware/dvisvgm/src/HyperlinkManager.hpp
index 3e7ba17373..99151db0e5 100644
--- a/dviware/dvisvgm/src/HyperlinkManager.hpp
+++ b/dviware/dvisvgm/src/HyperlinkManager.hpp
@@ -42,7 +42,7 @@ class HyperlinkManager {
enum class ColorSource {DEFAULT, LINKMARKER, STATIC};
using NamedAnchors = std::unordered_map<std::string, NamedAnchor>;
- public:
+ public:
HyperlinkManager (const HyperlinkManager&) =delete;
HyperlinkManager (HyperlinkManager&&) =delete;
void addHrefAnchor (const std::string &uri);
@@ -68,7 +68,7 @@ class HyperlinkManager {
static Color LINK_LINECOLOR; ///< line color if linkmark type is LM_LINE or LM_BOX
static ColorSource COLORSOURCE; ///< if true, LINK_LINECOLOR is applied
- private:
+ private:
AnchorType _anchorType=AnchorType::NONE; ///< type of active anchor
int _depthThreshold=0; ///< break anchor box if the DVI stack depth underruns this threshold
double _linewidth=-1; ///< line width of link marker (-1 => compute individual value per link)
diff --git a/dviware/dvisvgm/src/Makefile.am b/dviware/dvisvgm/src/Makefile.am
index df03cea805..bd2cfd3a43 100644
--- a/dviware/dvisvgm/src/Makefile.am
+++ b/dviware/dvisvgm/src/Makefile.am
@@ -87,6 +87,7 @@ libdvisvgm_la_SOURCES = \
Glyph.hpp \
GlyphTracerMessages.hpp \
GraphicsPath.hpp \
+ GraphicsPathParser.hpp \
HashFunction.hpp HashFunction.cpp \
HtmlSpecialHandler.hpp HtmlSpecialHandler.cpp \
HyperlinkManager.hpp HyperlinkManager.cpp \
@@ -157,6 +158,7 @@ libdvisvgm_la_SOURCES = \
windows.hpp \
XMLDocument.hpp XMLDocument.cpp \
XMLNode.hpp XMLNode.cpp \
+ XMLParser.hpp XMLParser.cpp \
XMLString.hpp XMLString.cpp \
XXHashFunction.hpp \
ZLibOutputStream.hpp
diff --git a/dviware/dvisvgm/src/Makefile.in b/dviware/dvisvgm/src/Makefile.in
index 0ef19f52c2..65df7c6162 100644
--- a/dviware/dvisvgm/src/Makefile.in
+++ b/dviware/dvisvgm/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -114,12 +114,7 @@ bin_PROGRAMS = dvisvgm$(EXEEXT)
@ENABLE_WOFF_TRUE@am__append_13 = $(TTFAUTOHINT_LIBS)
subdir = src
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
- $(top_srcdir)/m4/ax_code_coverage.m4 \
- $(top_srcdir)/m4/ax_cxx_compile_stdcxx.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)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -154,8 +149,9 @@ am__libdvisvgm_la_SOURCES_DIST = AGLTable.hpp BasicDVIReader.hpp \
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 \
+ GlyphTracerMessages.hpp GraphicsPath.hpp \
+ GraphicsPathParser.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 \
@@ -193,8 +189,9 @@ am__libdvisvgm_la_SOURCES_DIST = AGLTable.hpp BasicDVIReader.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
+ XMLNode.cpp XMLParser.hpp XMLParser.cpp XMLString.hpp \
+ XMLString.cpp XXHashFunction.hpp ZLibOutputStream.hpp \
+ ffwrapper.c ffwrapper.h
@ENABLE_WOFF_TRUE@am__objects_1 = ffwrapper.lo
am_libdvisvgm_la_OBJECTS = BasicDVIReader.lo Bezier.lo \
BgColorSpecialHandler.lo Bitmap.lo BoundingBox.lo \
@@ -222,7 +219,8 @@ am_libdvisvgm_la_OBJECTS = BasicDVIReader.lo Bezier.lo \
TensorProductPatch.lo Terminal.lo TFM.lo ToUnicodeMap.lo \
TpicSpecialHandler.lo TriangularPatch.lo TrueTypeFont.lo \
TTFAutohint.lo Unicode.lo utility.lo VFReader.lo \
- XMLDocument.lo XMLNode.lo XMLString.lo $(am__objects_1)
+ XMLDocument.lo XMLNode.lo XMLParser.lo XMLString.lo \
+ $(am__objects_1)
libdvisvgm_la_OBJECTS = $(am_libdvisvgm_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -303,9 +301,9 @@ am__depfiles_remade = ./$(DEPDIR)/BasicDVIReader.Plo \
./$(DEPDIR)/TriangularPatch.Plo ./$(DEPDIR)/TrueTypeFont.Plo \
./$(DEPDIR)/Unicode.Plo ./$(DEPDIR)/VFReader.Plo \
./$(DEPDIR)/XMLDocument.Plo ./$(DEPDIR)/XMLNode.Plo \
- ./$(DEPDIR)/XMLString.Plo ./$(DEPDIR)/dvisvgm.Po \
- ./$(DEPDIR)/ffwrapper.Plo ./$(DEPDIR)/psdefs.Plo \
- ./$(DEPDIR)/utility.Plo
+ ./$(DEPDIR)/XMLParser.Plo ./$(DEPDIR)/XMLString.Plo \
+ ./$(DEPDIR)/dvisvgm.Po ./$(DEPDIR)/ffwrapper.Plo \
+ ./$(DEPDIR)/psdefs.Plo ./$(DEPDIR)/utility.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -383,8 +381,6 @@ am__define_uniq_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
DIST_SUBDIRS = $(SUBDIRS)
am__DIST_COMMON = $(srcdir)/../libs/defs.am $(srcdir)/Makefile.in \
$(srcdir)/version.hpp.in $(top_srcdir)/depcomp
@@ -438,6 +434,8 @@ CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -453,8 +451,10 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
FREETYPE_LIBS = @FREETYPE_LIBS@
GCOV = @GCOV@
@@ -611,8 +611,9 @@ libdvisvgm_la_SOURCES = AGLTable.hpp BasicDVIReader.hpp \
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 \
+ GlyphTracerMessages.hpp GraphicsPath.hpp \
+ GraphicsPathParser.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 \
@@ -650,8 +651,9 @@ libdvisvgm_la_SOURCES = AGLTable.hpp BasicDVIReader.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)
+ XMLNode.cpp XMLParser.hpp XMLParser.cpp XMLString.hpp \
+ XMLString.cpp XXHashFunction.hpp ZLibOutputStream.hpp \
+ $(am__append_8)
libdvisvgm_la_LIBADD = optimizer/liboptimizer.la
EXTRA_DIST = options.xml options.dtd iapi.h ierrors.h MiKTeXCom.hpp MiKTeXCom.cpp
AM_CFLAGS = -Wall $(ZLIB_CFLAGS) $(CODE_COVERAGE_CFLAGS) \
@@ -676,9 +678,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../libs/defs.am $(am__co
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --foreign src/Makefile
+ $(AUTOMAKE) --gnu src/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -866,6 +868,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VFReader.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XMLDocument.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XMLNode.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XMLParser.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XMLString.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvisvgm.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffwrapper.Plo@am__quote@ # am--include-marker
@@ -1030,7 +1033,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -1227,6 +1229,7 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/VFReader.Plo
-rm -f ./$(DEPDIR)/XMLDocument.Plo
-rm -f ./$(DEPDIR)/XMLNode.Plo
+ -rm -f ./$(DEPDIR)/XMLParser.Plo
-rm -f ./$(DEPDIR)/XMLString.Plo
-rm -f ./$(DEPDIR)/dvisvgm.Po
-rm -f ./$(DEPDIR)/ffwrapper.Plo
@@ -1370,6 +1373,7 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/VFReader.Plo
-rm -f ./$(DEPDIR)/XMLDocument.Plo
-rm -f ./$(DEPDIR)/XMLNode.Plo
+ -rm -f ./$(DEPDIR)/XMLParser.Plo
-rm -f ./$(DEPDIR)/XMLString.Plo
-rm -f ./$(DEPDIR)/dvisvgm.Po
-rm -f ./$(DEPDIR)/ffwrapper.Plo
diff --git a/dviware/dvisvgm/src/MapLine.cpp b/dviware/dvisvgm/src/MapLine.cpp
index 531550788d..0c432cab23 100644
--- a/dviware/dvisvgm/src/MapLine.cpp
+++ b/dviware/dvisvgm/src/MapLine.cpp
@@ -37,7 +37,7 @@ MapLine::MapLine (istream &is) : MapLine() {
MapLine::MapLine (string str) : MapLine() {
- size_t pos = str.rfind('\n');
+ auto pos = str.rfind('\n');
if (pos != string::npos)
str = str.substr(0, pos);
parse(str.c_str());
@@ -75,9 +75,9 @@ bool MapLine::isDVIPSFormat (const char *line) const {
* @param[out] sfdname name of subfont definition
* @return true on success */
static bool split_fontname (string &fontname, string &sfdname) {
- size_t pos1; // index of first '@'
+ string::size_type pos1; // index of first '@'
if ((pos1 = fontname.find('@')) != string::npos && pos1 > 0) {
- size_t pos2; // index of second '@'
+ string::size_type pos2; // index of second '@'
if ((pos2 = fontname.find('@', pos1+1)) != string::npos && pos2 > pos1+1) {
sfdname = fontname.substr(pos1+1, pos2-pos1-1);
fontname = fontname.substr(0, pos1) + fontname.substr(pos2+1);
diff --git a/dviware/dvisvgm/src/MetafontWrapper.cpp b/dviware/dvisvgm/src/MetafontWrapper.cpp
index bf1bbf1ba4..03c3e2b5ef 100644
--- a/dviware/dvisvgm/src/MetafontWrapper.cpp
+++ b/dviware/dvisvgm/src/MetafontWrapper.cpp
@@ -118,7 +118,7 @@ int MetafontWrapper::getResolution (const string &mfMessage) const {
string line = buf;
if (line.substr(0, 18) == "Output written on ") {
line = line.substr(18);
- size_t pos = line.find(' ');
+ auto pos = line.find(' ');
line = line.substr(0, pos);
pos = line.rfind('.');
if (pos != string::npos && line.substr(line.length()-2) == "gf") {
diff --git a/dviware/dvisvgm/src/MiKTeXCom.cpp b/dviware/dvisvgm/src/MiKTeXCom.cpp
index 7da0342f9f..6f9d6f6e13 100644
--- a/dviware/dvisvgm/src/MiKTeXCom.cpp
+++ b/dviware/dvisvgm/src/MiKTeXCom.cpp
@@ -66,8 +66,7 @@ string MiKTeXCom::getVersion () {
MiKTeXSetupInfo info;
_session->GetMiKTeXSetupInfo(&info);
#endif
- _bstr_t version = info.version;
- return string(version);
+ return to_string(info.series/100)+"."+ to_string(info.series%100);
}
@@ -105,6 +104,6 @@ const char* MiKTeXCom::findFile (const char *fname) {
return nullptr;
}
catch (_com_error &e) {
- throw MessageException((const char*)e.Description());
+ throw MessageException(static_cast<const char*>(e.Description()));
}
}
diff --git a/dviware/dvisvgm/src/Opacity.hpp b/dviware/dvisvgm/src/Opacity.hpp
index 3d211b82bc..84880e7b66 100644
--- a/dviware/dvisvgm/src/Opacity.hpp
+++ b/dviware/dvisvgm/src/Opacity.hpp
@@ -48,11 +48,11 @@ class Opacity {
BM_HUE, BM_SATURATION, BM_COLOR, BM_LUMINOSITY
};
- public:
+ public:
Opacity () =default;
Opacity (OpacityAlpha fillalpha, OpacityAlpha strokealpha, BlendMode bm) : _fillalpha(fillalpha), _strokealpha(strokealpha), _blendMode(bm) {}
Opacity (OpacityAlpha fillalpha, OpacityAlpha strokealpha) : Opacity(fillalpha, strokealpha, BM_NORMAL) {}
- explicit Opacity (BlendMode bm) : _blendMode(bm) {}
+ explicit Opacity (BlendMode bm) : _blendMode(bm) {}
OpacityAlpha& fillalpha () {return _fillalpha;}
OpacityAlpha& strokealpha () {return _strokealpha;}
const OpacityAlpha& fillalpha () const {return _fillalpha;}
@@ -66,7 +66,7 @@ class Opacity {
bool operator == (const Opacity &opacity) const;
bool operator != (const Opacity &opacity) const;
- private:
+ private:
OpacityAlpha _fillalpha;
OpacityAlpha _strokealpha;
BlendMode _blendMode=BM_NORMAL;
diff --git a/dviware/dvisvgm/src/PDFParser.cpp b/dviware/dvisvgm/src/PDFParser.cpp
index 04b9fe661c..5d00a5da58 100644
--- a/dviware/dvisvgm/src/PDFParser.cpp
+++ b/dviware/dvisvgm/src/PDFParser.cpp
@@ -207,7 +207,7 @@ static bool parse_number (const string &str, NumberVariant &nv) {
if (str.empty())
return false;
try {
- size_t dotpos = str.find('.');
+ auto dotpos = str.find('.');
if (dotpos == string::npos) { // not a real number?
size_t count;
nv = NumberVariant(stoi(str, &count, 10)); // then try to convert str to int
@@ -218,7 +218,7 @@ static bool parse_number (const string &str, NumberVariant &nv) {
// which is not allowed in PDF real number constants
if (!postdot.empty() && isdigit(postdot[0])) {
size_t count;
- stoi(postdot, &count, 10);
+ static_cast<void>(stoi(postdot, &count, 10));
if (count != postdot.length())
return false;
}
@@ -310,7 +310,7 @@ static PDFObjectRef parse_object_ref (vector<PDFObject> &objects) {
/** Replaces all occurences of "#XX" (XX are two hex digits) with the corresponding character. */
static string& subst_numeric_chars (string &str) {
- for (size_t pos=str.find('#'); pos != string::npos; pos=str.find('#', pos+1)) {
+ for (auto pos=str.find('#'); pos != string::npos; pos=str.find('#', pos+1)) {
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])) {
diff --git a/dviware/dvisvgm/src/PageSize.cpp b/dviware/dvisvgm/src/PageSize.cpp
index 2fcdd917fb..a1d29bfcb6 100644
--- a/dviware/dvisvgm/src/PageSize.cpp
+++ b/dviware/dvisvgm/src/PageSize.cpp
@@ -96,7 +96,7 @@ void PageSize::resize (string name) {
name = util::tolower(name);
// extract optional suffix
- size_t pos = name.rfind('-');
+ auto pos = name.rfind('-');
bool landscape = false;
if (pos != string::npos) {
string suffix = name.substr(pos);
diff --git a/dviware/dvisvgm/src/PapersizeSpecialHandler.cpp b/dviware/dvisvgm/src/PapersizeSpecialHandler.cpp
index 42a9fcbc1a..557bea8679 100644
--- a/dviware/dvisvgm/src/PapersizeSpecialHandler.cpp
+++ b/dviware/dvisvgm/src/PapersizeSpecialHandler.cpp
@@ -28,7 +28,7 @@ void PapersizeSpecialHandler::preprocess (const string&, std::istream &is, Speci
string params;
is >> params;
Length w, h;
- const size_t splitpos = params.find(',');
+ const auto splitpos = params.find(',');
try {
if (splitpos == string::npos) {
w.set(params);
diff --git a/dviware/dvisvgm/src/PsSpecialHandler.cpp b/dviware/dvisvgm/src/PsSpecialHandler.cpp
index 45328fbd18..7ece9b16ba 100644
--- a/dviware/dvisvgm/src/PsSpecialHandler.cpp
+++ b/dviware/dvisvgm/src/PsSpecialHandler.cpp
@@ -190,7 +190,7 @@ void PsSpecialHandler::preprocess (const string &prefix, istream &is, SpecialAct
static string filename_suffix (const string &fname) {
string ret;
- size_t pos = fname.rfind('.');
+ auto pos = fname.rfind('.');
if (pos != string::npos)
ret = util::tolower(fname.substr(pos+1));
return ret;
diff --git a/dviware/dvisvgm/src/SVGElement.hpp b/dviware/dvisvgm/src/SVGElement.hpp
index c326b79f87..d1103a8551 100644
--- a/dviware/dvisvgm/src/SVGElement.hpp
+++ b/dviware/dvisvgm/src/SVGElement.hpp
@@ -33,7 +33,7 @@ class SVGElement : public XMLElement {
enum LineCap {LC_BUTT, LC_ROUND, LC_SQUARE};
enum LineJoin {LJ_BEVEL, LJ_MITER, LJ_ROUND};
- public:
+ public:
explicit SVGElement (std::string name) : XMLElement(std::move(name)) {}
explicit SVGElement (const XMLElement &node) : XMLElement(node) {}
explicit SVGElement (XMLElement &&node) noexcept : XMLElement(std::move(node)) {}
diff --git a/dviware/dvisvgm/src/SVGOutput.cpp b/dviware/dvisvgm/src/SVGOutput.cpp
index 6ba41f1c7d..013dd8f8f9 100644
--- a/dviware/dvisvgm/src/SVGOutput.cpp
+++ b/dviware/dvisvgm/src/SVGOutput.cpp
@@ -108,7 +108,7 @@ FilePath SVGOutput::filepath (int page, int numPages, const HashTriple &hashes)
string SVGOutput::expandFormatString (string str, int page, int numPages, const HashTriple &hashes) const {
string result;
while (!str.empty()) {
- size_t pos = str.find('%');
+ auto pos = str.find('%');
if (pos == string::npos) {
result += str;
str.clear();
@@ -150,7 +150,7 @@ string SVGOutput::expandFormatString (string str, int page, int numPages, const
result += oss.str();
break;
case '(': {
- size_t endpos = str.find(')', pos);
+ auto endpos = str.find(')', pos);
if (endpos == string::npos)
throw MessageException("missing ')' in filename pattern");
else if (endpos-pos-1 > 1) {
diff --git a/dviware/dvisvgm/src/SVGTree.cpp b/dviware/dvisvgm/src/SVGTree.cpp
index f4cd9a85ef..1fed40b443 100644
--- a/dviware/dvisvgm/src/SVGTree.cpp
+++ b/dviware/dvisvgm/src/SVGTree.cpp
@@ -92,7 +92,7 @@ void SVGTree::setFont (int num, const Font &font) {
bool SVGTree::setFontFormat (string formatstr) {
- size_t pos = formatstr.find(',');
+ auto pos = formatstr.find(',');
string opt;
if (pos != string::npos) {
opt = formatstr.substr(pos+1);
diff --git a/dviware/dvisvgm/src/TFM.cpp b/dviware/dvisvgm/src/TFM.cpp
index 37da112757..a5b88f180d 100644
--- a/dviware/dvisvgm/src/TFM.cpp
+++ b/dviware/dvisvgm/src/TFM.cpp
@@ -43,8 +43,8 @@ static void read_words (StreamReader &reader, vector<T> &v, unsigned n) {
TFM::TFM (istream &is) : _checksum(0), _firstChar(0), _lastChar(0), _designSize(0), _ascent(0), _descent(0) {
- if (!is)
- return;
+ if (!is)
+ return;
is.seekg(0);
StreamReader reader(is);
uint16_t lf = uint16_t(reader.readUnsigned(2)); // length of entire file in 4 byte words
diff --git a/dviware/dvisvgm/src/Unicode.cpp b/dviware/dvisvgm/src/Unicode.cpp
index af35bdf9bd..2293be0399 100644
--- a/dviware/dvisvgm/src/Unicode.cpp
+++ b/dviware/dvisvgm/src/Unicode.cpp
@@ -189,7 +189,7 @@ static const char* get_suffix (const string &name) {
"small", "swash", "superior", "inferior", "numerator", "denominator", "oldstyle",
"display", "text", "big", "bigg", "Big", "Bigg", 0
};
- size_t pos = name.rfind('.');
+ auto pos = name.rfind('.');
if (pos != string::npos) {
string suffix = name.substr(pos+1);
for (const char **p=suffixes; *p; p++)
diff --git a/dviware/dvisvgm/src/XMLNode.cpp b/dviware/dvisvgm/src/XMLNode.cpp
index 743da58b93..0f2602f8f0 100644
--- a/dviware/dvisvgm/src/XMLNode.cpp
+++ b/dviware/dvisvgm/src/XMLNode.cpp
@@ -103,6 +103,19 @@ void XMLElement::clear () {
}
+/** Returns true if element has no child nodes or, alternatively, only whitespace children.
+ * @param[in] ignoreWhitespace if true and if there are only whitespace children, the functions returns true */
+bool XMLElement::empty (bool ignoreWhitespace) const {
+ if (!_firstChild || !ignoreWhitespace)
+ return _firstChild == nullptr;
+ for (const XMLNode *node : *this) {
+ if (!node->toWSNode())
+ return false;
+ }
+ return true;
+}
+
+
void XMLElement::addAttribute (const string &name, const string &value) {
if (Attribute *attr = getAttribute(name))
attr->value = value;
@@ -363,7 +376,7 @@ ostream& XMLElement::write (ostream &os) const {
os << attrib.name << "='" << attrib.value << '\'';
else {
os << attrib.name.substr(1) << "='";
- size_t pos = attrib.value.find("base64,");
+ auto pos = attrib.value.find("base64,");
if (pos == string::npos)
os << attrib.value;
else {
@@ -434,6 +447,29 @@ const XMLElement::Attribute* XMLElement::getAttribute (const string &name) const
}
+/** 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.
+ * @return true if the attribute is inheritable */
+bool XMLElement::Attribute::inheritable () const {
+ // 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(std::begin(names), std::end(names), name, [](const string &name1, const string &name2) {
+ return name1 < name2;
+ });
+}
+
+
//////////////////////
void XMLText::append (unique_ptr<XMLNode> node) {
diff --git a/dviware/dvisvgm/src/XMLNode.hpp b/dviware/dvisvgm/src/XMLNode.hpp
index f1880352f2..fc34f05db8 100644
--- a/dviware/dvisvgm/src/XMLNode.hpp
+++ b/dviware/dvisvgm/src/XMLNode.hpp
@@ -118,6 +118,7 @@ class XMLElement : public XMLNode {
public:
struct Attribute {
Attribute (std::string nam, std::string val) : name(std::move(nam)), value(std::move(val)) {}
+ bool inheritable () const;
std::string name;
std::string value;
};
@@ -146,7 +147,7 @@ class XMLElement : public XMLNode {
XMLNode* firstChild () const {return _firstChild.get();}
XMLNode* lastChild () const {return _lastChild;}
std::ostream& write (std::ostream &os) const override;
- bool empty () const {return !_firstChild;}
+ bool empty (bool ignoreWhitespace=false) const;
Attributes& attributes () {return _attributes;}
const Attributes& attributes () const {return _attributes;}
XMLNodeIterator begin () {return XMLNodeIterator(_firstChild.get());}
diff --git a/dviware/dvisvgm/src/XMLParser.cpp b/dviware/dvisvgm/src/XMLParser.cpp
new file mode 100644
index 0000000000..166a49e0cf
--- /dev/null
+++ b/dviware/dvisvgm/src/XMLParser.cpp
@@ -0,0 +1,182 @@
+/*************************************************************************
+** XMLParser.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2022 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 "InputReader.hpp"
+#include "GraphicsPathParser.hpp"
+#include "XMLParser.hpp"
+
+using namespace std;
+
+/** Parses a fragment of XML code, creates corresponding XML nodes and adds them
+ * to an 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 a call of this function
+ * is supposed to finish the parsing of an XML subtree, parameter 'finish' must be set.
+ * @param[in] xml XML fragment to parse
+ * @param[in] svgTree the parsed nodes are added to this SVG tree
+ * @param[in] finish if true, no more XML is expected and parsing is finished */
+void XMLParser::parse (const string &xml, SVGTree &svgTree, bool finish) {
+ // collect/extract an XML fragment that only contains complete tags
+ // incomplete tags are held back
+ _xmlbuf += xml;
+ string::size_type left=0;
+ try {
+ while (left != string::npos) {
+ auto right = _xmlbuf.find('<', left);
+ if (left < right && left < _xmlbuf.length()) // plain text found?
+ (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 XMLParserException("expected ']]>' at end of CDATA block");
+ break;
+ }
+ (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 XMLParserException("expected '-->' at end of comment");
+ break;
+ }
+ (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 XMLParserException("expected '?>' at end of processing instruction");
+ break;
+ }
+ (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 XMLParserException("missing '>' at end of closing XML tag");
+ break;
+ }
+ closeElement(_xmlbuf.substr(left+2, right-left-2), svgTree);
+ }
+ else {
+ right = _xmlbuf.find('>', left+1);
+ if (right == string::npos) {
+ if (finish) throw XMLParserException("missing '>' or '/>' at end of opening XML tag");
+ break;
+ }
+ openElement(_xmlbuf.substr(left+1, right-left-1), svgTree);
+ }
+ }
+ left = right;
+ if (right != string::npos)
+ left++;
+ }
+ }
+ catch (const XMLParserException &e) {
+ _error = true;
+ throw;
+ }
+ 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 XMLParser::openElement (const string &tag, SVGTree &svgTree) {
+ StringInputBuffer ib(tag);
+ BufferInputReader ir(ib);
+ string name = ir.getString("/ \t\n\r");
+ bool isPathElement = (name == "path" || name == "svg:path");
+ ir.skipSpace();
+ auto elemNode = util::make_unique<SVGElement>(name);
+ map<string, string> attribs;
+ if (ir.parseAttributes(attribs, true, "\"'")) {
+ for (const auto &attrpair : attribs) {
+ if (!isPathElement || attrpair.first != "d")
+ elemNode->addAttribute(attrpair.first, attrpair.second);
+ else {
+ try {
+ // parse and reformat path definition
+ auto path = GraphicsPathParser<double>().parse(attrpair.second);
+ ostringstream oss;
+ path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS);
+ elemNode->addAttribute("d", oss.str());
+ }
+ catch (const GraphicsPathParserException &e) {
+ throw XMLParserException(string("error in path data: ")+e.what());
+ }
+ }
+ }
+ }
+ ir.skipSpace();
+ if (ir.peek() == '/') // end of empty element tag
+ (svgTree.*_append)(std::move(elemNode));
+ else if (ir.peek() < 0) { // end of opening tag
+ _nameStack.push_back(name);
+ (svgTree.*_pushContext)(std::move(elemNode));
+ }
+ else
+ throw XMLParserException("'>' or '/>' expected at end of opening tag <"+name);
+}
+
+
+/** Processes a closing element tag.
+ * @param[in] tag tag without leading and trailing angle brackets */
+void XMLParser::closeElement (const string &tag, SVGTree &svgTree) {
+ StringInputBuffer ib(tag);
+ BufferInputReader ir(ib);
+ string name = ir.getString(" \t\n\r");
+ ir.skipSpace();
+ if (ir.peek() >= 0)
+ throw XMLParserException("'>' expected at end of closing tag </"+name);
+ if (_nameStack.empty())
+ throw XMLParserException("spurious closing tag </" + name + ">");
+ if (_nameStack.back() != name)
+ throw XMLParserException("expected </" + _nameStack.back() + "> but found </" + name + ">");
+ (svgTree.*_popContext)();
+ _nameStack.pop_back();
+}
+
+
+/** Processes any remaining XML fragments, checks for missing closing tags,
+ * and resets the parser state. */
+void XMLParser::finish (SVGTree &svgTree) {
+ if (!_xmlbuf.empty()) {
+ if (!_error)
+ parse("", svgTree, true);
+ _xmlbuf.clear();
+ }
+ string tags;
+ while (!_nameStack.empty()) {
+ tags += "</"+_nameStack.back()+">, ";
+ _nameStack.pop_back();
+ }
+ if (!tags.empty() && !_error) {
+ tags.resize(tags.length()-2);
+ throw XMLParserException("missing closing tag(s): "+tags);
+ }
+}
diff --git a/dviware/dvisvgm/src/XMLParser.hpp b/dviware/dvisvgm/src/XMLParser.hpp
new file mode 100644
index 0000000000..51f6a62544
--- /dev/null
+++ b/dviware/dvisvgm/src/XMLParser.hpp
@@ -0,0 +1,58 @@
+/*************************************************************************
+** XMLParser.hpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2022 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/>. **
+*************************************************************************/
+
+#ifndef XMLPARSER_HPP
+#define XMLPARSER_HPP
+
+#include <string>
+#include "MessageException.hpp"
+#include "SVGTree.hpp"
+
+struct XMLParserException : MessageException {
+ explicit XMLParserException (const std::string &msg) : MessageException(msg) {}
+};
+
+class XMLParser {
+ using AppendFunc = void (SVGTree::*)(std::unique_ptr<XMLNode>);
+ using PushFunc = void (SVGTree::*)(std::unique_ptr<SVGElement>);
+ 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, SVGTree &svgTree, bool finish=false);
+ void finish (SVGTree &svgTree);
+
+ protected:
+ void openElement (const std::string &tag, SVGTree &svgTree);
+ void closeElement (const std::string &tag, SVGTree &svgTree);
+
+ private:
+ AppendFunc _append;
+ PushFunc _pushContext;
+ PopFunc _popContext;
+ std::string _xmlbuf;
+ NameStack _nameStack; ///< names of nested elements still missing a closing tag
+ bool _error=false;
+};
+
+#endif
diff --git a/dviware/dvisvgm/src/XMLString.cpp b/dviware/dvisvgm/src/XMLString.cpp
index 6ce89b3d86..ae489ea16c 100644
--- a/dviware/dvisvgm/src/XMLString.cpp
+++ b/dviware/dvisvgm/src/XMLString.cpp
@@ -91,7 +91,7 @@ XMLString::XMLString (double x) {
if (std::abs(x) < 1e-6)
x = 0;
assign(util::to_string(x));
- size_t pos = find("0.");
+ auto pos = find("0.");
if (pos != string::npos && (pos == 0 || at(pos-1) == '-'))
erase(pos, 1);
}
diff --git a/dviware/dvisvgm/src/dvisvgm.cpp b/dviware/dvisvgm/src/dvisvgm.cpp
index 089064a1b9..488e9e2b47 100644
--- a/dviware/dvisvgm/src/dvisvgm.cpp
+++ b/dviware/dvisvgm/src/dvisvgm.cpp
@@ -48,6 +48,7 @@
#include "optimizer/SVGOptimizer.hpp"
#include "SVGOutput.hpp"
#include "System.hpp"
+#include "XMLParser.hpp"
#include "XXHashFunction.hpp"
#include "utility.hpp"
#include "version.hpp"
@@ -65,7 +66,7 @@ using namespace std;
static string remove_path (string fname) {
fname = FileSystem::ensureForwardSlashes(fname);
- size_t slashpos = fname.rfind('/');
+ auto slashpos = fname.rfind('/');
if (slashpos == string::npos)
return fname;
return fname.substr(slashpos+1);
@@ -74,7 +75,7 @@ static string remove_path (string fname) {
static string ensure_suffix (string fname, const string &suffix) {
if (!fname.empty()) {
- size_t dotpos = remove_path(fname).rfind('.');
+ auto dotpos = remove_path(fname).rfind('.');
if (dotpos == string::npos)
fname += "." + suffix;
}
@@ -494,6 +495,10 @@ int main (int argc, char *argv[]) {
Message::estream() << "\nPostScript error: " << e.what() << '\n';
return -2;
}
+ catch (XMLParserException &e) {
+ Message::estream() << "\nXML error: " << e.what() << '\n';
+ return -5;
+ }
catch (SignalException &e) {
Message::wstream().clearline();
Message::wstream(true) << "execution interrupted by user\n";
diff --git a/dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp b/dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp
index d36314aae4..1d1c6579b8 100644
--- a/dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp
+++ b/dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp
@@ -82,7 +82,7 @@ void AttributeExtractor::execute (XMLElement *context, bool recurse) {
* @return the new group element if attributes could be grouped, 'elem' otherwise */
XMLNode* AttributeExtractor::extractAttribute (XMLElement *elem) {
for (const auto &currentAttribute : elem->attributes()) {
- if (!inheritable(currentAttribute) || extracted(currentAttribute))
+ if (!currentAttribute.inheritable() || extracted(currentAttribute))
continue;
AttributeRun run(currentAttribute, elem);
if (run.length() >= MIN_RUN_LENGTH) {
@@ -126,30 +126,6 @@ bool AttributeExtractor::groupable (const XMLElement &elem) {
}
-/** 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"))
diff --git a/dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp b/dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp
index 19cd4f0fed..4b53b66551 100644
--- a/dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp
+++ b/dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp
@@ -46,7 +46,6 @@ class AttributeExtractor : public OptimizerModule {
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:
diff --git a/dviware/dvisvgm/src/optimizer/GroupCollapser.cpp b/dviware/dvisvgm/src/optimizer/GroupCollapser.cpp
index 03fc3ac185..e86313e74b 100644
--- a/dviware/dvisvgm/src/optimizer/GroupCollapser.cpp
+++ b/dviware/dvisvgm/src/optimizer/GroupCollapser.cpp
@@ -22,7 +22,6 @@
#include <array>
#include <string>
#include <vector>
-#include "AttributeExtractor.hpp"
#include "GroupCollapser.hpp"
#include "TransformSimplifier.hpp"
#include "../XMLNode.hpp"
@@ -83,8 +82,8 @@ void GroupCollapser::execute (XMLElement *context, int depth) {
XMLNode *next=child->next();
if (XMLElement *childElement = child->toElement()) {
execute(childElement, depth+1);
- // check for groups without attributes and remove them
- if (childElement->name() == "g" && childElement->attributes().empty()) {
+ // remove empty groups and groups without attributes
+ if (childElement->name() == "g" && (childElement->attributes().empty() || (!childElement->hasAttribute("id") && childElement->empty(true)))) {
remove_ws_nodes(childElement);
if (XMLNode *firstUnwrappedNode = XMLElement::unwrap(childElement))
next = firstUnwrappedNode;
@@ -127,7 +126,7 @@ bool GroupCollapser::moveAttributes (XMLElement &source, XMLElement &dest) {
dest.addAttribute("transform", transform);
movedAttributes.emplace_back("transform");
}
- else if (AttributeExtractor::inheritable(attr)) {
+ else if (attr.inheritable()) {
dest.addAttribute(attr.name, attr.value);
movedAttributes.emplace_back(attr.name);
}
diff --git a/dviware/dvisvgm/src/optimizer/Makefile.am b/dviware/dvisvgm/src/optimizer/Makefile.am
index af23fd22a7..cdd802b2ab 100644
--- a/dviware/dvisvgm/src/optimizer/Makefile.am
+++ b/dviware/dvisvgm/src/optimizer/Makefile.am
@@ -10,7 +10,7 @@ liboptimizer_la_SOURCES = \
SVGOptimizer.hpp SVGOptimizer.cpp \
TextSimplifier.hpp TextSimplifier.cpp \
TransformSimplifier.hpp TransformSimplifier.cpp \
- WSNodeRemover.hpp WSNodeRemover.cpp
+ WSNodeRemover.hpp WSNodeRemover.cpp
include ../../libs/defs.am
diff --git a/dviware/dvisvgm/src/optimizer/Makefile.in b/dviware/dvisvgm/src/optimizer/Makefile.in
index 3d7cf25df6..a100cb9d65 100644
--- a/dviware/dvisvgm/src/optimizer/Makefile.in
+++ b/dviware/dvisvgm/src/optimizer/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -95,12 +95,7 @@ target_triplet = @target@
@HAVE_WOFF2_FALSE@am__append_4 = ../libs/woff2/libwoff2.a
subdir = src/optimizer
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
- $(top_srcdir)/m4/ax_code_coverage.m4 \
- $(top_srcdir)/m4/ax_cxx_compile_stdcxx.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)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -202,8 +197,6 @@ am__define_uniq_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)/../../libs/defs.am $(srcdir)/Makefile.in \
$(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -231,6 +224,8 @@ CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -246,8 +241,10 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
+FILECMD = @FILECMD@
FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
FREETYPE_LIBS = @FREETYPE_LIBS@
GCOV = @GCOV@
@@ -377,7 +374,7 @@ liboptimizer_la_SOURCES = \
SVGOptimizer.hpp SVGOptimizer.cpp \
TextSimplifier.hpp TextSimplifier.cpp \
TransformSimplifier.hpp TransformSimplifier.cpp \
- WSNodeRemover.hpp WSNodeRemover.cpp
+ WSNodeRemover.hpp WSNodeRemover.cpp
@HAVE_POTRACE_FALSE@POTRACE_CFLAGS = -I$(dvisvgm_srcdir)/libs/potrace
@HAVE_POTRACE_FALSE@POTRACE_LIBS = ../libs/potrace/libpotrace.a
@@ -397,9 +394,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../../libs/defs.am $(am_
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/optimizer/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/optimizer/Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --foreign src/optimizer/Makefile
+ $(AUTOMAKE) --gnu src/optimizer/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -535,7 +532,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
diff --git a/dviware/dvisvgm/src/optimizer/TextSimplifier.cpp b/dviware/dvisvgm/src/optimizer/TextSimplifier.cpp
index b07db7701b..855d88c101 100644
--- a/dviware/dvisvgm/src/optimizer/TextSimplifier.cpp
+++ b/dviware/dvisvgm/src/optimizer/TextSimplifier.cpp
@@ -40,7 +40,7 @@ static XMLElement::Attributes common_inheritable_attributes (const vector<XMLEle
if (intersected)
break;
for (const auto &attrib : elem->attributes()) {
- if (AttributeExtractor::inheritable(attrib))
+ if (attrib.inheritable())
commonAttribs.push_back(attrib);
}
}
diff --git a/dviware/dvisvgm/src/utility.cpp b/dviware/dvisvgm/src/utility.cpp
index 56f2c17ae7..4877690ef4 100644
--- a/dviware/dvisvgm/src/utility.cpp
+++ b/dviware/dvisvgm/src/utility.cpp
@@ -84,10 +84,10 @@ double math::normalize_0_2pi (double rad) {
* @param[in] ws characters treated as whitespace
* @return the trimmed string */
string util::trim (const std::string &str, const char *ws) {
- size_t first = str.find_first_not_of(ws);
+ auto first = str.find_first_not_of(ws);
if (first == string::npos)
return "";
- size_t last = str.find_last_not_of(ws);
+ auto last = str.find_last_not_of(ws);
return str.substr(first, last-first+1);
}
@@ -99,9 +99,9 @@ string util::trim (const std::string &str, const char *ws) {
* @return the normalized string */
string util::normalize_space (string str, const char *ws) {
str = trim(str);
- size_t first = str.find_first_of(ws);
+ auto first = str.find_first_of(ws);
while (first != string::npos) {
- size_t last = str.find_first_not_of(ws, first);
+ auto last = str.find_first_not_of(ws, first);
str.replace(first, last-first, " ");
first = str.find_first_of(ws, first+1);
}
@@ -116,7 +116,7 @@ string util::normalize_space (string str, const char *ws) {
* @return the resulting string */
string util::replace (string str, const string &find, const string &repl) {
if (!find.empty() && !repl.empty()) {
- size_t first = str.find(find);
+ auto first = str.find(find);
while (first != string::npos) {
str.replace(first, find.length(), repl);
first = str.find(find, first+repl.length());
@@ -136,9 +136,9 @@ vector<string> util::split (const string &str, const string &sep) {
if (str.empty() || sep.empty())
parts.push_back(str);
else {
- size_t left=0;
+ string::size_type left=0;
while (left <= str.length()) {
- size_t right = str.find(sep, left);
+ auto right = str.find(sep, left);
if (right == string::npos) {
parts.push_back(str.substr(left));
left = string::npos;
@@ -164,7 +164,7 @@ string util::tolower (const string &str) {
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');
+ auto pos = str.find_last_not_of('0');
if (pos != string::npos) // trailing zeros
str.erase(pos+1, string::npos);
if (str.back() == '.') // trailing dot?
diff --git a/dviware/dvisvgm/src/utility.hpp b/dviware/dvisvgm/src/utility.hpp
index 9ab0d60542..b8a36daceb 100644
--- a/dviware/dvisvgm/src/utility.hpp
+++ b/dviware/dvisvgm/src/utility.hpp
@@ -137,17 +137,17 @@ inline void base64_copy (std::istream &is, std::ostream &os, int wrap=0) {
* @param[in] args arguments forwarded to an constructor of T */
template<typename T, typename... Args>
std::unique_ptr<T> make_unique (Args&&... args) {
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<typename T, typename U>
std::unique_ptr<T> static_unique_ptr_cast (std::unique_ptr<U> &&old){
- return std::unique_ptr<T>{static_cast<T*>(old.release())};
+ return std::unique_ptr<T>{static_cast<T*>(old.release())};
}
template <typename T>
-struct set_const_of {
+struct set_const_of {
template <typename U>
struct by {
using type = typename std::conditional<
@@ -155,7 +155,7 @@ struct set_const_of {
typename std::add_const<T>::type,
typename std::remove_const<T>::type
>::type;
- };
+ };
};
} // namespace util