]> git.lyx.org Git - features.git/blob - src/LaTeXFonts.cpp
4084a736945c94992f347fc89389af3f2b685e08
[features.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 bool LaTeXFont::available(bool ot1) const
38 {
39         return ot1 ? available_ot1_ : available_;
40 }
41
42
43 bool LaTeXFont::providesOSF(bool ot1) const
44 {
45         if (!osfpackage_.empty())
46                 return LaTeXFeatures::isAvailable(to_ascii(osfpackage_));
47
48         if (ot1 && !ot1package_.empty() && ot1package_ != "none")
49                 return false;
50
51         if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
52                 return false;
53
54         return (!osfoption_.empty() || !osfscoption_.empty());
55 }
56
57
58 bool LaTeXFont::providesSC(bool ot1) const
59 {
60         if (ot1 && !ot1package_.empty() && ot1package_ != "none")
61                 return false;
62
63         if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
64                 return false;
65
66         return (!scoption_.empty() || !osfscoption_.empty());
67 }
68
69
70 bool LaTeXFont::providesScale(bool ot1) const
71 {
72         if (ot1 && !ot1package_.empty() && ot1package_ != "none")
73                 return false;
74
75         if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
76                 return false;
77
78         return (!scaleoption_.empty());
79 }
80
81 bool LaTeXFont::provides(std::string const & name) const
82 {
83         if (provides_.empty())
84                 return false;
85         for (size_t i = 0; i < provides_.size(); ++i) {
86                 if (provides_[i] == name)
87                         return true;
88         }
89         return false;
90 }
91
92
93 string const LaTeXFont::getAvailablePackage(bool dryrun, bool ot1, bool complete, bool & alt)
94 {
95         if (ot1 && !ot1package_.empty()) {
96                 if (ot1package_ != "none"
97                     && (LaTeXFeatures::isAvailable(to_ascii(ot1package_)) || dryrun))
98                         return to_ascii(ot1package_);
99                 if (!dryrun && ot1package_ != "none")
100                         frontend::Alert::warning(_("Font not available"),
101                                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
102                                                   "is not available on your system. LyX will fall back to the default font."),
103                                                 ot1package_, guiname_), true);
104                 return string();
105         }
106         if (family_ == "rm" && complete && !completepackage_.empty()) {
107                 if (LaTeXFeatures::isAvailable(to_ascii(completepackage_)) || dryrun)
108                         return to_ascii(completepackage_);
109         }
110         if (!package_.empty()) {
111                 if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
112                         return to_ascii(package_);
113                 if (LaTeXFeatures::isAvailable(to_ascii(package_)))
114                         return to_ascii(package_);
115                 else if (!altpackages_.empty()) {
116                         for (size_t i = 0; i < altpackages_.size(); ++i) {
117                                 if (LaTeXFeatures::isAvailable(to_ascii(altpackages_[i]))) {
118                                         alt = true;
119                                         return to_ascii(altpackages_[i]);
120                                 }
121                         }
122                 }
123                 // Output unavailable packages in source preview
124                 if (dryrun)
125                         return to_ascii(package_);
126                 docstring const req = requires_.empty() ? package_ : requires_;
127                         frontend::Alert::warning(_("Font not available"),
128                                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
129                                                   "is not available on your system. LyX will fall back to the default font."),
130                                                 req, guiname_), true);
131         }
132         return string();
133 }
134
135
136 string const LaTeXFont::getPackageOptions(bool ot1, bool sc, bool osf, int scale)
137 {
138         if (ot1 && !ot1package_.empty())
139                 return string();
140
141         ostringstream os;
142         bool const needosfopt = (osf != osfdefault_);
143         if (!packageoption_.empty())
144                 os << to_ascii(packageoption_);
145         if (sc && needosfopt && providesOSF() && providesSC()) {
146                 if (!os.str().empty())
147                         os << ',';
148                 if (!osfscoption_.empty())
149                         os << to_ascii(osfscoption_);
150                 else
151                         os << to_ascii(osfoption_) << ',' << to_ascii(scoption_);
152         } else if (needosfopt && providesOSF()) {
153                 if (!os.str().empty())
154                         os << ',';
155                 os << to_ascii(osfoption_);
156         } else if (sc && providesSC()) {
157                 if (!os.str().empty())
158                         os << ',';
159                 os << to_ascii(scoption_);
160         }
161         if (scale != 100 && !scaleoption_.empty()) {
162                 if (!os.str().empty())
163                         os << ',';
164                 os << subst(to_ascii(scaleoption_), "$$val",
165                             convert<std::string>(float(scale) / 100));
166         }
167         return os.str();
168 }
169
170
171 string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc,
172                                      bool osf, int const & scale)
173 {
174         ostringstream os;
175
176         if (switchdefault_) {
177                 if (family_.empty()) {
178                         LYXERR0("Error: Font `" << name_ << "' has no family defined!");
179                         return string();
180                 }
181                 if (available(ot1) || dryrun)
182                         os << "\\renewcommand{\\" << to_ascii(family_) << "default}{"
183                         << to_ascii(name_) << "}\n";
184                 else
185                         frontend::Alert::warning(_("Font not available"),
186                                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
187                                                   "is not available on your system. LyX will fall back to the default font."),
188                                                 requires_, guiname_), true);
189         } else {
190                 bool alt = false;
191                 string const package =
192                         getAvailablePackage(dryrun, ot1, complete, alt);
193                 // Package options are not for alternative packages
194                 string const packageopts = alt ? string() : getPackageOptions(ot1, sc, osf, scale);
195                 if (packageopts.empty() && !package.empty())
196                         os << "\\usepackage{" << package << "}\n";
197                 else if (!packageopts.empty() && !package.empty())
198                         os << "\\usepackage[" << packageopts << "]{" << package << "}\n";
199         }
200         if (osf && providesOSF(ot1) && !osfpackage_.empty())
201                 os << "\\usepackage{" << to_ascii(osfpackage_) << "}\n";
202
203         return os.str();
204 }
205
206
207 bool LaTeXFont::readFont(Lexer & lex)
208 {
209         enum LaTeXFontTags {
210                 LF_ALT_PACKAGES = 1,
211                 LF_COMPLETE_PACKAGE,
212                 LF_END,
213                 LF_FAMILY,
214                 LF_GUINAME,
215                 LF_OSFDEFAULT,
216                 LF_OSFOPTION,
217                 LF_OSFPACKAGE,
218                 LF_OSFSCOPTION,
219                 LF_OT1_PACKAGE,
220                 LF_PACKAGE,
221                 LF_PACKAGEOPTION,
222                 LF_PROVIDES,
223                 LF_REQUIRES,
224                 LF_SCALEOPTION,
225                 LF_SCOPTION,
226                 LF_SWITCHDEFAULT
227         };
228
229         // Keep these sorted alphabetically!
230         LexerKeyword latexFontTags[] = {
231                 { "altpackages",          LF_ALT_PACKAGES },
232                 { "completepackage",      LF_COMPLETE_PACKAGE },
233                 { "endfont",              LF_END },
234                 { "family",               LF_FAMILY },
235                 { "guiname",              LF_GUINAME },
236                 { "osfdefault",           LF_OSFDEFAULT },
237                 { "osfoption",            LF_OSFOPTION },
238                 { "osfpackage",           LF_OSFPACKAGE },
239                 { "osfscoption",          LF_OSFSCOPTION },
240                 { "ot1package",           LF_OT1_PACKAGE },
241                 { "package",              LF_PACKAGE },
242                 { "packageoption",        LF_PACKAGEOPTION },
243                 { "provides",             LF_PROVIDES },
244                 { "requires",             LF_REQUIRES },
245                 { "scaleoption",          LF_SCALEOPTION },
246                 { "scoption",             LF_SCOPTION },
247                 { "switchdefault",        LF_SWITCHDEFAULT }
248         };
249
250         bool error = false;
251         bool finished = false;
252         lex.pushTable(latexFontTags);
253         // parse style section
254         while (!finished && lex.isOK() && !error) {
255                 int le = lex.lex();
256                 // See comment in LyXRC.cpp.
257                 switch (le) {
258                 case Lexer::LEX_FEOF:
259                         continue;
260
261                 case Lexer::LEX_UNDEF: // parse error
262                         lex.printError("Unknown LaTeXFont tag `$$Token'");
263                         error = true;
264                         continue;
265
266                 default: 
267                         break;
268                 }
269                 switch (static_cast<LaTeXFontTags>(le)) {
270                 case LF_END: // end of structure
271                         finished = true;
272                         break;
273                 case LF_ALT_PACKAGES: {
274                         lex.eatLine();
275                         docstring altp = lex.getDocString();
276                         altpackages_ = getVectorFromString(altp);
277                         break;
278                 }
279                 case LF_COMPLETE_PACKAGE:
280                         lex >> completepackage_;
281                         break;
282                 case LF_FAMILY:
283                         lex >> family_;
284                         break;
285                 case LF_GUINAME:
286                         lex >> guiname_;
287                         break;
288                 case LF_OSFOPTION:
289                         lex >> osfoption_;
290                         break;
291                 case LF_OSFPACKAGE:
292                         lex >> osfpackage_;
293                         break;
294                 case LF_OSFDEFAULT:
295                         lex >> osfdefault_;
296                         break;
297                 case LF_OSFSCOPTION:
298                         lex >> osfscoption_;
299                         break;
300                 case LF_OT1_PACKAGE:
301                         lex >> ot1package_;
302                         break;
303                 case LF_PACKAGE:
304                         lex >> package_;
305                         break;
306                 case LF_PACKAGEOPTION:
307                         lex >> packageoption_;
308                         break;
309                 case LF_PROVIDES: {
310                         lex.eatLine();
311                         string features = lex.getString();
312                         provides_ = getVectorFromString(features);
313                         break;
314                 }
315                 case LF_REQUIRES:
316                         lex >> requires_;
317                         break;
318                 case LF_SCALEOPTION:
319                         lex >> scaleoption_;
320                         break;
321                 case LF_SCOPTION:
322                         lex >> scoption_;
323                         break;
324                 case LF_SWITCHDEFAULT:
325                         lex >> switchdefault_;
326                         break;
327                 }
328         }
329         if (!finished) {
330                 lex.printError("No End tag found for LaTeXFont tag `$$Token'");
331                 return false;
332         }
333         lex.popTable();
334         return finished && !error;
335 }
336
337
338 bool LaTeXFont::read(Lexer & lex)
339 {
340         switchdefault_ = 0;
341         osfdefault_ = 0;
342
343         if (!lex.next()) {
344                 lex.printError("No name given for LaTeX font: `$$Token'.");
345                 return false;
346         }
347
348         name_ = lex.getDocString();
349         LYXERR(Debug::INFO, "Reading LaTeX font " << name_);
350         if (!readFont(lex)) {
351                 LYXERR0("Error parsing LaTeX font `" << name_ << '\'');
352                 return false;
353         }
354
355         bool available = true;
356         if (!requires_.empty())
357                 available = LaTeXFeatures::isAvailable(to_ascii(requires_));
358         else if (!package_.empty()) {
359                 available = LaTeXFeatures::isAvailable(to_ascii(package_));
360                 if (!available && !altpackages_.empty()) {
361                         for (size_t i = 0; i < altpackages_.size(); ++i) {
362                                 available = LaTeXFeatures::isAvailable(to_ascii(altpackages_[i]));
363                                 if (available)
364                                         break;
365                         }
366                 }
367         }
368         available_ = available;
369
370         if (!ot1package_.empty() && ot1package_ != "none")
371                 available_ot1_ = LaTeXFeatures::isAvailable(to_ascii(ot1package_));
372         else
373                 available_ot1_ = available;
374
375         return true;
376 }
377
378
379 void LaTeXFonts::readLaTeXFonts()
380 {
381         // Read latexfonts file
382         FileName filename = libFileSearch(string(), "latexfonts");
383         if (filename.empty()) {
384                 LYXERR0("Error: latexfonts file not found!");
385                 return;
386         }
387         Lexer lex;
388         lex.setFile(filename);
389         lex.setContext("LaTeXFeatures::readLaTeXFonts");
390         while (lex.isOK()) {
391                 int le = lex.lex();
392                 switch (le) {
393                 case Lexer::LEX_FEOF:
394                         continue;
395
396                 default:
397                         break;
398                 }
399                 if (lex.getString() != "Font") {
400                         lex.printError("Unknown LaTeXFont tag `$$Token'");
401                         continue;
402                 }
403                 LaTeXFont f;
404                 f.read(lex);
405                 if (!lex)
406                         break;
407
408                 texfontmap_[f.name()] = f;
409         }
410 }
411
412
413 LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts()
414 {
415         if (texfontmap_.empty())
416                 readLaTeXFonts();
417         return texfontmap_;
418 }
419
420
421 LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name)
422 {
423         if (name == "default")
424                 return LaTeXFont();
425         if (texfontmap_.empty())
426                 readLaTeXFonts();
427         if (texfontmap_.find(name) == texfontmap_.end()) {
428                 LYXERR0("LaTeXFonts::getLaTeXFont: font '" << name << "' not found!");
429                 return LaTeXFont();
430         }
431         return texfontmap_[name];
432 }
433
434
435 } // namespace lyx