summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-1.3/src/DvisvgmSpecialHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-1.3/src/DvisvgmSpecialHandler.cpp')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-1.3/src/DvisvgmSpecialHandler.cpp202
1 files changed, 202 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-1.3/src/DvisvgmSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-1.3/src/DvisvgmSpecialHandler.cpp
new file mode 100644
index 00000000000..11e3c0fc42a
--- /dev/null
+++ b/Build/source/texk/dvisvgm/dvisvgm-1.3/src/DvisvgmSpecialHandler.cpp
@@ -0,0 +1,202 @@
+/*************************************************************************
+** DvisvgmSpecialHandler.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 <cstring>
+#include "DvisvgmSpecialHandler.h"
+#include "InputBuffer.h"
+#include "InputReader.h"
+#include "SpecialActions.h"
+#include "XMLNode.h"
+#include "XMLString.h"
+
+using namespace std;
+
+
+/** Replaces constants of the form {?name} by their corresponding value.
+ * @param[in,out] str text to expand
+ * @param[in] actions interfcae to the world outside the special handler */
+static void expand_constants (string &str, SpecialActions *actions) {
+ struct Constant {
+ const char *name;
+ string val;
+ }
+ constants[] = {
+ {"x", XMLString(actions->getX())},
+ {"y", XMLString(actions->getY())},
+ {"color", actions->getColor().rgbString()},
+ {"nl", "\n"},
+ {0, ""}
+ };
+ bool repl_bbox = true;
+ while (repl_bbox) {
+ size_t pos = str.find(string("{?bbox "));
+ if (pos == string::npos)
+ repl_bbox = false;
+ else {
+ size_t endpos = pos+7;
+ while (endpos < str.length() && isalnum(str[endpos]))
+ ++endpos;
+ if (str[endpos] == '}') {
+ BoundingBox &box=actions->bbox(str.substr(pos+7, endpos-pos-7));
+ str.replace(pos, endpos-pos+1, box.toSVGViewBox());
+ }
+ else
+ repl_bbox = false;
+ }
+ }
+ for (const Constant *p=constants; p->name; p++) {
+ const string pattern = string("{?")+p->name+"}";
+ size_t pos = str.find(pattern);
+ while (pos != string::npos) {
+ str.replace(pos, strlen(p->name)+3, p->val);
+ pos = str.find(pattern, pos+p->val.length()); // look for further matches
+ }
+ }
+}
+
+
+/** Embeds the virtual rectangle (x, y ,w , h) into the current bounding box,
+ * where (x,y) is the lower left vertex composed of the current DVI position.
+ * @param[in] w width of the rectangle in TeX point units
+ * @param[in] h height of the rectangle in TeX point units
+ * @param[in] d depth of the rectangle in TeX point units */
+static void update_bbox (double w, double h, double d, SpecialActions *actions) {
+ double x = actions->getX();
+ double y = actions->getY();
+ actions->embed(BoundingBox(x, y, x+w, y-h));
+ actions->embed(BoundingBox(x, y, x+w, y+d));
+}
+
+
+/** Inserts raw text into the SVG tree.
+ * @param[in,out] in the raw text is read from this input buffer
+ * @param[in] actions interfcae to the world outside the special handler
+ * @param[in] group true if the text should be wrapped by a group element */
+static void raw (InputReader &in, SpecialActions *actions, bool group=false) {
+ string str;
+ while (!in.eof()) {
+ int c = in.get();
+ if (isprint(c))
+ str += char(c);
+ }
+ expand_constants(str, actions);
+ if (!str.empty()) {
+ XMLNode *node = new XMLTextNode(str);
+ if (group) {
+ XMLElementNode *g = new XMLElementNode("g");
+ g->addAttribute("x", actions->getX());
+ g->addAttribute("y", actions->getY());
+ if (actions->getColor() != Color::BLACK)
+ g->addAttribute("fill", actions->getColor().rgbString());
+ g->append(node);
+ node = g;
+ }
+ actions->appendToPage(node);
+ }
+}
+
+
+/** Evaluates the special dvisvgm:bbox.
+ * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>]
+ * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2>
+ * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2>
+ * variant 4: dvisvgm:bbox n[ew] <name> */
+static void bbox (InputReader &in, SpecialActions *actions) {
+ in.skipSpace();
+ int c = in.peek();
+ if (isalpha(c)) {
+ while (!isspace(in.peek())) // skip trailing characters
+ in.get();
+ if (c == 'n') {
+ in.skipSpace();
+ string name;
+ while (isalnum(in.peek()))
+ name += char(in.get());
+ in.skipSpace();
+ if (!name.empty() && in.eof())
+ actions->bbox(name, true); // create new user box
+ }
+ else if (c == 'a' || c == 'f') {
+ double p[4];
+ for (int i=0; i < 4; i++)
+ p[i] = in.getDouble();
+ BoundingBox b(p[0], p[1], p[2], p[3]);
+ if (c == 'a')
+ actions->embed(b);
+ else {
+ actions->bbox() = b;
+ actions->bbox().lock();
+ }
+ }
+ }
+ else
+ c = 'r'; // no mode specifier => relative box parameters
+
+ if (c == 'r') {
+ double w = in.getDouble();
+ double h = in.getDouble();
+ double d = in.getDouble();
+ update_bbox(w, h, d, actions);
+ }
+}
+
+
+static void img (InputReader &in, SpecialActions *actions) {
+ double w = in.getDouble();
+ double h = in.getDouble();
+ string f = in.getString();
+ update_bbox(w, h, 0, actions);
+ XMLElementNode *img = new XMLElementNode("image");
+ img->addAttribute("x", actions->getX());
+ img->addAttribute("y", actions->getY());
+ img->addAttribute("width", w);
+ img->addAttribute("height", h);
+ img->addAttribute("xlink:href", f);
+ if (actions && !actions->getMatrix().isIdentity())
+ img->addAttribute("transform", actions->getMatrix().getSVG());
+ actions->appendToPage(img);
+}
+
+
+/** Evaluates and executes a dvisvgm special statement.
+ * @param[in] prefix special prefix read by the SpecialManager
+ * @param[in] is the special statement is read from this stream
+ * @param[in,out] in the raw text is read from this input buffer */
+bool DvisvgmSpecialHandler::process (const char *prefix, istream &is, SpecialActions *actions) {
+ if (actions) {
+ StreamInputBuffer ib(is);
+ BufferInputReader in(ib);
+ string cmd = in.getWord();
+ if (cmd == "raw") // raw <text>
+ raw(in, actions);
+ else if (cmd == "bbox") // bbox [r] <width> <height> <depth> or bbox a <x1> <y1> <x2> <y2>
+ bbox(in, actions);
+ else if (cmd == "img") { // img <width> <height> <file>
+ img(in, actions);
+ }
+ }
+ return true;
+}
+
+
+const char** DvisvgmSpecialHandler::prefixes () const {
+ static const char *pfx[] = {"dvisvgm:", 0};
+ return pfx;
+}