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)
45 if (ot1 && !ot1font_.empty())
46 return (ot1font_ == "none") ?
47 true : altFont(ot1font_).available(ot1);
48 else if (requires_.empty() && package_.empty())
50 else if (!requires_.empty()
51 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
53 else if (!package_.empty()
54 && LaTeXFeatures::isAvailable(to_ascii(package_)))
56 else if (!altfonts_.empty()) {
57 for (size_t i = 0; i < altfonts_.size(); ++i) {
58 if (altFont(altfonts_[i]).available(ot1))
66 bool LaTeXFont::providesOSF(bool ot1, bool complete)
68 docstring const usedfont = getUsedFont(ot1, complete);
72 else if (usedfont != name_)
73 return altFont(usedfont).providesOSF(ot1, complete);
74 else if (!osffont_.empty())
75 return altFont(osffont_).available(ot1);
76 else if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
79 return (!osfoption_.empty() || !osfscoption_.empty());
83 bool LaTeXFont::providesSC(bool ot1, bool complete)
85 docstring const usedfont = getUsedFont(ot1, complete);
89 else if (usedfont != name_)
90 return altFont(usedfont).providesSC(ot1, complete);
91 else if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
94 return (!scoption_.empty() || !osfscoption_.empty());
98 bool LaTeXFont::providesScale(bool ot1, bool complete)
100 docstring const usedfont = getUsedFont(ot1, complete);
102 if (usedfont.empty())
104 else if (usedfont != name_)
105 return altFont(usedfont).providesScale(ot1, complete);
106 else if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
109 return (!scaleoption_.empty());
112 bool LaTeXFont::provides(std::string const & name, bool ot1, bool complete)
114 docstring const usedfont = getUsedFont(ot1, complete);
116 if (usedfont.empty())
118 else if (usedfont != name_)
119 return altFont(usedfont).provides(name, ot1, complete);
120 else if (provides_.empty())
123 for (size_t i = 0; i < provides_.size(); ++i) {
124 if (provides_[i] == name)
131 docstring const LaTeXFont::getUsedFont(bool ot1, bool complete)
133 if (ot1 && !ot1font_.empty())
134 return (ot1font_ == "none") ? docstring() : ot1font_;
135 else if (family_ == "rm" && complete && !completefont_.empty()
136 && altFont(completefont_).available(ot1))
137 return completefont_;
138 else if (switchdefault_) {
139 if (requires_.empty()
140 || (!requires_.empty()
141 && LaTeXFeatures::isAvailable(to_ascii(requires_))))
144 else if (!requires_.empty()
145 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
147 else if (!package_.empty()
148 && LaTeXFeatures::isAvailable(to_ascii(package_)))
150 else if (!altfonts_.empty()) {
151 for (size_t i = 0; i < altfonts_.size(); ++i) {
152 LaTeXFont altf = altFont(altfonts_[i]);
153 if (altf.available(ot1))
154 return altf.getUsedFont(ot1, complete);
162 string const LaTeXFont::getAvailablePackage(bool dryrun)
164 if (package_.empty())
167 string const package = to_ascii(package_);
168 if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
170 else if (LaTeXFeatures::isAvailable(package))
172 // Output unavailable packages in source preview
176 docstring const req = requires_.empty() ? package_ : requires_;
177 frontend::Alert::warning(_("Font not available"),
178 bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
179 "is not available on your system. LyX will fall back to the default font."),
180 req, guiname_), true);
186 string const LaTeXFont::getPackageOptions(bool ot1, bool complete, bool sc, bool osf, int scale)
189 bool const needosfopt = (osf != osfdefault_);
190 bool const has_osf = providesOSF(ot1, complete);
191 bool const has_sc = providesSC(ot1, complete);
193 if (!packageoption_.empty())
194 os << to_ascii(packageoption_);
196 if (sc && needosfopt && has_osf && has_sc) {
197 if (!os.str().empty())
199 if (!osfscoption_.empty())
200 os << to_ascii(osfscoption_);
202 os << to_ascii(osfoption_)
203 << ',' << to_ascii(scoption_);
204 } else if (needosfopt && has_osf) {
205 if (!os.str().empty())
207 os << to_ascii(osfoption_);
208 } else if (sc && has_sc) {
209 if (!os.str().empty())
211 os << to_ascii(scoption_);
214 if (scale != 100 && !scaleoption_.empty()
215 && providesScale(ot1, complete)) {
216 if (!os.str().empty())
218 os << subst(to_ascii(scaleoption_), "$$val",
219 convert<std::string>(float(scale) / 100));
225 string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc,
226 bool osf, int const & scale)
230 docstring const usedfont = getUsedFont(ot1, complete);
231 if (usedfont.empty())
233 else if (usedfont != name_)
234 return altFont(usedfont).getLaTeXCode(dryrun, ot1, complete, sc, osf, scale);
236 if (switchdefault_) {
237 if (family_.empty()) {
238 LYXERR0("Error: Font `" << name_ << "' has no family defined!");
241 if (available(ot1) || dryrun)
242 os << "\\renewcommand{\\" << to_ascii(family_) << "default}{"
243 << to_ascii(name_) << "}\n";
245 frontend::Alert::warning(_("Font not available"),
246 bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
247 "is not available on your system. LyX will fall back to the default font."),
248 requires_, guiname_), true);
250 string const package =
251 getAvailablePackage(dryrun);
252 string const packageopts = getPackageOptions(ot1, complete, sc, osf, scale);
253 if (packageopts.empty() && !package.empty())
254 os << "\\usepackage{" << package << "}\n";
255 else if (!packageopts.empty() && !package.empty())
256 os << "\\usepackage[" << packageopts << "]{" << package << "}\n";
258 if (osf && providesOSF(ot1, complete) && !osffont_.empty())
259 os << altFont(osffont_).getLaTeXCode(dryrun, ot1, complete, sc, osf, scale);
265 bool LaTeXFont::readFont(Lexer & lex)
287 // Keep these sorted alphabetically!
288 LexerKeyword latexFontTags[] = {
289 { "altfonts", LF_ALT_FONTS },
290 { "completefont", LF_COMPLETE_FONT },
291 { "endfont", LF_END },
292 { "family", LF_FAMILY },
293 { "guiname", LF_GUINAME },
294 { "osfdefault", LF_OSFDEFAULT },
295 { "osffont", LF_OSFFONT },
296 { "osfoption", LF_OSFOPTION },
297 { "osfscoption", LF_OSFSCOPTION },
298 { "ot1font", LF_OT1_FONT },
299 { "package", LF_PACKAGE },
300 { "packageoption", LF_PACKAGEOPTION },
301 { "provides", LF_PROVIDES },
302 { "requires", LF_REQUIRES },
303 { "scaleoption", LF_SCALEOPTION },
304 { "scoption", LF_SCOPTION },
305 { "switchdefault", LF_SWITCHDEFAULT }
309 bool finished = false;
310 lex.pushTable(latexFontTags);
311 // parse style section
312 while (!finished && lex.isOK() && !error) {
314 // See comment in LyXRC.cpp.
316 case Lexer::LEX_FEOF:
319 case Lexer::LEX_UNDEF: // parse error
320 lex.printError("Unknown LaTeXFont tag `$$Token'");
327 switch (static_cast<LaTeXFontTags>(le)) {
328 case LF_END: // end of structure
333 docstring altp = lex.getDocString();
334 altfonts_ = getVectorFromString(altp);
337 case LF_COMPLETE_FONT:
338 lex >> completefont_;
364 case LF_PACKAGEOPTION:
365 lex >> packageoption_;
369 string features = lex.getString();
370 provides_ = getVectorFromString(features);
382 case LF_SWITCHDEFAULT:
383 lex >> switchdefault_;
388 lex.printError("No End tag found for LaTeXFont tag `$$Token'");
392 return finished && !error;
396 bool LaTeXFont::read(Lexer & lex)
402 lex.printError("No name given for LaTeX font: `$$Token'.");
406 name_ = lex.getDocString();
407 LYXERR(Debug::INFO, "Reading LaTeX font " << name_);
408 if (!readFont(lex)) {
409 LYXERR0("Error parsing LaTeX font `" << name_ << '\'');
417 void LaTeXFonts::readLaTeXFonts()
419 // Read latexfonts file
420 FileName filename = libFileSearch(string(), "latexfonts");
421 if (filename.empty()) {
422 LYXERR0("Error: latexfonts file not found!");
426 lex.setFile(filename);
427 lex.setContext("LaTeXFeatures::readLaTeXFonts");
431 case Lexer::LEX_FEOF:
437 string const type = lex.getString();
438 if (type != "Font" && type != "AltFont") {
439 lex.printError("Unknown LaTeXFont tag `$$Token'");
447 if (type == "AltFont")
448 texaltfontmap_[f.name()] = f;
450 texfontmap_[f.name()] = f;
455 LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts()
457 if (texfontmap_.empty())
463 LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name)
465 if (name == "default")
467 if (texfontmap_.empty())
469 if (texfontmap_.find(name) == texfontmap_.end()) {
470 LYXERR0("LaTeXFonts::getLaTeXFont: font '" << name << "' not found!");
473 return texfontmap_[name];
477 LaTeXFont LaTeXFonts::getAltFont(docstring const & name)
479 if (name == "default")
481 if (texaltfontmap_.empty())
483 if (texaltfontmap_.find(name) == texaltfontmap_.end()) {
484 LYXERR0("LaTeXFonts::getAltFont: alternative font '" << name << "' not found!");
487 return texaltfontmap_[name];