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/docstream.h"
23 #include "support/FileName.h"
24 #include "support/filetools.h"
25 #include "support/gettext.h"
26 #include "support/lstrings.h"
30 using namespace lyx::support;
35 LaTeXFonts latexfonts;
38 LaTeXFont LaTeXFont::altFont(docstring const & name)
40 return theLaTeXFonts().getAltFont(name);
44 bool LaTeXFont::available(bool ot1, bool nomath)
46 if (nomath && !nomathfont_.empty())
47 return altFont(nomathfont_).available(ot1, nomath);
48 else if (ot1 && !ot1font_.empty())
49 return (ot1font_ == "none") ?
50 true : altFont(ot1font_).available(ot1, nomath);
51 else if (requires_.empty() && package_.empty())
53 else if (!requires_.empty()
54 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
56 else if (requires_.empty() && !package_.empty()
57 && LaTeXFeatures::isAvailable(to_ascii(package_)))
59 else if (!altfonts_.empty()) {
60 for (size_t i = 0; i < altfonts_.size(); ++i) {
61 if (altFont(altfonts_[i]).available(ot1, nomath))
69 bool LaTeXFont::providesNoMath(bool ot1, bool complete)
71 docstring const usedfont = getUsedFont(ot1, complete, false);
75 else if (usedfont != name_)
76 return altFont(usedfont).providesNoMath(ot1, complete);
78 return (!nomathfont_.empty() && available(ot1, true));
82 bool LaTeXFont::providesOSF(bool ot1, bool complete, bool nomath)
84 docstring const usedfont = getUsedFont(ot1, complete, nomath);
88 else if (usedfont != name_)
89 return altFont(usedfont).providesOSF(ot1, complete, nomath);
90 else if (!osffont_.empty())
91 return altFont(osffont_).available(ot1, nomath);
92 else if (!available(ot1, nomath))
95 return (!osfoption_.empty() || !osfscoption_.empty());
99 bool LaTeXFont::providesSC(bool ot1, bool complete, bool nomath)
101 docstring const usedfont = getUsedFont(ot1, complete, nomath);
103 if (usedfont.empty())
105 else if (usedfont != name_)
106 return altFont(usedfont).providesSC(ot1, complete, nomath);
107 else if (!available(ot1, nomath))
110 return (!scoption_.empty() || !osfscoption_.empty());
114 bool LaTeXFont::hasMonolithicExpertSet(bool ot1, bool complete, bool nomath)
116 docstring const usedfont = getUsedFont(ot1, complete, nomath);
118 if (usedfont.empty())
120 else if (usedfont != name_)
121 return altFont(usedfont).hasMonolithicExpertSet(ot1, complete, nomath);
122 return (!osfoption_.empty() && !scoption_.empty() && osfoption_ == scoption_)
123 || (osfoption_.empty() && scoption_.empty() && !osfscoption_.empty());
127 bool LaTeXFont::providesScale(bool ot1, bool complete, bool nomath)
129 docstring const usedfont = getUsedFont(ot1, complete, nomath);
131 if (usedfont.empty())
133 else if (usedfont != name_)
134 return altFont(usedfont).providesScale(ot1, complete, nomath);
135 else if (!available(ot1, nomath))
137 return (!scaleoption_.empty());
140 bool LaTeXFont::provides(std::string const & name, bool ot1, bool complete, bool nomath)
142 docstring const usedfont = getUsedFont(ot1, complete, nomath);
144 if (usedfont.empty())
146 else if (usedfont != name_)
147 return altFont(usedfont).provides(name, ot1, complete, nomath);
148 else if (provides_.empty())
151 for (size_t i = 0; i < provides_.size(); ++i) {
152 if (provides_[i] == name)
159 docstring const LaTeXFont::getUsedFont(bool ot1, bool complete, bool nomath)
161 if (nomath && !nomathfont_.empty() && available(ot1, true))
163 else if (ot1 && !ot1font_.empty())
164 return (ot1font_ == "none") ? docstring() : ot1font_;
165 else if (family_ == "rm" && complete && !completefont_.empty()
166 && altFont(completefont_).available(ot1, nomath))
167 return completefont_;
168 else if (switchdefault_) {
169 if (requires_.empty()
170 || (!requires_.empty()
171 && LaTeXFeatures::isAvailable(to_ascii(requires_))))
174 else if (!requires_.empty()
175 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
177 else if (!package_.empty()
178 && LaTeXFeatures::isAvailable(to_ascii(package_)))
180 else if (!preamble_.empty() && package_.empty()
181 && requires_.empty() && !switchdefault_
182 && altfonts_.empty()) {
185 else if (!altfonts_.empty()) {
186 for (size_t i = 0; i < altfonts_.size(); ++i) {
187 LaTeXFont altf = altFont(altfonts_[i]);
188 if (altf.available(ot1, nomath))
189 return altf.getUsedFont(ot1, complete, nomath);
197 docstring const LaTeXFont::getUsedPackage(bool ot1, bool complete, bool nomath)
199 docstring const usedfont = getUsedFont(ot1, complete, nomath);
200 if (usedfont.empty())
202 return theLaTeXFonts().getLaTeXFont(usedfont).package();
206 string const LaTeXFont::getAvailablePackage(bool dryrun)
208 if (package_.empty())
211 string const package = to_ascii(package_);
212 if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
214 else if (LaTeXFeatures::isAvailable(package))
216 // Output unavailable packages in source preview
220 docstring const req = requires_.empty() ? package_ : requires_;
221 frontend::Alert::warning(_("Font not available"),
222 bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
223 "is not available on your system. LyX will fall back to the default font."),
224 req, guiname_), true);
230 string const LaTeXFont::getPackageOptions(bool ot1, bool complete, bool sc, bool osf,
231 int scale, bool nomath)
234 bool const needosfopt = (osf != osfdefault_);
235 bool const has_osf = providesOSF(ot1, complete, nomath);
236 bool const has_sc = providesSC(ot1, complete, nomath);
238 if (!packageoption_.empty())
239 os << to_ascii(packageoption_);
241 if (sc && needosfopt && has_osf && has_sc) {
242 if (!os.str().empty())
244 if (!osfscoption_.empty())
245 os << to_ascii(osfscoption_);
247 os << to_ascii(osfoption_)
248 << ',' << to_ascii(scoption_);
249 } else if (needosfopt && has_osf) {
250 if (!os.str().empty())
252 os << to_ascii(osfoption_);
253 } else if (sc && has_sc) {
254 if (!os.str().empty())
256 os << to_ascii(scoption_);
259 if (scale != 100 && !scaleoption_.empty()
260 && providesScale(ot1, complete, nomath)) {
261 if (!os.str().empty())
263 os << subst(to_ascii(scaleoption_), "$$val",
264 convert<std::string>(float(scale) / 100));
270 string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc,
271 bool osf, bool nomath, int const & scale)
275 docstring const usedfont = getUsedFont(ot1, complete, nomath);
276 if (usedfont.empty())
278 else if (usedfont != name_)
279 return altFont(usedfont).getLaTeXCode(dryrun, ot1, complete, sc, osf, nomath, scale);
281 if (switchdefault_) {
282 if (family_.empty()) {
283 LYXERR0("Error: Font `" << name_ << "' has no family defined!");
286 if (available(ot1, nomath) || dryrun)
287 os << "\\renewcommand{\\" << to_ascii(family_) << "default}{"
288 << to_ascii(name_) << "}\n";
290 frontend::Alert::warning(_("Font not available"),
291 bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
292 "is not available on your system. LyX will fall back to the default font."),
293 requires_, guiname_), true);
295 string const package =
296 getAvailablePackage(dryrun);
297 string const packageopts = getPackageOptions(ot1, complete, sc, osf, scale, nomath);
298 if (packageopts.empty() && !package.empty())
299 os << "\\usepackage{" << package << "}\n";
300 else if (!packageopts.empty() && !package.empty())
301 os << "\\usepackage[" << packageopts << "]{" << package << "}\n";
303 if (osf && providesOSF(ot1, complete, nomath) && !osffont_.empty())
304 os << altFont(osffont_).getLaTeXCode(dryrun, ot1, complete, sc, osf, nomath, scale);
306 if (!preamble_.empty())
313 bool LaTeXFont::readFont(Lexer & lex)
337 // Keep these sorted alphabetically!
338 LexerKeyword latexFontTags[] = {
339 { "altfonts", LF_ALT_FONTS },
340 { "completefont", LF_COMPLETE_FONT },
341 { "endfont", LF_END },
342 { "family", LF_FAMILY },
343 { "guiname", LF_GUINAME },
344 { "nomathfont", LF_NOMATHFONT },
345 { "osfdefault", LF_OSFDEFAULT },
346 { "osffont", LF_OSFFONT },
347 { "osfoption", LF_OSFOPTION },
348 { "osfscoption", LF_OSFSCOPTION },
349 { "ot1font", LF_OT1_FONT },
350 { "package", LF_PACKAGE },
351 { "packageoption", LF_PACKAGEOPTION },
352 { "preamble", LF_PREAMBLE },
353 { "provides", LF_PROVIDES },
354 { "requires", LF_REQUIRES },
355 { "scaleoption", LF_SCALEOPTION },
356 { "scoption", LF_SCOPTION },
357 { "switchdefault", LF_SWITCHDEFAULT }
361 bool finished = false;
362 lex.pushTable(latexFontTags);
363 // parse style section
364 while (!finished && lex.isOK() && !error) {
366 // See comment in LyXRC.cpp.
368 case Lexer::LEX_FEOF:
371 case Lexer::LEX_UNDEF: // parse error
372 lex.printError("Unknown LaTeXFont tag `$$Token'");
379 switch (static_cast<LaTeXFontTags>(le)) {
380 case LF_END: // end of structure
385 docstring altp = lex.getDocString();
386 altfonts_ = getVectorFromString(altp);
389 case LF_COMPLETE_FONT:
390 lex >> completefont_;
419 case LF_PACKAGEOPTION:
420 lex >> packageoption_;
423 preamble_ = lex.getLongString("EndPreamble");
427 string features = lex.getString();
428 provides_ = getVectorFromString(features);
440 case LF_SWITCHDEFAULT:
441 lex >> switchdefault_;
446 lex.printError("No End tag found for LaTeXFont tag `$$Token'");
450 return finished && !error;
454 bool LaTeXFont::read(Lexer & lex)
460 lex.printError("No name given for LaTeX font: `$$Token'.");
464 name_ = lex.getDocString();
465 LYXERR(Debug::INFO, "Reading LaTeX font " << name_);
466 if (!readFont(lex)) {
467 LYXERR0("Error parsing LaTeX font `" << name_ << '\'');
475 void LaTeXFonts::readLaTeXFonts()
477 // Read latexfonts file
478 FileName filename = libFileSearch(string(), "latexfonts");
479 if (filename.empty()) {
480 LYXERR0("Error: latexfonts file not found!");
484 lex.setFile(filename);
485 lex.setContext("LaTeXFeatures::readLaTeXFonts");
489 case Lexer::LEX_FEOF:
495 string const type = lex.getString();
496 if (type != "Font" && type != "AltFont") {
497 lex.printError("Unknown LaTeXFont tag `$$Token'");
505 if (type == "AltFont")
506 texaltfontmap_[f.name()] = f;
508 texfontmap_[f.name()] = f;
513 LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts()
515 if (texfontmap_.empty())
521 LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name)
523 if (name == "default" || name == "auto")
525 if (texfontmap_.empty())
527 if (texfontmap_.find(name) == texfontmap_.end()) {
528 LYXERR0("LaTeXFonts::getLaTeXFont: font '" << name << "' not found!");
531 return texfontmap_[name];
535 LaTeXFont LaTeXFonts::getAltFont(docstring const & name)
537 if (name == "default" || name == "auto")
539 if (texaltfontmap_.empty())
541 if (texaltfontmap_.find(name) == texaltfontmap_.end()) {
542 LYXERR0("LaTeXFonts::getAltFont: alternative font '" << name << "' not found!");
545 return texaltfontmap_[name];