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