X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLaTeXFonts.cpp;h=00e19fa57dce537979b854e4652a52b6f7c46f48;hb=7b0f9d95248820bc70b820dd6b558de4a6713bae;hp=8d18a04f6bad8baa2ef23b8497d3bea664959e5f;hpb=869b84aef9dbec9c90ba4483db0b28a3fb92b947;p=lyx.git diff --git a/src/LaTeXFonts.cpp b/src/LaTeXFonts.cpp index 8d18a04f6b..00e19fa57d 100644 --- a/src/LaTeXFonts.cpp +++ b/src/LaTeXFonts.cpp @@ -15,10 +15,14 @@ #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" @@ -31,118 +35,350 @@ namespace lyx { 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::available(bool ot1, bool nomath) +{ + 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 (required_.empty() && package_.empty()) + return true; + else if (!required_.empty() + && LaTeXFeatures::isAvailable(to_ascii(required_))) + return true; + else if (required_.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; } -bool LaTeXFont::providesOSF(bool ot1) const +bool LaTeXFont::providesNoMath(bool ot1, bool complete) { - if (!osfpackage_.empty()) - return LaTeXFeatures::isAvailable(to_ascii(osfpackage_)); + docstring const usedfont = getUsedFont(ot1, complete, false, false); - if (ot1 && !ot1package_.empty() && ot1package_ != "none") + if (usedfont.empty()) return false; + else if (usedfont != name_) + return altFont(usedfont).providesNoMath(ot1, complete); - if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_))) + return (!nomathfont_.empty() && available(ot1, true)); +} + + +bool LaTeXFont::providesOSF(bool ot1, bool complete, bool nomath) +{ + docstring const usedfont = getUsedFont(ot1, complete, nomath, false); + + 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, false); - 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") + docstring const usedfont = getUsedFont(ot1, complete, nomath, false); + + 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()); +} + - if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_))) +bool LaTeXFont::providesScale(bool ot1, bool complete, bool nomath) +{ + docstring const usedfont = getUsedFont(ot1, complete, nomath, false); + + 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() || !scalecmd_.empty()); +} + + +bool LaTeXFont::providesMoreOptions(bool ot1, bool complete, bool nomath) +{ + docstring const usedfont = getUsedFont(ot1, complete, nomath, false); - return (!scaleoption_.empty()); + if (usedfont.empty()) + return false; + else if (usedfont != name_) + return altFont(usedfont).providesMoreOptions(ot1, complete, nomath); + else if (!available(ot1, nomath)) + return false; + + return (moreopts_); } +bool LaTeXFont::provides(std::string const & name, bool ot1, bool complete, bool nomath) +{ + docstring const usedfont = getUsedFont(ot1, complete, nomath, false); -string const LaTeXFont::getAvailablePackage(bool ot1, bool complete) + if (usedfont.empty()) + return false; + else if (usedfont != name_) + return altFont(usedfont).provides(name, ot1, complete, nomath); + else if (provides_.empty()) + return false; + + 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, bool osf) { - if (ot1 && !ot1package_.empty()) { - if (ot1package_ != "none" && LaTeXFeatures::isAvailable(to_ascii(ot1package_))) - return to_ascii(ot1package_); - return string(); + if (osf && osfFontOnly()) + return osffont_; + else 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 (required_.empty() + || (!required_.empty() + && LaTeXFeatures::isAvailable(to_ascii(required_)))) + return name_; } - if (complete && !completepackage_.empty()) { - if (LaTeXFeatures::isAvailable(to_ascii(completepackage_))) - return to_ascii(completepackage_); + else if (!required_.empty() + && LaTeXFeatures::isAvailable(to_ascii(required_))) + return name_; + else if (!package_.empty() + && LaTeXFeatures::isAvailable(to_ascii(package_))) + return name_; + else if (!preamble_.empty() && package_.empty() + && required_.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, osf); } } - return string(); + + return docstring(); +} + + +docstring const LaTeXFont::getUsedPackage(bool ot1, bool complete, bool nomath) +{ + docstring const usedfont = getUsedFont(ot1, complete, nomath, false); + if (usedfont.empty()) + return docstring(); + return theLaTeXFonts().getLaTeXFont(usedfont).package(); } -string const LaTeXFont::getPackageOptions(bool const & ot1, bool const & sc, - bool const & osf, int const & scale) +string const LaTeXFont::getAvailablePackage(bool dryrun) { - if (ot1 && !ot1package_.empty()) + if (package_.empty()) return string(); + string const package = to_ascii(package_); + if (!required_.empty() && LaTeXFeatures::isAvailable(to_ascii(required_))) + return package; + else if (LaTeXFeatures::isAvailable(package)) + return package; + // Output unavailable packages in source preview + else if (dryrun) + return package; + + docstring const req = required_.empty() ? package_ : required_; + 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, string const & extraopts, 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); + bool const moreopts = providesMoreOptions(ot1, complete, nomath); + + if (!packageoptions_.empty()) + os << to_ascii(packageoptions_); + + 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", convert(float(scale) / 100)); } + + if (moreopts && !extraopts.empty()) { + if (!os.str().empty()) + os << ','; + os << extraopts; + } + return os.str(); +} + + +string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc, + bool osf, bool nomath, string const & extraopts, + int const & scale) +{ + ostringstream os; + + docstring const usedfont = getUsedFont(ot1, complete, nomath, osf); + if (usedfont.empty()) + return string(); + else if (usedfont != name_) + return altFont(usedfont).getLaTeXCode(dryrun, ot1, complete, sc, + osf, nomath, extraopts, 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."), + required_, guiname_), true); + } else { + string const package = + getAvailablePackage(dryrun); + string const packageopts = getPackageOptions(ot1, complete, sc, osf, scale, extraopts, 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, extraopts, scale); + if (scale != 100 && !scalecmd_.empty() + && providesScale(ot1, complete, nomath)) { + if (contains(scalecmd_, '@')) + os << "\\makeatletter\n"; + os << subst(to_ascii(scalecmd_), "$$val", + convert(float(scale) / 100)) << '\n'; + if (contains(scalecmd_, '@')) + os << "\\makeatother\n"; + } + + if (!preamble_.empty()) + os << to_utf8(preamble_); + return os.str(); } +bool LaTeXFont::hasFontenc(string const & name) const +{ + for (auto const & fe : fontenc_) { + if (fe == name) + return true; + } + return false; +} + + 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_FONTENC, LF_GUINAME, + LF_NOMATHFONT, + LF_OSFDEFAULT, + LF_OSFFONT, + LF_OSFFONTONLY, LF_OSFOPTION, - LF_OSFPACKAGE, LF_OSFSCOPTION, - LF_OT1_PACKAGE, + LF_OT1_FONT, + LF_MOREOPTS, LF_PACKAGE, + LF_PACKAGEOPTIONS, + LF_PREAMBLE, + LF_PROVIDES, LF_REQUIRES, + LF_SCALECMD, LF_SCALEOPTION, LF_SCOPTION, LF_SWITCHDEFAULT @@ -150,17 +386,26 @@ bool LaTeXFont::readFont(Lexer & lex) // 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 }, + { "fontencoding", LF_FONTENC }, { "guiname", LF_GUINAME }, + { "moreoptions", LF_MOREOPTS }, + { "nomathfont", LF_NOMATHFONT }, + { "osfdefault", LF_OSFDEFAULT }, + { "osffont", LF_OSFFONT }, + { "osffontonly", LF_OSFFONTONLY }, { "osfoption", LF_OSFOPTION }, - { "osfpackage", LF_OSFPACKAGE }, { "osfscoption", LF_OSFSCOPTION }, - { "ot1package", LF_OT1_PACKAGE }, + { "ot1font", LF_OT1_FONT }, { "package", LF_PACKAGE }, + { "packageoptions", LF_PACKAGEOPTIONS }, + { "preamble", LF_PREAMBLE }, + { "provides", LF_PROVIDES }, { "requires", LF_REQUIRES }, + { "scalecommand", LF_SCALECMD }, { "scaleoption", LF_SCALEOPTION }, { "scoption", LF_SCOPTION }, { "switchdefault", LF_SWITCHDEFAULT } @@ -182,21 +427,21 @@ bool LaTeXFont::readFont(Lexer & lex) error = true; continue; - default: + default: break; } switch (static_cast(le)) { 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_; @@ -204,23 +449,53 @@ bool LaTeXFont::readFont(Lexer & lex) case LF_GUINAME: lex >> guiname_; break; + case LF_FONTENC: { + lex.eatLine(); + string fe = lex.getString(); + fontenc_ = getVectorFromString(fe); + 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_OSFFONTONLY: + lex >> osffontonly_; 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_PACKAGEOPTIONS: + lex >> packageoptions_; + 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_; + lex >> required_; + break; + case LF_SCALECMD: + lex >> scalecmd_; break; case LF_SCALEOPTION: lex >> scaleoption_; @@ -228,6 +503,9 @@ bool LaTeXFont::readFont(Lexer & lex) case LF_SCOPTION: lex >> scoption_; break; + case LF_MOREOPTS: + lex >> moreopts_; + break; case LF_SWITCHDEFAULT: lex >> switchdefault_; break; @@ -245,6 +523,9 @@ bool LaTeXFont::readFont(Lexer & lex) bool LaTeXFont::read(Lexer & lex) { switchdefault_ = 0; + osfdefault_ = 0; + moreopts_ = 0; + osffontonly_ = 0; if (!lex.next()) { lex.printError("No name given for LaTeX font: `$$Token'."); @@ -258,25 +539,8 @@ bool LaTeXFont::read(Lexer & lex) 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; + if (fontenc_.empty()) + fontenc_.push_back("T1"); return true; } @@ -302,7 +566,8 @@ void LaTeXFonts::readLaTeXFonts() default: break; } - if (lex.getString() != "Font") { + string const type = lex.getString(); + if (type != "Font" && type != "AltFont") { lex.printError("Unknown LaTeXFont tag `$$Token'"); continue; } @@ -311,7 +576,10 @@ void LaTeXFonts::readLaTeXFonts() if (!lex) break; - texfontmap_[f.name()] = f; + if (type == "AltFont") + texaltfontmap_[f.name()] = f; + else + texfontmap_[f.name()] = f; } } @@ -326,10 +594,30 @@ LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts() 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