]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Reimplement RowPainter::paintSelection() using row elements
[lyx.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "LaTeXFonts.h"
28 #include "LaTeXPackages.h"
29 #include "Layout.h"
30 #include "Lexer.h"
31 #include "LyXRC.h"
32 #include "TextClass.h"
33 #include "TexRow.h"
34 #include "texstream.h"
35
36 #include "insets/InsetLayout.h"
37
38 #include "support/debug.h"
39 #include "support/docstream.h"
40 #include "support/FileName.h"
41 #include "support/filetools.h"
42 #include "support/gettext.h"
43 #include "support/lstrings.h"
44 #include "support/regex.h"
45
46 #include <algorithm>
47
48
49 using namespace std;
50 using namespace lyx::support;
51
52
53 namespace lyx {
54
55 /////////////////////////////////////////////////////////////////////
56 //
57 // Strings
58 //
59 /////////////////////////////////////////////////////////////////////
60
61 //\NeedsTeXFormat{LaTeX2e}
62 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
63 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
64
65 static docstring const lyx_def = from_ascii(
66         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
67
68 static docstring const lyx_hyperref_def = from_ascii(
69         "\\providecommand{\\LyX}{\\texorpdfstring%\n"
70         "  {L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}\n"
71         "  {LyX}}");
72
73 static docstring const noun_def = from_ascii(
74         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
75
76 static docstring const lyxarrow_def = from_ascii(
77         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
78         "\\@ifstar\n"
79         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
80         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
81
82 // for quotes without babel. This does not give perfect results, but
83 // anybody serious about non-english quotes should use babel (JMarc).
84
85 static docstring const quotedblbase_def = from_ascii(
86         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
87         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
88         "  \\penalty10000\\hskip0em\\relax%\n"
89         "}");
90
91 static docstring const quotesinglbase_def = from_ascii(
92         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
93         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
94         "  \\penalty10000\\hskip0em\\relax%\n"
95         "}");
96
97 static docstring const guillemotleft_def = from_ascii(
98         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
99         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
100         "\\penalty10000\\hskip0pt\\relax%\n"
101         "}");
102
103 static docstring const guillemotright_def = from_ascii(
104         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
105         "  \\penalty10000\\hskip0pt%\n"
106         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
107         "}");
108
109 static docstring const guilsinglleft_def = from_ascii(
110         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
111         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
112         "  \\penalty10000\\hskip0pt\\relax%\n"
113         "}");
114
115 static docstring const guilsinglright_def = from_ascii(
116         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
117         "  \\penalty10000\\hskip0pt%\n"
118         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
119         "}");
120
121 static docstring const paragraphleftindent_def = from_ascii(
122         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
123         "{\n"
124         "  \\begin{list}{}{%\n"
125         "    \\setlength{\\topsep}{0pt}%\n"
126         "    \\addtolength{\\leftmargin}{#1}\n"
127 // ho hum, yet more things commented out with no hint as to why they
128 // weren't just removed
129 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
130 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
131 //      "%%    \\setlength\\listparindent\\parindent%\n"
132 //      "%%    \\setlength\\itemindent\\parindent%\n"
133         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
134         "  }\n"
135         "  \\item[]\n"
136         "}\n"
137         "{\\end{list}}\n");
138
139 static docstring const floatingfootnote_def = from_ascii(
140         "%% Special footnote code from the package 'stblftnt.sty'\n"
141         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
142         "\\let\\SF@@footnote\\footnote\n"
143         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
144         "    \\expandafter\\SF@@footnote\n"
145         "  \\else\n"
146         "    \\expandafter\\SF@gobble@opt\n"
147         "  \\fi\n"
148         "}\n"
149         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
150         "  \\SF@gobble@twobracket\n"
151         "  \\@gobble\n"
152         "}\n"
153         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
154         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
155         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
156
157 static docstring const binom_def = from_ascii(
158         "%% Binom macro for standard LaTeX users\n"
159         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
160
161 static docstring const mathcircumflex_def = from_ascii(
162         "%% For printing a cirumflex inside a formula\n"
163         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
164
165 static docstring const tabularnewline_def = from_ascii(
166         "%% Because html converters don't know tabularnewline\n"
167         "\\providecommand{\\tabularnewline}{\\\\}\n");
168
169 static docstring const lyxgreyedout_def = from_ascii(
170         "%% The greyedout annotation environment\n"
171         "\\newenvironment{lyxgreyedout}\n"
172         "  {\\textcolor{note_fontcolor}\\bgroup\\ignorespaces}\n"
173         "  {\\ignorespacesafterend\\egroup}\n");
174
175 // We want to omit the file extension for includegraphics, but this does not
176 // work when the filename contains other dots.
177 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
178 static docstring const lyxdot_def = from_ascii(
179         "%% A simple dot to overcome graphicx limitations\n"
180         "\\newcommand{\\lyxdot}{.}\n");
181
182 static docstring const changetracking_dvipost_def = from_ascii(
183         "%% Change tracking with dvipost\n"
184         "\\dvipostlayout\n"
185         "\\dvipost{osstart color push Red}\n"
186         "\\dvipost{osend color pop}\n"
187         "\\dvipost{cbstart color push Blue}\n"
188         "\\dvipost{cbend color pop}\n"
189         "\\DeclareRobustCommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
190         "\\DeclareRobustCommand{\\lyxdeleted}[3]{%\n"
191         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
192
193 static docstring const changetracking_xcolor_ulem_def = from_ascii(
194         "%% Change tracking with ulem\n"
195         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
196         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\lyxsout{#3}}}\n"
197         "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n");
198
199 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
200         "%% Change tracking with ulem\n"
201         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
202         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\lyxsout{#3}}{}}}\n"
203         "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n");
204
205 static docstring const changetracking_tikz_math_sout_def = from_ascii(
206         "%% Strike out display math with tikz\n"
207         "\\usepackage{tikz}\n"
208         "\\usetikzlibrary{calc}\n"
209         "\\newcommand{\\lyxmathsout}[1]{%\n"
210         "  \\tikz[baseline=(math.base)]{\n"
211         "    \\node[inner sep=0pt,outer sep=0pt](math){#1};\n"
212         "    \\draw($(math.south west)+(2em,.5em)$)--($(math.north east)-(2em,.5em)$);\n"
213         "  }\n"
214         "}\n");
215
216 static docstring const changetracking_none_def = from_ascii(
217         "\\newcommand{\\lyxadded}[3]{#3}\n"
218         "\\newcommand{\\lyxdeleted}[3]{}\n");
219
220 static docstring const textgreek_LGR_def = from_ascii(
221         "\\DeclareFontEncoding{LGR}{}{}\n");
222 static docstring const textgreek_def = from_ascii(
223         "\\DeclareRobustCommand{\\greektext}{%\n"
224         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
225         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
226         "\\ProvideTextCommand{\\~}{LGR}[1]{\\char126#1}\n");
227
228 static docstring const textcyr_T2A_def = from_ascii(
229         "\\InputIfFileExists{t2aenc.def}{}{%\n"
230         "  \\errmessage{File `t2aenc.def' not found: Cyrillic script not supported}}\n");
231 static docstring const textcyr_def = from_ascii(
232         "\\DeclareRobustCommand{\\cyrtext}{%\n"
233         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
234         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n");
235
236 static docstring const lyxmathsym_def = from_ascii(
237         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
238         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
239
240 static docstring const papersizedvi_def = from_ascii(
241         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
242
243 static docstring const papersizepdf_def = from_ascii(
244         "\\pdfpageheight\\paperheight\n"
245         "\\pdfpagewidth\\paperwidth\n");
246
247 static docstring const papersizepdflua_def = from_ascii(
248         "% Backwards compatibility for LuaTeX < 0.90\n"
249         "\\@ifundefined{pageheight}{\\let\\pageheight\\pdfpageheight}{}\n"
250         "\\@ifundefined{pagewidth}{\\let\\pagewidth\\pdfpagewidth}{}\n"
251         "\\pageheight\\paperheight\n"
252         "\\pagewidth\\paperwidth\n");
253
254 static docstring const cedilla_def = from_ascii(
255         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
256         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
257
258 static docstring const subring_def = from_ascii(
259         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
260         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
261
262 static docstring const subdot_def = from_ascii(
263         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
264         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
265
266 static docstring const subhat_def = from_ascii(
267         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
268         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
269
270 static docstring const subtilde_def = from_ascii(
271         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
272         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
273
274 static docstring const dacute_def = from_ascii(
275         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
276
277 static docstring const tipasymb_def = from_ascii(
278         "\\DeclareFontEncoding{T3}{}{}\n"
279         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
280
281 static docstring const dgrave_def = from_ascii(
282         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
283
284 static docstring const rcap_def = from_ascii(
285         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
286
287 static docstring const ogonek_def = from_ascii(
288         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
289         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
290         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
291         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
292         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
293
294 static docstring const lyxaccent_def = from_ascii(
295         "%% custom text accent \\LyxTextAccent[<rise value (length)>]{<accent>}{<base>}\n"
296         "\\newcommand*{\\LyxTextAccent}[3][0ex]{%\n"
297         "  \\hmode@bgroup\\ooalign{\\null#3\\crcr\\hidewidth\n"
298         "  \\raise#1\\hbox{#2}\\hidewidth}\\egroup}\n"
299         "%% select a font size smaller than the current font size:\n"
300         "\\newcommand{\\LyxAccentSize}[1][\\sf@size]{%\n"
301         "  \\check@mathfonts\\fontsize#1\\z@\\math@fontsfalse\\selectfont\n"
302         "}\n");
303
304 static docstring const textcommabelow_def = from_ascii(
305         "\\ProvideTextCommandDefault{\\textcommabelow}[1]{%%\n"
306         "  \\LyxTextAccent[-.31ex]{\\LyxAccentSize,}{#1}}\n");
307
308 static docstring const textcommaabove_def = from_ascii(
309         "\\ProvideTextCommandDefault{\\textcommaabove}[1]{%%\n"
310         "  \\LyxTextAccent[.5ex]{\\LyxAccentSize`}{#1}}\n");
311
312 static docstring const textcommaaboveright_def = from_ascii(
313         "\\ProvideTextCommandDefault{\\textcommaaboveright}[1]{%%\n"
314         "  \\LyxTextAccent[.5ex]{\\LyxAccentSize\\ '}{#1}}\n");
315
316 // Baltic languages use a comma-accent instead of a cedilla
317 static docstring const textbaltic_def = from_ascii(
318         "%% use comma accent instead of cedilla for these characters:\n"
319         "\\DeclareTextCompositeCommand{\\c}{T1}{g}{\\textcommaabove{g}}\n"
320         "\\DeclareTextCompositeCommand{\\c}{T1}{G}{\\textcommabelow{G}}\n"
321         "\\DeclareTextCompositeCommand{\\c}{T1}{k}{\\textcommabelow{k}}\n"
322         "\\DeclareTextCompositeCommand{\\c}{T1}{K}{\\textcommabelow{K}}\n"
323         "\\DeclareTextCompositeCommand{\\c}{T1}{l}{\\textcommabelow{l}}\n"
324         "\\DeclareTextCompositeCommand{\\c}{T1}{L}{\\textcommabelow{L}}\n"
325         "\\DeclareTextCompositeCommand{\\c}{T1}{n}{\\textcommabelow{n}}\n"
326         "\\DeclareTextCompositeCommand{\\c}{T1}{N}{\\textcommabelow{N}}\n"
327         "\\DeclareTextCompositeCommand{\\c}{T1}{r}{\\textcommabelow{r}}\n"
328         "\\DeclareTextCompositeCommand{\\c}{T1}{R}{\\textcommabelow{R}}\n");
329
330 static docstring const lyxref_def = from_ascii(
331                 "\\RS@ifundefined{subsecref}\n"
332                 "  {\\newref{subsec}{name = \\RSsectxt}}\n"
333                 "  {}\n"
334                 "\\RS@ifundefined{thmref}\n"
335                 "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
336                 "  {}\n"
337                 "\\RS@ifundefined{lemref}\n"
338                 "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n"
339                 "  {}\n");
340
341 // Make sure the columns are also outputed as rtl
342 static docstring const rtloutputdblcol_def = from_ascii(
343         "\\def\\@outputdblcol{%\n"
344         "  \\if@firstcolumn\n"
345         "    \\global \\@firstcolumnfalse\n"
346         "    \\global \\setbox\\@leftcolumn \\box\\@outputbox\n"
347         "  \\else\n"
348         "    \\global \\@firstcolumntrue\n"
349         "    \\setbox\\@outputbox \\vbox {%\n"
350         "      \\hb@xt@\\textwidth {%\n"
351         "      \\kern\\textwidth \\kern-\\columnwidth %**\n"
352         "      \\hb@xt@\\columnwidth {%\n"
353         "         \\box\\@leftcolumn \\hss}%\n"
354         "      \\kern-\\textwidth %**\n"
355         "      \\hfil\n"
356         "      {\\normalcolor\\vrule \\@width\\columnseprule}%\n"
357         "      \\hfil\n"
358         "      \\kern-\\textwidth  %**\n"
359         "      \\hb@xt@\\columnwidth {%\n"
360         "         \\box\\@outputbox \\hss}%\n"
361         "      \\kern-\\columnwidth \\kern\\textwidth %**\n"
362         "    }%\n"
363         "  }%\n"
364         "  \\@combinedblfloats\n"
365         "  \\@outputpage\n"
366         "  \\begingroup\n"
367         "  \\@dblfloatplacement\n"
368         "  \\@startdblcolumn\n"
369         "  \\@whilesw\\if@fcolmade \\fi\n"
370         "  {\\@outputpage\n"
371         "    \\@startdblcolumn}%\n"
372         "  \\endgroup\n"
373         "  \\fi\n"
374         "}\n"
375         "\\@mparswitchtrue\n");
376
377
378 /////////////////////////////////////////////////////////////////////
379 //
380 // LyXHTML strings
381 //
382 /////////////////////////////////////////////////////////////////////
383
384 static docstring const lyxnoun_style = from_ascii(
385         "dfn.lyxnoun {\n"
386         "  font-variant: small-caps;\n"
387         "}\n");
388
389
390 // this is how it normally renders, but it might not always do so.
391 static docstring const lyxstrikeout_style = from_ascii(
392         "del.strikeout {\n"
393         "  text-decoration: line-through;\n"
394         "}\n");
395
396
397 /////////////////////////////////////////////////////////////////////
398 //
399 // LaTeXFeatures
400 //
401 /////////////////////////////////////////////////////////////////////
402
403
404 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
405                              OutputParams const & r)
406         : buffer_(&b), params_(p), runparams_(r), in_float_(false),
407           in_deleted_inset_(false)
408 {}
409
410
411 LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const
412 {
413         string const local_lp = bufferParams().lang_package;
414
415         // Locally, custom is just stored as a string
416         // in bufferParams().lang_package.
417         if (local_lp != "auto"
418             && local_lp != "babel"
419             && local_lp != "default"
420             && local_lp != "none")
421                  return LANG_PACK_CUSTOM;
422
423         if (local_lp == "none")
424                 return LANG_PACK_NONE;
425
426         /* If "auto" is selected, we load polyglossia with non-TeX fonts,
427          * else we select babel.
428          * If babel is selected (either directly or via the "auto"
429          * mechanism), we really do only require it if we have
430          * a language that needs it.
431          */
432         bool const polyglossia_required =
433                 params_.useNonTeXFonts
434                 && isAvailable("polyglossia")
435                 && !isProvided("babel")
436                 && this->hasOnlyPolyglossiaLanguages();
437         bool const babel_required =
438                 !bufferParams().language->babel().empty()
439                 || !this->getBabelLanguages().empty();
440
441         if (local_lp == "auto") {
442                 // polyglossia requirement has priority over babel
443                 if (polyglossia_required)
444                         return LANG_PACK_POLYGLOSSIA;
445                 else if (babel_required)
446                         return LANG_PACK_BABEL;
447         }
448
449         if (local_lp == "babel") {
450                 if (babel_required)
451                         return LANG_PACK_BABEL;
452         }
453
454         if (local_lp == "default") {
455                 switch (lyxrc.language_package_selection) {
456                 case LyXRC::LP_AUTO:
457                         // polyglossia requirement has priority over babel
458                         if (polyglossia_required)
459                                 return LANG_PACK_POLYGLOSSIA;
460                         else if (babel_required)
461                                 return LANG_PACK_BABEL;
462                         break;
463                 case LyXRC::LP_BABEL:
464                         if (babel_required)
465                                 return LANG_PACK_BABEL;
466                         break;
467                 case LyXRC::LP_CUSTOM:
468                         return LANG_PACK_CUSTOM;
469                 case LyXRC::LP_NONE:
470                         return LANG_PACK_NONE;
471                 }
472         }
473
474         return LANG_PACK_NONE;
475 }
476
477
478 void LaTeXFeatures::require(string const & name)
479 {
480         features_.insert(name);
481 }
482
483
484 void LaTeXFeatures::require(set<string> const & names)
485 {
486         features_.insert(names.begin(), names.end());
487 }
488
489
490 void LaTeXFeatures::useLayout(docstring const & layoutname)
491 {
492         useLayout(layoutname, 0);
493 }
494
495
496 void LaTeXFeatures::useLayout(docstring const & layoutname, int level)
497 {
498         // Some code to avoid loops in dependency definition
499         const int maxlevel = 30;
500         if (level > maxlevel) {
501                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
502                        << "recursion attained by layout "
503                        << to_utf8(layoutname) << endl;
504                 return;
505         }
506
507         DocumentClass const & tclass = params_.documentClass();
508         if (tclass.hasLayout(layoutname)) {
509                 // Is this layout already in usedLayouts?
510                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
511                     != usedLayouts_.end())
512                         return;
513
514                 Layout const & layout = tclass[layoutname];
515                 require(layout.requires());
516
517                 if (!layout.depends_on().empty()) {
518                         useLayout(layout.depends_on(), level + 1);
519                 }
520                 usedLayouts_.push_back(layoutname);
521         } else {
522                 lyxerr << "LaTeXFeatures::useLayout: layout `"
523                        << to_utf8(layoutname) << "' does not exist in this class"
524                        << endl;
525         }
526 }
527
528
529 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
530 {
531         docstring const & lname = lay.name();
532         DocumentClass const & tclass = params_.documentClass();
533
534         // this is a default inset layout, nothing useful here
535         if (!tclass.hasInsetLayout(lname))
536                 return;
537         // Is this layout already in usedInsetLayouts?
538         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
539                         != usedInsetLayouts_.end())
540                 return;
541
542         require(lay.requires());
543         usedInsetLayouts_.push_back(lname);
544 }
545
546
547 bool LaTeXFeatures::isRequired(string const & name) const
548 {
549         return features_.find(name) != features_.end();
550 }
551
552
553 bool LaTeXFeatures::isProvided(string const & name) const
554 {
555         if (params_.useNonTeXFonts)
556                 return params_.documentClass().provides(name);
557
558         bool const ot1 = (params_.font_encoding() == "default"
559                 || params_.font_encoding() == "OT1");
560         bool const complete = (params_.fontsSans() == "default"
561                 && params_.fontsTypewriter() == "default");
562         bool const nomath = (params_.fontsMath() == "default");
563         return params_.documentClass().provides(name)
564                 || theLaTeXFonts().getLaTeXFont(
565                         from_ascii(params_.fontsRoman())).provides(name, ot1,
566                                                                   complete,
567                                                                   nomath)
568                 || theLaTeXFonts().getLaTeXFont(
569                         from_ascii(params_.fontsSans())).provides(name, ot1,
570                                                                  complete,
571                                                                  nomath)
572                 || theLaTeXFonts().getLaTeXFont(
573                         from_ascii(params_.fontsTypewriter())).provides(name, ot1,
574                                                                        complete,
575                                                                        nomath)
576                 || theLaTeXFonts().getLaTeXFont(
577                         from_ascii(params_.fontsMath())).provides(name, ot1,
578                                                                        complete,
579                                                                        nomath);
580         // TODO: "textbaltic" provided, if the font-encoding is "L7x"
581         //       "textgreek" provided, if a language with font-encoding LGR is used in the document
582         //       "textcyr" provided, if a language with font-encoding T2A is used in the document
583 }
584
585
586 bool LaTeXFeatures::mustProvide(string const & name) const
587 {
588         return isRequired(name) && !isProvided(name);
589 }
590
591
592 bool LaTeXFeatures::isAvailable(string const & name)
593 {
594         string::size_type const i = name.find("->");
595         if (i != string::npos) {
596                 string const from = name.substr(0,i);
597                 string const to = name.substr(i+2);
598                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
599                 return theConverters().isReachable(from, to);
600         }
601         return LaTeXPackages::isAvailable(name);
602 }
603
604
605 namespace {
606
607 void addSnippet(std::list<TexString> & list, TexString ts, bool allow_dupes)
608 {
609         if (allow_dupes ||
610             // test the absense of duplicates, i.e. elements with same str
611             none_of(list.begin(), list.end(), [&](TexString const & ts2){
612                             return ts.str == ts2.str;
613                     })
614             )
615                 list.push_back(move(ts));
616 }
617
618
619 TexString getSnippets(std::list<TexString> const & list)
620 {
621         otexstringstream snip;
622         for (TexString const & ts : list)
623                 snip << TexString(ts) << '\n';
624         return snip.release();
625 }
626
627 } //anon namespace
628
629
630 void LaTeXFeatures::addPreambleSnippet(TexString ts, bool allow_dupes)
631 {
632         addSnippet(preamble_snippets_, move(ts), allow_dupes);
633 }
634
635
636 void LaTeXFeatures::addPreambleSnippet(docstring const & str, bool allow_dupes)
637 {
638         addSnippet(preamble_snippets_, TexString(str), allow_dupes);
639 }
640
641
642 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
643 {
644         addSnippet(css_snippets_, TexString(from_ascii(snippet)), false);
645 }
646
647
648 TexString LaTeXFeatures::getPreambleSnippets() const
649 {
650         return getSnippets(preamble_snippets_);
651 }
652
653
654 docstring LaTeXFeatures::getCSSSnippets() const
655 {
656         return getSnippets(css_snippets_).str;
657 }
658
659
660
661 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
662 {
663         if (!usedFloats_[name])
664                 usedFloats_[name] = subfloat;
665         if (subfloat)
666                 require("subfig");
667         // We only need float.sty if we use non builtin floats, or if we
668         // use the "H" modifier. This includes modified table and
669         // figure floats. (Lgb)
670         Floating const & fl = params_.documentClass().floats().getType(name);
671         if (!fl.floattype().empty() && fl.usesFloatPkg()) {
672                 require("float");
673         }
674 }
675
676
677 void LaTeXFeatures::useLanguage(Language const * lang)
678 {
679         if (!lang->babel().empty() || !lang->polyglossia().empty())
680                 UsedLanguages_.insert(lang);
681         if (!lang->requires().empty())
682                 require(lang->requires());
683         // CJK languages do not have a babel name.
684         // They use the CJK package
685         if (lang->encoding()->package() == Encoding::CJK)
686                 require("CJK");
687         // japanese package is special
688         if (lang->encoding()->package() == Encoding::japanese)
689                 require("japanese");
690 }
691
692
693 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
694 {
695         IncludedFiles_[key] = name;
696 }
697
698
699 bool LaTeXFeatures::hasLanguages() const
700 {
701         return !UsedLanguages_.empty();
702 }
703
704
705 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
706 {
707         // first the main language
708         if (params_.language->polyglossia().empty())
709                 return false;
710         // now the secondary languages
711         LanguageList::const_iterator const begin = UsedLanguages_.begin();
712         for (LanguageList::const_iterator cit = begin;
713              cit != UsedLanguages_.end();
714              ++cit) {
715                 if ((*cit)->polyglossia().empty())
716                         return false;
717         }
718         return true;
719 }
720
721
722 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
723 {
724         // first the main language
725         if (params_.language->isPolyglossiaExclusive())
726                 return true;
727         // now the secondary languages
728         LanguageList::const_iterator const begin = UsedLanguages_.begin();
729         for (LanguageList::const_iterator cit = begin;
730              cit != UsedLanguages_.end();
731              ++cit) {
732                 if ((*cit)->isPolyglossiaExclusive())
733                         return true;
734         }
735         return false;
736 }
737
738
739 string LaTeXFeatures::getBabelLanguages() const
740 {
741         ostringstream languages;
742
743         bool first = true;
744         LanguageList::const_iterator const begin = UsedLanguages_.begin();
745         for (LanguageList::const_iterator cit = begin;
746              cit != UsedLanguages_.end();
747              ++cit) {
748                 if ((*cit)->babel().empty())
749                         continue;
750                 if (!first)
751                         languages << ',';
752                 else
753                         first = false;
754                 languages << (*cit)->babel();
755         }
756         return languages.str();
757 }
758
759
760 std::map<std::string, std::string> LaTeXFeatures::getPolyglossiaLanguages() const
761 {
762         std::map<std::string, std::string> languages;
763
764         LanguageList::const_iterator const begin = UsedLanguages_.begin();
765         for (LanguageList::const_iterator cit = begin;
766              cit != UsedLanguages_.end();
767              ++cit) {
768                 languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts();
769         }
770         return languages;
771 }
772
773
774 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
775 {
776         // This does only find encodings of languages supported by babel, but
777         // that does not matter since we don't have a language with an
778         // encoding supported by inputenc but without babel support.
779         set<string> encodings;
780         LanguageList::const_iterator it  = UsedLanguages_.begin();
781         LanguageList::const_iterator end = UsedLanguages_.end();
782         for (; it != end; ++it)
783                 if ((*it)->encoding()->latexName() != doc_encoding &&
784                     ((*it)->encoding()->package() == Encoding::inputenc
785                      || (*it)->encoding()->package() == Encoding::japanese))
786                         encodings.insert((*it)->encoding()->latexName());
787         return encodings;
788 }
789
790
791 void LaTeXFeatures::getFontEncodings(vector<string> & encodings) const
792 {
793         // these must be loaded if glyphs of this script are used
794         // unless a language providing them is used in the document
795         // FIXME: currently the option is written twice in this case
796         if (mustProvide("textgreek"))
797                 encodings.insert(encodings.begin(), "LGR");
798         if (mustProvide("textcyr"))
799                 encodings.insert(encodings.begin(), "T2A");
800
801         LanguageList::const_iterator it  = UsedLanguages_.begin();
802         LanguageList::const_iterator end = UsedLanguages_.end();
803         for (; it != end; ++it)
804                 if (!(*it)->fontenc().empty()
805                     && ascii_lowercase((*it)->fontenc()) != "none") {
806                         vector<string> extraencs = getVectorFromString((*it)->fontenc());
807                         vector<string>::const_iterator fit = extraencs.begin();
808                         for (; fit != extraencs.end(); ++fit) {
809                                 if (find(encodings.begin(), encodings.end(), *fit) == encodings.end())
810                                         encodings.insert(encodings.begin(), *fit);
811                         }
812                 }
813 }
814
815 namespace {
816
817 char const * simplefeatures[] = {
818 // note that the package order here will be the same in the LaTeX-output
819         "array",
820         "verbatim",
821         "longtable",
822         "rotating",
823         "latexsym",
824         "pifont",
825         // subfig is handled in BufferParams.cpp
826         "varioref",
827         "prettyref",
828         "refstyle",
829         /*For a successful cooperation of the `wrapfig' package with the
830           `float' package you should load the `wrapfig' package *after*
831           the `float' package. See the caption package documentation
832           for explanation.*/
833         "float",
834         "rotfloat",
835         "wrapfig",
836         "booktabs",
837         "dvipost",
838         "fancybox",
839         "calc",
840         "units",
841         "framed",
842         "soul",
843         "textcomp",
844         "pmboxdraw",
845         "bbding",
846         "ifsym",
847         "txfonts",
848         "pxfonts",
849         "mathdesign",
850         "mathrsfs",
851         "mathabx",
852         "mathtools",
853         // "cancel",
854         "ascii",
855         "url",
856         "covington",
857         "csquotes",
858         "enumitem",
859         "endnotes",
860         "hhline",
861         "ifthen",
862         // listings is handled in BufferParams.cpp
863         "bm",
864         "pdfpages",
865         "amscd",
866         "slashed",
867         "multicol",
868         "multirow",
869         "tfrupee",
870         "shapepar",
871         "rsphrase",
872         "hpstatement",
873         "algorithm2e",
874         "sectionbox",
875         "tcolorbox",
876         "pdfcomment",
877         "fixme",
878         "todonotes",
879         "forest",
880         "varwidth"
881 };
882
883 char const * bibliofeatures[] = {
884         // Known bibliography packages (will be loaded before natbib)
885         "achicago",
886         "apacite",
887         "apalike",
888         "astron",
889         "authordate1-4",
890         "babelbib",
891         "bibgerm",
892         "chicago",
893         "chscite",
894         "harvard",
895         "mslapa",
896         "named"
897 };
898
899 int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *);
900
901 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
902
903 }
904
905
906 string const LaTeXFeatures::getColorOptions() const
907 {
908         ostringstream colors;
909
910         // Handling the color packages separately is needed to be able to load them
911         // before babel when hyperref is loaded with the colorlinks option
912         // for more info see Bufferparams.cpp
913
914         // [x]color.sty
915         if (mustProvide("color") || mustProvide("xcolor")) {
916                 string const package =
917                         (mustProvide("xcolor") ? "xcolor" : "color");
918                 if (params_.graphics_driver == "default"
919                         || params_.graphics_driver == "none")
920                         colors << "\\usepackage{" << package << "}\n";
921                 else
922                         colors << "\\usepackage["
923                                  << params_.graphics_driver
924                                  << "]{" << package << "}\n";
925         }
926
927         // pdfcolmk must be loaded after color
928         if (mustProvide("pdfcolmk"))
929                 colors << "\\usepackage{pdfcolmk}\n";
930
931         // the following 3 color commands must be set after color
932         // is loaded and before pdfpages, therefore add the command
933         // here define the set color
934         if (mustProvide("pagecolor")) {
935                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
936                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
937                 // set the page color
938                 colors << "\\pagecolor{page_backgroundcolor}\n";
939         }
940
941         if (mustProvide("fontcolor")) {
942                 colors << "\\definecolor{document_fontcolor}{rgb}{";
943                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
944                 // set the color
945                 colors << "\\color{document_fontcolor}\n";
946         }
947
948         if (mustProvide("lyxgreyedout")) {
949                 colors << "\\definecolor{note_fontcolor}{rgb}{";
950                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
951                 // the color will be set together with the definition of
952                 // the lyxgreyedout environment (see lyxgreyedout_def)
953         }
954
955         // color for shaded boxes
956         if (isRequired("framed") && mustProvide("color")) {
957                 colors << "\\definecolor{shadecolor}{rgb}{";
958                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
959                 // this color is automatically used by the LaTeX-package "framed"
960         }
961
962         return colors.str();
963 }
964
965
966 string const LaTeXFeatures::getPackageOptions() const
967 {
968         ostringstream packageopts;
969         // Output all the package option stuff we have been asked to do.
970         map<string, string>::const_iterator it =
971                 params_.documentClass().packageOptions().begin();
972         map<string, string>::const_iterator en =
973                 params_.documentClass().packageOptions().end();
974         for (; it != en; ++it)
975                 if (mustProvide(it->first))
976                         packageopts << "\\PassOptionsToPackage{" << it->second << "}"
977                                  << "{" << it->first << "}\n";
978         return packageopts.str();
979 }
980
981
982 string const LaTeXFeatures::getPackages() const
983 {
984         ostringstream packages;
985
986         // FIXME: currently, we can only load packages and macros known
987         // to LyX.
988         // However, with the Require tag of layouts/custom insets,
989         // also unknown packages can be requested. They are silently
990         // swallowed now. We should change this eventually.
991
992         //  These are all the 'simple' includes.  i.e
993         //  packages which we just \usepackage{package}
994         for (int i = 0; i < nb_simplefeatures; ++i) {
995                 if (mustProvide(simplefeatures[i]))
996                         packages << "\\usepackage{" << simplefeatures[i] << "}\n";
997         }
998
999         // The rest of these packages are somewhat more complicated
1000         // than those above.
1001
1002         // The tipa package and its extensions (tipx, tone) must not
1003         // be loaded with non-TeX fonts, since fontspec includes the
1004         // respective macros
1005         if (mustProvide("tipa") && !params_.useNonTeXFonts)
1006                 packages << "\\usepackage{tipa}\n";
1007         if (mustProvide("tipx") && !params_.useNonTeXFonts)
1008                 packages << "\\usepackage{tipx}\n";
1009         if (mustProvide("extraipa") && !params_.useNonTeXFonts)
1010                 packages << "\\usepackage{extraipa}\n";
1011         if (mustProvide("tone") && !params_.useNonTeXFonts)
1012                 packages << "\\usepackage{tone}\n";
1013
1014         // if fontspec or newtxmath is used, AMS packages have to be loaded
1015         // before fontspec (in BufferParams)
1016         string const amsPackages = loadAMSPackages();
1017         bool const ot1 = (params_.font_encoding() == "default" || params_.font_encoding() == "OT1");
1018         bool const use_newtxmath =
1019                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fontsMath())).getUsedPackage(
1020                         ot1, false, false) == "newtxmath";
1021
1022         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
1023                 packages << amsPackages;
1024
1025         if (mustProvide("cancel") &&
1026             params_.use_package("cancel") != BufferParams::package_off)
1027                 packages << "\\usepackage{cancel}\n";
1028
1029         // marvosym and bbding both define the \Cross macro
1030         if (mustProvide("marvosym")) {
1031             if (mustProvide("bbding"))
1032                 packages << "\\let\\Cross\\relax\n";
1033             packages << "\\usepackage{marvosym}\n";
1034         }
1035
1036         // accents must be loaded after amsmath
1037         if (mustProvide("accents") &&
1038             params_.use_package("accents") != BufferParams::package_off)
1039                 packages << "\\usepackage{accents}\n";
1040
1041         // mathdots must be loaded after amsmath
1042         if (mustProvide("mathdots") &&
1043                 params_.use_package("mathdots") != BufferParams::package_off)
1044                 packages << "\\usepackage{mathdots}\n";
1045
1046         // yhmath must be loaded after amsmath
1047         if (mustProvide("yhmath") &&
1048             params_.use_package("yhmath") != BufferParams::package_off)
1049                 packages << "\\usepackage{yhmath}\n";
1050
1051         // stmaryrd must be loaded after amsmath
1052         if (mustProvide("stmaryrd") &&
1053             params_.use_package("stmaryrd") != BufferParams::package_off)
1054                 packages << "\\usepackage{stmaryrd}\n";
1055
1056         if (mustProvide("stackrel") &&
1057             params_.use_package("stackrel") != BufferParams::package_off)
1058                 packages << "\\usepackage{stackrel}\n";
1059
1060         if (mustProvide("undertilde") &&
1061                 params_.use_package("undertilde") != BufferParams::package_off)
1062                 packages << "\\usepackage{undertilde}\n";
1063
1064         // [x]color and pdfcolmk are handled in getColorOptions() above
1065
1066         // makeidx.sty
1067         if (isRequired("makeidx") || isRequired("splitidx")) {
1068                 if (!isProvided("makeidx") && !isRequired("splitidx"))
1069                         packages << "\\usepackage{makeidx}\n";
1070                 if (mustProvide("splitidx"))
1071                         packages << "\\usepackage{splitidx}\n";
1072                 packages << "\\makeindex\n";
1073         }
1074
1075         // graphicx.sty
1076         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
1077                 if (params_.graphics_driver == "default")
1078                         packages << "\\usepackage{graphicx}\n";
1079                 else
1080                         packages << "\\usepackage["
1081                                  << params_.graphics_driver
1082                                  << "]{graphicx}\n";
1083         }
1084
1085         // lyxskak.sty --- newer chess support based on skak.sty
1086         if (mustProvide("chess"))
1087                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
1088
1089         // setspace.sty
1090         if (mustProvide("setspace") && !isProvided("SetSpace"))
1091                 packages << "\\usepackage{setspace}\n";
1092
1093         // we need to assure that mhchem is loaded before esint and every other
1094         // package that redefines command of amsmath because mhchem loads amlatex
1095         // (this info is from the author of mhchem from June 2013)
1096         if (mustProvide("mhchem") &&
1097             params_.use_package("mhchem") != BufferParams::package_off)
1098                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
1099                             "\\usepackage{mhchem}\n";
1100
1101         // wasysym is a simple feature, but it must be after amsmath if both
1102         // are used
1103         // wasysym redefines some integrals (e.g. iint) from amsmath. That
1104         // leads to inconsistent integrals. We only load this package if
1105         // the document does not contain integrals (then isRequired("esint")
1106         // is false) or if esint is used, since esint redefines all relevant
1107         // integral symbols from wasysym and amsmath.
1108         // See http://www.lyx.org/trac/ticket/1942
1109         if (mustProvide("wasysym") &&
1110             params_.use_package("wasysym") != BufferParams::package_off &&
1111             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
1112                 packages << "\\usepackage{wasysym}\n";
1113
1114         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
1115         // and wasysym, since it will redeclare inconsistent integral symbols
1116         if (mustProvide("esint") &&
1117             params_.use_package("esint") != BufferParams::package_off)
1118                 packages << "\\usepackage{esint}\n";
1119
1120         // Known bibliography packages (simple \usepackage{package})
1121         for (int i = 0; i < nb_bibliofeatures; ++i) {
1122                 if (mustProvide(bibliofeatures[i]))
1123                         packages << "\\usepackage{"
1124                                  << bibliofeatures[i] << "}\n";
1125         }
1126
1127         // Compatibility between achicago and natbib
1128         if (mustProvide("achicago") && mustProvide("natbib"))
1129                 packages << "\\let\\achicagobib\\thebibliography\n";
1130
1131         // natbib.sty
1132         // Some classes load natbib themselves, but still allow (or even require)
1133         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1134         // This special case is indicated by the "natbib-internal" key.
1135         if (mustProvide("natbib") && !isProvided("natbib-internal")) {
1136                 packages << "\\usepackage[";
1137                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1138                         packages << "numbers";
1139                 else
1140                         packages << "authoryear";
1141                 packages << "]{natbib}\n";
1142         }
1143
1144         // Compatibility between achicago and natbib
1145         if (mustProvide("achicago") && mustProvide("natbib")) {
1146                 packages << "\\let\\thebibliography\\achicagobib\n";
1147                 packages << "\\let\\SCcite\\astroncite\n";
1148                 packages << "\\let\\UnexpandableProtect\\protect\n";
1149         }
1150
1151         // jurabib -- we need version 0.6 at least.
1152         if (mustProvide("jurabib"))
1153                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
1154
1155         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1156         if (mustProvide("opcit")) {
1157                 if (isRequired("hyperref"))
1158                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1159                 else
1160                         packages << "\\usepackage[custombst]{opcit}\n";
1161         }
1162
1163         // xargs -- we need version 1.09 at least
1164         if (mustProvide("xargs"))
1165                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1166
1167         if (mustProvide("xy"))
1168                 packages << "\\usepackage[all]{xy}\n";
1169
1170         if (mustProvide("feyn"))
1171                 packages << "\\usepackage{feyn}\n"; //Diagram
1172
1173         if (mustProvide("ulem"))
1174                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1175                             "\\usepackage{ulem}\n";
1176
1177         if (mustProvide("nomencl")) {
1178                 // Make it work with the new and old version of the package,
1179                 // but don't use the compatibility option since it is
1180                 // incompatible to other packages.
1181                 packages << "\\usepackage{nomencl}\n"
1182                             "% the following is useful when we have the old nomencl.sty package\n"
1183                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1184                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1185                             "\\makenomenclature\n";
1186         }
1187
1188         // fixltx2e provides subscript
1189         if (mustProvide("subscript") && !isRequired("fixltx2e"))
1190                 packages << "\\usepackage{subscript}\n";
1191
1192         // footmisc must be loaded after setspace
1193         // Set options here, load the package after the user preamble to
1194         // avoid problems with manual loaded footmisc.
1195         if (mustProvide("footmisc"))
1196                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1197
1198         if (mustProvide("microtype")){
1199                 packages << "\\usepackage{microtype}\n";
1200         }
1201
1202         return packages.str();
1203 }
1204
1205
1206 TexString LaTeXFeatures::getMacros() const
1207 {
1208         otexstringstream macros;
1209
1210         if (!preamble_snippets_.empty()) {
1211                 macros << '\n';
1212                 macros << getPreambleSnippets();
1213         }
1214
1215         if (mustProvide("papersize")) {
1216                 if (runparams_.flavor == OutputParams::LATEX
1217                     || runparams_.flavor == OutputParams::DVILUATEX)
1218                         macros << papersizedvi_def << '\n';
1219                 else if  (runparams_.flavor == OutputParams::LUATEX)
1220                         macros << papersizepdflua_def << '\n';
1221                 else
1222                         macros << papersizepdf_def << '\n';
1223         }
1224
1225         if (mustProvide("LyX")) {
1226                 if (isRequired("hyperref"))
1227                         macros << lyx_hyperref_def << '\n';
1228                 else
1229                         macros << lyx_def << '\n';
1230         }
1231
1232         if (mustProvide("noun"))
1233                 macros << noun_def << '\n';
1234
1235         if (mustProvide("lyxarrow"))
1236                 macros << lyxarrow_def << '\n';
1237
1238         if (!usePolyglossia() && mustProvide("textgreek")) {
1239                 // ensure LGR font encoding is defined also if fontenc is not loaded by LyX
1240                 if (params_.font_encoding() == "default")
1241                         macros << textgreek_LGR_def;
1242                 macros << textgreek_def << '\n';
1243         }
1244
1245         if (!usePolyglossia() && mustProvide("textcyr")) {
1246                 // ensure T2A font encoding is set up also if fontenc is not loaded by LyX
1247                 if (params_.font_encoding() == "default")
1248                         macros << textcyr_T2A_def;
1249                 macros << textcyr_def << '\n';
1250         }
1251
1252         // non-standard text accents:
1253         if (mustProvide("textcommaabove") || mustProvide("textcommaaboveright") ||
1254             mustProvide("textcommabelow") || mustProvide("textbaltic"))
1255                 macros << lyxaccent_def;
1256
1257         if (mustProvide("textcommabelow") || mustProvide("textbaltic"))
1258                 macros << textcommabelow_def << '\n';
1259
1260         if (mustProvide("textcommaabove") || mustProvide("textbaltic"))
1261                 macros << textcommaabove_def << '\n';
1262
1263         if (mustProvide("textcommaaboveright"))
1264                 macros << textcommaaboveright_def << '\n';
1265
1266         if (mustProvide("textbaltic"))
1267                 macros << textbaltic_def << '\n';
1268
1269         if (mustProvide("lyxmathsym"))
1270                 macros << lyxmathsym_def << '\n';
1271
1272         if (mustProvide("cedilla"))
1273                 macros << cedilla_def << '\n';
1274
1275         if (mustProvide("subring"))
1276                 macros << subring_def << '\n';
1277
1278         if (mustProvide("subdot"))
1279                 macros << subdot_def << '\n';
1280
1281         if (mustProvide("subhat"))
1282                 macros << subhat_def << '\n';
1283
1284         if (mustProvide("subtilde"))
1285                 macros << subtilde_def << '\n';
1286
1287         if (mustProvide("dacute"))
1288                 macros << dacute_def << '\n';
1289
1290         if (mustProvide("tipasymb"))
1291                 macros << tipasymb_def << '\n';
1292
1293         if (mustProvide("dgrave"))
1294                 macros << dgrave_def << '\n';
1295
1296         if (mustProvide("rcap"))
1297                 macros << rcap_def << '\n';
1298
1299         if (mustProvide("ogonek"))
1300                 macros << ogonek_def << '\n';
1301
1302         // quotes.
1303         if (mustProvide("quotesinglbase"))
1304                 macros << quotesinglbase_def << '\n';
1305         if (mustProvide("quotedblbase"))
1306                 macros << quotedblbase_def << '\n';
1307         if (mustProvide("guilsinglleft"))
1308                 macros << guilsinglleft_def << '\n';
1309         if (mustProvide("guilsinglright"))
1310                 macros << guilsinglright_def << '\n';
1311         if (mustProvide("guillemotleft"))
1312                 macros << guillemotleft_def << '\n';
1313         if (mustProvide("guillemotright"))
1314                 macros << guillemotright_def << '\n';
1315
1316         // Math mode
1317         if (mustProvide("binom") && !isRequired("amsmath"))
1318                 macros << binom_def << '\n';
1319         if (mustProvide("mathcircumflex"))
1320                 macros << mathcircumflex_def << '\n';
1321
1322         // other
1323         if (mustProvide("ParagraphLeftIndent"))
1324                 macros << paragraphleftindent_def;
1325         if (mustProvide("NeedLyXFootnoteCode"))
1326                 macros << floatingfootnote_def;
1327
1328         // some problems with tex->html converters
1329         if (mustProvide("NeedTabularnewline"))
1330                 macros << tabularnewline_def;
1331
1332         // greyed-out environment (note inset)
1333         // the color is specified in the routine
1334         // getColorOptions() to avoid LaTeX-package clashes
1335         if (mustProvide("lyxgreyedout"))
1336                 macros << lyxgreyedout_def;
1337
1338         if (mustProvide("lyxdot"))
1339                 macros << lyxdot_def << '\n';
1340
1341         // floats
1342         getFloatDefinitions(macros);
1343
1344         if (mustProvide("refstyle"))
1345                 macros << lyxref_def << '\n';
1346
1347         // change tracking
1348         if (mustProvide("ct-dvipost"))
1349                 macros << changetracking_dvipost_def;
1350
1351         if (mustProvide("ct-xcolor-ulem")) {
1352                 streamsize const prec = macros.os().precision(2);
1353
1354                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1355                 macros << "\\providecolor{lyxadded}{rgb}{"
1356                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1357
1358                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1359                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1360                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1361
1362                 macros.os().precision(prec);
1363
1364                 if (isRequired("hyperref"))
1365                         macros << changetracking_xcolor_ulem_hyperref_def;
1366                 else
1367                         macros << changetracking_xcolor_ulem_def;
1368         }
1369
1370         if (mustProvide("ct-tikz-math-sout"))
1371                         macros << changetracking_tikz_math_sout_def;
1372
1373         if (mustProvide("ct-none"))
1374                 macros << changetracking_none_def;
1375
1376         if (mustProvide("rtloutputdblcol"))
1377                 macros << rtloutputdblcol_def;
1378
1379         return macros.release();
1380 }
1381
1382
1383 docstring const LaTeXFeatures::getBabelPresettings() const
1384 {
1385         odocstringstream tmp;
1386
1387         for (Language const * lang : UsedLanguages_)
1388                 if (!lang->babel_presettings().empty())
1389                         tmp << lang->babel_presettings() << '\n';
1390         if (!params_.language->babel_presettings().empty())
1391                 tmp << params_.language->babel_presettings() << '\n';
1392
1393         if (!contains(tmp.str(), '@'))
1394                 return tmp.str();
1395
1396         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1397 }
1398
1399
1400 docstring const LaTeXFeatures::getBabelPostsettings() const
1401 {
1402         odocstringstream tmp;
1403
1404         for (Language const * lang : UsedLanguages_)
1405                 if (!lang->babel_postsettings().empty())
1406                         tmp << lang->babel_postsettings() << '\n';
1407         if (!params_.language->babel_postsettings().empty())
1408                 tmp << params_.language->babel_postsettings() << '\n';
1409
1410         if (!contains(tmp.str(), '@'))
1411                 return tmp.str();
1412
1413         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1414 }
1415
1416
1417 bool LaTeXFeatures::needBabelLangOptions() const
1418 {
1419         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1420                 return true;
1421
1422         LanguageList::const_iterator it  = UsedLanguages_.begin();
1423         LanguageList::const_iterator end = UsedLanguages_.end();
1424         for (; it != end; ++it)
1425                 if ((*it)->asBabelOptions())
1426                         return true;
1427
1428         return false;
1429 }
1430
1431
1432 string const LaTeXFeatures::loadAMSPackages() const
1433 {
1434         ostringstream tmp;
1435
1436         if (mustProvide("amsmath")
1437             && params_.use_package("amsmath") != BufferParams::package_off) {
1438                 tmp << "\\usepackage{amsmath}\n";
1439         } else {
1440                 // amsbsy and amstext are already provided by amsmath
1441                 if (mustProvide("amsbsy"))
1442                         tmp << "\\usepackage{amsbsy}\n";
1443                 if (mustProvide("amstext"))
1444                         tmp << "\\usepackage{amstext}\n";
1445         }
1446
1447         if (mustProvide("amsthm"))
1448                 tmp << "\\usepackage{amsthm}\n";
1449
1450         if (mustProvide("amssymb")
1451             && params_.use_package("amssymb") != BufferParams::package_off)
1452                 tmp << "\\usepackage{amssymb}\n";
1453
1454         return tmp.str();
1455 }
1456
1457
1458 docstring const LaTeXFeatures::getTClassPreamble() const
1459 {
1460         // the text class specific preamble
1461         DocumentClass const & tclass = params_.documentClass();
1462         odocstringstream tcpreamble;
1463
1464         tcpreamble << tclass.preamble();
1465
1466         list<docstring>::const_iterator cit = usedLayouts_.begin();
1467         list<docstring>::const_iterator end = usedLayouts_.end();
1468         for (; cit != end; ++cit)
1469                 tcpreamble << tclass[*cit].preamble();
1470
1471         cit = usedInsetLayouts_.begin();
1472         end = usedInsetLayouts_.end();
1473         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1474         for (; cit != end; ++cit) {
1475                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1476                 if (it == ils.end())
1477                         continue;
1478                 tcpreamble << it->second.preamble();
1479         }
1480
1481         return tcpreamble.str();
1482 }
1483
1484
1485 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1486 {
1487         DocumentClass const & tclass = params_.documentClass();
1488         odocstringstream tcpreamble;
1489
1490         tcpreamble << tclass.htmlpreamble();
1491
1492         list<docstring>::const_iterator cit = usedLayouts_.begin();
1493         list<docstring>::const_iterator end = usedLayouts_.end();
1494         for (; cit != end; ++cit)
1495                 tcpreamble << tclass[*cit].htmlpreamble();
1496
1497         cit = usedInsetLayouts_.begin();
1498         end = usedInsetLayouts_.end();
1499         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1500         for (; cit != end; ++cit) {
1501                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1502                 if (it == ils.end())
1503                         continue;
1504                 tcpreamble << it->second.htmlpreamble();
1505         }
1506
1507         return tcpreamble.str();
1508 }
1509
1510
1511 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1512 {
1513         DocumentClass const & tclass = params_.documentClass();
1514         odocstringstream tcpreamble;
1515
1516         if (mustProvide("noun"))
1517                 tcpreamble << lyxnoun_style;
1518         // this isn't exact, but it won't hurt that much if it
1519         // wasn't for this.
1520         if (mustProvide("ulem"))
1521                 tcpreamble << lyxstrikeout_style;
1522
1523         tcpreamble << tclass.htmlstyles();
1524
1525         list<docstring>::const_iterator cit = usedLayouts_.begin();
1526         list<docstring>::const_iterator end = usedLayouts_.end();
1527         for (; cit != end; ++cit)
1528                 tcpreamble << tclass[*cit].htmlstyle();
1529
1530         cit = usedInsetLayouts_.begin();
1531         end = usedInsetLayouts_.end();
1532         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1533         for (; cit != end; ++cit) {
1534                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1535                 if (it == ils.end())
1536                         continue;
1537                 tcpreamble << it->second.htmlstyle();
1538         }
1539
1540         return tcpreamble.str();
1541 }
1542
1543
1544 namespace {
1545
1546 docstring const getFloatI18nPreamble(docstring const & type,
1547                         docstring const & name, Language const * lang,
1548                         Encoding const & enc, bool const polyglossia)
1549 {
1550         // Check whether name can be encoded in the buffer encoding
1551         bool encodable = true;
1552         for (size_t i = 0; i < name.size(); ++i) {
1553                 if (!enc.encodable(name[i])) {
1554                         encodable = false;
1555                         break;
1556                 }
1557         }
1558
1559         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1560                                                : from_ascii(lang->babel());
1561         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1562         docstring const texenc = from_ascii(lang->encoding()->latexName());
1563         docstring const bufenc = from_ascii(enc.iconvName());
1564         docstring const s1 = docstring(1, 0xF0000);
1565         docstring const s2 = docstring(1, 0xF0001);
1566         docstring const translated = encodable ? name
1567                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1568                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1569
1570         odocstringstream os;
1571         os << "\\addto\\captions" << language
1572            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1573         return os.str();
1574 }
1575
1576
1577 docstring const i18npreamble(docstring const & templ, Language const * lang,
1578                              Encoding const & enc, bool const polyglossia,
1579                              bool const need_fixedwidth)
1580 {
1581         if (templ.empty())
1582                 return templ;
1583
1584         string preamble = polyglossia ?
1585                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1586                 subst(to_utf8(templ), "$$lang", lang->babel());
1587
1588         string const langenc = lang->encoding()->iconvName();
1589         string const texenc = lang->encoding()->latexName();
1590         string const bufenc = enc.iconvName();
1591         Encoding const * testenc(&enc);
1592         bool lang_fallback = false;
1593         bool ascii_fallback = false;
1594         if (need_fixedwidth && !enc.hasFixedWidth()) {
1595                 if (lang->encoding()->hasFixedWidth()) {
1596                         testenc = lang->encoding();
1597                         lang_fallback = true;
1598                 } else {
1599                         // We need a fixed width encoding, but both the buffer
1600                         // encoding and the language encoding are variable
1601                         // width. As a last fallback, try to convert to pure
1602                         // ASCII using the LaTeX commands defined in unicodesymbols.
1603                         testenc = encodings.fromLyXName("ascii");
1604                         if (!testenc)
1605                                 return docstring();
1606                         ascii_fallback = true;
1607                 }
1608         }
1609         // First and second character of plane 15 (Private Use Area)
1610         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1611         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1612         // FIXME UNICODE
1613         // lyx::regex is not unicode-safe.
1614         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1615         static regex const reg("_\\(([^\\)]+)\\)");
1616         smatch sub;
1617         while (regex_search(preamble, sub, reg)) {
1618                 string const key = sub.str(1);
1619                 docstring const name = lang->translateLayout(key);
1620                 // Check whether name can be encoded in the buffer encoding
1621                 bool encodable = true;
1622                 for (size_t i = 0; i < name.size() && encodable; ++i)
1623                         if (!testenc->encodable(name[i]))
1624                                 encodable = false;
1625                 string translated;
1626                 if (encodable && !lang_fallback)
1627                         translated = to_utf8(name);
1628                 else if (ascii_fallback)
1629                         translated = to_ascii(testenc->latexString(name).first);
1630                 else
1631                         translated = "\\inputencoding{" + texenc + "}"
1632                                 + s1 + langenc + s2 + to_utf8(name)
1633                                 + s1 + bufenc + s2;
1634                 preamble = subst(preamble, sub.str(), translated);
1635         }
1636         return from_utf8(preamble);
1637 }
1638
1639 }
1640
1641
1642 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1643 {
1644         DocumentClass const & tclass = params_.documentClass();
1645         // collect preamble snippets in a set to prevent multiple identical
1646         // commands (would happen if e.g. both theorem and theorem* are used)
1647         set<docstring> snippets;
1648         typedef LanguageList::const_iterator lang_it;
1649         lang_it const lbeg = UsedLanguages_.begin();
1650         lang_it const lend =  UsedLanguages_.end();
1651         list<docstring>::const_iterator cit = usedLayouts_.begin();
1652         list<docstring>::const_iterator end = usedLayouts_.end();
1653         for (; cit != end; ++cit) {
1654                 // language dependent commands (once per document)
1655                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1656                                                 buffer().language(),
1657                                                 buffer().params().encoding(),
1658                                                 use_polyglossia, false));
1659                 // commands for language changing (for multilanguage documents)
1660                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1661                         snippets.insert(i18npreamble(
1662                                                 tclass[*cit].babelpreamble(),
1663                                                 buffer().language(),
1664                                                 buffer().params().encoding(),
1665                                                 use_polyglossia, false));
1666                         for (lang_it lit = lbeg; lit != lend; ++lit)
1667                                 snippets.insert(i18npreamble(
1668                                                 tclass[*cit].babelpreamble(),
1669                                                 *lit,
1670                                                 buffer().params().encoding(),
1671                                                 use_polyglossia, false));
1672                 }
1673         }
1674         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1675                 FloatList const & floats = params_.documentClass().floats();
1676                 UsedFloats::const_iterator fit = usedFloats_.begin();
1677                 UsedFloats::const_iterator fend = usedFloats_.end();
1678                 for (; fit != fend; ++fit) {
1679                         Floating const & fl = floats.getType(fit->first);
1680                         // we assume builtin floats are translated
1681                         if (fl.isPredefined())
1682                                 continue;
1683                         docstring const type = from_ascii(fl.floattype());
1684                         docstring const flname = from_utf8(fl.name());
1685                         docstring name = buffer().language()->translateLayout(fl.name());
1686                         // only request translation if we have a real translation
1687                         // (that differs from the source)
1688                         if (flname != name)
1689                                 snippets.insert(getFloatI18nPreamble(
1690                                                 type, name, buffer().language(),
1691                                                 buffer().params().encoding(),
1692                                                 use_polyglossia));
1693                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1694                                 string const code = (*lit)->code();
1695                                 name = (*lit)->translateLayout(fl.name());
1696                                 // we assume we have a suitable translation if
1697                                 // either the language is English (we need to
1698                                 // translate into English if English is a secondary
1699                                 // language) or if translateIfPossible returns
1700                                 // something different to the English source.
1701                                 bool const have_translation =
1702                                         (flname != name || contains(code, "en"));
1703                                 if (have_translation)
1704                                         snippets.insert(getFloatI18nPreamble(
1705                                                 type, name, *lit,
1706                                                 buffer().params().encoding(),
1707                                                 use_polyglossia));
1708                         }
1709                 }
1710         }
1711
1712         cit = usedInsetLayouts_.begin();
1713         end = usedInsetLayouts_.end();
1714         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1715         for (; cit != end; ++cit) {
1716                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1717                 if (it == ils.end())
1718                         continue;
1719                 // The listings package does not work with variable width
1720                 // encodings, only with fixed width encodings. Therefore we
1721                 // need to force a fixed width encoding for
1722                 // \lstlistlistingname and \lstlistingname (bug 9382).
1723                 // This needs to be consistent with InsetListings::latex().
1724                 bool const need_fixedwidth = !runparams_.isFullUnicode() &&
1725                                 it->second.fixedwidthpreambleencoding();
1726                 // language dependent commands (once per document)
1727                 snippets.insert(i18npreamble(it->second.langpreamble(),
1728                                                 buffer().language(),
1729                                                 buffer().params().encoding(),
1730                                                 use_polyglossia, need_fixedwidth));
1731                 // commands for language changing (for multilanguage documents)
1732                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1733                         snippets.insert(i18npreamble(
1734                                                 it->second.babelpreamble(),
1735                                                 buffer().language(),
1736                                                 buffer().params().encoding(),
1737                                                 use_polyglossia, need_fixedwidth));
1738                         for (lang_it lit = lbeg; lit != lend; ++lit)
1739                                 snippets.insert(i18npreamble(
1740                                                 it->second.babelpreamble(),
1741                                                 *lit,
1742                                                 buffer().params().encoding(),
1743                                                 use_polyglossia, need_fixedwidth));
1744                 }
1745         }
1746
1747         odocstringstream tcpreamble;
1748         set<docstring>::const_iterator const send = snippets.end();
1749         set<docstring>::const_iterator it = snippets.begin();
1750         for (; it != send; ++it)
1751                 tcpreamble << *it;
1752         return tcpreamble.str();
1753 }
1754
1755
1756 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1757 {
1758         // Definition of entities used in the document that are LyX related.
1759         odocstringstream entities;
1760
1761         if (mustProvide("lyxarrow")) {
1762                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1763         }
1764
1765         return entities.str();
1766 }
1767
1768
1769 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1770 {
1771         odocstringstream sgmlpreamble;
1772         // FIXME UNICODE
1773         docstring const basename(from_utf8(onlyPath(fname)));
1774
1775         FileMap::const_iterator end = IncludedFiles_.end();
1776         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1777              fi != end; ++fi)
1778                 // FIXME UNICODE
1779                 sgmlpreamble << "\n<!ENTITY " << fi->first
1780                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1781                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1782
1783         return sgmlpreamble.str();
1784 }
1785
1786
1787 void LaTeXFeatures::showStruct() const
1788 {
1789         lyxerr << "LyX needs the following commands when LaTeXing:"
1790                << "\n***** Packages:" << getPackages()
1791                << "\n***** Macros:" << to_utf8(getMacros().str)
1792                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1793                << "\n***** done." << endl;
1794 }
1795
1796
1797 Buffer const & LaTeXFeatures::buffer() const
1798 {
1799         return *buffer_;
1800 }
1801
1802
1803 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1804 {
1805         buffer_ = &buffer;
1806 }
1807
1808
1809 BufferParams const & LaTeXFeatures::bufferParams() const
1810 {
1811         return params_;
1812 }
1813
1814
1815 void LaTeXFeatures::getFloatDefinitions(otexstream & os) const
1816 {
1817         FloatList const & floats = params_.documentClass().floats();
1818
1819         // Here we will output the code to create the needed float styles.
1820         // We will try to do this as minimal as possible.
1821         // \floatstyle{ruled}
1822         // \newfloat{algorithm}{htbp}{loa}
1823         // \providecommand{\algorithmname}{Algorithm}
1824         // \floatname{algorithm}{\protect\algorithmname}
1825         UsedFloats::const_iterator cit = usedFloats_.begin();
1826         UsedFloats::const_iterator end = usedFloats_.end();
1827         for (; cit != end; ++cit) {
1828                 Floating const & fl = floats.getType(cit->first);
1829
1830                 // For builtin floats we do nothing.
1831                 if (fl.isPredefined())
1832                         continue;
1833
1834                 // We have to special case "table" and "figure"
1835                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1836                         // Output code to modify "table" or "figure"
1837                         // but only if builtin == false
1838                         // and that have to be true at this point in the
1839                         // function.
1840                         docstring const type = from_ascii(fl.floattype());
1841                         docstring const placement = from_ascii(fl.placement());
1842                         docstring const style = from_ascii(fl.style());
1843                         if (!style.empty()) {
1844                                 os << "\\floatstyle{" << style << "}\n"
1845                                    << "\\restylefloat{" << type << "}\n";
1846                         }
1847                         if (!placement.empty()) {
1848                                 os << "\\floatplacement{" << type << "}{"
1849                                    << placement << "}\n";
1850                         }
1851                 } else {
1852                         // The other non builtin floats.
1853
1854                         docstring const type = from_ascii(fl.floattype());
1855                         docstring const placement = from_ascii(fl.placement());
1856                         docstring const ext = from_ascii(fl.ext());
1857                         docstring const within = from_ascii(fl.within());
1858                         docstring const style = from_ascii(fl.style());
1859                         docstring const name =
1860                                 buffer().language()->translateLayout(fl.name());
1861                         os << "\\floatstyle{" << style << "}\n"
1862                            << "\\newfloat{" << type << "}{" << placement
1863                            << "}{" << ext << '}';
1864                         if (!within.empty())
1865                                 os << '[' << within << ']';
1866                         os << '\n'
1867                            << "\\providecommand{\\" << type << "name}{"
1868                            << name << "}\n"
1869                            << "\\floatname{" << type << "}{\\protect\\"
1870                            << type << "name}\n";
1871
1872                         // What missing here is to code to minimalize the code
1873                         // output so that the same floatstyle will not be
1874                         // used several times, when the same style is still in
1875                         // effect. (Lgb)
1876                 }
1877                 if (cit->second)
1878                         // The subfig package is loaded later
1879                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
1880         }
1881 }
1882
1883
1884 void LaTeXFeatures::resolveAlternatives()
1885 {
1886         for (Features::iterator it = features_.begin(); it != features_.end();) {
1887                 if (contains(*it, '|')) {
1888                         vector<string> const alternatives = getVectorFromString(*it, "|");
1889                         vector<string>::const_iterator const end = alternatives.end();
1890                         vector<string>::const_iterator ita = alternatives.begin();
1891                         // Is any alternative already required? => use that
1892                         for (; ita != end; ++ita) {
1893                                 if (isRequired(*ita))
1894                                         break;
1895                         }
1896                         // Is any alternative available? => use the first one
1897                         // (bug 9498)
1898                         if (ita == end) {
1899                                 for (ita = alternatives.begin(); ita != end; ++ita) {
1900                                         if (isAvailable(*ita)) {
1901                                                 require(*ita);
1902                                                 break;
1903                                         }
1904                                 }
1905                         }
1906                         // This will not work, but not requiring something
1907                         // would be more confusing
1908                         if (ita == end)
1909                                 require(alternatives.front());
1910                         features_.erase(it);
1911                         it = features_.begin();
1912                 } else
1913                         ++it;
1914         }
1915 }
1916
1917
1918 void LaTeXFeatures::expandMultiples()
1919 {
1920         for (Features::iterator it = features_.begin(); it != features_.end();) {
1921                 if (contains(*it, ',')) {
1922                         vector<string> const multiples = getVectorFromString(*it, ",");
1923                         vector<string>::const_iterator const end = multiples.end();
1924                         vector<string>::const_iterator itm = multiples.begin();
1925                         // Do nothing if any multiple is already required
1926                         for (; itm != end; ++itm) {
1927                                 if (!isRequired(*itm))
1928                                         require(*itm);
1929                         }
1930                         features_.erase(it);
1931                         it = features_.begin();
1932                 } else
1933                         ++it;
1934         }
1935 }
1936
1937
1938 } // namespace lyx