3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Jürgen Spitzmüller
8 * Full author contact details are available in file CREDITS.
13 #include "LaTeXFonts.h"
15 #include "LaTeXFeatures.h"
18 #include "frontends/alert.h"
20 #include "support/convert.h"
21 #include "support/debug.h"
22 #include "support/FileName.h"
23 #include "support/filetools.h"
24 #include "support/gettext.h"
25 #include "support/lstrings.h"
29 using namespace lyx::support;
34 LaTeXFonts latexfonts;
37 LaTeXFont LaTeXFont::altFont(docstring const & name)
39 return theLaTeXFonts().getAltFont(name);
43 bool LaTeXFont::available(bool ot1, bool nomath)
45 if (nomath && !nomathfont_.empty())
46 return altFont(nomathfont_).available(ot1, nomath);
47 else if (ot1 && !ot1font_.empty())
48 return (ot1font_ == "none") ?
49 true : altFont(ot1font_).available(ot1, nomath);
50 else if (requires_.empty() && package_.empty())
52 else if (!requires_.empty()
53 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
55 else if (requires_.empty() && !package_.empty()
56 && LaTeXFeatures::isAvailable(to_ascii(package_)))
58 else if (!altfonts_.empty()) {
59 for (size_t i = 0; i < altfonts_.size(); ++i) {
60 if (altFont(altfonts_[i]).available(ot1, nomath))
68 bool LaTeXFont::providesNoMath(bool ot1, bool complete)
70 docstring const usedfont = getUsedFont(ot1, complete, false);
74 else if (usedfont != name_)
75 return altFont(usedfont).providesNoMath(ot1, complete);
77 return (!nomathfont_.empty() && available(ot1, true));
81 bool LaTeXFont::providesOSF(bool ot1, bool complete, bool nomath)
83 docstring const usedfont = getUsedFont(ot1, complete, nomath);
87 else if (usedfont != name_)
88 return altFont(usedfont).providesOSF(ot1, complete, nomath);
89 else if (!osffont_.empty())
90 return altFont(osffont_).available(ot1, nomath);
91 else if (!available(ot1, nomath))
94 return (!osfoption_.empty() || !osfscoption_.empty());
98 bool LaTeXFont::providesSC(bool ot1, bool complete, bool nomath)
100 docstring const usedfont = getUsedFont(ot1, complete, nomath);
102 if (usedfont.empty())
104 else if (usedfont != name_)
105 return altFont(usedfont).providesSC(ot1, complete, nomath);
106 else if (!available(ot1, nomath))
109 return (!scoption_.empty() || !osfscoption_.empty());
113 bool LaTeXFont::hasMonolithicExpertSet(bool ot1, bool complete, bool nomath)
115 docstring const usedfont = getUsedFont(ot1, complete, nomath);
117 if (usedfont.empty())
119 else if (usedfont != name_)
120 return altFont(usedfont).hasMonolithicExpertSet(ot1, complete, nomath);
121 return (!osfoption_.empty() && !scoption_.empty() && osfoption_ == scoption_)
122 || (osfoption_.empty() && scoption_.empty() && !osfscoption_.empty());
126 bool LaTeXFont::providesScale(bool ot1, bool complete, bool nomath)
128 docstring const usedfont = getUsedFont(ot1, complete, nomath);
130 if (usedfont.empty())
132 else if (usedfont != name_)
133 return altFont(usedfont).providesScale(ot1, complete, nomath);
134 else if (!available(ot1, nomath))
136 return (!scaleoption_.empty());
139 bool LaTeXFont::provides(std::string const & name, bool ot1, bool complete, bool nomath)
141 docstring const usedfont = getUsedFont(ot1, complete, nomath);
143 if (usedfont.empty())
145 else if (usedfont != name_)
146 return altFont(usedfont).provides(name, ot1, complete, nomath);
147 else if (provides_.empty())
150 for (size_t i = 0; i < provides_.size(); ++i) {
151 if (provides_[i] == name)
158 docstring const LaTeXFont::getUsedFont(bool ot1, bool complete, bool nomath)
160 if (nomath && !nomathfont_.empty() && available(ot1, true))
162 else if (ot1 && !ot1font_.empty())
163 return (ot1font_ == "none") ? docstring() : ot1font_;
164 else if (family_ == "rm" && complete && !completefont_.empty()
165 && altFont(completefont_).available(ot1, nomath))
166 return completefont_;
167 else if (switchdefault_) {
168 if (requires_.empty()
169 || (!requires_.empty()
170 && LaTeXFeatures::isAvailable(to_ascii(requires_))))
173 else if (!requires_.empty()
174 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
176 else if (!package_.empty()
177 && LaTeXFeatures::isAvailable(to_ascii(package_)))
179 else if (!preamble_.empty() && package_.empty()
180 && requires_.empty() && !switchdefault_
181 && altfonts_.empty()) {
184 else if (!altfonts_.empty()) {
185 for (size_t i = 0; i < altfonts_.size(); ++i) {
186 LaTeXFont altf = altFont(altfonts_[i]);
187 if (altf.available(ot1, nomath))
188 return altf.getUsedFont(ot1, complete, nomath);
196 docstring const LaTeXFont::getUsedPackage(bool ot1, bool complete, bool nomath)
198 docstring const usedfont = getUsedFont(ot1, complete, nomath);
199 if (usedfont.empty())
201 return theLaTeXFonts().getLaTeXFont(usedfont).package();
205 string const LaTeXFont::getAvailablePackage(bool dryrun)
207 if (package_.empty())
210 string const package = to_ascii(package_);
211 if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
213 else if (LaTeXFeatures::isAvailable(package))
215 // Output unavailable packages in source preview
219 docstring const req = requires_.empty() ? package_ : requires_;
220 frontend::Alert::warning(_("Font not available"),
221 bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
222 "is not available on your system. LyX will fall back to the default font."),
223 req, guiname_), true);
229 string const LaTeXFont::getPackageOptions(bool ot1, bool complete, bool sc, bool osf,
230 int scale, bool nomath)
233 bool const needosfopt = (osf != osfdefault_);
234 bool const has_osf = providesOSF(ot1, complete, nomath);
235 bool const has_sc = providesSC(ot1, complete, nomath);
237 if (!packageoption_.empty())
238 os << to_ascii(packageoption_);
240 if (sc && needosfopt && has_osf && has_sc) {
241 if (!os.str().empty())
243 if (!osfscoption_.empty())
244 os << to_ascii(osfscoption_);
246 os << to_ascii(osfoption_)
247 << ',' << to_ascii(scoption_);
248 } else if (needosfopt && has_osf) {
249 if (!os.str().empty())
251 os << to_ascii(osfoption_);
252 } else if (sc && has_sc) {
253 if (!os.str().empty())
255 os << to_ascii(scoption_);
258 if (scale != 100 && !scaleoption_.empty()
259 && providesScale(ot1, complete, nomath)) {
260 if (!os.str().empty())
262 os << subst(to_ascii(scaleoption_), "$$val",
263 convert<std::string>(float(scale) / 100));
269 string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc,
270 bool osf, bool nomath, int const & scale)
274 docstring const usedfont = getUsedFont(ot1, complete, nomath);
275 if (usedfont.empty())
277 else if (usedfont != name_)
278 return altFont(usedfont).getLaTeXCode(dryrun, ot1, complete, sc, osf, nomath, scale);
280 if (switchdefault_) {
281 if (family_.empty()) {
282 LYXERR0("Error: Font `" << name_ << "' has no family defined!");
285 if (available(ot1, nomath) || dryrun)
286 os << "\\renewcommand{\\" << to_ascii(family_) << "default}{"
287 << to_ascii(name_) << "}\n";
289 frontend::Alert::warning(_("Font not available"),
290 bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
291 "is not available on your system. LyX will fall back to the default font."),
292 requires_, guiname_), true);
294 string const package =
295 getAvailablePackage(dryrun);
296 string const packageopts = getPackageOptions(ot1, complete, sc, osf, scale, nomath);
297 if (packageopts.empty() && !package.empty())
298 os << "\\usepackage{" << package << "}\n";
299 else if (!packageopts.empty() && !package.empty())
300 os << "\\usepackage[" << packageopts << "]{" << package << "}\n";
302 if (osf && providesOSF(ot1, complete, nomath) && !osffont_.empty())
303 os << altFont(osffont_).getLaTeXCode(dryrun, ot1, complete, sc, osf, nomath, scale);
305 if (!preamble_.empty())
312 bool LaTeXFont::readFont(Lexer & lex)
336 // Keep these sorted alphabetically!
337 LexerKeyword latexFontTags[] = {
338 { "altfonts", LF_ALT_FONTS },
339 { "completefont", LF_COMPLETE_FONT },
340 { "endfont", LF_END },
341 { "family", LF_FAMILY },
342 { "guiname", LF_GUINAME },
343 { "nomathfont", LF_NOMATHFONT },
344 { "osfdefault", LF_OSFDEFAULT },
345 { "osffont", LF_OSFFONT },
346 { "osfoption", LF_OSFOPTION },
347 { "osfscoption", LF_OSFSCOPTION },
348 { "ot1font", LF_OT1_FONT },
349 { "package", LF_PACKAGE },
350 { "packageoption", LF_PACKAGEOPTION },
351 { "preamble", LF_PREAMBLE },
352 { "provides", LF_PROVIDES },
353 { "requires", LF_REQUIRES },
354 { "scaleoption", LF_SCALEOPTION },
355 { "scoption", LF_SCOPTION },
356 { "switchdefault", LF_SWITCHDEFAULT }
360 bool finished = false;
361 lex.pushTable(latexFontTags);
362 // parse style section
363 while (!finished && lex.isOK() && !error) {
365 // See comment in LyXRC.cpp.
367 case Lexer::LEX_FEOF:
370 case Lexer::LEX_UNDEF: // parse error
371 lex.printError("Unknown LaTeXFont tag `$$Token'");
378 switch (static_cast<LaTeXFontTags>(le)) {
379 case LF_END: // end of structure
384 docstring altp = lex.getDocString();
385 altfonts_ = getVectorFromString(altp);
388 case LF_COMPLETE_FONT:
389 lex >> completefont_;
418 case LF_PACKAGEOPTION:
419 lex >> packageoption_;
422 preamble_ = lex.getLongString("EndPreamble");
426 string features = lex.getString();
427 provides_ = getVectorFromString(features);
439 case LF_SWITCHDEFAULT:
440 lex >> switchdefault_;
445 lex.printError("No End tag found for LaTeXFont tag `$$Token'");
449 return finished && !error;
453 bool LaTeXFont::read(Lexer & lex)
459 lex.printError("No name given for LaTeX font: `$$Token'.");
463 name_ = lex.getDocString();
464 LYXERR(Debug::INFO, "Reading LaTeX font " << name_);
465 if (!readFont(lex)) {
466 LYXERR0("Error parsing LaTeX font `" << name_ << '\'');
474 void LaTeXFonts::readLaTeXFonts()
476 // Read latexfonts file
477 FileName filename = libFileSearch(string(), "latexfonts");
478 if (filename.empty()) {
479 LYXERR0("Error: latexfonts file not found!");
483 lex.setFile(filename);
484 lex.setContext("LaTeXFeatures::readLaTeXFonts");
488 case Lexer::LEX_FEOF:
494 string const type = lex.getString();
495 if (type != "Font" && type != "AltFont") {
496 lex.printError("Unknown LaTeXFont tag `$$Token'");
504 if (type == "AltFont")
505 texaltfontmap_[f.name()] = f;
507 texfontmap_[f.name()] = f;
512 LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts()
514 if (texfontmap_.empty())
520 LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name)
522 if (name == "default" || name == "auto")
524 if (texfontmap_.empty())
526 if (texfontmap_.find(name) == texfontmap_.end()) {
527 LYXERR0("LaTeXFonts::getLaTeXFont: font '" << name << "' not found!");
530 return texfontmap_[name];
534 LaTeXFont LaTeXFonts::getAltFont(docstring const & name)
536 if (name == "default" || name == "auto")
538 if (texaltfontmap_.empty())
540 if (texaltfontmap_.find(name) == texaltfontmap_.end()) {
541 LYXERR0("LaTeXFonts::getAltFont: alternative font '" << name << "' not found!");
544 return texaltfontmap_[name];