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 <cmath> // abs
26 using namespace lyx::support;
32 string const ExtraData::get(string const & id) const
34 map<string, string>::const_iterator it = data_.find(id);
35 return it == data_.end() ? string() : it->second;
39 void ExtraData::set(string const & id, string const & data)
45 bool ResizeData::no_resize() const
47 return !usingScale() && width.zero() && height.zero();
51 bool ResizeData::usingScale() const
53 return (!scale.empty() && !float_equal(convert<double>(scale), 0.0, 0.05));
57 bool RotationData::no_rotation() const
59 return (angle.empty() || abs(convert<double>(angle)) < 0.1);
63 string const RotationData::adjAngle() const
65 // Ensure that angle lies in the range -360 < angle < 360
66 double rotAngle = convert<double>(angle);
67 if (abs(rotAngle) > 360.0) {
68 rotAngle -= 360.0 * floor(rotAngle / 360.0);
69 return convert<string>(rotAngle);
77 typedef Translator<RotationData::OriginType, string> OriginTranslator;
78 OriginTranslator const & originTranslator();
83 void RotationData::origin(string const & o)
85 origin_ = originTranslator().find(o);
89 string const RotationData::originString() const
91 return originTranslator().find(origin_);
95 string const ResizeLatexCommand::front_impl() const
101 if (data.usingScale()) {
102 double const scl = convert<double>(data.scale) / 100.0;
103 os << "\\scalebox{" << scl << "}[" << scl << "]{";
107 if (data.keepAspectRatio) {
108 if (data.width.inPixels(10) > data.height.inPixels(10))
109 width = data.width.asLatexString();
111 height = data.height.asLatexString();
113 if (!data.width.zero())
114 width = data.width.asLatexString();
115 if (!data.height.zero())
116 height = data.height.asLatexString();
127 string const ResizeLatexCommand::back_impl() const
129 if (data.no_resize())
138 ostream & operator<<(ostream & os, RotationData::OriginType type)
141 case RotationData::DEFAULT:
142 case RotationData::CENTER:
144 case RotationData::TOPLEFT:
145 case RotationData::TOPCENTER:
146 case RotationData::TOPRIGHT:
149 case RotationData::BOTTOMLEFT:
150 case RotationData::BOTTOMCENTER:
151 case RotationData::BOTTOMRIGHT:
154 case RotationData::BASELINELEFT:
155 case RotationData::BASELINECENTER:
156 case RotationData::BASELINERIGHT:
162 case RotationData::DEFAULT:
164 case RotationData::TOPLEFT:
165 case RotationData::BOTTOMLEFT:
166 case RotationData::BASELINELEFT:
169 case RotationData::CENTER:
170 case RotationData::TOPCENTER:
171 case RotationData::BOTTOMCENTER:
172 case RotationData::BASELINECENTER:
175 case RotationData::TOPRIGHT:
176 case RotationData::BOTTOMRIGHT:
177 case RotationData::BASELINERIGHT:
188 string const RotationLatexCommand::front_impl() const
190 if (data.no_rotation())
196 if (data.origin() != RotationData::DEFAULT)
197 os << "[origin=" << data.origin() << ']';
199 os << '{' << data.angle << "}{";
204 string const RotationLatexCommand::back_impl() const
206 if (data.no_rotation())
213 string const ClipLatexOption::option_impl() const
215 if (!data.clip || data.bbox.empty())
219 if (!data.bbox.empty())
220 os << "bb=" << data.bbox.xl.asLatexString() << ' '
221 << data.bbox.yb.asLatexString() << ' '
222 << data.bbox.xr.asLatexString() << ' '
223 << data.bbox.yt.asLatexString() << ',';
230 string const ResizeLatexOption::option_impl() const
232 if (data.no_resize())
236 if (data.usingScale()) {
237 double const scl = convert<double>(data.scale);
238 if (!float_equal(scl, 100.0, 0.05))
239 os << "scale=" << scl / 100.0 << ',';
243 if (!data.width.zero())
244 os << "width=" << data.width.asLatexString() << ',';
245 if (!data.height.zero())
246 os << "height=" << data.height.asLatexString() << ',';
247 if (data.keepAspectRatio)
248 os << "keepaspectratio,";
254 string const RotationLatexOption ::option_impl() const
256 if (data.no_rotation())
260 os << "angle=" << data.angle << ',';
262 if (data.origin() != RotationData::DEFAULT)
263 os << "origin=" << data.origin() << ',';
269 string const sanitizeDocBookOption(string const & input)
275 string const sanitizeLatexOption(string const & input)
277 string::const_iterator begin = input.begin();
278 string::const_iterator end = input.end();
279 string::const_iterator it = begin;
281 // Strip any leading commas
282 // "[,,,,foo..." -> "foo..." ("foo..." may be empty)
285 static regex const front("^( *\\[,*)(.*)$");
287 if (!regex_match(it, end, what, front)) {
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 regex const commas("([^,]*)(,,*)(.*)$");
299 if (!regex_match(it, end, what, commas)) {
300 output += string(it, end);
303 output += what.str(1) + ",";
307 // Strip any trailing commas
308 // "...foo,,,]" -> "...foo" ("...foo,,," may be empty)
309 static regex const back("^(.*[^,])?,*\\] *$");
310 if (!regex_match(output, what, back)) {
311 lyxerr << "Unable to sanitize LaTeX \"Option\": "
315 output = what.str(1);
317 // Remove any surrounding whitespace
318 output = trim(output);
320 // If the thing is empty, leave it so, else wrap it in square brackets.
321 return output.empty() ? output : "[" + output + "]";
327 template <typename Factory, typename Data, typename Transformer>
328 void extractIt(any const & any_factory,
329 Data const & data, Transformer & transformer)
331 if (any_factory.type() != typeid(Factory))
334 Factory factory = any_cast<Factory>(any_factory);
336 transformer = factory(data);
342 TransformCommand::ptr_type
343 TransformStore::getCommandTransformer(RotationData const & data) const
345 TransformCommand::ptr_type ptr;
347 extractIt<RotationCommandFactory>(any_factory, data, ptr);
352 TransformCommand::ptr_type
353 TransformStore::getCommandTransformer(ResizeData const & data) const
355 TransformCommand::ptr_type ptr;
357 extractIt<ResizeCommandFactory>(any_factory, data, ptr);
362 TransformOption::ptr_type
363 TransformStore::getOptionTransformer(RotationData const & data) const
365 TransformOption::ptr_type ptr;
367 extractIt<RotationOptionFactory>(any_factory, data, ptr);
372 TransformOption::ptr_type
373 TransformStore::getOptionTransformer(ResizeData const & data) const
375 TransformOption::ptr_type ptr;
377 extractIt<ResizeOptionFactory>(any_factory, data, ptr);
382 TransformOption::ptr_type
383 TransformStore::getOptionTransformer(ClipData const & data) const
385 TransformOption::ptr_type ptr;
387 extractIt<ClipOptionFactory>(any_factory, data, ptr);
393 TransformOption::ptr_type
394 TransformStore::getOptionTransformer(string const & data) const
396 TransformOption::ptr_type ptr;
398 extractIt<ExtraOptionFactory>(any_factory, data, ptr);
405 OriginTranslator const initOriginTranslator()
407 OriginTranslator translator(RotationData::DEFAULT, "default");
408 translator.addPair(RotationData::TOPLEFT, "topleft");
409 translator.addPair(RotationData::BOTTOMLEFT, "bottomleft");
410 translator.addPair(RotationData::BASELINELEFT, "baselineleft");
411 translator.addPair(RotationData::CENTER, "center");
412 translator.addPair(RotationData::TOPCENTER, "topcenter");
413 translator.addPair(RotationData::BOTTOMCENTER, "bottomcenter");
414 translator.addPair(RotationData::BASELINECENTER, "baselinecenter");
415 translator.addPair(RotationData::TOPRIGHT, "topright");
416 translator.addPair(RotationData::BOTTOMRIGHT, "bottomright");
417 translator.addPair(RotationData::BASELINERIGHT, "baselineright");
422 OriginTranslator const & originTranslator()
424 static OriginTranslator const translator = initOriginTranslator();
430 } // namespace external