]> git.lyx.org Git - lyx.git/blob - src/LaTeXFonts.cpp
Remove obsolete (and false) comment.
[lyx.git] / src / LaTeXFonts.cpp
1 /**
2  * \file LaTeXFonts.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Spitzmüller
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "LaTeXFonts.h"
14
15 #include "LaTeXFeatures.h"
16 #include "Lexer.h"
17
18 #include "frontends/alert.h"
19
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"
27
28
29 using namespace std;
30 using namespace lyx::support;
31
32
33 namespace lyx {
34
35 LaTeXFonts latexfonts;
36
37
38 LaTeXFont LaTeXFont::altFont(docstring const & name)
39 {
40         return theLaTeXFonts().getAltFont(name);
41 }
42
43
44 bool LaTeXFont::available(bool ot1, bool nomath)
45 {
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())
52                 return true;
53         else if (!requires_.empty()
54                 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
55                 return true;
56         else if (requires_.empty() && !package_.empty()
57                 && LaTeXFeatures::isAvailable(to_ascii(package_)))
58                 return true;
59         else if (!altfonts_.empty()) {
60                 for (size_t i = 0; i < altfonts_.size(); ++i) {
61                         if (altFont(altfonts_[i]).available(ot1, nomath))
62                                 return true;
63                 }
64         }
65         return false;
66 }
67
68
69 bool LaTeXFont::providesNoMath(bool ot1, bool complete)
70 {
71         docstring const usedfont = getUsedFont(ot1, complete, false);
72
73         if (usedfont.empty())
74                 return false;
75         else if (usedfont != name_)
76                 return altFont(usedfont).providesNoMath(ot1, complete);
77
78         return (!nomathfont_.empty() && available(ot1, true));
79 }
80
81
82 bool LaTeXFont::providesOSF(bool ot1, bool complete, bool nomath)
83 {
84         docstring const usedfont = getUsedFont(ot1, complete, nomath);
85
86         if (usedfont.empty())
87                 return false;
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))
93                 return false;
94
95         return (!osfoption_.empty() || !osfscoption_.empty());
96 }
97
98
99 bool LaTeXFont::providesSC(bool ot1, bool complete, bool nomath)
100 {
101         docstring const usedfont = getUsedFont(ot1, complete, nomath);
102
103         if (usedfont.empty())
104                 return false;
105         else if (usedfont != name_)
106                 return altFont(usedfont).providesSC(ot1, complete, nomath);
107         else if (!available(ot1, nomath))
108                 return false;
109
110         return (!scoption_.empty() || !osfscoption_.empty());
111 }
112
113
114 bool LaTeXFont::hasMonolithicExpertSet(bool ot1, bool complete, bool nomath)
115 {
116         docstring const usedfont = getUsedFont(ot1, complete, nomath);
117
118         if (usedfont.empty())
119                 return false;
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());
124 }
125
126
127 bool LaTeXFont::providesScale(bool ot1, bool complete, bool nomath)
128 {
129         docstring const usedfont = getUsedFont(ot1, complete, nomath);
130
131         if (usedfont.empty())
132                 return false;
133         else if (usedfont != name_)
134                 return altFont(usedfont).providesScale(ot1, complete, nomath);
135         else if (!available(ot1, nomath))
136                 return false;
137         return (!scaleoption_.empty());
138 }
139
140
141 bool LaTeXFont::providesMoreOptions(bool ot1, bool complete, bool nomath)
142 {
143         docstring const usedfont = getUsedFont(ot1, complete, nomath);
144
145         if (usedfont.empty())
146                 return false;
147         else if (usedfont != name_)
148                 return altFont(usedfont).providesMoreOptions(ot1, complete, nomath);
149         else if (!available(ot1, nomath))
150                 return false;
151
152         return (moreopts_);
153 }
154
155 bool LaTeXFont::provides(std::string const & name, bool ot1, bool complete, bool nomath)
156 {
157         docstring const usedfont = getUsedFont(ot1, complete, nomath);
158
159         if (usedfont.empty())
160                 return false;
161         else if (usedfont != name_)
162                 return altFont(usedfont).provides(name, ot1, complete, nomath);
163         else if (provides_.empty())
164                 return false;
165
166         for (size_t i = 0; i < provides_.size(); ++i) {
167                 if (provides_[i] == name)
168                         return true;
169         }
170         return false;
171 }
172
173
174 docstring const LaTeXFont::getUsedFont(bool ot1, bool complete, bool nomath)
175 {
176         if (nomath && !nomathfont_.empty() && available(ot1, true))
177                 return nomathfont_;
178         else if (ot1 && !ot1font_.empty())
179                 return (ot1font_ == "none") ? docstring() : ot1font_;
180         else if (family_ == "rm" && complete && !completefont_.empty()
181                  && altFont(completefont_).available(ot1, nomath))
182                         return completefont_;
183         else if (switchdefault_) {
184                 if (requires_.empty()
185                     || (!requires_.empty()
186                         && LaTeXFeatures::isAvailable(to_ascii(requires_))))
187                         return name_;
188         }
189         else if (!requires_.empty()
190                 && LaTeXFeatures::isAvailable(to_ascii(requires_)))
191                         return name_;
192         else if (!package_.empty()
193                 && LaTeXFeatures::isAvailable(to_ascii(package_)))
194                         return name_;
195         else if (!preamble_.empty() && package_.empty()
196                  && requires_.empty() && !switchdefault_
197                  && altfonts_.empty()) {
198                         return name_;
199         }
200         else if (!altfonts_.empty()) {
201                 for (size_t i = 0; i < altfonts_.size(); ++i) {
202                         LaTeXFont altf = altFont(altfonts_[i]);
203                         if (altf.available(ot1, nomath))
204                                 return altf.getUsedFont(ot1, complete, nomath);
205                 }
206         }
207
208         return docstring();
209 }
210
211
212 docstring const LaTeXFont::getUsedPackage(bool ot1, bool complete, bool nomath)
213 {
214         docstring const usedfont = getUsedFont(ot1, complete, nomath);
215         if (usedfont.empty())
216                 return docstring();
217         return theLaTeXFonts().getLaTeXFont(usedfont).package();
218 }
219
220
221 string const LaTeXFont::getAvailablePackage(bool dryrun)
222 {
223         if (package_.empty())
224                 return string();
225
226         string const package = to_ascii(package_);
227         if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
228                 return package;
229         else if (LaTeXFeatures::isAvailable(package))
230                 return package;
231         // Output unavailable packages in source preview
232         else if (dryrun)
233                 return package;
234
235         docstring const req = requires_.empty() ? package_ : requires_;
236         frontend::Alert::warning(_("Font not available"),
237                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
238                                   "is not available on your system. LyX will fall back to the default font."),
239                                 req, guiname_), true);
240
241         return string();
242 }
243
244
245 string const LaTeXFont::getPackageOptions(bool ot1, bool complete, bool sc, bool osf,
246                                           int scale, string const & extraopts, bool nomath)
247 {
248         ostringstream os;
249         bool const needosfopt = (osf != osfdefault_);
250         bool const has_osf = providesOSF(ot1, complete, nomath);
251         bool const has_sc = providesSC(ot1, complete, nomath);
252         bool const moreopts = providesMoreOptions(ot1, complete, nomath);
253
254         if (!packageoptions_.empty())
255                 os << to_ascii(packageoptions_);
256
257         if (sc && needosfopt && has_osf && has_sc) {
258                 if (!os.str().empty())
259                         os << ',';
260                 if (!osfscoption_.empty())
261                         os << to_ascii(osfscoption_);
262                 else
263                         os << to_ascii(osfoption_)
264                            << ',' << to_ascii(scoption_);
265         } else if (needosfopt && has_osf) {
266                 if (!os.str().empty())
267                         os << ',';
268                 os << to_ascii(osfoption_);
269         } else if (sc && has_sc) {
270                 if (!os.str().empty())
271                         os << ',';
272                 os << to_ascii(scoption_);
273         }
274
275         if (scale != 100 && !scaleoption_.empty()
276             && providesScale(ot1, complete, nomath)) {
277                 if (!os.str().empty())
278                         os << ',';
279                 os << subst(to_ascii(scaleoption_), "$$val",
280                             convert<std::string>(float(scale) / 100));
281         }
282
283         if (moreopts && !extraopts.empty()) {
284                 if (!os.str().empty())
285                         os << ',';
286                 os << extraopts;
287         }
288         return os.str();
289 }
290
291
292 string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc,
293                                      bool osf, bool nomath, string const & extraopts,
294                                      int const & scale)
295 {
296         ostringstream os;
297
298         docstring const usedfont = getUsedFont(ot1, complete, nomath);
299         if (usedfont.empty())
300                 return string();
301         else if (usedfont != name_)
302                 return altFont(usedfont).getLaTeXCode(dryrun, ot1, complete, sc,
303                                                       osf, nomath, extraopts, scale);
304
305         if (switchdefault_) {
306                 if (family_.empty()) {
307                         LYXERR0("Error: Font `" << name_ << "' has no family defined!");
308                         return string();
309                 }
310                 if (available(ot1, nomath) || dryrun)
311                         os << "\\renewcommand{\\" << to_ascii(family_) << "default}{"
312                            << to_ascii(name_) << "}\n";
313                 else
314                         frontend::Alert::warning(_("Font not available"),
315                                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
316                                                   "is not available on your system. LyX will fall back to the default font."),
317                                                 requires_, guiname_), true);
318         } else {
319                 string const package =
320                         getAvailablePackage(dryrun);
321                 string const packageopts = getPackageOptions(ot1, complete, sc, osf, scale, extraopts, nomath);
322                 if (packageopts.empty() && !package.empty())
323                         os << "\\usepackage{" << package << "}\n";
324                 else if (!packageopts.empty() && !package.empty())
325                         os << "\\usepackage[" << packageopts << "]{" << package << "}\n";
326         }
327         if (osf && providesOSF(ot1, complete, nomath) && !osffont_.empty())
328                 os << altFont(osffont_).getLaTeXCode(dryrun, ot1, complete, sc, osf,
329                                                      nomath, extraopts, scale);
330
331         if (!preamble_.empty())
332                 os << to_utf8(preamble_);
333
334         return os.str();
335 }
336
337
338 bool LaTeXFont::hasFontenc(string const & name) const
339 {
340         for (auto const & fe : fontenc_) {
341                 if (fe == name)
342                         return true;
343         }
344         return false;
345 }
346
347
348 bool LaTeXFont::readFont(Lexer & lex)
349 {
350         enum LaTeXFontTags {
351                 LF_ALT_FONTS = 1,
352                 LF_COMPLETE_FONT,
353                 LF_END,
354                 LF_FAMILY,
355                 LF_FONTENC,
356                 LF_GUINAME,
357                 LF_NOMATHFONT,
358                 LF_OSFDEFAULT,
359                 LF_OSFFONT,
360                 LF_OSFOPTION,
361                 LF_OSFSCOPTION,
362                 LF_OT1_FONT,
363                 LF_MOREOPTS,
364                 LF_PACKAGE,
365                 LF_PACKAGEOPTIONS,
366                 LF_PREAMBLE,
367                 LF_PROVIDES,
368                 LF_REQUIRES,
369                 LF_SCALEOPTION,
370                 LF_SCOPTION,
371                 LF_SWITCHDEFAULT
372         };
373
374         // Keep these sorted alphabetically!
375         LexerKeyword latexFontTags[] = {
376                 { "altfonts",             LF_ALT_FONTS },
377                 { "completefont",         LF_COMPLETE_FONT },
378                 { "endfont",              LF_END },
379                 { "family",               LF_FAMILY },
380                 { "fontencoding",         LF_FONTENC },
381                 { "guiname",              LF_GUINAME },
382                 { "moreoptions",          LF_MOREOPTS },
383                 { "nomathfont",           LF_NOMATHFONT },
384                 { "osfdefault",           LF_OSFDEFAULT },
385                 { "osffont",              LF_OSFFONT },
386                 { "osfoption",            LF_OSFOPTION },
387                 { "osfscoption",          LF_OSFSCOPTION },
388                 { "ot1font",              LF_OT1_FONT },
389                 { "package",              LF_PACKAGE },
390                 { "packageoptions",       LF_PACKAGEOPTIONS },
391                 { "preamble",             LF_PREAMBLE },
392                 { "provides",             LF_PROVIDES },
393                 { "requires",             LF_REQUIRES },
394                 { "scaleoption",          LF_SCALEOPTION },
395                 { "scoption",             LF_SCOPTION },
396                 { "switchdefault",        LF_SWITCHDEFAULT }
397         };
398
399         bool error = false;
400         bool finished = false;
401         lex.pushTable(latexFontTags);
402         // parse style section
403         while (!finished && lex.isOK() && !error) {
404                 int le = lex.lex();
405                 // See comment in LyXRC.cpp.
406                 switch (le) {
407                 case Lexer::LEX_FEOF:
408                         continue;
409
410                 case Lexer::LEX_UNDEF: // parse error
411                         lex.printError("Unknown LaTeXFont tag `$$Token'");
412                         error = true;
413                         continue;
414
415                 default:
416                         break;
417                 }
418                 switch (static_cast<LaTeXFontTags>(le)) {
419                 case LF_END: // end of structure
420                         finished = true;
421                         break;
422                 case LF_ALT_FONTS: {
423                         lex.eatLine();
424                         docstring altp = lex.getDocString();
425                         altfonts_ = getVectorFromString(altp);
426                         break;
427                 }
428                 case LF_COMPLETE_FONT:
429                         lex >> completefont_;
430                         break;
431                 case LF_FAMILY:
432                         lex >> family_;
433                         break;
434                 case LF_GUINAME:
435                         lex >> guiname_;
436                         break;
437                 case LF_FONTENC: {
438                         lex.eatLine();
439                         string fe = lex.getString();
440                         fontenc_ = getVectorFromString(fe);
441                         break;
442                 }
443                 case LF_NOMATHFONT:
444                         lex >> nomathfont_;
445                         break;
446                 case LF_OSFOPTION:
447                         lex >> osfoption_;
448                         break;
449                 case LF_OSFFONT:
450                         lex >> osffont_;
451                         break;
452                 case LF_OSFDEFAULT:
453                         lex >> osfdefault_;
454                         break;
455                 case LF_OSFSCOPTION:
456                         lex >> osfscoption_;
457                         break;
458                 case LF_OT1_FONT:
459                         lex >> ot1font_;
460                         break;
461                 case LF_PACKAGE:
462                         lex >> package_;
463                         break;
464                 case LF_PACKAGEOPTIONS:
465                         lex >> packageoptions_;
466                         break;
467                 case LF_PREAMBLE:
468                         preamble_ = lex.getLongString(from_ascii("EndPreamble"));
469                         break;
470                 case LF_PROVIDES: {
471                         lex.eatLine();
472                         string features = lex.getString();
473                         provides_ = getVectorFromString(features);
474                         break;
475                 }
476                 case LF_REQUIRES:
477                         lex >> requires_;
478                         break;
479                 case LF_SCALEOPTION:
480                         lex >> scaleoption_;
481                         break;
482                 case LF_SCOPTION:
483                         lex >> scoption_;
484                         break;
485                 case LF_MOREOPTS:
486                         lex >> moreopts_;
487                         break;
488                 case LF_SWITCHDEFAULT:
489                         lex >> switchdefault_;
490                         break;
491                 }
492         }
493         if (!finished) {
494                 lex.printError("No End tag found for LaTeXFont tag `$$Token'");
495                 return false;
496         }
497         lex.popTable();
498         return finished && !error;
499 }
500
501
502 bool LaTeXFont::read(Lexer & lex)
503 {
504         switchdefault_ = 0;
505         osfdefault_ = 0;
506         moreopts_ = 0;
507
508         if (!lex.next()) {
509                 lex.printError("No name given for LaTeX font: `$$Token'.");
510                 return false;
511         }
512
513         name_ = lex.getDocString();
514         LYXERR(Debug::INFO, "Reading LaTeX font " << name_);
515         if (!readFont(lex)) {
516                 LYXERR0("Error parsing LaTeX font `" << name_ << '\'');
517                 return false;
518         }
519
520         if (fontenc_.empty())
521                 fontenc_.push_back("T1");
522
523         return true;
524 }
525
526
527 void LaTeXFonts::readLaTeXFonts()
528 {
529         // Read latexfonts file
530         FileName filename = libFileSearch(string(), "latexfonts");
531         if (filename.empty()) {
532                 LYXERR0("Error: latexfonts file not found!");
533                 return;
534         }
535         Lexer lex;
536         lex.setFile(filename);
537         lex.setContext("LaTeXFeatures::readLaTeXFonts");
538         while (lex.isOK()) {
539                 int le = lex.lex();
540                 switch (le) {
541                 case Lexer::LEX_FEOF:
542                         continue;
543
544                 default:
545                         break;
546                 }
547                 string const type = lex.getString();
548                 if (type != "Font" && type != "AltFont") {
549                         lex.printError("Unknown LaTeXFont tag `$$Token'");
550                         continue;
551                 }
552                 LaTeXFont f;
553                 f.read(lex);
554                 if (!lex)
555                         break;
556
557                 if (type == "AltFont")
558                         texaltfontmap_[f.name()] = f;
559                 else
560                         texfontmap_[f.name()] = f;
561         }
562 }
563
564
565 LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts()
566 {
567         if (texfontmap_.empty())
568                 readLaTeXFonts();
569         return texfontmap_;
570 }
571
572
573 LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name)
574 {
575         if (name == "default" || name == "auto")
576                 return LaTeXFont();
577         if (texfontmap_.empty())
578                 readLaTeXFonts();
579         if (texfontmap_.find(name) == texfontmap_.end()) {
580                 LYXERR0("LaTeXFonts::getLaTeXFont: font '" << name << "' not found!");
581                 return LaTeXFont();
582         }
583         return texfontmap_[name];
584 }
585
586
587 LaTeXFont LaTeXFonts::getAltFont(docstring const & name)
588 {
589         if (name == "default" || name == "auto")
590                 return LaTeXFont();
591         if (texaltfontmap_.empty())
592                 readLaTeXFonts();
593         if (texaltfontmap_.find(name) == texaltfontmap_.end()) {
594                 LYXERR0("LaTeXFonts::getAltFont: alternative font '" << name << "' not found!");
595                 return LaTeXFont();
596         }
597         return texaltfontmap_[name];
598 }
599
600
601 } // namespace lyx