#include "LaTeXFeatures.h"
#include "Lexer.h"
+#include "frontends/alert.h"
+
#include "support/convert.h"
#include "support/debug.h"
+#include "support/docstream.h"
#include "support/FileName.h"
#include "support/filetools.h"
+#include "support/gettext.h"
#include "support/lstrings.h"
LaTeXFonts latexfonts;
-bool LaTeXFont::available(bool ot1) const
+LaTeXFont LaTeXFont::altFont(docstring const & name)
{
- return ot1 ? available_ot1_ : available_;
+ return theLaTeXFonts().getAltFont(name);
}
-bool LaTeXFont::providesOSF(bool ot1) const
+bool LaTeXFont::available(bool ot1, bool nomath)
{
- if (!osfpackage_.empty())
- return LaTeXFeatures::isAvailable(to_ascii(osfpackage_));
+ if (nomath && !nomathfont_.empty())
+ return altFont(nomathfont_).available(ot1, nomath);
+ else if (ot1 && !ot1font_.empty())
+ return (ot1font_ == "none") ?
+ true : altFont(ot1font_).available(ot1, nomath);
+ else if (requires_.empty() && package_.empty())
+ return true;
+ else if (!requires_.empty()
+ && LaTeXFeatures::isAvailable(to_ascii(requires_)))
+ return true;
+ else if (requires_.empty() && !package_.empty()
+ && LaTeXFeatures::isAvailable(to_ascii(package_)))
+ return true;
+ else if (!altfonts_.empty()) {
+ for (size_t i = 0; i < altfonts_.size(); ++i) {
+ if (altFont(altfonts_[i]).available(ot1, nomath))
+ return true;
+ }
+ }
+ return false;
+}
+
- if (ot1 && !ot1package_.empty() && ot1package_ != "none")
+bool LaTeXFont::providesNoMath(bool ot1, bool complete)
+{
+ docstring const usedfont = getUsedFont(ot1, complete, false);
+
+ if (usedfont.empty())
return false;
+ else if (usedfont != name_)
+ return altFont(usedfont).providesNoMath(ot1, complete);
+
+ return (!nomathfont_.empty() && available(ot1, true));
+}
+
+
+bool LaTeXFont::providesOSF(bool ot1, bool complete, bool nomath)
+{
+ docstring const usedfont = getUsedFont(ot1, complete, nomath);
- if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
+ if (usedfont.empty())
+ return false;
+ else if (usedfont != name_)
+ return altFont(usedfont).providesOSF(ot1, complete, nomath);
+ else if (!osffont_.empty())
+ return altFont(osffont_).available(ot1, nomath);
+ else if (!available(ot1, nomath))
return false;
return (!osfoption_.empty() || !osfscoption_.empty());
}
-bool LaTeXFont::providesSC(bool ot1) const
+bool LaTeXFont::providesSC(bool ot1, bool complete, bool nomath)
{
- if (ot1 && !ot1package_.empty() && ot1package_ != "none")
- return false;
+ docstring const usedfont = getUsedFont(ot1, complete, nomath);
- if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
+ if (usedfont.empty())
+ return false;
+ else if (usedfont != name_)
+ return altFont(usedfont).providesSC(ot1, complete, nomath);
+ else if (!available(ot1, nomath))
return false;
return (!scoption_.empty() || !osfscoption_.empty());
}
-bool LaTeXFont::providesScale(bool ot1) const
+bool LaTeXFont::hasMonolithicExpertSet(bool ot1, bool complete, bool nomath)
{
- if (ot1 && !ot1package_.empty() && ot1package_ != "none")
- return false;
+ docstring const usedfont = getUsedFont(ot1, complete, nomath);
- if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
+ if (usedfont.empty())
return false;
+ else if (usedfont != name_)
+ return altFont(usedfont).hasMonolithicExpertSet(ot1, complete, nomath);
+ return (!osfoption_.empty() && !scoption_.empty() && osfoption_ == scoption_)
+ || (osfoption_.empty() && scoption_.empty() && !osfscoption_.empty());
+}
+
+bool LaTeXFont::providesScale(bool ot1, bool complete, bool nomath)
+{
+ docstring const usedfont = getUsedFont(ot1, complete, nomath);
+
+ if (usedfont.empty())
+ return false;
+ else if (usedfont != name_)
+ return altFont(usedfont).providesScale(ot1, complete, nomath);
+ else if (!available(ot1, nomath))
+ return false;
return (!scaleoption_.empty());
}
+bool LaTeXFont::provides(std::string const & name, bool ot1, bool complete, bool nomath)
+{
+ docstring const usedfont = getUsedFont(ot1, complete, nomath);
+
+ if (usedfont.empty())
+ return false;
+ else if (usedfont != name_)
+ return altFont(usedfont).provides(name, ot1, complete, nomath);
+ else if (provides_.empty())
+ return false;
-string const LaTeXFont::getAvailablePackage(bool ot1, bool complete)
+ for (size_t i = 0; i < provides_.size(); ++i) {
+ if (provides_[i] == name)
+ return true;
+ }
+ return false;
+}
+
+
+docstring const LaTeXFont::getUsedFont(bool ot1, bool complete, bool nomath)
{
- if (ot1 && !ot1package_.empty()) {
- if (ot1package_ != "none" && LaTeXFeatures::isAvailable(to_ascii(ot1package_)))
- return to_ascii(ot1package_);
- return string();
+ if (nomath && !nomathfont_.empty() && available(ot1, true))
+ return nomathfont_;
+ else if (ot1 && !ot1font_.empty())
+ return (ot1font_ == "none") ? docstring() : ot1font_;
+ else if (family_ == "rm" && complete && !completefont_.empty()
+ && altFont(completefont_).available(ot1, nomath))
+ return completefont_;
+ else if (switchdefault_) {
+ if (requires_.empty()
+ || (!requires_.empty()
+ && LaTeXFeatures::isAvailable(to_ascii(requires_))))
+ return name_;
}
- if (complete && !completepackage_.empty()) {
- if (LaTeXFeatures::isAvailable(to_ascii(completepackage_)))
- return to_ascii(completepackage_);
+ else if (!requires_.empty()
+ && LaTeXFeatures::isAvailable(to_ascii(requires_)))
+ return name_;
+ else if (!package_.empty()
+ && LaTeXFeatures::isAvailable(to_ascii(package_)))
+ return name_;
+ else if (!preamble_.empty() && package_.empty()
+ && requires_.empty() && !switchdefault_
+ && altfonts_.empty()) {
+ return name_;
}
- if (!package_.empty()) {
- if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
- return to_ascii(package_);
- if (LaTeXFeatures::isAvailable(to_ascii(package_)))
- return to_ascii(package_);
- else if (!altpackages_.empty()) {
- for (size_t i = 0; i < altpackages_.size(); ++i) {
- if (LaTeXFeatures::isAvailable(to_ascii(altpackages_[i])))
- return to_ascii(altpackages_[i]);
- }
+ else if (!altfonts_.empty()) {
+ for (size_t i = 0; i < altfonts_.size(); ++i) {
+ LaTeXFont altf = altFont(altfonts_[i]);
+ if (altf.available(ot1, nomath))
+ return altf.getUsedFont(ot1, complete, nomath);
}
}
- return string();
+
+ return docstring();
}
-string const LaTeXFont::getPackageOptions(bool const & ot1, bool const & sc,
- bool const & osf, int const & scale)
+docstring const LaTeXFont::getUsedPackage(bool ot1, bool complete, bool nomath)
{
- if (ot1 && !ot1package_.empty())
+ docstring const usedfont = getUsedFont(ot1, complete, nomath);
+ if (usedfont.empty())
+ return docstring();
+ return theLaTeXFonts().getLaTeXFont(usedfont).package();
+}
+
+
+string const LaTeXFont::getAvailablePackage(bool dryrun)
+{
+ if (package_.empty())
return string();
+ string const package = to_ascii(package_);
+ if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
+ return package;
+ else if (LaTeXFeatures::isAvailable(package))
+ return package;
+ // Output unavailable packages in source preview
+ else if (dryrun)
+ return package;
+
+ docstring const req = requires_.empty() ? package_ : requires_;
+ frontend::Alert::warning(_("Font not available"),
+ bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
+ "is not available on your system. LyX will fall back to the default font."),
+ req, guiname_), true);
+
+ return string();
+}
+
+
+string const LaTeXFont::getPackageOptions(bool ot1, bool complete, bool sc, bool osf,
+ int scale, bool nomath)
+{
ostringstream os;
- if (sc && osf && providesOSF() && providesSC()) {
+ bool const needosfopt = (osf != osfdefault_);
+ bool const has_osf = providesOSF(ot1, complete, nomath);
+ bool const has_sc = providesSC(ot1, complete, nomath);
+
+ if (!packageoption_.empty())
+ os << to_ascii(packageoption_);
+
+ if (sc && needosfopt && has_osf && has_sc) {
+ if (!os.str().empty())
+ os << ',';
if (!osfscoption_.empty())
os << to_ascii(osfscoption_);
else
- os << to_ascii(osfoption_) << ',' << to_ascii(scoption_);
- } else if (osf && providesOSF())
+ os << to_ascii(osfoption_)
+ << ',' << to_ascii(scoption_);
+ } else if (needosfopt && has_osf) {
+ if (!os.str().empty())
+ os << ',';
os << to_ascii(osfoption_);
- else if (sc && providesSC())
+ } else if (sc && has_sc) {
+ if (!os.str().empty())
+ os << ',';
os << to_ascii(scoption_);
- if (scale != 100 && !scaleoption_.empty()) {
+ }
+
+ if (scale != 100 && !scaleoption_.empty()
+ && providesScale(ot1, complete, nomath)) {
if (!os.str().empty())
os << ',';
os << subst(to_ascii(scaleoption_), "$$val",
}
+string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc,
+ bool osf, bool nomath, int const & scale)
+{
+ ostringstream os;
+
+ docstring const usedfont = getUsedFont(ot1, complete, nomath);
+ if (usedfont.empty())
+ return string();
+ else if (usedfont != name_)
+ return altFont(usedfont).getLaTeXCode(dryrun, ot1, complete, sc, osf, nomath, scale);
+
+ if (switchdefault_) {
+ if (family_.empty()) {
+ LYXERR0("Error: Font `" << name_ << "' has no family defined!");
+ return string();
+ }
+ if (available(ot1, nomath) || dryrun)
+ os << "\\renewcommand{\\" << to_ascii(family_) << "default}{"
+ << to_ascii(name_) << "}\n";
+ else
+ frontend::Alert::warning(_("Font not available"),
+ bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
+ "is not available on your system. LyX will fall back to the default font."),
+ requires_, guiname_), true);
+ } else {
+ string const package =
+ getAvailablePackage(dryrun);
+ string const packageopts = getPackageOptions(ot1, complete, sc, osf, scale, nomath);
+ if (packageopts.empty() && !package.empty())
+ os << "\\usepackage{" << package << "}\n";
+ else if (!packageopts.empty() && !package.empty())
+ os << "\\usepackage[" << packageopts << "]{" << package << "}\n";
+ }
+ if (osf && providesOSF(ot1, complete, nomath) && !osffont_.empty())
+ os << altFont(osffont_).getLaTeXCode(dryrun, ot1, complete, sc, osf, nomath, scale);
+
+ if (!preamble_.empty())
+ os << to_utf8(preamble_);
+
+ return os.str();
+}
+
+
bool LaTeXFont::readFont(Lexer & lex)
{
enum LaTeXFontTags {
- LF_ALT_PACKAGES = 1,
- LF_COMPLETE_PACKAGE,
+ LF_ALT_FONTS = 1,
+ LF_COMPLETE_FONT,
LF_END,
LF_FAMILY,
LF_GUINAME,
+ LF_NOMATHFONT,
+ LF_OSFDEFAULT,
+ LF_OSFFONT,
LF_OSFOPTION,
- LF_OSFPACKAGE,
LF_OSFSCOPTION,
- LF_OT1_PACKAGE,
+ LF_OT1_FONT,
LF_PACKAGE,
+ LF_PACKAGEOPTION,
+ LF_PREAMBLE,
+ LF_PROVIDES,
LF_REQUIRES,
LF_SCALEOPTION,
LF_SCOPTION,
// Keep these sorted alphabetically!
LexerKeyword latexFontTags[] = {
- { "altpackages", LF_ALT_PACKAGES },
- { "completepackage", LF_COMPLETE_PACKAGE },
+ { "altfonts", LF_ALT_FONTS },
+ { "completefont", LF_COMPLETE_FONT },
{ "endfont", LF_END },
{ "family", LF_FAMILY },
{ "guiname", LF_GUINAME },
+ { "nomathfont", LF_NOMATHFONT },
+ { "osfdefault", LF_OSFDEFAULT },
+ { "osffont", LF_OSFFONT },
{ "osfoption", LF_OSFOPTION },
- { "osfpackage", LF_OSFPACKAGE },
{ "osfscoption", LF_OSFSCOPTION },
- { "ot1package", LF_OT1_PACKAGE },
+ { "ot1font", LF_OT1_FONT },
{ "package", LF_PACKAGE },
+ { "packageoption", LF_PACKAGEOPTION },
+ { "preamble", LF_PREAMBLE },
+ { "provides", LF_PROVIDES },
{ "requires", LF_REQUIRES },
{ "scaleoption", LF_SCALEOPTION },
{ "scoption", LF_SCOPTION },
case LF_END: // end of structure
finished = true;
break;
- case LF_ALT_PACKAGES: {
- docstring altp;
- lex >> altp;
- altpackages_ = getVectorFromString(altp);
+ case LF_ALT_FONTS: {
+ lex.eatLine();
+ docstring altp = lex.getDocString();
+ altfonts_ = getVectorFromString(altp);
break;
}
- case LF_COMPLETE_PACKAGE:
- lex >> completepackage_;
+ case LF_COMPLETE_FONT:
+ lex >> completefont_;
break;
case LF_FAMILY:
lex >> family_;
case LF_GUINAME:
lex >> guiname_;
break;
+ case LF_NOMATHFONT:
+ lex >> nomathfont_;
+ break;
case LF_OSFOPTION:
lex >> osfoption_;
break;
- case LF_OSFPACKAGE:
- lex >> osfpackage_;
+ case LF_OSFFONT:
+ lex >> osffont_;
+ break;
+ case LF_OSFDEFAULT:
+ lex >> osfdefault_;
break;
case LF_OSFSCOPTION:
lex >> osfscoption_;
break;
- case LF_OT1_PACKAGE:
- lex >> ot1package_;
+ case LF_OT1_FONT:
+ lex >> ot1font_;
break;
case LF_PACKAGE:
lex >> package_;
break;
+ case LF_PACKAGEOPTION:
+ lex >> packageoption_;
+ break;
+ case LF_PREAMBLE:
+ preamble_ = lex.getLongString(from_ascii("EndPreamble"));
+ break;
+ case LF_PROVIDES: {
+ lex.eatLine();
+ string features = lex.getString();
+ provides_ = getVectorFromString(features);
+ break;
+ }
case LF_REQUIRES:
lex >> requires_;
break;
bool LaTeXFont::read(Lexer & lex)
{
switchdefault_ = 0;
+ osfdefault_ = 0;
if (!lex.next()) {
lex.printError("No name given for LaTeX font: `$$Token'.");
return false;
}
- bool available = true;
- if (!requires_.empty())
- available = LaTeXFeatures::isAvailable(to_ascii(requires_));
- else if (!package_.empty()) {
- available = LaTeXFeatures::isAvailable(to_ascii(package_));
- if (!available && !altpackages_.empty()) {
- for (size_t i = 0; i < altpackages_.size(); ++i) {
- available = LaTeXFeatures::isAvailable(to_ascii(altpackages_[i]));
- if (available)
- break;
- }
- }
- }
- available_ = available;
-
- if (!ot1package_.empty() && ot1package_ != "none")
- available_ot1_ = LaTeXFeatures::isAvailable(to_ascii(ot1package_));
- else
- available_ot1_ = available;
-
return true;
}
default:
break;
}
- if (lex.getString() != "Font") {
+ string const type = lex.getString();
+ if (type != "Font" && type != "AltFont") {
lex.printError("Unknown LaTeXFont tag `$$Token'");
continue;
}
if (!lex)
break;
- texfontmap_[f.name()] = f;
+ if (type == "AltFont")
+ texaltfontmap_[f.name()] = f;
+ else
+ texfontmap_[f.name()] = f;
}
}
LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name)
{
+ if (name == "default" || name == "auto")
+ return LaTeXFont();
if (texfontmap_.empty())
readLaTeXFonts();
+ if (texfontmap_.find(name) == texfontmap_.end()) {
+ LYXERR0("LaTeXFonts::getLaTeXFont: font '" << name << "' not found!");
+ return LaTeXFont();
+ }
return texfontmap_[name];
}
+LaTeXFont LaTeXFonts::getAltFont(docstring const & name)
+{
+ if (name == "default" || name == "auto")
+ return LaTeXFont();
+ if (texaltfontmap_.empty())
+ readLaTeXFonts();
+ if (texaltfontmap_.find(name) == texaltfontmap_.end()) {
+ LYXERR0("LaTeXFonts::getAltFont: alternative font '" << name << "' not found!");
+ return LaTeXFont();
+ }
+ return texaltfontmap_[name];
+}
+
+
} // namespace lyx