summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-1.3/src/Font.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-1.3/src/Font.cpp')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-1.3/src/Font.cpp453
1 files changed, 453 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-1.3/src/Font.cpp b/Build/source/texk/dvisvgm/dvisvgm-1.3/src/Font.cpp
new file mode 100644
index 00000000000..45950818ea3
--- /dev/null
+++ b/Build/source/texk/dvisvgm/dvisvgm-1.3/src/Font.cpp
@@ -0,0 +1,453 @@
+/*************************************************************************
+** Font.cpp **
+** **
+** This file is part of dvisvgm -- the DVI to SVG converter **
+** Copyright (C) 2005-2013 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 <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include "FileFinder.h"
+#include "FileSystem.h"
+#include "Font.h"
+#include "FontEngine.h"
+#include "FontMap.h"
+#include "GFGlyphTracer.h"
+#include "Glyph.h"
+#include "Message.h"
+#include "MetafontWrapper.h"
+#include "TFM.h"
+#include "VFReader.h"
+#include "SignalHandler.h"
+#include "Subfont.h"
+#include "SVGTree.h"
+#include "macros.h"
+
+using namespace std;
+
+
+/** Returns true if 'unicode' is a valid unicode value in XML documents.
+ * XML version 1.0 doesn't allow various unicode character references
+ * (&#1; for example). */
+static bool valid_unicode (UInt32 unicode) {
+ UInt32 ranges[] = {
+ 0x0000, 0x0020,
+ 0x007f, 0x0084,
+ 0x0086, 0x009f,
+ 0xfdd0, 0xfddf
+ };
+ for (int i=0; i < 4; i++)
+ if (unicode >= ranges[2*i] && unicode <= ranges[2*i+1])
+ return false;
+ return true;
+}
+
+
+UInt32 Font::unicode (UInt32 c) const {
+ // @@ this should be optimized :-)
+ return valid_unicode(c) ? c : 0x3400+c;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+
+TFMFont::TFMFont (string name, UInt32 cs, double ds, double ss)
+ : _metrics(0), _fontname(name), _checksum(cs), _dsize(ds), _ssize(ss)
+{
+}
+
+
+TFMFont::~TFMFont () {
+ delete _metrics;
+}
+
+
+/** Returns a font metrics object for the current font.
+ * @throw FontException if TFM file can't be found */
+const FontMetric* TFMFont::getMetrics () const {
+ if (!_metrics) {
+ try {
+ _metrics = FontMetric::read(_fontname.c_str());
+ if (!_metrics) {
+ _metrics = new NullFontMetric;
+ Message::wstream(true) << "can't find "+_fontname+".tfm\n";
+ }
+ }
+ catch (FontMetricException &e) {
+ _metrics = new NullFontMetric;
+ Message::wstream(true) << e.what() << " in " << _fontname << ".tfm\n";
+ }
+ }
+ return _metrics;
+}
+
+
+double TFMFont::charWidth (int c) const {
+ double w = getMetrics() ? getMetrics()->getCharWidth(c) : 0;
+ if (style())
+ w *= style()->extend;
+ return w;
+}
+
+
+double TFMFont::italicCorr (int c) const {
+ double w = getMetrics() ? getMetrics()->getItalicCorr(c) : 0;
+ if (style())
+ w *= style()->extend;
+ return w;
+}
+
+
+double TFMFont::charDepth (int c) const {return getMetrics() ? getMetrics()->getCharDepth(c) : 0;}
+double TFMFont::charHeight (int c) const {return getMetrics() ? getMetrics()->getCharHeight(c) : 0;}
+
+
+bool TFMFont::verifyChecksums () const {
+ if (_checksum != 0 && getMetrics() && getMetrics()->getChecksum() != 0)
+ return _checksum == getMetrics()->getChecksum();
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// static class variables
+bool PhysicalFont::KEEP_TEMP_FILES = false;
+const char *PhysicalFont::CACHE_PATH = 0;
+double PhysicalFont::METAFONT_MAG = 4;
+FontCache PhysicalFont::_cache;
+
+
+Font* PhysicalFont::create (string name, UInt32 checksum, double dsize, double ssize, PhysicalFont::Type type) {
+ return new PhysicalFontImpl(name, 0, checksum, dsize, ssize, type);
+}
+
+
+Font* PhysicalFont::create (string name, int fontindex, UInt32 checksum, double dsize, double ssize) {
+ return new PhysicalFontImpl(name, fontindex, checksum, dsize, ssize, PhysicalFont::TTC);
+}
+
+
+const char* PhysicalFont::path () const {
+ string ext;
+ switch (type()) {
+ case PFB: ext = "pfb"; break;
+ case TTC: ext = "ttc"; break;
+ case TTF: ext = "ttf"; break;
+ case MF : ext = "mf"; break;
+ }
+ return FileFinder::lookup(name()+"."+ext);
+}
+
+
+/** Returns the number of units per EM. The EM square is the virtual area a glyph is designed on.
+ * All coordinates used to specify portions of the glyph are relative to the origin (0,0) at the
+ * lower left corner of this square, while the upper right corner is located at (m,m), where m
+ * is an integer value defined with the font, and returned by this function. */
+int PhysicalFont::unitsPerEm() const {
+ if (type() == MF)
+ return 1000;
+ FontEngine::instance().setFont(*this);
+ return FontEngine::instance().getUnitsPerEM();
+}
+
+
+int PhysicalFont::hAdvance () const {
+ if (type() == MF)
+ return 0;
+ FontEngine::instance().setFont(*this);
+ return FontEngine::instance().getHAdvance();
+}
+
+
+double PhysicalFont::hAdvance (int c) const {
+ if (type() == MF)
+ return unitsPerEm()*charWidth(c)/designSize();
+ FontEngine::instance().setFont(*this);
+ if (FontEncoding *enc = encoding())
+ return FontEngine::instance().getHAdvance(enc->getEntry(c));
+ if (const FontMap::Entry *map_entry = FontMap::instance().lookup(name()))
+ if (Subfont *sf = map_entry->subfont)
+ c = sf->decode(c);
+ return FontEngine::instance().getHAdvance(c);
+}
+
+
+string PhysicalFont::glyphName (int c) const {
+ if (type() == MF)
+ return "";
+ FontEngine::instance().setFont(*this);
+ if (FontEncoding *enc = encoding()) {
+ const char *name = enc->getEntry(c);
+ return name ? name : "";
+ }
+ if (const FontMap::Entry *map_entry = FontMap::instance().lookup(name()))
+ if (Subfont *sf = map_entry->subfont)
+ c = sf->decode(c);
+ return FontEngine::instance().getGlyphName(c);
+}
+
+
+int PhysicalFont::ascent () const {
+ if (type() == MF)
+ return 0;
+ FontEngine::instance().setFont(*this);
+ return FontEngine::instance().getAscender();
+}
+
+
+int PhysicalFont::descent () const {
+ if (type() == MF)
+ return 0;
+ FontEngine::instance().setFont(*this);
+ return FontEngine::instance().getDescender();
+}
+
+
+/** Extracts the glyph outlines of a given character.
+ * @param[in] c character code of requested glyph
+ * @param[out] glyph path segments of the glyph outline
+ * @param[in] cb optional callback object for tracer class
+ * @return true if outline could be computed */
+bool PhysicalFont::getGlyph (int c, GraphicPath<Int32> &glyph, GFGlyphTracer::Callback *cb) const {
+ if (type() == MF) {
+ const Glyph *cached_glyph=0;
+ if (CACHE_PATH) {
+ _cache.write(CACHE_PATH);
+ _cache.read(name().c_str(), CACHE_PATH);
+ cached_glyph = _cache.getGlyph(c);
+ }
+ if (cached_glyph) {
+ glyph = *cached_glyph;
+ return true;
+ }
+ else {
+ string gfname;
+ if (createGF(gfname)) {
+ try {
+ double ds = getMetrics() ? getMetrics()->getDesignSize() : 1;
+ GFGlyphTracer tracer(gfname, unitsPerEm()/ds, cb);
+ tracer.setGlyph(glyph);
+ tracer.executeChar(c);
+ glyph.closeOpenSubPaths();
+ if (CACHE_PATH)
+ _cache.setGlyph(c, glyph);
+ return true;
+ }
+ catch (GFException &e) {
+ // @@ print error message
+ }
+ }
+ else {
+ Message::wstream(true) << "failed creating " << name() << ".gf\n";
+ }
+ }
+ }
+ else { // PFB or TTF
+ bool ok=true;
+ FontEngine::instance().setFont(*this);
+ if (FontEncoding *enc = encoding()) {
+ if (const char *encname = enc->getEntry(c))
+ ok = FontEngine::instance().traceOutline(encname, glyph, false);
+ }
+ else {
+ if (const FontMap::Entry *map_entry = FontMap::instance().lookup(name()))
+ if (Subfont *sf = map_entry->subfont)
+ c = sf->decode(c);
+ ok = FontEngine::instance().traceOutline(c, glyph, false);
+ }
+ glyph.closeOpenSubPaths();
+ return ok;
+ }
+ return false;
+}
+
+
+/** Creates a GF file for this font object.
+ * @param[out] gfname name of GF font file
+ * @return true on success */
+bool PhysicalFont::createGF (string &gfname) const {
+ SignalHandler::instance().check();
+ gfname = name()+".gf";
+ MetafontWrapper mf(name());
+ bool ok = mf.make("ljfour", METAFONT_MAG); // call Metafont if necessary
+ return ok && mf.success() && getMetrics();
+}
+
+
+/** Traces all glyphs of the current font and stores them in the cache. If caching is disabled, nothing happens.
+ * @param[in] includeCached if true, glyphs already cached are traced again
+ * @param[in] cb optional callback methods called by the tracer
+ * @return number of glyphs traced */
+int PhysicalFont::traceAllGlyphs (bool includeCached, GFGlyphTracer::Callback *cb) const {
+ int count = 0;
+ if (type() == MF && CACHE_PATH) {
+ if (const FontMetric *metrics = getMetrics()) {
+ int fchar = metrics->firstChar();
+ int lchar = metrics->lastChar();
+ string gfname;
+ Glyph glyph;
+ if (createGF(gfname)) {
+ _cache.read(name().c_str(), CACHE_PATH);
+ double ds = getMetrics() ? getMetrics()->getDesignSize() : 1;
+ GFGlyphTracer tracer(gfname, unitsPerEm()/ds, cb);
+ tracer.setGlyph(glyph);
+ for (int i=fchar; i <= lchar; i++) {
+ if (includeCached || !_cache.getGlyph(i)) {
+ glyph.newpath();
+ tracer.executeChar(i);
+ glyph.closeOpenSubPaths();
+ _cache.setGlyph(i, glyph);
+ ++count;
+ }
+ }
+ _cache.write(CACHE_PATH);
+ }
+ }
+ }
+ return count;
+}
+
+
+/** Computes the exact bounding box of a glyph.
+ * @param[in] c character code of the glyph
+ * @param[out] bbox the computed bounding box
+ * @param[in] optional calback object forwarded to the tracer
+ * @return true if the box could be computed successfully */
+bool PhysicalFont::getGlyphBox(int c, BoundingBox& bbox, GFGlyphTracer::Callback* cb) const {
+ Glyph glyph;
+ if (getGlyph(c, glyph, cb)) {
+ glyph.computeBBox(bbox);
+ double s = scaledSize()/unitsPerEm();
+ bbox.scale(s, s);
+ return true;
+ }
+ return false;
+}
+
+
+Font* VirtualFont::create (string name, UInt32 checksum, double dsize, double ssize) {
+ return new VirtualFontImpl(name, checksum, dsize, ssize);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+PhysicalFontImpl::PhysicalFontImpl (string name, int fontindex, UInt32 cs, double ds, double ss, PhysicalFont::Type type)
+ : TFMFont(name, cs, ds, ss), _filetype(type), _fontIndex(fontindex), _style(0), _charmap(0)
+{
+}
+
+
+PhysicalFontImpl::~PhysicalFontImpl () {
+ if (CACHE_PATH)
+ _cache.write(CACHE_PATH);
+ if (!KEEP_TEMP_FILES)
+ tidy();
+ delete _style;
+ delete _charmap;
+}
+
+
+UInt32 PhysicalFontImpl::unicode (UInt32 c) const {
+ if (type() == MF)
+ return Font::unicode(c);
+
+ if (_charmap == 0) {
+ FontEngine &fe = FontEngine::instance();
+ if (fe.setFont(*this)) {
+ _charmap = new map<UInt32,UInt32>;
+ fe.buildTranslationMap(*_charmap);
+ }
+ }
+ typedef map<UInt32,UInt32>::const_iterator ConstIterator;
+ ConstIterator it = _charmap->find(c);
+ if (it != _charmap->end())
+ return it->second;
+
+ // No unicode equivalent found in font file.
+ // Now we should look for a smart alternative but at the moment
+ // it's sufficient to simply choose a valid unused unicode value...
+ map<UInt32,UInt32> reverse_map;
+ FORALL(*_charmap, ConstIterator, it)
+ reverse_map[it->second] = it->first;
+ // can we use charcode itself as unicode replacement?
+ if (valid_unicode(c) && (reverse_map.empty() || reverse_map.find(c) != reverse_map.end()))
+ return c;
+ return 0x3400+c;
+}
+
+
+void PhysicalFontImpl::tidy () const {
+ if (type() == MF) {
+ const char *ext[] = {"gf", "tfm", "log", 0};
+ for (const char **p=ext; *p; ++p) {
+ if (FileSystem::exists((name()+"."+(*p)).c_str()))
+ FileSystem::remove(name()+"."+(*p));
+ }
+ }
+}
+
+
+void PhysicalFontImpl::setStyle (double bold, double extend, double slant) {
+ if (_style) {
+ _style->bold = bold;
+ _style->extend = extend;
+ _style->slant = slant;
+ }
+ else if (bold != 0 || extend != 1 || slant != 0)
+ _style = new Style(bold, extend, slant);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+VirtualFontImpl::VirtualFontImpl (string name, UInt32 cs, double ds, double ss)
+ : TFMFont(name, cs, ds, ss)
+{
+}
+
+
+VirtualFontImpl::~VirtualFontImpl () {
+ // delete dvi vectors received by VFReaderAction
+ for (map<UInt32, DVIVector*>::iterator i=_charDefs.begin(); i != _charDefs.end(); ++i)
+ delete i->second;
+}
+
+
+const char* VirtualFontImpl::path () const {
+ return FileFinder::lookup(name()+".vf");
+}
+
+
+void VirtualFontImpl::assignChar (UInt32 c, DVIVector *dvi) {
+ if (dvi) {
+ if (_charDefs.find(c) == _charDefs.end())
+ _charDefs[c] = dvi;
+ else
+ delete dvi;
+ }
+}
+
+
+const vector<UInt8>* VirtualFontImpl::getDVI (int c) const {
+ map<UInt32,DVIVector*>::const_iterator it = _charDefs.find(c);
+ return (it == _charDefs.end() ? 0 : it->second);
+}
+