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/convert.h"
16 #include "support/debug.h"
17 #include "support/lstrings.h"
18 #include "support/lyxlib.h" // float_equal
19 #include "support/Translator.h"
21 #include <boost/regex.hpp>
23 #include <cmath> // abs
27 using namespace lyx::support;
33 string const ExtraData::get(string const & id) const
35 map<string, string>::const_iterator it = data_.find(id);
36 return it == data_.end() ? string() : it->second;
40 void ExtraData::set(string const & id, string const & data)
46 bool ResizeData::no_resize() const
48 return !usingScale() && width.zero() && height.zero();
52 bool ResizeData::usingScale() const
54 return (!scale.empty() && !float_equal(convert<double>(scale), 0.0, 0.05));
58 bool RotationData::no_rotation() const
60 return (angle.empty() || abs(convert<double>(angle)) < 0.1);
64 string const RotationData::adjAngle() const
66 // Ensure that angle lies in the range -360 < angle < 360
67 double rotAngle = convert<double>(angle);
68 if (abs(rotAngle) > 360.0) {
69 rotAngle -= 360.0 * floor(rotAngle / 360.0);
70 return convert<string>(rotAngle);
78 typedef Translator<RotationData::OriginType, string> OriginTranslator;
79 OriginTranslator const & originTranslator();
84 void RotationData::origin(string const & o)
86 origin_ = originTranslator().find(o);
90 string const RotationData::originString() const
92 return originTranslator().find(origin_);
96 string const ResizeLatexCommand::front_impl() const
102 if (data.usingScale()) {
103 double const scl = convert<double>(data.scale) / 100.0;
104 os << "\\scalebox{" << scl << "}[" << scl << "]{";
108 if (data.keepAspectRatio) {
109 if (data.width.inPixels(10) > data.height.inPixels(10))
110 width = data.width.asLatexString();
112 height = data.height.asLatexString();
114 if (!data.width.zero())
115 width = data.width.asLatexString();
116 if (!data.height.zero())
117 height = data.height.asLatexString();
128 string const ResizeLatexCommand::back_impl() const
130 if (data.no_resize())
139 ostream & operator<<(ostream & os, RotationData::OriginType type)
142 case RotationData::DEFAULT:
143 case RotationData::CENTER:
145 case RotationData::TOPLEFT:
146 case RotationData::TOPCENTER:
147 case RotationData::TOPRIGHT:
150 case RotationData::BOTTOMLEFT:
151 case RotationData::BOTTOMCENTER:
152 case RotationData::BOTTOMRIGHT:
155 case RotationData::BASELINELEFT:
156 case RotationData::BASELINECENTER:
157 case RotationData::BASELINERIGHT:
163 case RotationData::DEFAULT:
165 case RotationData::TOPLEFT:
166 case RotationData::BOTTOMLEFT:
167 case RotationData::BASELINELEFT:
170 case RotationData::CENTER:
171 case RotationData::TOPCENTER:
172 case RotationData::BOTTOMCENTER:
173 case RotationData::BASELINECENTER:
176 case RotationData::TOPRIGHT:
177 case RotationData::BOTTOMRIGHT:
178 case RotationData::BASELINERIGHT:
189 string const RotationLatexCommand::front_impl() const
191 if (data.no_rotation())
197 if (data.origin() != RotationData::DEFAULT)
198 os << "[origin=" << data.origin() << ']';
200 os << '{' << data.angle << "}{";
205 string const RotationLatexCommand::back_impl() const
207 if (data.no_rotation())
214 string const ClipLatexOption::option_impl() const
216 if (!data.clip || data.bbox.empty())
220 if (!data.bbox.empty())
221 os << "bb=" << data.bbox << ',';
228 string const ResizeLatexOption::option_impl() const
230 if (data.no_resize())
234 if (data.usingScale()) {
235 double const scl = convert<double>(data.scale);
236 if (!float_equal(scl, 100.0, 0.05))
237 os << "scale=" << scl / 100.0 << ',';
241 if (!data.width.zero())
242 os << "width=" << data.width.asLatexString() << ',';
243 if (!data.height.zero())
244 os << "height=" << data.height.asLatexString() << ',';
245 if (data.keepAspectRatio)
246 os << "keepaspectratio,";
252 string const RotationLatexOption ::option_impl() const
254 if (data.no_rotation())
258 os << "angle=" << data.angle << ',';
260 if (data.origin() != RotationData::DEFAULT)
261 os << "origin=" << data.origin() << ',';
267 string const sanitizeDocBookOption(string const & input)
273 string const sanitizeLatexOption(string const & input)
275 string::const_iterator begin = input.begin();
276 string::const_iterator end = input.end();
277 string::const_iterator it = begin;
279 // Strip any leading commas
280 // "[,,,,foo..." -> "foo..." ("foo..." may be empty)
283 static boost::regex const front("^( *[[],*)(.*)$");
285 regex_match(it, end, what, front, boost::match_partial);
286 if (!what[0].matched) {
287 lyxerr << "Unable to sanitize LaTeX \"Option\": "
293 // Replace any consecutive commas with a single one
294 // "foo,,,,bar" -> "foo,bar"
295 // with iterator now pointing to 'b'
296 static boost::regex const commas("([^,]*)(,,*)(.*)$");
298 regex_match(it, end, what, commas, boost::match_partial);
299 if (!what[0].matched) {
300 output += string(it, end);
303 output += what.str(1) + ",";
307 // Strip any trailing commas
308 // "...foo,,,]" -> "...foo" ("...foo,,," may be empty)
309 static boost::regex const back("^(.*[^,])?,*[]] *$");
310 regex_match(output, what, back);
311 if (!what[0].matched) {
312 lyxerr << "Unable to sanitize LaTeX \"Option\": "
316 output = what.str(1);
318 // Remove any surrounding whitespace
319 output = trim(output);
321 // If the thing is empty, leave it so, else wrap it in square brackets.
322 return output.empty() ? output : "[" + output + "]";
328 template <typename Factory, typename Data, typename Transformer>
329 void extractIt(boost::any const & any_factory,
330 Data const & data, Transformer & transformer)
332 if (any_factory.type() != typeid(Factory))
335 Factory factory = boost::any_cast<Factory>(any_factory);
336 if (!factory.empty())
337 transformer = factory(data);
343 TransformCommand::ptr_type
344 TransformStore::getCommandTransformer(RotationData const & data) const
346 TransformCommand::ptr_type ptr;
348 extractIt<RotationCommandFactory>(any_factory, data, ptr);
353 TransformCommand::ptr_type
354 TransformStore::getCommandTransformer(ResizeData const & data) const
356 TransformCommand::ptr_type ptr;
358 extractIt<ResizeCommandFactory>(any_factory, data, ptr);
363 TransformOption::ptr_type
364 TransformStore::getOptionTransformer(RotationData const & data) const
366 TransformOption::ptr_type ptr;
368 extractIt<RotationOptionFactory>(any_factory, data, ptr);
373 TransformOption::ptr_type
374 TransformStore::getOptionTransformer(ResizeData const & data) const
376 TransformOption::ptr_type ptr;
378 extractIt<ResizeOptionFactory>(any_factory, data, ptr);
383 TransformOption::ptr_type
384 TransformStore::getOptionTransformer(ClipData const & data) const
386 TransformOption::ptr_type ptr;
388 extractIt<ClipOptionFactory>(any_factory, data, ptr);
394 TransformOption::ptr_type
395 TransformStore::getOptionTransformer(string const & data) const
397 TransformOption::ptr_type ptr;
399 extractIt<ExtraOptionFactory>(any_factory, data, ptr);
406 OriginTranslator const initOriginTranslator()
408 OriginTranslator translator(RotationData::DEFAULT, "default");
409 translator.addPair(RotationData::TOPLEFT, "topleft");
410 translator.addPair(RotationData::BOTTOMLEFT, "bottomleft");
411 translator.addPair(RotationData::BASELINELEFT, "baselineleft");
412 translator.addPair(RotationData::CENTER, "center");
413 translator.addPair(RotationData::TOPCENTER, "topcenter");
414 translator.addPair(RotationData::BOTTOMCENTER, "bottomcenter");
415 translator.addPair(RotationData::BASELINECENTER, "baselinecenter");
416 translator.addPair(RotationData::TOPRIGHT, "topright");
417 translator.addPair(RotationData::BOTTOMRIGHT, "bottomright");
418 translator.addPair(RotationData::BASELINERIGHT, "baselineright");
423 OriginTranslator const & originTranslator()
425 static OriginTranslator const translator = initOriginTranslator();
431 } // namespace external