diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp | 181 |
1 files changed, 107 insertions, 74 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp index 2e4ac726ded..5a88650b864 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp @@ -2,7 +2,7 @@ ** SVGTree.cpp ** ** ** ** This file is part of dvisvgm -- a fast DVI to SVG converter ** -** Copyright (C) 2005-2016 Martin Gieseking <martin.gieseking@uos.de> ** +** Copyright (C) 2005-2017 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 ** @@ -20,17 +20,20 @@ #include <config.h> #include <algorithm> +#include <array> #include <sstream> -#include "BoundingBox.h" -#include "DependencyGraph.h" -#include "DVIToSVG.h" -#include "Font.h" -#include "FontManager.h" -#include "SVGCharHandlerFactory.h" -#include "SVGTree.h" -#include "XMLDocument.h" -#include "XMLNode.h" -#include "XMLString.h" +#include "BoundingBox.hpp" +#include "DependencyGraph.hpp" +#include "DVIToSVG.hpp" +#include "FileSystem.hpp" +#include "Font.hpp" +#include "FontManager.hpp" +#include "FontWriter.hpp" +#include "SVGCharHandlerFactory.hpp" +#include "SVGTree.hpp" +#include "XMLDocument.hpp" +#include "XMLNode.hpp" +#include "XMLString.hpp" using namespace std; @@ -38,6 +41,7 @@ using namespace std; // static class variables bool SVGTree::CREATE_CSS=true; bool SVGTree::USE_FONTS=true; +FontWriter::FontFormat SVGTree::FONT_FORMAT = FontWriter::FontFormat::SVG; bool SVGTree::CREATE_USE_ELEMENTS=false; bool SVGTree::RELATIVE_PATH_CMDS=false; bool SVGTree::MERGE_CHARS=true; @@ -46,16 +50,11 @@ double SVGTree::ZOOM_FACTOR=1.0; SVGTree::SVGTree () { - _charHandler = SVGCharHandlerFactory::createHandler(); + _charHandler.reset(SVGCharHandlerFactory::createHandler()); reset(); } -SVGTree::~SVGTree () { - delete _charHandler; -} - - /** Clears the SVG tree and initializes the root element. */ void SVGTree::reset () { _doc.clear(); @@ -64,7 +63,8 @@ void SVGTree::reset () { _root->addAttribute("xmlns", "http://www.w3.org/2000/svg"); _root->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); _doc.setRootNode(_root); - _page = _defs = 0; + _page = _defs = nullptr; + _styleCDataNode = nullptr; } @@ -94,6 +94,22 @@ void SVGTree::setFont (int num, const Font &font) { } +bool SVGTree::setFontFormat (string formatstr) { + size_t pos = formatstr.find(','); + string opt; + if (pos != string::npos) { + opt = formatstr.substr(pos+1); + formatstr = formatstr.substr(0, pos); + } + FontWriter::FontFormat format = FontWriter::toFontFormat(formatstr); + if (format == FontWriter::FontFormat::UNKNOWN) + return false; + FONT_FORMAT = format; + FontWriter::AUTOHINT_FONTS = (opt == "autohint" || opt == "ah"); + return true; +} + + /** Starts a new page. * @param[in] pageno number of new page */ void SVGTree::newPage (int pageno) { @@ -193,33 +209,30 @@ static string font_info (const Font &font) { void SVGTree::appendFontStyles (const set<const Font*> &fonts) { - if (CREATE_CSS && USE_FONTS && !fonts.empty() && _defs) { - XMLElementNode *styleNode = new XMLElementNode("style"); - styleNode->addAttribute("type", "text/css"); - _root->insertAfter(styleNode, _defs); - typedef map<int, const Font*> SortMap; - SortMap sortmap; - FORALL(fonts, set<const Font*>::const_iterator, it) - if (!dynamic_cast<const VirtualFont*>(*it)) // skip virtual fonts - sortmap[FontManager::instance().fontID(*it)] = *it; + if (CREATE_CSS && USE_FONTS && !fonts.empty() && _page) { + map<int, const Font*> sortmap; + for (const Font *font : fonts) + if (!dynamic_cast<const VirtualFont*>(font)) // skip virtual fonts + sortmap[FontManager::instance().fontID(font)] = font; ostringstream style; // add font style definitions in ascending order - FORALL(sortmap, SortMap::const_iterator, it) { - style << "text.f" << it->first << ' ' - << "{font-family:" << it->second->name() - << ";font-size:" << XMLString(it->second->scaledSize()) << "px"; - if (it->second->color() != Color::BLACK) - style << ";fill:" << it->second->color().svgColorString(); - style << '}'; - if (ADD_COMMENTS) { - string info = font_info(*it->second); - if (!info.empty()) - style << " /* " << info << " */"; + for (auto &idfontpair : sortmap) { + if (CREATE_CSS) { + style << "text.f" << idfontpair.first << ' ' + << "{font-family:" << idfontpair.second->name() + << ";font-size:" << XMLString(idfontpair.second->scaledSize()) << "px"; + if (idfontpair.second->color() != Color::BLACK) + style << ";fill:" << idfontpair.second->color().svgColorString(); + style << '}'; + if (ADD_COMMENTS) { + string info = font_info(*idfontpair.second); + if (!info.empty()) + style << " /* " << info << " */"; + } + style << '\n'; } - style << '\n'; } - XMLCDataNode *cdata = new XMLCDataNode(style.str()); - styleNode->append(cdata); + styleCDataNode()->append(style.str()); } } @@ -227,46 +240,54 @@ void SVGTree::appendFontStyles (const set<const Font*> &fonts) { /** Appends glyph definitions of a given font to the defs section of the SVG tree. * @param[in] font font to be appended * @param[in] chars codes of the characters whose glyph outlines should be appended - * @param[in] cb pointer to callback object for sending feedback to the glyph tracer (may be 0) */ -void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTracer::Callback *cb) { + * @param[in] callback pointer to callback object for sending feedback to the glyph tracer (may be 0) */ +void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTracer::Callback *callback) { if (chars.empty()) return; if (USE_FONTS) { - if (ADD_COMMENTS) { - string info = font_info(font); - if (!info.empty()) - appendToDefs(new XMLCommentNode(string(" font: ")+info+" ")); + if (FONT_FORMAT != FontWriter::FontFormat::SVG) { + ostringstream style; + FontWriter fontWriter(font); + if (fontWriter.writeCSSFontFace(FONT_FORMAT, chars, style, callback)) + styleCDataNode()->append(style.str()); } - XMLElementNode *fontNode = new XMLElementNode("font"); - string fontname = font.name(); - fontNode->addAttribute("id", fontname); - fontNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance())); - appendToDefs(fontNode); - - XMLElementNode *faceNode = new XMLElementNode("font-face"); - faceNode->addAttribute("font-family", fontname); - faceNode->addAttribute("units-per-em", XMLString(font.unitsPerEm())); - if (font.type() != PhysicalFont::MF && !font.verticalLayout()) { - faceNode->addAttribute("ascent", XMLString(font.ascent())); - faceNode->addAttribute("descent", XMLString(font.descent())); + else { + if (ADD_COMMENTS) { + string info = font_info(font); + if (!info.empty()) + appendToDefs(new XMLCommentNode(string(" font: ")+info+" ")); + } + XMLElementNode *fontNode = new XMLElementNode("font"); + string fontname = font.name(); + fontNode->addAttribute("id", fontname); + fontNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance())); + appendToDefs(fontNode); + + XMLElementNode *faceNode = new XMLElementNode("font-face"); + faceNode->addAttribute("font-family", fontname); + faceNode->addAttribute("units-per-em", XMLString(font.unitsPerEm())); + if (!font.verticalLayout()) { + faceNode->addAttribute("ascent", XMLString(font.ascent())); + faceNode->addAttribute("descent", XMLString(font.descent())); + } + fontNode->append(faceNode); + for (int c : chars) + fontNode->append(createGlyphNode(c, font, callback)); } - fontNode->append(faceNode); - FORALL(chars, set<int>::const_iterator, i) - fontNode->append(createGlyphNode(*i, font, cb)); } else if (CREATE_USE_ELEMENTS && &font != font.uniqueFont()) { // If the same character is used in various sizes, we don't want to embed the complete (lengthy) path // descriptions multiple times. Because they would only differ by a scale factor, it's better to // reference the already embedded path together with a transformation attribute and let the SVG renderer // scale the glyphs properly. This is only necessary if we don't want to use font but path elements. - FORALL(chars, set<int>::const_iterator, it) { + for (int c : chars) { ostringstream oss; XMLElementNode *use = new XMLElementNode("use"); - oss << 'g' << FontManager::instance().fontID(&font) << '-' << *it; + oss << 'g' << FontManager::instance().fontID(&font) << '-' << c; use->addAttribute("id", oss.str()); oss.str(""); - oss << "#g" << FontManager::instance().fontID(font.uniqueFont()) << '-' << *it; + oss << "#g" << FontManager::instance().fontID(font.uniqueFont()) << '-' << c; use->addAttribute("xlink:href", oss.str()); double scale = font.scaledSize()/font.uniqueFont()->scaledSize(); if (scale != 1.0) { @@ -278,8 +299,8 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr } } else { - FORALL(chars, set<int>::const_iterator, i) - appendToDefs(createGlyphNode(*i, font, cb)); + for (int c : chars) + appendToDefs(createGlyphNode(c, font, callback)); } } @@ -318,9 +339,9 @@ void SVGTree::removeRedundantElements () { // collect dependencies between clipPath elements in the defs section of the SVG tree DependencyGraph<string> idTree; - for (vector<XMLElementNode*>::iterator it=clipElements.begin(); it != clipElements.end(); ++it) { - if (const char *id = (*it)->getAttributeValue("id")) { - if (const char *url = (*it)->getAttributeValue("clip-path")) + for (const XMLElementNode *clip : clipElements) { + 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); @@ -330,15 +351,27 @@ void SVGTree::removeRedundantElements () { vector<XMLElementNode*> descendants; _page->getDescendants(0, "clip-path", descendants); // remove referenced IDs and their dependencies from the dependency graph - for (vector<XMLElementNode*>::iterator it=descendants.begin(); it != descendants.end(); ++it) { - string idref = extract_id_from_url((*it)->getAttributeValue("clip-path")); + for (const XMLElementNode *elem : descendants) { + string idref = extract_id_from_url(elem->getAttributeValue("clip-path")); idTree.removeDependencyPath(idref); } descendants.clear(); vector<string> ids; idTree.getKeys(ids); - for (vector<string>::iterator it=ids.begin(); it != ids.end(); ++it) { - XMLElementNode *node = _defs->getFirstDescendant("clipPath", "id", it->c_str()); + for (const string &str : ids) { + XMLElementNode *node = _defs->getFirstDescendant("clipPath", "id", str.c_str()); _defs->remove(node); } } + + +XMLCDataNode* SVGTree::styleCDataNode () { + if (!_styleCDataNode) { + XMLElementNode *styleNode = new XMLElementNode("style"); + styleNode->addAttribute("type", "text/css"); + _root->insertBefore(styleNode, _page); + _styleCDataNode = new XMLCDataNode; + styleNode->append(_styleCDataNode); + } + return _styleCDataNode; +}
\ No newline at end of file |