summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-1.0.3/src/DVIToSVGActions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-1.0.3/src/DVIToSVGActions.cpp')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-1.0.3/src/DVIToSVGActions.cpp332
1 files changed, 332 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-1.0.3/src/DVIToSVGActions.cpp b/Build/source/texk/dvisvgm/dvisvgm-1.0.3/src/DVIToSVGActions.cpp
new file mode 100644
index 00000000000..d3043bffd5b
--- /dev/null
+++ b/Build/source/texk/dvisvgm/dvisvgm-1.0.3/src/DVIToSVGActions.cpp
@@ -0,0 +1,332 @@
+/*************************************************************************
+** DVIToSVGActions.cpp **
+** **
+** This file is part of dvisvgm -- the DVI to SVG converter **
+** Copyright (C) 2005-2010 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 <ctime>
+#include "BoundingBox.h"
+#include "DVIToSVG.h"
+#include "DVIToSVGActions.h"
+#include "Font.h"
+#include "FontManager.h"
+#include "Ghostscript.h"
+#include "GlyphTracerMessages.h"
+#include "SpecialManager.h"
+#include "System.h"
+#include "XMLNode.h"
+#include "XMLString.h"
+
+using namespace std;
+
+
+double DVIToSVGActions::PROGRESSBAR_DELAY=1000; // initial delay in seconds (values >= 1000 disable the progressbar)
+bool DVIToSVGActions::EXACT_BBOX = false;
+
+
+DVIToSVGActions::DVIToSVGActions (DVIToSVG &dvisvg, SVGTree &svg)
+ : _svg(svg), _dvisvg(dvisvg), _pageMatrix(0), _bgcolor(Color::WHITE), _boxes(0)
+{
+ _currentFontNum = -1;
+ _pageCount = 0;
+}
+
+
+DVIToSVGActions::~DVIToSVGActions () {
+ delete _pageMatrix;
+ delete _boxes;
+}
+
+
+void DVIToSVGActions::reset() {
+ _usedChars.clear();
+ _usedFonts.clear();
+ _bbox = BoundingBox();
+ _currentFontNum = -1;
+ _bgcolor = Color::WHITE;
+}
+
+
+void DVIToSVGActions::setPageMatrix (const Matrix &matrix) {
+ delete _pageMatrix;
+ _pageMatrix = new Matrix(matrix);
+}
+
+
+/** This method is called when a "set char" command was found in the DVI file.
+ * It draws a character of the current font.
+ * @param[in] x horizontal position of left bounding box edge
+ * @param[in] y vertical position of the character's baseline
+ * @param[in] c character code relative to the current font
+ * @param[in] font font to be used */
+void DVIToSVGActions::setChar (double x, double y, unsigned c, const Font *font) {
+ // If we use SVG fonts there is no need to record all font name/char/size combinations
+ // because the SVG font mechanism handles this automatically. It's sufficient to
+ // record font names and chars. The various font sizes can be ignored here.
+ // For a given font object, Font::uniqueFont() returns the same unique font object for
+ // all fonts with the same name.
+ _usedChars[SVGTree::USE_FONTS ? font->uniqueFont() : font].insert(c);
+
+ // However, we record all required fonts
+ _usedFonts.insert(font);
+
+ _svg.appendChar(c, x, y, *font);
+ // update bounding box
+ double wl=0, wr=0, h=0, d=0; // left/right width, height, and depth of character c
+ static string fontname;
+ GlyphTracerMessages callback(fontname != font->name(), false);
+ fontname = font->name();
+ BoundingBox charbox;
+ const PhysicalFont *ph_font = dynamic_cast<const PhysicalFont*>(font);
+ if (EXACT_BBOX && ph_font && ph_font->getGlyphBox(c, charbox, &callback)) {
+ if ((wl = charbox.minX()) > 0) wl=0;
+ if ((wr = charbox.maxX()) < 0) wr=0;
+ if ((h = charbox.maxY()) < 0) h=0;
+ if ((d = -charbox.minY()) < 0) d=0;
+ }
+ else {
+ double s = font->scaleFactor();
+ wr = s*(font->charWidth(c) + font->italicCorr(c));
+ h = s*font->charHeight(c);
+ d = s*font->charDepth(c);
+ }
+
+ BoundingBox bbox(x+wl, y-h, x+wr, y+d);
+/* XMLElementNode *rect = new XMLElementNode("rect");
+ rect->addAttribute("x", x+wl);
+ rect->addAttribute("y", y-h);
+ rect->addAttribute("width", (-wl+wr));
+ rect->addAttribute("height", (h+d));
+ rect->addAttribute("fill", "none");
+ rect->addAttribute("stroke", "red");
+ rect->addAttribute("stroke-width", "0.5");
+ _svg.appendToPage(rect);*/
+ if (!getMatrix().isIdentity())
+ bbox.transform(getMatrix());
+ embed(bbox);
+}
+
+
+/** This method is called when a "set rule" or "put rule" command was found in the
+ * DVI file. It draws a solid unrotated rectangle.
+ * @param[in] x horizontal position of left edge
+ * @param[in] y vertical position of bottom(!) edge
+ * @param[in] height length of the vertical edges
+ * @param[in] width length of the horizontal edges */
+void DVIToSVGActions::setRule (double x, double y, double height, double width) {
+/* x *= BP;
+ y *= BP;
+ height *= BP;
+ width *= BP; */
+ // (x,y) is the lower left corner of the rectangle
+ XMLElementNode *rect = new XMLElementNode("rect");
+ rect->addAttribute("x", x);
+ rect->addAttribute("y", y-height);
+ rect->addAttribute("height", height);
+ rect->addAttribute("width", width);
+ if (!getMatrix().isIdentity())
+ rect->addAttribute("transform", getMatrix().getSVG());
+ if (getColor() != Color::BLACK)
+ rect->addAttribute("fill", _svg.getColor().rgbString());
+ _svg.appendToPage(rect);
+
+ // update bounding box
+ BoundingBox bb(x, y+height, x+width, y);
+ if (!getMatrix().isIdentity())
+ bb.transform(getMatrix());
+ embed(bb);
+}
+
+
+/** This method is called when a "set font" command was found in the DVI file. The
+ * font must be previously defined.
+ * @param[in] num unique number of the font in the DVI file (not necessarily equal to the DVI font number)
+ * @param[in] font pointer to the font object (always represents a physical font and never a virtual font) */
+void DVIToSVGActions::setFont (int num, const Font *font) {
+ _currentFontNum = num;
+ _svg.setFont(num, font);
+}
+
+
+/** This method is called when a "special" command was found in the DVI file.
+ * @param[in] s the special expression */
+void DVIToSVGActions::special (const string &s) {
+ try {
+ _dvisvg.specialManager().process(s, this, this);
+ // @@ output message in case of unsupported specials?
+ }
+ catch (const SpecialException &e) {
+ Message::estream(true) << "error in special '" << s << "': " << e.getMessage() << '\n';
+ }
+}
+
+
+void DVIToSVGActions::beginSpecial (const char *prefix) {
+}
+
+
+void DVIToSVGActions::endSpecial (const char *) {
+}
+
+
+/** This method is called when the DVI preamble was read
+ * @param[in] cmt preamble comment text. */
+void DVIToSVGActions::preamble (const string &cmt) {
+}
+
+
+void DVIToSVGActions::postamble () {
+}
+
+
+/** This method is called when a "begin of page (bop)" command was found in the DVI file.
+ * @param[in] c array with 10 components representing \count0 ... \count9. c[0] contains the
+ * current (printed) page number (may differ from page count) */
+void DVIToSVGActions::beginPage (unsigned n, Int32 *c) {
+ _svg.newPage(++_pageCount);
+ _bbox = BoundingBox(); // clear bounding box
+ if (_boxes)
+ _boxes->clear();
+}
+
+
+/** This method is called when an "end of page (eop)" command was found in the DVI file. */
+void DVIToSVGActions::endPage () {
+ if (_pageMatrix)
+ _svg.transformPage(*_pageMatrix);
+ if (_bgcolor != Color::WHITE) {
+ XMLElementNode *r = new XMLElementNode("rect");
+ r->addAttribute("x", _bbox.minX());
+ r->addAttribute("y", _bbox.minY());
+ r->addAttribute("width", _bbox.width());
+ r->addAttribute("height", _bbox.height());
+ r->addAttribute("fill", _bgcolor.rgbString());
+ _svg.prependToPage(r);
+ }
+}
+
+
+void DVIToSVGActions::setBgColor (const Color &color) {
+ _bgcolor = color;
+}
+
+
+void DVIToSVGActions::embed(const BoundingBox& bbox) {
+ _bbox.embed(bbox);
+ if (_boxes) {
+ FORALL(*_boxes, BoxMap::iterator, it)
+ it->second.embed(bbox);
+ }
+}
+
+
+void DVIToSVGActions::embed(const DPair& p, double r) {
+ if (r == 0)
+ _bbox.embed(p);
+ else
+ _bbox.embed(p, r);
+ if (_boxes)
+ FORALL(*_boxes, BoxMap::iterator, it)
+ it->second.embed(p, r);
+}
+
+
+BoundingBox& DVIToSVGActions::bbox(const string& name, bool reset) {
+ if (!_boxes)
+ _boxes = new BoxMap;
+ BoundingBox &box = (*_boxes)[name];
+ if (reset)
+ box = BoundingBox();
+ return box;
+}
+
+
+/** This method is called by subprocesses like the PS handler when
+ * a computation step has finished. Since the total number of steps
+ * can't be determined in advance, we don't show a percent value but
+ * a rotating dash. */
+void DVIToSVGActions::progress (const char *id) {
+ if (PROGRESSBAR_DELAY < 1000) {
+ static double time=0;
+ // slow down updating of the progress indicator to prevent flickering
+ if (System::time() - time > 0.1) {
+ progress(0, 0, id);
+ time = System::time();
+ }
+ }
+}
+
+
+/** Returns the number of digits of a given integer. */
+static int digits (int n) {
+ if (n == 0)
+ return 1;
+ if (n > 0)
+ return int(log10(double(n))+1);
+ return int(log10(double(-n))+2);
+}
+
+
+/** Draws a simple progress indicator.
+ * @param[in] current current iteration step (of 'total' steps)
+ * @param[in] total total number of iteration steps
+ * @param[in] id ID of the subprocess providing the information */
+void DVIToSVGActions::progress (size_t current, size_t total, const char *id) {
+ static double time=0;
+ static bool draw=false; // show progress indicator?
+ static int step = -1; // >=0: rotating dash
+ static size_t prev_current=0, prev_total=1;
+ static const char *prev_id=0;
+ const char *tips = "-\\|/";
+ if (current == 0 && total > 0) {
+ time = System::time();
+ draw = false;
+ Message::mstream() << '\n';
+ }
+ // don't show the progress indicator before the given time has elapsed
+ if (!draw && System::time()-time > PROGRESSBAR_DELAY)
+ draw = true;
+ if (draw && (System::time() - time > 0.1 || (total > 0 && current == total) || prev_id != id)) {
+ if (total == 0) {
+ current = prev_current;
+ total = prev_total;
+ step = (step+1) % 4;
+ }
+ else {
+ prev_current = current;
+ prev_total = total;
+ step = -1;
+ }
+ // adapt length of progress indicator to terminal width
+ int cols = Terminal::columns();
+ int width = (cols == 0 || cols > 60) ? 50 : 49-60+cols;
+ double factor = double(current)/double(total);
+ int length = int(width*factor);
+ Message::mstream(false, Terminal::MAGENTA)
+ << '[' << string(length, '=')
+ << (factor < 1.0 ? (step < 0 ? ' ' : tips[step]) : '=')
+ << string(width-length, ' ')
+ << "] " << string(3-digits(int(100*factor)), ' ') << int(100*factor)
+ << "%\r";
+ // overprint indicator when finished
+ if (factor == 1.0)
+ Message::estream().clearline();
+ time = System::time();
+ prev_id = id;
+ }
+}