diff options
author | Peter Breitenlohner <peb@mppmu.mpg.de> | 2009-11-13 14:43:15 +0000 |
---|---|---|
committer | Peter Breitenlohner <peb@mppmu.mpg.de> | 2009-11-13 14:43:15 +0000 |
commit | 4b03955aab00a38ad11244687daec832f83a350a (patch) | |
tree | 0d638f8a003f7c17642ca0b11779ba01779870ae /Build/source/texk/dvisvgm/dvisvgm-0.8.7/src/SVGFontTraceEmitter.cpp | |
parent | 56cd2a40f239fb8a84ff7fcfa393f449bec2d41d (diff) |
Import dvisvgm-0.8.7
git-svn-id: svn://tug.org/texlive/trunk@16003 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-0.8.7/src/SVGFontTraceEmitter.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-0.8.7/src/SVGFontTraceEmitter.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-0.8.7/src/SVGFontTraceEmitter.cpp b/Build/source/texk/dvisvgm/dvisvgm-0.8.7/src/SVGFontTraceEmitter.cpp new file mode 100644 index 00000000000..e7da9986581 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-0.8.7/src/SVGFontTraceEmitter.cpp @@ -0,0 +1,213 @@ +/************************************************************************* +** SVGFontTraceEmitter.cpp ** +** ** +** This file is part of dvisvgm -- the DVI to SVG converter ** +** Copyright (C) 2005-2009 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** This program is free software; you can redistribute it and/or ** +** modify it under the terms of the GNU General Public License as ** +** published by the Free Software Foundation; either version 3 of ** +** the License, or (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, but ** +** WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program; if not, see <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <cstring> +#include <fstream> +#include <iostream> +#include <sstream> +#include <string> +#include "Font.h" +#include "FontCache.h" +#include "FontManager.h" +#include "GFGlyphTracer.h" +#include "macros.h" +#include "Message.h" +#include "MetafontWrapper.h" +#include "SVGFontTraceEmitter.h" +#include "SVGTree.h" +#include "TFM.h" +#include "XMLNode.h" +#include "XMLString.h" + +using namespace std; + +const char *SVGFontTraceEmitter::CACHE_PATH = 0; +bool SVGFontTraceEmitter::TRACE_ALL = false; +double SVGFontTraceEmitter::METAFONT_MAG = 4; + + +SVGFontTraceEmitter::SVGFontTraceEmitter (const Font *f, const FontManager &fm, const CharmapTranslator &cmt, SVGTree &svg, bool uf) + : _gfTracer(0), _in(0), _font(f), _fontManager(fm), _cache(0), + _charmapTranslator(cmt), _svg(svg), _glyphNode(0), _useFonts(uf) +{ + if (CACHE_PATH && _font) { + _cache = new FontCache; + if (TRACE_ALL && prepareTracer()) { + traceAllGlyphs(); + _cache->write(_font->name().c_str(), CACHE_PATH); + } + else + _cache->read(_font->name().c_str(), CACHE_PATH); + } +} + + +SVGFontTraceEmitter::~SVGFontTraceEmitter () { + delete _gfTracer; + delete _in; + if (_cache && _font) + _cache->write(_font->name().c_str(), CACHE_PATH); + delete _cache; + MetafontWrapper::removeOutputFiles(_font->name()); +} + + +/** Creates the tracer object and calls Metafont to generate a GF file of the current font. + * @return true if GF file tracer were successfully created */ +bool SVGFontTraceEmitter::prepareTracer () { + if (!_gfTracer) { + MetafontWrapper mf(_font->name()); + mf.make("ljfour", METAFONT_MAG); // call Metafont if necessary + if (mf.success() && _font->getTFM()) { + _in = new ifstream((_font->name()+".gf").c_str(), ios_base::binary); + _gfTracer = new GFGlyphTracer(*_in, 1000.0/_font->getTFM()->getDesignSize()); // 1000 units per em + Message::mstream() << "tracing glyphs of " << _font->name() << endl; + } + else { + Message::wstream(true) << "unable to find " << _font->name() << ".mf, can't embed font\n"; + return false; // Metafont failed + } + } + return true; +} + + +int SVGFontTraceEmitter::emitFont (const char *id) { + // @@ not needed at the moment + return 0; +} + + +/** Appends a new font element of the current font to the SVG document. + * @param[in] usedChars characters to be embedded + * @param[in] id unique font identifier (usually the font name) + * @return number of embedded glyphs */ +int SVGFontTraceEmitter::emitFont (const set<int> &usedChars, const char *id) { + return emitFont(&usedChars, id); +} + + +/** Appends a new font element of the current font to the SVG document. + * @param[in] usedChars characters to be embedded + * @param[in] id unique font identifier (usually the font name) + * @return number of embedded glyphs */ +int SVGFontTraceEmitter::emitFont (const set<int> *usedChars, const char *id) { + if (!usedChars || usedChars->empty()) + return 0; + + XMLElementNode *fontNode=0; + if (_useFonts) { + fontNode = new XMLElementNode("font"); + if (id && strlen(id) > 0) + fontNode->addAttribute("id", id); + _svg.appendToDefs(fontNode); + + XMLElementNode *faceNode = new XMLElementNode("font-face"); + faceNode->addAttribute("font-family", id); + faceNode->addAttribute("units-per-em", XMLString(1000)); + fontNode->append(faceNode); + FORALL(*usedChars, set<int>::const_iterator, i) { + emitGlyph(*i); // create new glyphNode + fontNode->append(_glyphNode); + } + } + else { + FORALL(*usedChars, set<int>::const_iterator, i) { + emitGlyph(*i); // create new glyphNode + _svg.appendToDefs(_glyphNode); + } + } + + if (_gfTracer) + Message::mstream() << endl; + return usedChars->size(); +} + + +static inline void write_char_info (int c, ostream &os) { + os << '['; + if (isprint(c)) + os << char(c); + else + os << '#' << c; +} + + +/** Creates the SVG definition of a single glyph. + * @param[in] c character code of the glyph + * @param[in] duplicate true if the glyph is already included in different size */ +bool SVGFontTraceEmitter::emitGlyph (int c) { + const TFM *tfm = _font->getTFM(); + if (!tfm) + return false; + + bool write_info=false; + const Glyph *glyph = _cache ? _cache->getGlyph(c) : 0; + if (!glyph && prepareTracer()) { + write_char_info(c, Message::wstream()); + _gfTracer->executeChar(c); + glyph = &_gfTracer->getGlyph(); + if (_cache) + _cache->setGlyph(c, _gfTracer->transferGlyph()); + write_info = true; + } + + ostringstream path; + double sx=1.0, sy=1.0; + if (_useFonts) { + _glyphNode = new XMLElementNode("glyph"); + _glyphNode->addAttribute("unicode", XMLString(_charmapTranslator.unicode(c), false)); + _glyphNode->addAttribute("horiz-adv-x", XMLString(1000.0*tfm->getCharWidth(c)/tfm->getDesignSize())); + } + else { + ostringstream oss; + oss << 'g' << _fontManager.fontID(_font) << c; + _glyphNode = new XMLElementNode("path"); + _glyphNode->addAttribute("id", oss.str()); + sx = _font->scaledSize()/1000.0; // 1000 units per em + sy = -sx; + } + glyph->writeSVGCommands(path, sx, sy); + _glyphNode->addAttribute("d", path.str()); + if (write_info) + Message::mstream() << ']'; + return true; +} + + +/** Traces all glyphs of the current font and stores them in the cache. + * If caching is disabled nothing happens. */ +void SVGFontTraceEmitter::traceAllGlyphs () { + const TFM *tfm = _font->getTFM(); + if (tfm && _cache && prepareTracer()) { + int fchar = tfm->firstChar(); + int lchar = tfm->lastChar(); + for (int i=fchar; i <= lchar; i++) { + if (!_cache->getGlyph(i)) { + write_char_info(i, Message::wstream()); + if (_gfTracer->executeChar(i)) // does char i exist in font? + _cache->setGlyph(i, _gfTracer->transferGlyph()); + else + Message::wstream() << "(empty)"; + Message::wstream() << ']'; + } + } + } +} |