]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
c1e259748b974dc3258fd4155252887d5eec81e1
[features.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";
1311                 if (runparams_.flavor == OutputParams::LATEX
1312                     || runparams_.flavor == OutputParams::DVILUATEX)
1313                         packages << "[dvips]";
1314                 packages << "{changebar}\n";
1315         }
1316
1317         if (mustProvide("footnote")) {
1318                 if (isRequired("hyperref"))
1319                         packages << "\\usepackage{footnotehyper}\n";
1320                 else
1321                         packages << "\\usepackage{footnote}\n";
1322         }
1323
1324         // [pdf]lscape is used to rotate longtables
1325         if (mustProvide("lscape")) {
1326                 if (runparams_.flavor == OutputParams::LATEX
1327                     || runparams_.flavor == OutputParams::DVILUATEX)
1328                         packages << "\\usepackage{lscape}\n";
1329                 else
1330                         packages << "\\usepackage{pdflscape}\n";
1331         }
1332
1333         // The tipa package and its extensions (tipx, tone) must not
1334         // be loaded with non-TeX fonts, since fontspec includes the
1335         // respective macros
1336         if (mustProvide("tipa") && !params_.useNonTeXFonts)
1337                 packages << "\\usepackage{tipa}\n";
1338         if (mustProvide("tipx") && !params_.useNonTeXFonts)
1339                 packages << "\\usepackage{tipx}\n";
1340         if (mustProvide("extraipa") && !params_.useNonTeXFonts)
1341                 packages << "\\usepackage{extraipa}\n";
1342         if (mustProvide("tone") && !params_.useNonTeXFonts)
1343                 packages << "\\usepackage{tone}\n";
1344
1345         // if fontspec or newtxmath is used, AMS packages have to be loaded
1346         // before fontspec (in BufferParams)
1347         string const amsPackages = loadAMSPackages();
1348         bool const ot1 = (params_.main_font_encoding() == "default"
1349                           || params_.main_font_encoding() == "OT1");
1350         bool const use_newtxmath =
1351                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fontsMath())).getUsedPackage(
1352                         ot1, false, false) == "newtxmath";
1353
1354         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
1355                 packages << amsPackages;
1356
1357         if (mustProvide("cancel") &&
1358             params_.use_package("cancel") != BufferParams::package_off)
1359                 packages << "\\usepackage{cancel}\n";
1360
1361         // marvosym and bbding both define the \Cross macro
1362         if (mustProvide("marvosym")) {
1363             if (mustProvide("bbding"))
1364                 packages << "\\let\\Cross\\relax\n";
1365             packages << "\\usepackage{marvosym}\n";
1366         }
1367
1368         // accents must be loaded after amsmath
1369         if (mustProvide("accents") &&
1370             params_.use_package("accents") != BufferParams::package_off)
1371                 packages << "\\usepackage{accents}\n";
1372
1373         // mathdots must be loaded after amsmath
1374         if (mustProvide("mathdots") &&
1375                 params_.use_package("mathdots") != BufferParams::package_off)
1376                 packages << "\\usepackage{mathdots}\n";
1377
1378         // yhmath must be loaded after amsmath
1379         if (mustProvide("yhmath") &&
1380             params_.use_package("yhmath") != BufferParams::package_off)
1381                 packages << "\\usepackage{yhmath}\n";
1382
1383         // stmaryrd must be loaded after amsmath
1384         if (mustProvide("stmaryrd") &&
1385             params_.use_package("stmaryrd") != BufferParams::package_off)
1386                 packages << "\\usepackage{stmaryrd}\n";
1387
1388         if (mustProvide("stackrel") &&
1389             params_.use_package("stackrel") != BufferParams::package_off)
1390                 packages << "\\usepackage{stackrel}\n";
1391
1392         if (mustProvide("undertilde") &&
1393                 params_.use_package("undertilde") != BufferParams::package_off)
1394                 packages << "\\usepackage{undertilde}\n";
1395
1396         // [x]color and pdfcolmk are handled in getColorOptions() above
1397
1398         // makeidx.sty
1399         if (isRequired("makeidx") || isRequired("splitidx")) {
1400                 if (!isProvided("makeidx") && !isRequired("splitidx"))
1401                         packages << "\\usepackage{makeidx}\n";
1402                 if (mustProvide("splitidx"))
1403                         packages << "\\usepackage{splitidx}\n";
1404                 packages << "\\makeindex\n";
1405         }
1406
1407         // graphicx.sty
1408         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
1409                 if (params_.graphics_driver == "default")
1410                         packages << "\\usepackage{graphicx}\n";
1411                 else
1412                         packages << "\\usepackage["
1413                                  << params_.graphics_driver
1414                                  << "]{graphicx}\n";
1415         }
1416
1417         // These must be loaded after graphicx, since they try
1418         // to load graphicx without options
1419         if (mustProvide("rotating"))
1420                 packages << "\\usepackage{rotating}\n";
1421         if (mustProvide("rotfloat"))
1422                 packages << "\\usepackage{rotfloat}\n";
1423
1424         // lyxskak.sty --- newer chess support based on skak.sty
1425         if (mustProvide("chess"))
1426                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
1427
1428         // setspace.sty
1429         if (mustProvide("setspace") && !isProvided("SetSpace"))
1430                 packages << "\\usepackage{setspace}\n";
1431
1432         // we need to assure that mhchem is loaded before esint and every other
1433         // package that redefines command of amsmath because mhchem loads amlatex
1434         // (this info is from the author of mhchem from June 2013)
1435         if (mustProvide("mhchem") &&
1436             params_.use_package("mhchem") != BufferParams::package_off)
1437                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
1438                             "\\usepackage{mhchem}\n";
1439
1440         // wasysym is a simple feature, but it must be after amsmath if both
1441         // are used
1442         // wasysym redefines some integrals (e.g. iint) from amsmath. That
1443         // leads to inconsistent integrals. We only load this package if
1444         // the document does not contain integrals (then isRequired("esint")
1445         // is false) or if esint is used, since esint redefines all relevant
1446         // integral symbols from wasysym and amsmath.
1447         // See http://www.lyx.org/trac/ticket/1942
1448         if (mustProvide("wasysym") &&
1449             params_.use_package("wasysym") != BufferParams::package_off &&
1450             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
1451                 packages << "\\usepackage{wasysym}\n";
1452
1453         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
1454         // and wasysym, since it will redeclare inconsistent integral symbols
1455         if (mustProvide("esint") &&
1456             params_.use_package("esint") != BufferParams::package_off)
1457                 packages << "\\usepackage{esint}\n";
1458
1459         // Known bibliography packages (simple \usepackage{package})
1460         for (int i = 0; i < nb_bibliofeatures; ++i) {
1461                 if (mustProvide(bibliofeatures[i]))
1462                         packages << "\\usepackage{"
1463                                  << bibliofeatures[i] << "}\n";
1464         }
1465
1466         // Compatibility between achicago and natbib
1467         if (mustProvide("achicago") && mustProvide("natbib"))
1468                 packages << "\\let\\achicagobib\\thebibliography\n";
1469
1470         // natbib.sty
1471         // Some classes load natbib themselves, but still allow (or even require)
1472         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1473         // This special case is indicated by the "natbib-internal" key.
1474         if (mustProvide("natbib")
1475             && !isProvided("natbib-internal")
1476             && !isProvided("biblatex")
1477             && !isProvided("biblatex-natbib")
1478             && !isProvided("jurabib")) {
1479                 packages << "\\usepackage[";
1480                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1481                         packages << "numbers";
1482                 else
1483                         packages << "authoryear";
1484                 if (!params_.biblio_opts.empty())
1485                         packages << ',' << params_.biblio_opts;
1486                 packages << "]{natbib}\n";
1487         }
1488
1489         // Compatibility between achicago and natbib
1490         if (mustProvide("achicago") && mustProvide("natbib")) {
1491                 packages << "\\let\\thebibliography\\achicagobib\n";
1492                 packages << "\\let\\SCcite\\astroncite\n";
1493                 packages << "\\let\\UnexpandableProtect\\protect\n";
1494         }
1495
1496         // jurabib -- we need version 0.6 at least.
1497         if (mustProvide("jurabib")
1498             && !isProvided("natbib-internal")
1499             && !isProvided("natbib")
1500             && !isProvided("biblatex")
1501             && !isProvided("biblatex-natbib")) {
1502                 packages << "\\usepackage";
1503                 if (!params_.biblio_opts.empty())
1504                         packages << '[' << params_.biblio_opts << ']';
1505                 packages << "{jurabib}[2004/01/25]\n";
1506         }
1507
1508         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1509         if (mustProvide("opcit")) {
1510                 if (isRequired("hyperref"))
1511                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1512                 else
1513                         packages << "\\usepackage[custombst]{opcit}\n";
1514         }
1515
1516         // xargs -- we need version 1.09 at least
1517         if (mustProvide("xargs"))
1518                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1519
1520         if (mustProvide("xy"))
1521                 packages << "\\usepackage[all]{xy}\n";
1522
1523         if (mustProvide("feyn"))
1524                 packages << "\\usepackage{feyn}\n"; //Diagram
1525
1526         if (mustProvide("ulem"))
1527                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1528                             "\\usepackage{ulem}\n";
1529
1530         if (mustProvide("nomencl")) {
1531                 // Make it work with the new and old version of the package,
1532                 // but don't use the compatibility option since it is
1533                 // incompatible to other packages.
1534                 packages << "\\usepackage{nomencl}\n"
1535                             "% the following is useful when we have the old nomencl.sty package\n"
1536                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1537                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1538                             "\\makenomenclature\n";
1539         }
1540
1541         // fixltx2e provides subscript
1542         if (mustProvide("subscript") && !isRequired("fixltx2e"))
1543                 packages << "\\usepackage{subscript}\n";
1544
1545         // footmisc must be loaded after setspace
1546         // Set options here, load the package after the user preamble to
1547         // avoid problems with manual loaded footmisc.
1548         if (mustProvide("footmisc"))
1549                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1550
1551         if (mustProvide("microtype")){
1552                 packages << "\\usepackage{microtype}\n";
1553         }
1554
1555         return packages.str();
1556 }
1557
1558
1559 TexString LaTeXFeatures::getMacros() const
1560 {
1561         otexstringstream macros;
1562
1563         if (!preamble_snippets_.empty()) {
1564                 macros << '\n';
1565                 macros << getPreambleSnippets();
1566         }
1567
1568         if (mustProvide("xetexdashbreakstate"))
1569                 macros << "\\XeTeXdashbreakstate 0" << '\n';
1570
1571         if (mustProvide("papersize")) {
1572                 if (runparams_.flavor == OutputParams::LATEX
1573                     || runparams_.flavor == OutputParams::DVILUATEX)
1574                         macros << papersizedvi_def << '\n';
1575                 else if  (runparams_.flavor == OutputParams::LUATEX)
1576                         macros << papersizepdflua_def << '\n';
1577                 else
1578                         macros << papersizepdf_def << '\n';
1579         }
1580
1581         if (mustProvide("LyX")) {
1582                 macros << "\\providecommand{\\LyX}";
1583                 // open conditional wrappers
1584                 if (runparams_.use_polyglossia && hasRTLLanguage())
1585                         macros << "{\\@ensure@LTR";
1586                 if (isRequired("hyperref"))
1587                         macros << "{\\texorpdfstring";
1588                 if (useBabel())
1589                         macros << "{\\ensureascii";
1590                 // main definition
1591                 macros << lyx_def;
1592                 // close conditional wrappers
1593                 if (useBabel())
1594                         macros << '}';
1595                 if (isRequired("hyperref"))
1596                         macros << "{LyX}}";
1597                 if (runparams_.use_polyglossia && hasRTLLanguage())
1598                         macros << '}';
1599                 macros << '\n';
1600         }
1601
1602         if (mustProvide("noun"))
1603                 macros << noun_def << '\n';
1604
1605         if (mustProvide("lyxarrow"))
1606                 macros << lyxarrow_def << '\n';
1607
1608         if (mustProvide("lyxzerowidthspace"))
1609                 macros << lyxZWSP_def << '\n';
1610
1611         if (!usePolyglossia() && mustProvide("textgreek")) {
1612             // ensure LGR font encoding is defined also if fontenc is not loaded by LyX
1613                 if (params_.main_font_encoding() == "default")
1614                         macros << textgreek_LGR_def;
1615                 macros << textgreek_def << '\n';
1616         }
1617
1618         if (!usePolyglossia() && mustProvide("textcyrillic")) {
1619                 // ensure T2A font encoding is set up also if fontenc is not loaded by LyX
1620                 if (params_.main_font_encoding() == "default")
1621                         macros << textcyr_T2A_def;
1622                 macros << textcyr_def << '\n';
1623         }
1624
1625         // non-standard text accents:
1626         if (mustProvide("textcommaabove") || mustProvide("textcommaaboveright") ||
1627             mustProvide("textcommabelow") || mustProvide("textbaltic"))
1628                 macros << lyxaccent_def;
1629
1630         if (mustProvide("textcommabelow") || mustProvide("textbaltic"))
1631                 macros << textcommabelow_def << '\n';
1632
1633         if (mustProvide("textcommaabove") || mustProvide("textbaltic"))
1634                 macros << textcommaabove_def << '\n';
1635
1636         if (mustProvide("textcommaaboveright"))
1637                 macros << textcommaaboveright_def << '\n';
1638
1639         if (mustProvide("textbaltic"))
1640                 macros << textbaltic_def << '\n';
1641
1642         if (mustProvide("textschwa"))
1643                 macros << textschwa_def << '\n';
1644
1645         // split-level fractions
1646         if (mustProvide("xfrac") || mustProvide("smallLetterFrac"))
1647                 macros << xfrac_def << '\n';
1648
1649         if (mustProvide("smallLetterFrac"))
1650                 macros << smallLetterFrac_def << '\n';
1651
1652         if (mustProvide("lyxmathsym"))
1653                 macros << lyxmathsym_def << '\n';
1654
1655         if (mustProvide("cedilla"))
1656                 macros << cedilla_def << '\n';
1657
1658         if (mustProvide("subring"))
1659                 macros << subring_def << '\n';
1660
1661         if (mustProvide("subdot"))
1662                 macros << subdot_def << '\n';
1663
1664         if (mustProvide("subhat"))
1665                 macros << subhat_def << '\n';
1666
1667         if (mustProvide("subtilde"))
1668                 macros << subtilde_def << '\n';
1669
1670         if (mustProvide("dacute"))
1671                 macros << dacute_def << '\n';
1672
1673         if (mustProvide("tipasymb"))
1674                 macros << tipasymb_def << '\n';
1675
1676         if (mustProvide("dgrave"))
1677                 macros << dgrave_def << '\n';
1678
1679         if (mustProvide("rcap"))
1680                 macros << rcap_def << '\n';
1681
1682         if (mustProvide("ogonek"))
1683                 macros << ogonek_def << '\n';
1684
1685         // quotes.
1686         if (mustProvide("quotesinglbase"))
1687                 macros << quotesinglbase_def << '\n';
1688         if (mustProvide("quotedblbase"))
1689                 macros << quotedblbase_def << '\n';
1690         if (mustProvide("guilsinglleft"))
1691                 macros << guilsinglleft_def << '\n';
1692         if (mustProvide("guilsinglright"))
1693                 macros << guilsinglright_def << '\n';
1694         if (mustProvide("guillemotleft"))
1695                 macros << guillemotleft_def << '\n';
1696         if (mustProvide("guillemotright"))
1697                 macros << guillemotright_def << '\n';
1698         if (mustProvide("textquotedbl"))
1699                 macros << textquotedbl_def << '\n';
1700         if (mustProvide("textquotesinglep")) {
1701                 if (runparams_.flavor == OutputParams::XETEX)
1702                         macros << textquotesinglep_xetex_def << '\n';
1703                 else
1704                         macros << textquotesinglep_luatex_def << '\n';
1705         }
1706         if (mustProvide("textquotedblp")) {
1707                 if (runparams_.flavor == OutputParams::XETEX)
1708                         macros << textquotedblp_xetex_def << '\n';
1709                 else
1710                         macros << textquotedblp_luatex_def << '\n';
1711         }
1712
1713         // Math mode
1714         if (mustProvide("binom") && !isRequired("amsmath"))
1715                 macros << binom_def << '\n';
1716         if (mustProvide("mathcircumflex"))
1717                 macros << mathcircumflex_def << '\n';
1718
1719         // other
1720         if (mustProvide("ParagraphLeftIndent"))
1721                 macros << paragraphleftindent_def;
1722         if (mustProvide("NeedLyXFootnoteCode"))
1723                 macros << floatingfootnote_def;
1724
1725         // some problems with tex->html converters
1726         if (mustProvide("NeedTabularnewline"))
1727                 macros << tabularnewline_def;
1728
1729         // greyed-out environment (note inset)
1730         // the color is specified in the routine
1731         // getColorOptions() to avoid LaTeX-package clashes
1732         if (mustProvide("lyxgreyedout")) {
1733                 // We need different version for RTL (#8647)
1734                 if (hasRTLLanguage()) {
1735                         if (runparams_.flavor == OutputParams::LUATEX)
1736                                 if (useBabel())
1737                                         macros << lyxgreyedout_luartl_babel_def;
1738                                 else
1739                                         macros << lyxgreyedout_luartl_def;
1740                         else
1741                                 macros << lyxgreyedout_rtl_def;
1742                 } else
1743                         macros << lyxgreyedout_def;
1744         }
1745
1746         if (mustProvide("lyxdot"))
1747                 macros << lyxdot_def << '\n';
1748
1749         // floats
1750         getFloatDefinitions(macros);
1751
1752         if (mustProvide("refstyle"))
1753                 macros << lyxref_def << '\n';
1754
1755         // change tracking
1756         if (mustProvide("ct-dvipost")) {
1757                 if (isRequired("changebar"))
1758                         macros << changetracking_dvipost_cb_def;
1759                 else
1760                         macros << changetracking_dvipost_def;
1761         }
1762
1763         if (mustProvide("ct-xcolor-ulem")) {
1764                 streamsize const prec = macros.os().precision(2);
1765
1766                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1767                 macros << "\\providecolor{lyxadded}{rgb}{"
1768                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1769
1770                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1771                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1772                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1773
1774                 macros.os().precision(prec);
1775
1776                 macros << changetracking_xcolor_ulem_base_def;
1777
1778                 if (isRequired("changebar")) {
1779                         if (isRequired("hyperref"))
1780                                 macros << changetracking_xcolor_ulem_hyperref_cb_def;
1781                         else
1782                                 macros << changetracking_xcolor_ulem_cb_def;
1783                 } else {
1784                         if (isRequired("hyperref"))
1785                                 macros << changetracking_xcolor_ulem_hyperref_def;
1786                         else
1787                                 macros << changetracking_xcolor_ulem_def;
1788                 }
1789         }
1790
1791         if (mustProvide("ct-tikz-object-sout")) {
1792                 if (!mustProvide("ct-xcolor-ulem")) {
1793                         streamsize const prec = macros.os().precision(2);
1794
1795                         RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1796                         macros << "\\providecolor{lyxadded}{rgb}{"
1797                                << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1798         
1799                         RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1800                         macros << "\\providecolor{lyxdeleted}{rgb}{"
1801                                << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1802         
1803                         macros.os().precision(prec);
1804                 }
1805                 
1806                 macros << changetracking_tikz_object_sout_def;
1807                 
1808                 if (isRequired("changebar")) {
1809                         if (isRequired("hyperref"))
1810                                 macros << changetracking_xcolor_ulem_hyperref_cb_object_def;
1811                         else
1812                                 macros << changetracking_xcolor_ulem_cb_object_def;
1813                 } else {
1814                         if (isRequired("hyperref"))
1815                                 macros << changetracking_xcolor_ulem_hyperref_object_def;
1816                         else
1817                                 macros << changetracking_xcolor_ulem_object_def;
1818                 }
1819         }
1820
1821         if (mustProvide("ct-none"))
1822                 macros << changetracking_none_def;
1823
1824         if (mustProvide("rtloutputdblcol"))
1825                 macros << rtloutputdblcol_def;
1826
1827         if (mustProvide("lyxmintcaption"))
1828                 macros << lyxmintcaption_def;
1829
1830         return macros.release();
1831 }
1832
1833
1834 docstring const LaTeXFeatures::getBabelPresettings() const
1835 {
1836         odocstringstream tmp;
1837
1838         for (Language const * lang : UsedLanguages_)
1839                 if (!lang->babel_presettings().empty())
1840                         tmp << lang->babel_presettings() << '\n';
1841         if (!params_.language->babel_presettings().empty())
1842                 tmp << params_.language->babel_presettings() << '\n';
1843
1844         if (!contains(tmp.str(), '@'))
1845                 return tmp.str();
1846
1847         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1848 }
1849
1850
1851 docstring const LaTeXFeatures::getBabelPostsettings() const
1852 {
1853         odocstringstream tmp;
1854
1855         for (Language const * lang : UsedLanguages_)
1856                 if (!lang->babel_postsettings().empty())
1857                         tmp << lang->babel_postsettings() << '\n';
1858         if (!params_.language->babel_postsettings().empty())
1859                 tmp << params_.language->babel_postsettings() << '\n';
1860
1861         if (!contains(tmp.str(), '@'))
1862                 return tmp.str();
1863
1864         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1865 }
1866
1867
1868 string const LaTeXFeatures::loadAMSPackages() const
1869 {
1870         ostringstream tmp;
1871
1872         if (mustProvide("amsmath")
1873             && params_.use_package("amsmath") != BufferParams::package_off) {
1874                 tmp << "\\usepackage{amsmath}\n";
1875         } else {
1876                 // amsbsy and amstext are already provided by amsmath
1877                 if (mustProvide("amsbsy"))
1878                         tmp << "\\usepackage{amsbsy}\n";
1879                 if (mustProvide("amstext"))
1880                         tmp << "\\usepackage{amstext}\n";
1881         }
1882
1883         if (mustProvide("amsthm"))
1884                 tmp << "\\usepackage{amsthm}\n";
1885
1886         if (mustProvide("amssymb")
1887             && params_.use_package("amssymb") != BufferParams::package_off)
1888                 tmp << "\\usepackage{amssymb}\n";
1889
1890         return tmp.str();
1891 }
1892
1893
1894 docstring const LaTeXFeatures::getTClassPreamble() const
1895 {
1896         // the text class specific preamble
1897         DocumentClass const & tclass = params_.documentClass();
1898         odocstringstream tcpreamble;
1899
1900         tcpreamble << tclass.preamble();
1901
1902         list<docstring>::const_iterator cit = usedLayouts_.begin();
1903         list<docstring>::const_iterator end = usedLayouts_.end();
1904         for (; cit != end; ++cit)
1905                 // For InPreamble layouts, we output the preamble stuff earlier
1906                 // (before the layouts). See Paragraph::Private::validate.
1907                 if (!tclass[*cit].inpreamble)
1908                         tcpreamble << tclass[*cit].preamble();
1909
1910         cit = usedInsetLayouts_.begin();
1911         end = usedInsetLayouts_.end();
1912         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1913         for (; cit != end; ++cit) {
1914                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1915                 if (it == ils.end())
1916                         continue;
1917                 tcpreamble << it->second.preamble();
1918         }
1919
1920         return tcpreamble.str();
1921 }
1922
1923
1924 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1925 {
1926         DocumentClass const & tclass = params_.documentClass();
1927         odocstringstream tcpreamble;
1928
1929         tcpreamble << tclass.htmlpreamble();
1930
1931         list<docstring>::const_iterator cit = usedLayouts_.begin();
1932         list<docstring>::const_iterator end = usedLayouts_.end();
1933         for (; cit != end; ++cit)
1934                 tcpreamble << tclass[*cit].htmlpreamble();
1935
1936         cit = usedInsetLayouts_.begin();
1937         end = usedInsetLayouts_.end();
1938         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1939         for (; cit != end; ++cit) {
1940                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1941                 if (it == ils.end())
1942                         continue;
1943                 tcpreamble << it->second.htmlpreamble();
1944         }
1945
1946         return tcpreamble.str();
1947 }
1948
1949
1950 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1951 {
1952         DocumentClass const & tclass = params_.documentClass();
1953         odocstringstream tcpreamble;
1954
1955         if (mustProvide("noun"))
1956                 tcpreamble << lyxnoun_style;
1957         // this isn't exact, but it won't hurt that much if it
1958         // wasn't for this.
1959         if (mustProvide("ulem"))
1960                 tcpreamble << lyxstrikeout_style;
1961
1962         tcpreamble << tclass.htmlstyles();
1963
1964         list<docstring>::const_iterator cit = usedLayouts_.begin();
1965         list<docstring>::const_iterator end = usedLayouts_.end();
1966         for (; cit != end; ++cit)
1967                 tcpreamble << tclass[*cit].htmlstyle();
1968
1969         cit = usedInsetLayouts_.begin();
1970         end = usedInsetLayouts_.end();
1971         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1972         for (; cit != end; ++cit) {
1973                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1974                 if (it == ils.end())
1975                         continue;
1976                 tcpreamble << it->second.htmlstyle();
1977         }
1978
1979         return tcpreamble.str();
1980 }
1981
1982
1983 namespace {
1984
1985 docstring const getFloatI18nPreamble(docstring const & type,
1986                         docstring const & name, Language const * lang,
1987                         Encoding const & enc, bool const polyglossia)
1988 {
1989         // Check whether name can be encoded in the buffer encoding
1990         bool encodable = true;
1991         for (size_t i = 0; i < name.size(); ++i) {
1992                 if (!enc.encodable(name[i])) {
1993                         encodable = false;
1994                         break;
1995                 }
1996         }
1997
1998         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1999                                                : from_ascii(lang->babel());
2000         docstring const langenc = from_ascii(lang->encoding()->iconvName());
2001         docstring const texenc = from_ascii(lang->encoding()->latexName());
2002         docstring const bufenc = from_ascii(enc.iconvName());
2003         docstring const s1 = docstring(1, 0xF0000);
2004         docstring const s2 = docstring(1, 0xF0001);
2005         docstring const translated = encodable ? name
2006                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
2007                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
2008
2009         odocstringstream os;
2010         os << "\\addto\\captions" << language
2011            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
2012         return os.str();
2013 }
2014
2015
2016 docstring const i18npreamble(docstring const & templ, Language const * lang,
2017                              Encoding const & enc, bool const polyglossia,
2018                              bool const need_fixedwidth)
2019 {
2020         if (templ.empty())
2021                 return templ;
2022
2023         string preamble = polyglossia ?
2024                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
2025                 subst(to_utf8(templ), "$$lang", lang->babel());
2026
2027         string const langenc = lang->encoding()->iconvName();
2028         string const texenc = lang->encoding()->latexName();
2029         string const bufenc = enc.iconvName();
2030         Encoding const * testenc(&enc);
2031         bool lang_fallback = false;
2032         bool ascii_fallback = false;
2033         if (need_fixedwidth && !enc.hasFixedWidth()) {
2034                 if (lang->encoding()->hasFixedWidth()) {
2035                         testenc = lang->encoding();
2036                         lang_fallback = true;
2037                 } else {
2038                         // We need a fixed width encoding, but both the buffer
2039                         // encoding and the language encoding are variable
2040                         // width. As a last fallback, try to convert to pure
2041                         // ASCII using the LaTeX commands defined in unicodesymbols.
2042                         testenc = encodings.fromLyXName("ascii");
2043                         if (!testenc)
2044                                 return docstring();
2045                         ascii_fallback = true;
2046                 }
2047         }
2048         // First and second character of plane 15 (Private Use Area)
2049         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
2050         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
2051         // FIXME UNICODE
2052         // lyx::regex is not unicode-safe.
2053         // Should use QRegExp or (boost::u32regex, but that requires ICU)
2054         static regex const reg("_\\(([^\\)]+)\\)");
2055         smatch sub;
2056         while (regex_search(preamble, sub, reg)) {
2057                 string const key = sub.str(1);
2058                 docstring const name = lang->translateLayout(key);
2059                 // Check whether name can be encoded in the buffer encoding
2060                 bool encodable = true;
2061                 for (size_t i = 0; i < name.size() && encodable; ++i)
2062                         if (!testenc->encodable(name[i]))
2063                                 encodable = false;
2064                 string translated;
2065                 if (encodable && !lang_fallback)
2066                         translated = to_utf8(name);
2067                 else if (ascii_fallback)
2068                         translated = to_ascii(testenc->latexString(name).first);
2069                 else
2070                         translated = "\\inputencoding{" + texenc + "}"
2071                                 + s1 + langenc + s2 + to_utf8(name)
2072                                 + s1 + bufenc + s2;
2073                 preamble = subst(preamble, sub.str(), translated);
2074         }
2075         return from_utf8(preamble);
2076 }
2077
2078 } // namespace
2079
2080
2081 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel,
2082                                 bool use_polyglossia, bool use_minted) const
2083 {
2084         DocumentClass const & tclass = params_.documentClass();
2085         // collect preamble snippets in a set to prevent multiple identical
2086         // commands (would happen if e.g. both theorem and theorem* are used)
2087         set<docstring> snippets;
2088         typedef LanguageList::const_iterator lang_it;
2089         lang_it const lbeg = UsedLanguages_.begin();
2090         lang_it const lend =  UsedLanguages_.end();
2091         list<docstring>::const_iterator cit = usedLayouts_.begin();
2092         list<docstring>::const_iterator end = usedLayouts_.end();
2093         for (; cit != end; ++cit) {
2094                 // language dependent commands (once per document)
2095                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
2096                                                 buffer().language(),
2097                                                 buffer().params().encoding(),
2098                                                 use_polyglossia, false));
2099                 // commands for language changing (for multilanguage documents)
2100                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2101                         snippets.insert(i18npreamble(
2102                                                 tclass[*cit].babelpreamble(),
2103                                                 buffer().language(),
2104                                                 buffer().params().encoding(),
2105                                                 use_polyglossia, false));
2106                         for (lang_it lit = lbeg; lit != lend; ++lit)
2107                                 snippets.insert(i18npreamble(
2108                                                 tclass[*cit].babelpreamble(),
2109                                                 *lit,
2110                                                 buffer().params().encoding(),
2111                                                 use_polyglossia, false));
2112                 }
2113         }
2114         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2115                 FloatList const & floats = params_.documentClass().floats();
2116                 UsedFloats::const_iterator fit = usedFloats_.begin();
2117                 UsedFloats::const_iterator fend = usedFloats_.end();
2118                 for (; fit != fend; ++fit) {
2119                         Floating const & fl = floats.getType(fit->first);
2120                         // we assume builtin floats are translated
2121                         if (fl.isPredefined())
2122                                 continue;
2123                         docstring const type = from_ascii(fl.floattype());
2124                         docstring const flname = from_utf8(fl.name());
2125                         docstring name = buffer().language()->translateLayout(fl.name());
2126                         // only request translation if we have a real translation
2127                         // (that differs from the source)
2128                         if (flname != name)
2129                                 snippets.insert(getFloatI18nPreamble(
2130                                                 type, name, buffer().language(),
2131                                                 buffer().params().encoding(),
2132                                                 use_polyglossia));
2133                         for (lang_it lit = lbeg; lit != lend; ++lit) {
2134                                 string const code = (*lit)->code();
2135                                 name = (*lit)->translateLayout(fl.name());
2136                                 // we assume we have a suitable translation if
2137                                 // either the language is English (we need to
2138                                 // translate into English if English is a secondary
2139                                 // language) or if translateIfPossible returns
2140                                 // something different to the English source.
2141                                 bool const have_translation =
2142                                         (flname != name || contains(code, "en"));
2143                                 if (have_translation)
2144                                         snippets.insert(getFloatI18nPreamble(
2145                                                 type, name, *lit,
2146                                                 buffer().params().encoding(),
2147                                                 use_polyglossia));
2148                         }
2149                 }
2150         }
2151
2152         cit = usedInsetLayouts_.begin();
2153         end = usedInsetLayouts_.end();
2154         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
2155         for (; cit != end; ++cit) {
2156                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
2157                 if (it == ils.end())
2158                         continue;
2159                 // The listings package does not work with variable width
2160                 // encodings, only with fixed width encodings. Therefore we
2161                 // need to force a fixed width encoding for
2162                 // \lstlistlistingname and \lstlistingname (bug 9382).
2163                 // This needs to be consistent with InsetListings::latex()
2164                 // rsp. InsetListings::forcedEncoding().
2165                 bool const need_fixedwidth = !use_minted &&
2166                                         !runparams_.isFullUnicode() &&
2167                                         buffer().params().encoding().package() != Encoding::japanese &&
2168                                         it->second.fixedwidthpreambleencoding();
2169                 // language dependent commands (once per document)
2170                 snippets.insert(i18npreamble(it->second.langpreamble(),
2171                                                 buffer().language(),
2172                                                 buffer().params().encoding(),
2173                                                 use_polyglossia, need_fixedwidth));
2174                 // commands for language changing (for multilanguage documents)
2175                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2176                         snippets.insert(i18npreamble(
2177                                                 it->second.babelpreamble(),
2178                                                 buffer().language(),
2179                                                 buffer().params().encoding(),
2180                                                 use_polyglossia, need_fixedwidth));
2181                         for (lang_it lit = lbeg; lit != lend; ++lit)
2182                                 snippets.insert(i18npreamble(
2183                                                 it->second.babelpreamble(),
2184                                                 *lit,
2185                                                 buffer().params().encoding(),
2186                                                 use_polyglossia, need_fixedwidth));
2187                 }
2188         }
2189
2190         odocstringstream tcpreamble;
2191         set<docstring>::const_iterator const send = snippets.end();
2192         set<docstring>::const_iterator it = snippets.begin();
2193         for (; it != send; ++it)
2194                 tcpreamble << *it;
2195         return tcpreamble.str();
2196 }
2197
2198
2199 docstring const LaTeXFeatures::getLyXSGMLEntities() const
2200 {
2201         // Definition of entities used in the document that are LyX related.
2202         odocstringstream entities;
2203
2204         if (mustProvide("lyxarrow")) {
2205                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
2206         }
2207
2208         return entities.str();
2209 }
2210
2211
2212 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
2213 {
2214         odocstringstream sgmlpreamble;
2215         // FIXME UNICODE
2216         docstring const basename(from_utf8(onlyPath(fname)));
2217
2218         FileMap::const_iterator end = IncludedFiles_.end();
2219         for (FileMap::const_iterator fi = IncludedFiles_.begin();
2220              fi != end; ++fi)
2221                 // FIXME UNICODE
2222                 sgmlpreamble << "\n<!ENTITY " << fi->first
2223                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
2224                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
2225
2226         return sgmlpreamble.str();
2227 }
2228
2229
2230 void LaTeXFeatures::showStruct() const
2231 {
2232         lyxerr << "LyX needs the following commands when LaTeXing:"
2233                << "\n***** Packages:" << getPackages()
2234                << "\n***** Macros:" << to_utf8(getMacros().str)
2235                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
2236                << "\n***** done." << endl;
2237 }
2238
2239
2240 Buffer const & LaTeXFeatures::buffer() const
2241 {
2242         return *buffer_;
2243 }
2244
2245
2246 void LaTeXFeatures::setBuffer(Buffer const & buffer)
2247 {
2248         buffer_ = &buffer;
2249 }
2250
2251
2252 BufferParams const & LaTeXFeatures::bufferParams() const
2253 {
2254         return params_;
2255 }
2256
2257
2258 void LaTeXFeatures::getFloatDefinitions(otexstream & os) const
2259 {
2260         FloatList const & floats = params_.documentClass().floats();
2261
2262         // Here we will output the code to create the needed float styles.
2263         // We will try to do this as minimal as possible.
2264         // \floatstyle{ruled}
2265         // \newfloat{algorithm}{htbp}{loa}
2266         // \providecommand{\algorithmname}{Algorithm}
2267         // \floatname{algorithm}{\protect\algorithmname}
2268         UsedFloats::const_iterator cit = usedFloats_.begin();
2269         UsedFloats::const_iterator end = usedFloats_.end();
2270         for (; cit != end; ++cit) {
2271                 Floating const & fl = floats.getType(cit->first);
2272
2273                 // For builtin floats we do nothing.
2274                 if (fl.isPredefined())
2275                         continue;
2276
2277                 // We have to special case "table" and "figure"
2278                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
2279                         // Output code to modify "table" or "figure"
2280                         // but only if builtin == false
2281                         // and that have to be true at this point in the
2282                         // function.
2283                         docstring const type = from_ascii(fl.floattype());
2284                         docstring const placement = from_ascii(fl.placement());
2285                         docstring const style = from_ascii(fl.style());
2286                         if (!style.empty()) {
2287                                 os << "\\floatstyle{" << style << "}\n"
2288                                    << "\\restylefloat{" << type << "}\n";
2289                         }
2290                         if (!placement.empty()) {
2291                                 os << "\\floatplacement{" << type << "}{"
2292                                    << placement << "}\n";
2293                         }
2294                 } else {
2295                         // The other non builtin floats.
2296
2297                         docstring const type = from_ascii(fl.floattype());
2298                         docstring const placement = from_ascii(fl.placement());
2299                         docstring const ext = from_ascii(fl.ext());
2300                         docstring const within = from_ascii(fl.within());
2301                         docstring const style = from_ascii(fl.style());
2302                         docstring const name =
2303                                 buffer().language()->translateLayout(fl.name());
2304                         os << "\\floatstyle{" << style << "}\n"
2305                            << "\\newfloat{" << type << "}{" << placement
2306                            << "}{" << ext << '}';
2307                         if (!within.empty())
2308                                 os << '[' << within << ']';
2309                         os << '\n'
2310                            << "\\providecommand{\\" << type << "name}{"
2311                            << name << "}\n"
2312                            << "\\floatname{" << type << "}{\\protect\\"
2313                            << type << "name}\n";
2314
2315                         // What missing here is to code to minimalize the code
2316                         // output so that the same floatstyle will not be
2317                         // used several times, when the same style is still in
2318                         // effect. (Lgb)
2319                 }
2320                 if (cit->second)
2321                         // The subfig package is loaded later
2322                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
2323         }
2324 }
2325
2326
2327 void LaTeXFeatures::resolveAlternatives()
2328 {
2329         for (Features::iterator it = features_.begin(); it != features_.end();) {
2330                 if (contains(*it, '|')) {
2331                         vector<string> const alternatives = getVectorFromString(*it, "|");
2332                         vector<string>::const_iterator const end = alternatives.end();
2333                         vector<string>::const_iterator ita = alternatives.begin();
2334                         // Is any alternative already required? => use that
2335                         for (; ita != end; ++ita) {
2336                                 if (isRequired(*ita))
2337                                         break;
2338                         }
2339                         // Is any alternative available? => use the first one
2340                         // (bug 9498)
2341                         if (ita == end) {
2342                                 for (ita = alternatives.begin(); ita != end; ++ita) {
2343                                         if (isAvailable(*ita)) {
2344                                                 require(*ita);
2345                                                 break;
2346                                         }
2347                                 }
2348                         }
2349                         // This will not work, but not requiring something
2350                         // would be more confusing
2351                         if (ita == end)
2352                                 require(alternatives.front());
2353                         features_.erase(it);
2354                         it = features_.begin();
2355                 } else
2356                         ++it;
2357         }
2358 }
2359
2360
2361 void LaTeXFeatures::expandMultiples()
2362 {
2363         for (Features::iterator it = features_.begin(); it != features_.end();) {
2364                 if (contains(*it, ',')) {
2365                         vector<string> const multiples = getVectorFromString(*it, ",");
2366                         vector<string>::const_iterator const end = multiples.end();
2367                         vector<string>::const_iterator itm = multiples.begin();
2368                         // Do nothing if any multiple is already required
2369                         for (; itm != end; ++itm) {
2370                                 if (!isRequired(*itm))
2371                                         require(*itm);
2372                         }
2373                         features_.erase(it);
2374                         it = features_.begin();
2375                 } else
2376                         ++it;
2377         }
2378 }
2379
2380
2381 } // namespace lyx