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