2 * \file ExternalTransforms.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS.
13 #include "ExternalTransforms.h"
15 #include "support/debug.h"
17 #include "support/lstrings.h"
18 #include "support/lyxlib.h" // float_equal
19 #include "support/convert.h"
20 #include "support/Translator.h"
22 #include <boost/regex.hpp>
24 #include <cmath> // std::abs
32 using support::float_equal;
34 string const ExtraData::get(string const & id) const
36 std::map<string, string>::const_iterator it = data_.find(id);
37 return it == data_.end() ? string() : it->second;
41 void ExtraData::set(string const & id, string const & data)
47 bool ResizeData::no_resize() const
49 return !usingScale() && width.zero() && height.zero();
53 bool ResizeData::usingScale() const
55 return (!scale.empty() && !float_equal(convert<double>(scale), 0.0, 0.05));
59 bool RotationData::no_rotation() const
61 return (angle.empty() || std::abs(convert<double>(angle)) < 0.1);
65 string const RotationData::adjAngle() const
67 // Ensure that angle lies in the range -360 < angle < 360
68 double rotAngle = convert<double>(angle);
69 if (std::abs(rotAngle) > 360.0) {
70 rotAngle -= 360.0 * floor(rotAngle / 360.0);
71 return convert<string>(rotAngle);
79 typedef Translator<RotationData::OriginType, string> OriginTranslator;
80 OriginTranslator const & originTranslator();
85 void RotationData::origin(string const & o)
87 origin_ = originTranslator().find(o);
91 string const RotationData::originString() const
93 return originTranslator().find(origin_);
97 string const ResizeLatexCommand::front_impl() const
102 std::ostringstream os;
103 if (data.usingScale()) {
104 double const scl = convert<double>(data.scale) / 100.0;
105 os << "\\scalebox{" << scl << "}[" << scl << "]{";
109 if (data.keepAspectRatio) {
110 if (data.width.inPixels(10) > data.height.inPixels(10))
111 width = data.width.asLatexString();
113 height = data.height.asLatexString();
115 if (!data.width.zero())
116 width = data.width.asLatexString();
117 if (!data.height.zero())
118 height = data.height.asLatexString();
129 string const ResizeLatexCommand::back_impl() const
131 if (data.no_resize())
140 std::ostream & operator<<(std::ostream & os, RotationData::OriginType type)
143 case RotationData::DEFAULT:
144 case RotationData::CENTER:
146 case RotationData::TOPLEFT:
147 case RotationData::TOPCENTER:
148 case RotationData::TOPRIGHT:
151 case RotationData::BOTTOMLEFT:
152 case RotationData::BOTTOMCENTER:
153 case RotationData::BOTTOMRIGHT:
156 case RotationData::BASELINELEFT:
157 case RotationData::BASELINECENTER:
158 case RotationData::BASELINERIGHT:
164 case RotationData::DEFAULT:
166 case RotationData::TOPLEFT:
167 case RotationData::BOTTOMLEFT:
168 case RotationData::BASELINELEFT:
171 case RotationData::CENTER:
172 case RotationData::TOPCENTER:
173 case RotationData::BOTTOMCENTER:
174 case RotationData::BASELINECENTER:
177 case RotationData::TOPRIGHT:
178 case RotationData::BOTTOMRIGHT:
179 case RotationData::BASELINERIGHT:
190 string const RotationLatexCommand::front_impl() const
192 if (data.no_rotation())
195 std::ostringstream os;
198 if (data.origin() != RotationData::DEFAULT)
199 os << "[origin=" << data.origin() << ']';
201 os << '{' << data.angle << "}{";
206 string const RotationLatexCommand::back_impl() const
208 if (data.no_rotation())
215 string const ClipLatexOption::option_impl() const
217 if (!data.clip || data.bbox.empty())
220 std::ostringstream os;
221 if (!data.bbox.empty())
222 os << "bb=" << data.bbox << ',';
229 string const ResizeLatexOption::option_impl() const
231 if (data.no_resize())
234 std::ostringstream os;
235 if (data.usingScale()) {
236 double const scl = convert<double>(data.scale);
237 if (!float_equal(scl, 100.0, 0.05))
238 os << "scale=" << scl / 100.0 << ',';
242 if (!data.width.zero())
243 os << "width=" << data.width.asLatexString() << ',';
244 if (!data.height.zero())
245 os << "height=" << data.height.asLatexString() << ',';
246 if (data.keepAspectRatio)
247 os << "keepaspectratio,";
253 string const RotationLatexOption ::option_impl() const
255 if (data.no_rotation())
258 std::ostringstream os;
259 os << "angle=" << data.angle << ',';
261 if (data.origin() != RotationData::DEFAULT)
262 os << "origin=" << data.origin() << ',';
268 string const sanitizeDocBookOption(string const & input)
274 string const sanitizeLatexOption(string const & input)
276 string::const_iterator begin = input.begin();
277 string::const_iterator end = input.end();
278 string::const_iterator it = begin;
280 // Strip any leading commas
281 // "[,,,,foo..." -> "foo..." ("foo..." may be empty)
284 static boost::regex const front("^( *[[],*)(.*)$");
286 regex_match(it, end, what, front, boost::match_partial);
287 if (!what[0].matched) {
288 lyxerr << "Unable to sanitize LaTeX \"Option\": "
294 // Replace any consecutive commas with a single one
295 // "foo,,,,bar" -> "foo,bar"
296 // with iterator now pointing to 'b'
297 static boost::regex const commas("([^,]*)(,,*)(.*)$");
299 regex_match(it, end, what, commas, boost::match_partial);
300 if (!what[0].matched) {
301 output += string(it, end);
304 output += what.str(1) + ",";
308 // Strip any trailing commas
309 // "...foo,,,]" -> "...foo" ("...foo,,," may be empty)
310 static boost::regex const back("^(.*[^,])?,*[]] *$");
311 regex_match(output, what, back);
312 if (!what[0].matched) {
313 lyxerr << "Unable to sanitize LaTeX \"Option\": "
317 output = what.str(1);
319 // Remove any surrounding whitespace
320 output = support::trim(output);
322 // If the thing is empty, leave it so, else wrap it in square brackets.
323 return output.empty() ? output : "[" + output + "]";
329 template <typename Factory, typename Data, typename Transformer>
330 void extractIt(boost::any const & any_factory,
331 Data const & data, Transformer & transformer)
333 if (any_factory.type() != typeid(Factory))
336 Factory factory = boost::any_cast<Factory>(any_factory);
337 if (!factory.empty())
338 transformer = factory(data);
344 TransformCommand::ptr_type
345 TransformStore::getCommandTransformer(RotationData const & data) const
347 TransformCommand::ptr_type ptr;
349 extractIt<RotationCommandFactory>(any_factory, data, ptr);
354 TransformCommand::ptr_type
355 TransformStore::getCommandTransformer(ResizeData const & data) const
357 TransformCommand::ptr_type ptr;
359 extractIt<ResizeCommandFactory>(any_factory, data, ptr);
364 TransformOption::ptr_type
365 TransformStore::getOptionTransformer(RotationData const & data) const
367 TransformOption::ptr_type ptr;
369 extractIt<RotationOptionFactory>(any_factory, data, ptr);
374 TransformOption::ptr_type
375 TransformStore::getOptionTransformer(ResizeData const & data) const
377 TransformOption::ptr_type ptr;
379 extractIt<ResizeOptionFactory>(any_factory, data, ptr);
384 TransformOption::ptr_type
385 TransformStore::getOptionTransformer(ClipData const & data) const
387 TransformOption::ptr_type ptr;
389 extractIt<ClipOptionFactory>(any_factory, data, ptr);
395 TransformOption::ptr_type
396 TransformStore::getOptionTransformer(string const & data) const
398 TransformOption::ptr_type ptr;
400 extractIt<ExtraOptionFactory>(any_factory, data, ptr);
407 OriginTranslator const initOriginTranslator()
409 OriginTranslator translator(RotationData::DEFAULT, "default");
410 translator.addPair(RotationData::TOPLEFT, "topleft");
411 translator.addPair(RotationData::BOTTOMLEFT, "bottomleft");
412 translator.addPair(RotationData::BASELINELEFT, "baselineleft");
413 translator.addPair(RotationData::CENTER, "center");
414 translator.addPair(RotationData::TOPCENTER, "topcenter");
415 translator.addPair(RotationData::BOTTOMCENTER, "bottomcenter");
416 translator.addPair(RotationData::BASELINECENTER, "baselinecenter");
417 translator.addPair(RotationData::TOPRIGHT, "topright");
418 translator.addPair(RotationData::BOTTOMRIGHT, "bottomright");
419 translator.addPair(RotationData::BASELINERIGHT, "baselineright");
424 OriginTranslator const & originTranslator()
426 static OriginTranslator const translator = initOriginTranslator();
432 } // namespace external