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