diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvisvgm/src/optimizer |
Initial commit
Diffstat (limited to 'dviware/dvisvgm/src/optimizer')
-rw-r--r-- | dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp | 176 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp | 64 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/DependencyGraph.hpp | 133 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/GroupCollapser.cpp | 165 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/GroupCollapser.hpp | 36 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/Makefile.am | 12 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/Makefile.in | 690 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/OptimizerModule.hpp | 30 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/RedundantElementRemover.cpp | 68 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/RedundantElementRemover.hpp | 29 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/SVGOptimizer.cpp | 105 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/SVGOptimizer.hpp | 59 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/TransformSimplifier.cpp | 149 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/TransformSimplifier.hpp | 36 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/WSNodeRemover.cpp | 45 | ||||
-rw-r--r-- | dviware/dvisvgm/src/optimizer/WSNodeRemover.hpp | 30 |
16 files changed, 1827 insertions, 0 deletions
diff --git a/dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp b/dviware/dvisvgm/src/optimizer/AttributeExtractor.cpp new file mode 100644 index 0000000000..ae2a0e36d7 --- /dev/null +++ b/dviware/dvisvgm/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 constexpr auto names = util::make_array( + "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(names.begin(), names.end(), 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 constexpr auto names = util::make_array( + "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(names.begin(), names.end(), 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 constexpr auto names = util::make_array( + "animate", "animateColor", "animateMotion", "animateTransform", "set" + ); + auto it = find_if(names.begin(), names.end(), [&](const string &name) { + return element.name() == name; + }); + return it == names.end(); +} + + +/** 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/dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp b/dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp new file mode 100644 index 0000000000..8cb9de5bab --- /dev/null +++ b/dviware/dvisvgm/src/optimizer/AttributeExtractor.hpp @@ -0,0 +1,64 @@ +/************************************************************************* +** 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 { + friend class GroupCollapser; + 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;} +// XMLNodeIterator begin () {return XMLNodeIterator(_first);} +// XMLNodeIterator end () {return XMLNodeIterator(_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; + + protected: + void execute (XMLElement *context, bool recurse); + XMLNode* extractAttribute (XMLElement *elem); + bool extracted (const Attribute &attr) const; + static bool groupable (const XMLElement &elem); + static bool inheritable (const Attribute &attrib); + static bool extractable (const Attribute &attr, XMLElement &element); + + private: + std::set<std::string> _extractedAttributes; + static constexpr int MIN_RUN_LENGTH = 3; +}; + diff --git a/dviware/dvisvgm/src/optimizer/DependencyGraph.hpp b/dviware/dvisvgm/src/optimizer/DependencyGraph.hpp new file mode 100644 index 0000000000..c9111b43d5 --- /dev/null +++ b/dviware/dvisvgm/src/optimizer/DependencyGraph.hpp @@ -0,0 +1,133 @@ +/************************************************************************* +** DependencyGraph.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/>. ** +*************************************************************************/ + +#ifndef DEPENDENCYGRAPH_HPP +#define DEPENDENCYGRAPH_HPP + +#include <map> +#include <memory> +#include <set> +#include <vector> +#include "../utility.hpp" + +template <typename T> +class DependencyGraph { + struct GraphNode { + explicit GraphNode (const T &k) : key(k), dependent() {} + + void addDependee (GraphNode *node) { + if (node) { + node->dependent = this; + dependees.insert(node); + } + } + + void unlinkDependees () { + for (GraphNode *dependee : dependees) + dependee->dependent = nullptr; + dependees.clear(); + } + + void unlinkDependee (GraphNode *dependee) { + auto it = dependees.find(dependee); + if (it != dependees.end()) { + (*it)->dependent = nullptr; + dependees.erase(it); + } + } + + T key; + GraphNode *dependent; + std::set<GraphNode*> dependees; + }; + + using NodeMap = std::map<T, std::unique_ptr<GraphNode>>; + + public: + /** Inserts a new isolated node into the dependency graph. */ + void insert (const T &key) { + if (!contains(key)) + _nodeMap.emplace(key, util::make_unique<GraphNode>(key)); + } + + /** Inserts a new node to the graph and adds a dependency on an existing one to it. + * @param[in] key ID of new node to insert + * @param[in] dependantKey ID of node the new node should depend on */ + void insert (const T &dependentKey, const T &key) { + if (!contains(key)) { + auto dependentIter = _nodeMap.find(dependentKey); + if (dependentIter != _nodeMap.end()) { + auto node = util::make_unique<GraphNode>(key); + dependentIter->second->addDependee(node.get()); + _nodeMap.emplace(key, std::move(node)); + } + } + } + + /** Removes a node and all its dependents from the graph. */ + void removeDependencyPath (const T &key) { + auto it = _nodeMap.find(key); + if (it != _nodeMap.end()) { + for (GraphNode *node = it->second.get(); node;) { + GraphNode *dependent = node->dependent; + node->unlinkDependees(); + if (dependent) + dependent->unlinkDependee(node); + _nodeMap.erase(node->key); + node = dependent; + } + } + } + + /** Returns the IDs of all nodes present in the graph. */ + std::vector<T> getKeys () const { + std::vector<T> keys; + for (auto &entry : _nodeMap) + keys.emplace_back(entry.first); + return keys; + } + + bool contains (const T &value) const { + return _nodeMap.find(value) != _nodeMap.end(); + } + + bool empty () const { + return _nodeMap.empty(); + } + +#if 0 + void writeDOT (std::ostream &os) const { + os << "digraph {\n"; + for (auto it=_nodeMap.begin(); it != _nodeMap.end(); ++it) { + GraphNode *node = it->second; + if (node->dependent) + os << (node->key) << " -> " << (node->dependent->key) << ";\n"; + else if (node->dependees.empty()) + os << (node->key) << ";\n"; + } + os << "}\n"; + } +#endif + + private: + NodeMap _nodeMap; +}; + +#endif diff --git a/dviware/dvisvgm/src/optimizer/GroupCollapser.cpp b/dviware/dvisvgm/src/optimizer/GroupCollapser.cpp new file mode 100644 index 0000000000..5d580f5ba0 --- /dev/null +++ b/dviware/dvisvgm/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 constexpr auto names = util::make_array( + "animate", "animateColor", "animateMotion", "animateTransform", "set" + ); + auto it = find_if(names.begin(), names.end(), [&](const string &name) { + return element.name() == name; + }); + return it == names.end(); +} + + +/** 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 constexpr auto attribs = util::make_array( + "class", "id", "filter", "mask", "style" + ); + auto it = find_if(attribs.begin(), attribs.end(), [&](const string &name) { + return source.hasAttribute(name) || dest.hasAttribute(name); + }); + return it == attribs.end(); +} diff --git a/dviware/dvisvgm/src/optimizer/GroupCollapser.hpp b/dviware/dvisvgm/src/optimizer/GroupCollapser.hpp new file mode 100644 index 0000000000..8f8a22d4ba --- /dev/null +++ b/dviware/dvisvgm/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: + bool moveAttributes (XMLElement &source, XMLElement &dest); + static bool collapsible (const XMLElement &elem); + static bool unwrappable (const XMLElement &source, const XMLElement &dest); +}; diff --git a/dviware/dvisvgm/src/optimizer/Makefile.am b/dviware/dvisvgm/src/optimizer/Makefile.am new file mode 100644 index 0000000000..41c0266009 --- /dev/null +++ b/dviware/dvisvgm/src/optimizer/Makefile.am @@ -0,0 +1,12 @@ +noinst_LTLIBRARIES = liboptimizer.la + +liboptimizer_la_SOURCES = \ + AttributeExtractor.hpp AttributeExtractor.cpp \ + DependencyGraph.hpp \ + GroupCollapser.hpp GroupCollapser.cpp \ + OptimizerModule.hpp \ + RedundantElementRemover.hpp RedundantElementRemover.cpp \ + SVGOptimizer.hpp SVGOptimizer.cpp \ + TransformSimplifier.hpp TransformSimplifier.cpp \ + WSNodeRemover.hpp WSNodeRemover.cpp + diff --git a/dviware/dvisvgm/src/optimizer/Makefile.in b/dviware/dvisvgm/src/optimizer/Makefile.in new file mode 100644 index 0000000000..64b288a723 --- /dev/null +++ b/dviware/dvisvgm/src/optimizer/Makefile.in @@ -0,0 +1,690 @@ +# 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@ +target_triplet = @target@ +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__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 = +LTLIBRARIES = $(noinst_LTLIBRARIES) +liboptimizer_la_LIBADD = +am_liboptimizer_la_OBJECTS = AttributeExtractor.lo GroupCollapser.lo \ + RedundantElementRemover.lo SVGOptimizer.lo \ + TransformSimplifier.lo WSNodeRemover.lo +liboptimizer_la_OBJECTS = $(am_liboptimizer_la_OBJECTS) +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 = +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)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/AttributeExtractor.Plo \ + ./$(DEPDIR)/GroupCollapser.Plo \ + ./$(DEPDIR)/RedundantElementRemover.Plo \ + ./$(DEPDIR)/SVGOptimizer.Plo \ + ./$(DEPDIR)/TransformSimplifier.Plo \ + ./$(DEPDIR)/WSNodeRemover.Plo +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +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 = +CXXLD = $(CXX) +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_la_SOURCES) +DIST_SOURCES = $(liboptimizer_la_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)/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@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BROTLI_CFLAGS = @BROTLI_CFLAGS@ +BROTLI_LIBS = @BROTLI_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@ +CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@ +CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@ +CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@ +CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@ +CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATE = @DATE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +GCOV = @GCOV@ +GENHTML = @GENHTML@ +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@ +KPSE_CFLAGS = @KPSE_CFLAGS@ +KPSE_LIBS = @KPSE_LIBS@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +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@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TTFAUTOHINT_CFLAGS = @TTFAUTOHINT_CFLAGS@ +TTFAUTOHINT_LIBS = @TTFAUTOHINT_LIBS@ +VERSION = @VERSION@ +WOFF2_CFLAGS = @WOFF2_CFLAGS@ +WOFF2_LIBS = @WOFF2_LIBS@ +XMLTO = @XMLTO@ +XSLTPROC = @XSLTPROC@ +ZLIB_CFLAGS = @ZLIB_CFLAGS@ +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 = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = liboptimizer.la +liboptimizer_la_SOURCES = \ + AttributeExtractor.hpp AttributeExtractor.cpp \ + DependencyGraph.hpp \ + GroupCollapser.hpp GroupCollapser.cpp \ + OptimizerModule.hpp \ + RedundantElementRemover.hpp RedundantElementRemover.cpp \ + SVGOptimizer.hpp SVGOptimizer.cpp \ + TransformSimplifier.hpp TransformSimplifier.cpp \ + WSNodeRemover.hpp WSNodeRemover.cpp + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(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 src/optimizer/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign 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: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +liboptimizer.la: $(liboptimizer_la_OBJECTS) $(liboptimizer_la_DEPENDENCIES) $(EXTRA_liboptimizer_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(liboptimizer_la_OBJECTS) $(liboptimizer_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AttributeExtractor.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GroupCollapser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RedundantElementRemover.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SVGOptimizer.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransformSimplifier.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WSNodeRemover.Plo@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 $(LTLIBRARIES) +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-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/AttributeExtractor.Plo + -rm -f ./$(DEPDIR)/GroupCollapser.Plo + -rm -f ./$(DEPDIR)/RedundantElementRemover.Plo + -rm -f ./$(DEPDIR)/SVGOptimizer.Plo + -rm -f ./$(DEPDIR)/TransformSimplifier.Plo + -rm -f ./$(DEPDIR)/WSNodeRemover.Plo + -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.Plo + -rm -f ./$(DEPDIR)/GroupCollapser.Plo + -rm -f ./$(DEPDIR)/RedundantElementRemover.Plo + -rm -f ./$(DEPDIR)/SVGOptimizer.Plo + -rm -f ./$(DEPDIR)/TransformSimplifier.Plo + -rm -f ./$(DEPDIR)/WSNodeRemover.Plo + -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-noinstLTLIBRARIES \ + 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/dviware/dvisvgm/src/optimizer/OptimizerModule.hpp b/dviware/dvisvgm/src/optimizer/OptimizerModule.hpp new file mode 100644 index 0000000000..ff4fec1b4d --- /dev/null +++ b/dviware/dvisvgm/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/dviware/dvisvgm/src/optimizer/RedundantElementRemover.cpp b/dviware/dvisvgm/src/optimizer/RedundantElementRemover.cpp new file mode 100644 index 0000000000..85d8e5b1fa --- /dev/null +++ b/dviware/dvisvgm/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/dviware/dvisvgm/src/optimizer/RedundantElementRemover.hpp b/dviware/dvisvgm/src/optimizer/RedundantElementRemover.hpp new file mode 100644 index 0000000000..dd46cfeba5 --- /dev/null +++ b/dviware/dvisvgm/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/dviware/dvisvgm/src/optimizer/SVGOptimizer.cpp b/dviware/dvisvgm/src/optimizer/SVGOptimizer.cpp new file mode 100644 index 0000000000..31cfeff6ff --- /dev/null +++ b/dviware/dvisvgm/src/optimizer/SVGOptimizer.cpp @@ -0,0 +1,105 @@ +/************************************************************************* +** 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 "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("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/dviware/dvisvgm/src/optimizer/SVGOptimizer.hpp b/dviware/dvisvgm/src/optimizer/SVGOptimizer.hpp new file mode 100644 index 0000000000..809f1f497c --- /dev/null +++ b/dviware/dvisvgm/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/dviware/dvisvgm/src/optimizer/TransformSimplifier.cpp b/dviware/dvisvgm/src/optimizer/TransformSimplifier.cpp new file mode 100644 index 0000000000..06d28926d4 --- /dev/null +++ b/dviware/dvisvgm/src/optimizer/TransformSimplifier.cpp @@ -0,0 +1,149 @@ +/************************************************************************* +** 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 "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); + 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); + } +} + + +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/dviware/dvisvgm/src/optimizer/TransformSimplifier.hpp b/dviware/dvisvgm/src/optimizer/TransformSimplifier.hpp new file mode 100644 index 0000000000..40ac21a465 --- /dev/null +++ b/dviware/dvisvgm/src/optimizer/TransformSimplifier.hpp @@ -0,0 +1,36 @@ +/************************************************************************* +** TransformSimplifier.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 <string> +#include "OptimizerModule.hpp" + +class Matrix; + +class TransformSimplifier : public OptimizerModule { + public: + void execute (XMLElement*, XMLElement *context) override {execute(context);} + void execute (XMLElement *context); + const char* info () const override; + + protected: + std::string decompose (const Matrix &matrix); +}; diff --git a/dviware/dvisvgm/src/optimizer/WSNodeRemover.cpp b/dviware/dvisvgm/src/optimizer/WSNodeRemover.cpp new file mode 100644 index 0000000000..2135e285bb --- /dev/null +++ b/dviware/dvisvgm/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/dviware/dvisvgm/src/optimizer/WSNodeRemover.hpp b/dviware/dvisvgm/src/optimizer/WSNodeRemover.hpp new file mode 100644 index 0000000000..c4fe7f989e --- /dev/null +++ b/dviware/dvisvgm/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; +}; |