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 "support/regex.h"
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.xl.asLatexString() << ' '
222 << data.bbox.yb.asLatexString() << ' '
223 << data.bbox.xr.asLatexString() << ' '
224 << data.bbox.yt.asLatexString() << ',';
231 string const ResizeLatexOption::option_impl() const
233 if (data.no_resize())
237 if (data.usingScale()) {
238 double const scl = convert<double>(data.scale);
239 if (!float_equal(scl, 100.0, 0.05))
240 os << "scale=" << scl / 100.0 << ',';
244 if (!data.width.zero())
245 os << "width=" << data.width.asLatexString() << ',';
246 if (!data.height.zero())
247 os << "height=" << data.height.asLatexString() << ',';
248 if (data.keepAspectRatio)
249 os << "keepaspectratio,";
255 string const RotationLatexOption ::option_impl() const
257 if (data.no_rotation())
261 os << "angle=" << data.angle << ',';
263 if (data.origin() != RotationData::DEFAULT)
264 os << "origin=" << data.origin() << ',';
270 string const sanitizeDocBookOption(string const & input)
276 string const sanitizeLatexOption(string const & input)
278 string::const_iterator begin = input.begin();
279 string::const_iterator end = input.end();
280 string::const_iterator it = begin;
282 // Strip any leading commas
283 // "[,,,,foo..." -> "foo..." ("foo..." may be empty)
286 static lyx::regex const front("^( *\\[,*)(.*)$");
288 if (!regex_match(it, end, what, front)) {
289 lyxerr << "Unable to sanitize LaTeX \"Option\": "
295 // Replace any consecutive commas with a single one
296 // "foo,,,,bar" -> "foo,bar"
297 // with iterator now pointing to 'b'
298 static lyx::regex const commas("([^,]*)(,,*)(.*)$");
300 if (!regex_match(it, end, what, commas)) {
301 output += string(it, end);
304 output += what.str(1) + ",";
308 // Strip any trailing commas
309 // "...foo,,,]" -> "...foo" ("...foo,,," may be empty)
310 static lyx::regex const back("^(.*[^,])?,*\\] *$");
311 if (!regex_match(output, what, back)) {
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);
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