summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.cpp')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.cpp111
1 files changed, 111 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.cpp
new file mode 100644
index 00000000000..16cd1611020
--- /dev/null
+++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.cpp
@@ -0,0 +1,111 @@
+/*************************************************************************
+** SpecialActions.cpp **
+** **
+** This file is part of dvisvgm -- a fast DVI to SVG converter **
+** Copyright (C) 2005-2024 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 "Calculator.hpp"
+#include "SpecialActions.hpp"
+
+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) {
+ bool repl_bbox = true;
+ while (repl_bbox) {
+ const auto pos = str.find("{?bbox ");
+ if (pos == string::npos)
+ repl_bbox = false;
+ else {
+ auto endpos = pos+7;
+ while (endpos < str.length() && isalnum(str[endpos]))
+ ++endpos;
+ if (str[endpos] != '}')
+ repl_bbox = false;
+ else {
+ BoundingBox &box = actions.bbox(str.substr(pos+7, endpos-pos-7));
+ str.replace(pos, endpos-pos+1, box.svgViewBoxString());
+ }
+ }
+ }
+ const struct Constant {
+ const char *name;
+ string val;
+ } constants[] = {
+ {"x", XMLString(actions.getX())},
+ {"y", XMLString(actions.getY())},
+ {"color", SVGElement::USE_CURRENTCOLOR && SVGElement::CURRENTCOLOR == actions.getColor() ? "currentColor" : actions.getColor().svgColorString()},
+ {"matrix", actions.getMatrix().toSVG()},
+ {"nl", "\n"},
+ {"pageno", to_string(actions.getCurrentPageNumber())},
+ {"svgfile", actions.getSVGFilePath(actions.getCurrentPageNumber()).relative()},
+ {"svgpath", actions.getSVGFilePath(actions.getCurrentPageNumber()).absolute()},
+ };
+ for (const Constant &constant : constants) {
+ const string pattern = string("{?")+constant.name+"}";
+ auto pos = str.find(pattern);
+ while (pos != string::npos) {
+ str.replace(pos, strlen(constant.name)+3, constant.val);
+ pos = str.find(pattern, pos+constant.val.length()); // look for further matches
+ }
+ }
+}
+
+
+/** Evaluates substrings of the form {?(expr)} where 'expr' is a math expression,
+ * and replaces the substring by the computed value.
+ * @param[in,out] str string to scan for expressions */
+static void evaluate_expressions (string &str, const SpecialActions &actions) {
+ auto left = str.find("{?("); // start position of expression macro
+ while (left != string::npos) {
+ auto right = str.find(")}", left+2); // end position of expression macro
+ if (right == string::npos)
+ break;
+ Calculator calc;
+ calc.setVariable("x", actions.getX());
+ calc.setVariable("y", actions.getY());
+ string expr = str.substr(left+3, right-left-3); // math expression to evaluate
+ if (util::normalize_space(expr).empty()) // no expression given, e.g. {?( )}
+ str.erase(left, right-left+2); // => replace with empty string
+ else {
+ try {
+ double val = calc.eval(expr);
+ XMLString valstr(val);
+ str.replace(left, right-left+2, valstr);
+ right = left+valstr.length()-1;
+ }
+ catch (CalculatorException &e) {
+ throw SpecialException(string(e.what())+" in '{?("+expr+")}'");
+ }
+ }
+ left = str.find("{?(", right+1); // find next expression macro
+ }
+}
+
+
+/** Returns a given string with macros and arithmetic expressions expanded.
+ * @param[in] text string to be processed
+ * @return the expanded text */
+string SpecialActions::expandText (const string &text) {
+ string ret = text;
+ evaluate_expressions(ret, *this);
+ expand_constants(ret, *this);
+ return ret;
+} \ No newline at end of file