diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvisvgm/src/SpecialManager.cpp |
Initial commit
Diffstat (limited to 'dviware/dvisvgm/src/SpecialManager.cpp')
-rw-r--r-- | dviware/dvisvgm/src/SpecialManager.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/dviware/dvisvgm/src/SpecialManager.cpp b/dviware/dvisvgm/src/SpecialManager.cpp new file mode 100644 index 0000000000..4838cbdf47 --- /dev/null +++ b/dviware/dvisvgm/src/SpecialManager.cpp @@ -0,0 +1,179 @@ +/************************************************************************* +** SpecialManager.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 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 <iomanip> +#include <map> +#include <sstream> +#include "SpecialActions.hpp" +#include "SpecialHandler.hpp" +#include "SpecialManager.hpp" + +using namespace std; + +double SpecialActions::PROGRESSBAR_DELAY=1000; // initial delay in seconds (values >= 1000 disable the progressbar) + + +SpecialManager& SpecialManager::instance() { + static SpecialManager sm; + return sm; +} + + +/** Remove all registered handlers. */ +void SpecialManager::unregisterHandlers () { + _handlerPool.clear(); + _handlersByPrefix.clear(); +} + + +/** Registers a single special handler. This method doesn't check if a + * handler of the same class is already registered. + * @param[in] handler pointer to handler to be registered */ +void SpecialManager::registerHandler (unique_ptr<SpecialHandler> handler) { + if (handler) { + // get array of prefixes this handler is responsible for + for (const char *prefix : handler->prefixes()) + _handlersByPrefix[prefix] = handler.get(); + _handlerPool.emplace_back(std::move(handler)); + } +} + + +/** Registers several special handlers at once. + * If ignorelist == 0, all given handlers are registered. To exclude selected sets of + * specials, the corresponding names can be given separated by non alpha-numeric characters, + * e.g. "color, ps, em" or "color: ps em" etc. + * @param[in] handlers pointer to zero-terminated array of handlers to be registered + * @param[in] ignorelist list of special names to be ignored */ +void SpecialManager::registerHandlers (vector<unique_ptr<SpecialHandler>> &handlers, const char *ignorelist) { + if (handlers.empty()) + return; + string ignorestr = ignorelist ? ignorelist : ""; + for (char &c : ignorestr) + if (!isalnum(c)) + c = '%'; + ignorestr = "%"+ignorestr+"%"; + + for (auto &handler : handlers) + if (!handler->name() || ignorestr.find("%"+string(handler->name())+"%") == string::npos) + registerHandler(std::move(handler)); +} + + +/** Looks for a handler responsible for a given special prefix. + * @param[in] prefix the special prefix, e.g. "color" or "em" + * @return in case of success: pointer to handler, 0 otherwise */ +SpecialHandler* SpecialManager::findHandlerByPrefix (const string &prefix) const { + auto it = _handlersByPrefix.find(prefix); + if (it != _handlersByPrefix.end()) + return it->second; + return nullptr; +} + + +/** Looks for a handler with a given name. + * @param[in] name name of handler to look for, e.g. "papersize" + * @return in case of success: pointer to handler, 0 otherwise */ +SpecialHandler* SpecialManager::findHandlerByName (const string &name) const { + for (auto &handler : _handlerPool) { + if (handler->name() == name) + return handler.get(); + } + return nullptr; +} + + +static string extract_prefix (istream &is) { + int c; + string prefix; + while (isalnum(c=is.get())) + prefix += char(c); + if (ispunct(c)) // also add separation character to identifying prefix + prefix += char(c); + if (prefix == "ps:" && is.peek() == ':') + prefix += char(is.get()); + return prefix; +} + + +void SpecialManager::preprocess (const string &special, SpecialActions &actions) const { + istringstream iss(special); + const string prefix = extract_prefix(iss); + if (SpecialHandler *handler = findHandlerByPrefix(prefix)) + handler->preprocess(prefix, iss, actions); +} + + +/** Executes a special command. + * @param[in] special the special expression + * @param[in] dvi2bp factor to convert DVI units to PS points + * @param[in] actions actions the special handlers can perform + * @return true if the special could be processed successfully + * @throw SpecialException in case of errors during special processing */ +bool SpecialManager::process (const string &special, double dvi2bp, SpecialActions &actions) const { + istringstream iss(special); + const string prefix = extract_prefix(iss); + bool success=false; + if (SpecialHandler *handler = findHandlerByPrefix(prefix)) { + handler->setDviScaleFactor(dvi2bp); + success = handler->process(prefix, iss, actions); + } + return success; +} + + +void SpecialManager::notifyPreprocessingFinished () const { + for (auto &handler : _handlerPool) + handler->dviPreprocessingFinished(); +} + + +void SpecialManager::notifyBeginPage (unsigned pageno, SpecialActions &actions) const { + for (auto &handler : _handlerPool) + handler->dviBeginPage(pageno, actions); +} + + +void SpecialManager::notifyEndPage (unsigned pageno, SpecialActions &actions) const { + for (auto &handler : _handlerPool) + handler->dviEndPage(pageno, actions); +} + + +void SpecialManager::notifyPositionChange (double x, double y, SpecialActions &actions) const { + for (auto &handler : _handlerPool) + handler->dviMovedTo(x, y, actions); +} + + +void SpecialManager::writeHandlerInfo (ostream &os) const { + ios::fmtflags osflags(os.flags()); + map<string,SpecialHandler*> sortmap; + for (const auto &handler : _handlerPool) + if (handler->name()) + sortmap[handler->name()] = handler.get(); + for (const auto &strhandlerpair : sortmap) { + os << setw(10) << left << strhandlerpair.second->name() << ' '; + if (strhandlerpair.second->info()) + os << strhandlerpair.second->info(); + os << endl; + } + os.flags(osflags); // restore format flags +} |