diff options
author | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2016-07-04 22:07:54 +0000 |
---|---|---|
committer | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2016-07-04 22:07:54 +0000 |
commit | ab399d16f49b986d1de514b2fb8434872decf91d (patch) | |
tree | 6d3d0faca673d7aa1c0f48ca679ce7841a82e3df /Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp | |
parent | dd2749b37f7b6a9976869e29a028eeab80d686df (diff) |
dvisvgm 1.16
git-svn-id: svn://tug.org/texlive/trunk@41628 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp | 254 |
1 files changed, 35 insertions, 219 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp index 4d41b003ee7..2e4ac726ded 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp @@ -26,6 +26,7 @@ #include "DVIToSVG.h" #include "Font.h" #include "FontManager.h" +#include "SVGCharHandlerFactory.h" #include "SVGTree.h" #include "XMLDocument.h" #include "XMLNode.h" @@ -35,7 +36,7 @@ using namespace std; // static class variables -bool SVGTree::CREATE_STYLE=true; +bool SVGTree::CREATE_CSS=true; bool SVGTree::USE_FONTS=true; bool SVGTree::CREATE_USE_ELEMENTS=false; bool SVGTree::RELATIVE_PATH_CMDS=false; @@ -44,13 +45,17 @@ bool SVGTree::ADD_COMMENTS=false; double SVGTree::ZOOM_FACTOR=1.0; -SVGTree::SVGTree () : _vertical(false), _font(0), _color(Color::BLACK), _matrix(1) { - _xchanged = _ychanged = false; - _fontnum = 0; +SVGTree::SVGTree () { + _charHandler = SVGCharHandlerFactory::createHandler(); reset(); } +SVGTree::~SVGTree () { + delete _charHandler; +} + + /** Clears the SVG tree and initializes the root element. */ void SVGTree::reset () { _doc.clear(); @@ -59,7 +64,7 @@ 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 = _text = _span = _defs = 0; + _page = _defs = 0; } @@ -75,17 +80,17 @@ void SVGTree::setBBox (const BoundingBox &bbox) { void SVGTree::setColor (const Color &c) { - if (!_font.get() || _font.get()->color() == Color::BLACK) - _color.set(c); + const Font *font = _charHandler->getFont(); + if (!font || font->color() == Color::BLACK) + _charHandler->setColor(c); } void SVGTree::setFont (int num, const Font &font) { - _font.set(&font); - _fontnum = num; + _charHandler->setFont(font, num); // set default color assigned to the font - if (font.color() != Color::BLACK && _color.get() != font.color()) - _color.set(font.color()); + if (font.color() != Color::BLACK && getColor() != font.color()) + setColor(font.color()); } @@ -96,9 +101,9 @@ void SVGTree::newPage (int pageno) { if (pageno >= 0) _page->addAttribute("id", string("page")+XMLString(pageno)); _root->append(_page); - _text = _span = 0; - while (!_pageContainerStack.empty()) - _pageContainerStack.pop(); + _charHandler->setInitialContextNode(_page); + while (!_contextElementStack.empty()) + _contextElementStack.pop(); } @@ -112,210 +117,23 @@ void SVGTree::appendToDefs (XMLNode *node) { void SVGTree::appendToPage (XMLNode *node) { - if (_pageContainerStack.empty()) - _page->append(node); - else - _pageContainerStack.top()->append(node); - if (node != _text) // if the appended node differs from the text element currently in use, - _text = 0; // then force creating a new text element for the following characters + XMLElementNode *parent = _contextElementStack.empty() ? _page : _contextElementStack.top(); + parent->append(node); + _charHandler->setInitialContextNode(parent); } void SVGTree::prependToPage (XMLNode *node) { - if (_pageContainerStack.empty()) + if (_contextElementStack.empty()) _page->prepend(node); else - _pageContainerStack.top()->prepend(node); + _contextElementStack.top()->prepend(node); } -/** Appends a single character or its path represenatation to the current context node. - * If necessary, and depending on the selected output mode and further output states, - * new XML elements (text, tspan, g, use, ...) are created. - * @param[in] c character to be added - * @param[in] x x coordinate - * @param[in] y y coordinate - * @param[in] font font to be used */ -void SVGTree::appendChar (int c, double x, double y, const Font &font) { - if (USE_FONTS) - appendCharAsText(c, x, y, font); - else - appendCharAsPath(c, x, y, font); -} - - -/** Appends a single text character to the current context node. - * @param[in] c character to be added - * @param[in] x x coordinate - * @param[in] y y coordinate - * @param[in] font font to be used */ -void SVGTree::appendCharAsText (int c, double x, double y, const Font &font) { - XMLElementNode *node=_span; - // changes of fonts and transformations require a new text element - if (!MERGE_CHARS || !_text || _font.changed() || _matrix.changed() || _vertical.changed()) { - newTextNode(x, y); - node = _text; - _color.changed(true); - } - if (MERGE_CHARS && (_xchanged || _ychanged || (_color.changed() && _color.get() != Color::BLACK))) { - // if drawing position was explicitly changed, create a new tspan element - _span = new XMLElementNode("tspan"); - if (_xchanged) { - if (_vertical) { - // align glyphs designed for horizontal layout properly - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(_font.get())) - if (!pf->getMetrics()->verticalLayout()) - x += pf->scaledAscent()/2.5; // move vertical baseline to the right by strikethrough offset - } - _span->addAttribute("x", x); - _xchanged = false; - } - if (_ychanged) { - _span->addAttribute("y", y); - _ychanged = false; - } - if (_color.get() != font.color()) { - _span->addAttribute("fill", _color.get().svgColorString()); - _color.changed(false); - } - _text->append(_span); - node = _span; - } - if (!node) { - if (!_text) - newTextNode(x, y); - node = _text; - } - node->append(XMLString(font.unicode(c), false)); - if (!MERGE_CHARS && _color.get() != font.color()) { - node->addAttribute("fill", _color.get().svgColorString()); - _color.changed(false); - } -} - - -/** Appends a reference to the path representation of a single character to - * the current context node. - * @param[in] c character to be added - * @param[in] x x coordinate - * @param[in] y y coordinate - * @param[in] font font to be used */ -void SVGTree::appendCharAsPath (int c, double x, double y, const Font &font) { - XMLElementNode *node=_span; - if (_color.changed() || _matrix.changed()) { - bool set_color = (_color.changed() && _color.get() != Color::BLACK); - bool set_matrix = (_matrix.changed() && !_matrix.get().isIdentity()); - if (set_color || set_matrix) { - _span = new XMLElementNode("g"); - if (_color.get() != Color::BLACK) - _span->addAttribute("fill", _color.get().svgColorString()); - if (!_matrix.get().isIdentity()) - _span->addAttribute("transform", _matrix.get().getSVG()); - appendToPage(_span); - node = _span; - _color.changed(false); - _matrix.changed(false); - } - else if (_color.get() == Color::BLACK && _matrix.get().isIdentity()) - node = _span = 0; - } - if (!node) - node = _pageContainerStack.empty() ? _page : _pageContainerStack.top(); - if (font.verticalLayout()) { - // move glyph graphics so that its origin is located at the top center position - GlyphMetrics metrics; - font.getGlyphMetrics(c, _vertical, metrics); - x -= metrics.wl; - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(&font)) { - // Center glyph between top and bottom border of the TFM box. - // This is just an approximation used until I find a way to compute - // the exact location in vertical mode. - GlyphMetrics exact_metrics; - pf->getExactGlyphBox(c, exact_metrics, false); - y += exact_metrics.h+(metrics.d-exact_metrics.h-exact_metrics.d)/2; - } - else - y += metrics.d; - } - Matrix rotation(1); - if (_vertical && !font.verticalLayout()) { - // alphabetic text designed for horizontal mode - // must be rotated by 90 degrees if in vertical mode - rotation.translate(-x, -y); - rotation.rotate(90); - rotation.translate(x, y); - } - if (CREATE_USE_ELEMENTS) { - ostringstream oss; - oss << "#g" << FontManager::instance().fontID(_font) << '-' << c; - XMLElementNode *use = new XMLElementNode("use"); - use->addAttribute("x", XMLString(x)); - use->addAttribute("y", XMLString(y)); - use->addAttribute("xlink:href", oss.str()); - if (!rotation.isIdentity()) - use->addAttribute("transform", rotation.getSVG()); - node->append(use); - } - else { - Glyph glyph; - const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(&font); - if (pf && pf->getGlyph(c, glyph)) { - double sx = pf->scaledSize()/pf->unitsPerEm(); - double sy = -sx; - ostringstream oss; - glyph.writeSVG(oss, RELATIVE_PATH_CMDS, sx, sy, x, y); - XMLElementNode *glyph_node = new XMLElementNode("path"); - glyph_node->addAttribute("d", oss.str()); - if (!rotation.isIdentity()) - glyph_node->addAttribute("transform", rotation.getSVG()); - node->append(glyph_node); - } - } -} - - -/** Creates a new text element. This is a helper function used by appendChar(). - * @param[in] x current x coordinate - * @param[in] y current y coordinate */ -void SVGTree::newTextNode (double x, double y) { - _text = new XMLElementNode("text"); - _span = 0; // no tspan in text element yet - if (USE_FONTS) { - const Font *font = _font.get(); - if (CREATE_STYLE || !font) - _text->addAttribute("class", string("f")+XMLString(_fontnum)); - else { - _text->addAttribute("font-family", font->name()); - _text->addAttribute("font-size", XMLString(font->scaledSize())); - if (font->color() != Color::BLACK) - _text->addAttribute("fill", font->color().svgColorString()); - } - if (_vertical) { - _text->addAttribute("writing-mode", "tb"); - // align glyphs designed for horizontal layout properly - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(_font.get())) - if (!pf->getMetrics()->verticalLayout()) { // alphabetic text designed for horizontal layout? - x += pf->scaledAscent()/2.5; // move vertical baseline to the right by strikethrough offset - _text->addAttribute("glyph-orientation-vertical", 90); // ensure rotation - } - } - } - _text->addAttribute("x", x); - _text->addAttribute("y", y); - if (!_matrix.get().isIdentity()) - _text->addAttribute("transform", _matrix.get().getSVG()); - appendToPage(_text); - _vertical.changed(false); - _font.changed(false); - _matrix.changed(false); - _xchanged = false; - _ychanged = false; -} - - -void SVGTree::transformPage (const Matrix *usermatrix) { - if (usermatrix && !usermatrix->isIdentity()) - _page->addAttribute("transform", usermatrix->getSVG()); +void SVGTree::transformPage (const Matrix &usermatrix) { + if (!usermatrix.isIdentity()) + _page->addAttribute("transform", usermatrix.getSVG()); } @@ -375,7 +193,7 @@ static string font_info (const Font &font) { void SVGTree::appendFontStyles (const set<const Font*> &fonts) { - if (CREATE_STYLE && USE_FONTS && !fonts.empty() && _defs) { + if (CREATE_CSS && USE_FONTS && !fonts.empty() && _defs) { XMLElementNode *styleNode = new XMLElementNode("style"); styleNode->addAttribute("type", "text/css"); _root->insertAfter(styleNode, _defs); @@ -468,21 +286,20 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr /** Pushes a new context element that will take all following nodes added to the page. */ void SVGTree::pushContextElement (XMLElementNode *node) { - if (_pageContainerStack.empty()) + if (_contextElementStack.empty()) _page->append(node); else - _pageContainerStack.top()->append(node); - _pageContainerStack.push(node); - _text = _span = 0; // ensure the creation of a new text element for the following characters added + _contextElementStack.top()->append(node); + _contextElementStack.push(node); + _charHandler->setInitialContextNode(node); } /** Pops the current context element and restored the previous one. */ void SVGTree::popContextElement () { - if (!_pageContainerStack.empty()) { - _pageContainerStack.pop(); - _text = _span = 0; // ensure the creation of a new text element for the following characters added - } + if (!_contextElementStack.empty()) + _contextElementStack.pop(); + _charHandler->setInitialContextNode(_page); } @@ -525,4 +342,3 @@ void SVGTree::removeRedundantElements () { _defs->remove(node); } } - |