The branch, master, has been updated. - Log -----------------------------------------------------------------
commit 869b84aef9dbec9c90ba4483db0b28a3fb92b947 Author: Juergen Spitzmueller <sp...@lyx.org> Date: Thu Aug 16 13:23:39 2012 +0200 Clean up LaTeX font handling (#4999) The LaTeX font information are now centralized and outsourced. This removes a lot of hardcoding and duplication and makes it easier to support new LaTeX fonts. diff --git a/development/qmake/lyx.pro b/development/qmake/lyx.pro index 2b0d271..cef4569 100644 --- a/development/qmake/lyx.pro +++ b/development/qmake/lyx.pro @@ -91,6 +91,7 @@ SOURCES += \ ../../src/Language.cpp \ ../../src/LaTeX.cpp \ ../../src/LaTeXFeatures.cpp \ +../../src/LaTeXFonts.cpp \ ../../src/Layout.cpp \ ../../src/LayoutFile.cpp \ ../../src/LayoutModuleList.cpp \ @@ -439,6 +440,7 @@ HEADERS += \ ../../src/KeySequence.h \ ../../src/Language.h \ ../../src/LaTeXFeatures.h \ +../../src/LaTeXFonts.h \ ../../src/LaTeX.h \ ../../src/LayoutEnums.h \ ../../src/LayoutFile.h \ diff --git a/lib/Makefile.am b/lib/Makefile.am index 2111dfb..90935c3 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -5,7 +5,7 @@ SUBDIRS = doc lyx2lyx CHMOD = chmod dist_pkgdata_DATA = CREDITS autocorrect chkconfig.ltx external_templates \ - encodings layouttranslations languages symbols syntax.default \ + encodings layouttranslations languages latexfonts symbols syntax.default \ unicodesymbols nodist_pkgdata_DATA = installed_translations diff --git a/lib/latexfonts b/lib/latexfonts new file mode 100644 index 0000000..cf59405 --- /dev/null +++ b/lib/latexfonts @@ -0,0 +1,242 @@ +########################################################################## +# +# LaTeX fonts natively supported by LyX. +# +# Syntax: +# +# Font <name> +# GuiName "<Gui Name>" +# Family <rm|sf|tt> +# SwitchDefault <0|1> +# Package <LaTeX package to be loaded> +# Requires <LaTeX package to test for> +# AltPackages <alternative packages (comma-separated)> +# OT1Package <alternative package specifically for OT1 encoding> +# CompletePackage <alternative package for the complete family> +# OsfOption <option for oldstyle figure support> +# ScOption <option for true smallcaps support> +# OsfScOption <option for combined osf and true smallcaps support> +# ScaleOption <option for font scaling> +# EndFont +# +# +# NOTES: +# +# * Adding a new font results in a FILE FORMAT CHANGE. So if a new font +# is added for the LyX distribution, the according changes need to be +# done. +# * "SwitchDefault 1" makes the font to be loaded by switching the default +# family to <name> (e.g., \renewcommand{\rmdefault}{cmr}), whereas +# Package <package> loads it via \usepackage{package}. Normally, only +# one of these options is used per font. +# * If AltPackages are defined, LyX will try to load them in the defined +# order if the main package is not available. So +# Package mathptmx +# AltPackages mathptm,times +# will try to load mathptm if mathptmx is not available and then times +# if mathptm is not available either. +# * If Requires is set, LyX will check for this. If not, it will check +# for Package and AltPackages. +# * OT1Package will load the defined package instead of the default +# package if the font encoding is OT1. This is necessary since some +# newer packages for a font do not support this encoding. +# The value "none" tells LyX not to load a package in OT1 encoding. +# * CompletePackage is a package that is loaded if the current font is +# selected as rm and both sf and tt are set to "default" (this allows +# f. ex. to load "bera" as opposed to "beraserif"). +# * OsfScOption overrides any OsfOption and ScOption if both features +# are selected. +# * ScaleOption supports the placeholder $$val for the scale value. +# +########################################################################## + +# +# Roman fonts +# + +Font cmr + GuiName "Computer Modern Roman" + Family rm + SwitchDefault 1 + OsfPackage eco +EndFont + +Font lmodern + GuiName "Latin Modern Roman" + Family rm + Package lmodern +EndFont + +Font ae + GuiName "AE (Almost European)" + Family rm + Package "ae,aecompl" + OT1Package none + Requires ae +EndFont + +Font times + GuiName "Times Roman" + Family rm + Package mathptmx + AltPackages "mathptm,times" + Requires psnfss +EndFont + +Font palatino + GuiName "Palatino" + Family rm + OsfOption osf + ScOption sc + OsfScOption osf + Package mathpazo + AltPackages "mathpple,palatino" + Requires psnfss +EndFont + +Font charter + GuiName "Bitstream Charter" + Family rm + Package charter +EndFont + +Font newcent + GuiName "New Century Schoolbook" + Family rm + Package newcent +EndFont + +Font bookman + GuiName "Bookman" + Family rm + Package bookman +EndFont + +# fourier supersedes utopia.sty, but does +# not work with OT1 encoding. +Font utopia + GuiName "Utopia" + Family rm + OsfOption oldstyle + ScOption expert + Package fourier + AltPackages utopia + OT1Package utopia +EndFont + +Font beraserif + GuiName "Bera Serif" + Family rm + Package beraserif + CompletePackage bera + Requires bera +EndFont + +Font ccfonts + GuiName "Concrete Roman" + Family rm + Package ccfonts +EndFont + +Font chancery + GuiName "Zapf Chancery" + Family rm + Package chancery +EndFont + + +# +# SansSerif fonts +# + + +Font cmss + GuiName "Computer Modern Sans" + Family sf + SwitchDefault 1 +EndFont + + +Font lmss + GuiName "Latin Modern Sans" + Family sf + SwitchDefault 1 + Requires lmodern +EndFont + +Font helvet + GuiName "Helvetica" + Family sf + ScaleOption scaled=$$val + Package helvet + Requires psnfss +EndFont + +Font avant + GuiName "Avant Garde" + Family sf + Package avant +EndFont + +Font berasans + GuiName "Bera Sans" + Family sf + ScaleOption scaled=$$val + Package berasans + Requires bera +EndFont + +Font cmbr + GuiName "CM Bright" + Family sf + SwitchDefault 1 + Requires cmbright +EndFont + + +# +# Monospaced fonts +# + +Font cmtt + GuiName "Computer Modern Typewriter" + Family tt + SwitchDefault 1 +EndFont + +Font lmtt + GuiName "Latin Modern Typewriter" + Family tt + SwitchDefault 1 + Requires lmodern +EndFont + +Font courier + GuiName "Courier" + Family tt + Package courier + Requires psnfss +EndFont + +Font beramono + GuiName "Bera Mono" + Family tt + ScaleOption scaled=$$val + Package beramono + Requires bera +EndFont + +Font luximono + GuiName "LuxiMono" + Family tt + ScaleOption scaled=$$val + Package luximono +EndFont + +Font cmtl + GuiName "CM Typewriter Light" + Family tt + SwitchDefault 1 + Requires cmbright +EndFont + diff --git a/po/Rules-lyx b/po/Rules-lyx index c8cae85..b99f018 100644 --- a/po/Rules-lyx +++ b/po/Rules-lyx @@ -38,6 +38,9 @@ $(top_srcdir)/lib/layouttranslations: $(POFILES) $(top_srcdir)/lib/layouts/*.lay languages_l10n.pot: $(top_srcdir)/lib/languages $(PYTHON) $(srcdir)/lyx_pot.py -b $(top_srcdir) -o $@ -t languages ${top_srcdir}/lib/languages +latexfonts_l10n.pot: $(top_srcdir)/lib/latexfonts + $(PYTHON) $(srcdir)/lyx_pot.py -b $(top_srcdir) -o $@ -t latexfonts ${top_srcdir}/lib/latexfonts + encodings_l10n.pot: $(top_srcdir)/lib/encodings $(PYTHON) $(srcdir)/lyx_pot.py -b $(top_srcdir) -o $@ -t encodings ${top_srcdir}/lib/encodings diff --git a/po/lyx_pot.py b/po/lyx_pot.py index 25cb1fd..4ee9f55 100755 --- a/po/lyx_pot.py +++ b/po/lyx_pot.py @@ -435,6 +435,26 @@ def languages_l10n(input_files, output, base): out.close() +def latexfonts_l10n(input_files, output, base): + '''Generate pot file from lib/latexfonts''' + out = open(output, 'w') + GuiName = re.compile(r'^[^#]*GuiName\s+(.*)', re.IGNORECASE) + + for src in input_files: + descStartLine = -1 + descLines = [] + lineno = 0 + for line in open(src).readlines(): + lineno += 1 + res = GuiName.search(line) + if res != None: + string = res.group(1) + writeString(out, src, base, lineno, string) + continue + + out.close() + + def external_l10n(input_files, output, base): '''Generate pot file from lib/external_templates''' output = open(output, 'w') @@ -553,6 +573,7 @@ where layouttranslations: create lib/layouttranslations from po/*.po and lib/layouts/* qt4: qt4 ui files languages: file lib/languages + latexfonts: file lib/latexfonts encodings: file lib/encodings external: external templates file formats: formats predefined in lib/configure.py @@ -579,7 +600,7 @@ if __name__ == '__main__': elif opt in ['-s', '--src_file']: input_files = [f.strip() for f in open(value)] - if input_type not in ['ui', 'layouts', 'layouttranslations', 'qt4', 'languages', 'encodings', 'external', 'formats'] or output is None: + if input_type not in ['ui', 'layouts', 'layouttranslations', 'qt4', 'languages', 'latexfonts', 'encodings', 'external', 'formats'] or output is None: print 'Wrong input type or output filename.' sys.exit(1) @@ -587,6 +608,8 @@ if __name__ == '__main__': if input_type == 'ui': ui_l10n(input_files, output, base) + elif input_type == 'latexfonts': + latexfonts_l10n(input_files, output, base) elif input_type == 'layouts': layouts_l10n(input_files, output, base, False) elif input_type == 'layouttranslations': diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 36edd59..80f563d 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -30,6 +30,7 @@ #include "IndicesList.h" #include "Language.h" #include "LaTeXFeatures.h" +#include "LaTeXFonts.h" #include "ModuleList.h" #include "Font.h" #include "Lexer.h" @@ -2856,115 +2857,50 @@ string const BufferParams::loadFonts(string const & rm, return os.str(); } + // Tex Fonts + bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1"); + // ROMAN FONTS - // Computer Modern (must be explicitly selectable -- there might be classes - // that define a different default font! - if (rm == "cmr") { - os << "\\renewcommand{\\rmdefault}{cmr}\n"; - // osf for Computer Modern needs eco.sty - if (osf) - os << "\\usepackage{eco}\n"; - } - // Latin Modern Roman - else if (rm == "lmodern") - os << "\\usepackage{lmodern}\n"; - // AE - else if (rm == "ae") { - // not needed when using OT1 font encoding. - if (font_encoding() != "default") - os << "\\usepackage{ae,aecompl}\n"; - } - // Times - else if (rm == "times") { - // try to load the best available package - if (LaTeXFeatures::isAvailable("mathptmx")) - os << "\\usepackage{mathptmx}\n"; - else if (LaTeXFeatures::isAvailable("mathptm")) - os << "\\usepackage{mathptm}\n"; - else - os << "\\usepackage{times}\n"; - } - // Palatino - else if (rm == "palatino") { - // try to load the best available package - if (LaTeXFeatures::isAvailable("mathpazo")) { - os << "\\usepackage"; - if (osf || sc) { - os << '['; - if (!osf) - os << "sc"; - else - // "osf" includes "sc"! - os << "osf"; - os << ']'; - } - os << "{mathpazo}\n"; - } - else if (LaTeXFeatures::isAvailable("mathpple")) - os << "\\usepackage{mathpple}\n"; - else - os << "\\usepackage{palatino}\n"; - } - // Utopia - else if (rm == "utopia") { - // fourier supersedes utopia.sty, but does - // not work with OT1 encoding. - if (LaTeXFeatures::isAvailable("fourier") - && font_encoding() != "default") { - os << "\\usepackage"; - if (osf || sc) { - os << '['; - if (sc) - os << "expert"; - if (osf && sc) - os << ','; - if (osf) - os << "oldstyle"; - os << ']'; - } - os << "{fourier}\n"; - } - else - os << "\\usepackage{utopia}\n"; + LaTeXFont roman = theLaTeXFonts().getLaTeXFont(from_ascii(rm)); + if (roman.switchdefault()) + os << "\\renewcommand{\\rmdefault}{" << to_ascii(roman.name()) << "}\n"; + else { + bool const complete = (sf == "default" && tt == "default"); + string const package = roman.getAvailablePackage(ot1, complete); + string const packageopts = roman.getPackageOptions(ot1, sc, osf); + if (packageopts.empty() && !package.empty()) + os << "\\usepackage{" << package << "}\n"; + else if (!packageopts.empty() && !package.empty()) + os << "\\usepackage[" << packageopts << "]{" << package << "}\n"; } - // Bera (complete fontset) - else if (rm == "bera" && sf == "default" && tt == "default") - os << "\\usepackage{bera}\n"; - // everything else - else if (rm != "default") - os << "\\usepackage" << "{" << rm << "}\n"; + if (osf && roman.providesOSF(ot1) && !roman.osfpackage().empty()) + os << "\\usepackage{" << to_ascii(roman.osfpackage()) << "}\n"; // SANS SERIF - // Helvetica, Bera Sans - if (sf == "helvet" || sf == "berasans") { - if (sfscale != 100) - os << "\\usepackage[scaled=" << float(sfscale) / 100 - << "]{" << sf << "}\n"; - else - os << "\\usepackage{" << sf << "}\n"; - } - // Avant Garde - else if (sf == "avant") - os << "\\usepackage{" << sf << "}\n"; - // Computer Modern, Latin Modern, CM Bright - else if (sf != "default") - os << "\\renewcommand{\\sfdefault}{" << sf << "}\n"; - - // monospaced/typewriter - // Courier, LuxiMono - if (tt == "luximono" || tt == "beramono") { - if (ttscale != 100) - os << "\\usepackage[scaled=" << float(ttscale) / 100 - << "]{" << tt << "}\n"; - else - os << "\\usepackage{" << tt << "}\n"; - } - // Courier - else if (tt == "courier" ) - os << "\\usepackage{" << tt << "}\n"; - // Computer Modern, Latin Modern, CM Bright - else if (tt != "default") - os << "\\renewcommand{\\ttdefault}{" << tt << "}\n"; + LaTeXFont sans = theLaTeXFonts().getLaTeXFont(from_ascii(sf)); + if (sans.switchdefault()) + os << "\\renewcommand{\\sfdefault}{" << to_ascii(sans.name()) << "}\n"; + else { + string const package = sans.getAvailablePackage(ot1); + string const packageopts = sans.getPackageOptions(ot1, sc, osf, sfscale); + if (packageopts.empty() && !package.empty()) + os << "\\usepackage{" << package << "}\n"; + else if (!packageopts.empty() && !package.empty()) + os << "\\usepackage[" << packageopts << "]{" << package << "}\n"; + } + + // MONOSPACED/TYPEWRITER + LaTeXFont mono = theLaTeXFonts().getLaTeXFont(from_ascii(tt)); + if (mono.switchdefault()) + os << "\\renewcommand{\\ttdefault}{" << to_ascii(mono.name()) << "}\n"; + else { + string const package = mono.getAvailablePackage(ot1); + string const packageopts = mono.getPackageOptions(ot1, sc, osf, ttscale); + if (packageopts.empty() && !package.empty()) + os << "\\usepackage{" << package << "}\n"; + else if (!packageopts.empty() && !package.empty()) + os << "\\usepackage[" << packageopts << "]{" << package << "}\n"; + } return os.str(); } diff --git a/src/LaTeXFonts.cpp b/src/LaTeXFonts.cpp new file mode 100644 index 0000000..8d18a04 --- /dev/null +++ b/src/LaTeXFonts.cpp @@ -0,0 +1,335 @@ +/** + * \file LaTeXFonts.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jürgen Spitzmüller + * + * Full author contact details are available in file CREDITS. + */ + +#include <config.h> + +#include "LaTeXFonts.h" + +#include "LaTeXFeatures.h" +#include "Lexer.h" + +#include "support/convert.h" +#include "support/debug.h" +#include "support/FileName.h" +#include "support/filetools.h" +#include "support/lstrings.h" + + +using namespace std; +using namespace lyx::support; + + +namespace lyx { + +LaTeXFonts latexfonts; + + +bool LaTeXFont::available(bool ot1) const +{ + return ot1 ? available_ot1_ : available_; +} + + +bool LaTeXFont::providesOSF(bool ot1) const +{ + if (!osfpackage_.empty()) + return LaTeXFeatures::isAvailable(to_ascii(osfpackage_)); + + if (ot1 && !ot1package_.empty() && ot1package_ != "none") + return false; + + if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_))) + return false; + + return (!osfoption_.empty() || !osfscoption_.empty()); +} + + +bool LaTeXFont::providesSC(bool ot1) const +{ + if (ot1 && !ot1package_.empty() && ot1package_ != "none") + return false; + + if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_))) + return false; + + return (!scoption_.empty() || !osfscoption_.empty()); +} + + +bool LaTeXFont::providesScale(bool ot1) const +{ + if (ot1 && !ot1package_.empty() && ot1package_ != "none") + return false; + + if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_))) + return false; + + return (!scaleoption_.empty()); +} + + +string const LaTeXFont::getAvailablePackage(bool ot1, bool complete) +{ + if (ot1 && !ot1package_.empty()) { + if (ot1package_ != "none" && LaTeXFeatures::isAvailable(to_ascii(ot1package_))) + return to_ascii(ot1package_); + return string(); + } + if (complete && !completepackage_.empty()) { + if (LaTeXFeatures::isAvailable(to_ascii(completepackage_))) + return to_ascii(completepackage_); + } + 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]); + } + } + } + return string(); +} + + +string const LaTeXFont::getPackageOptions(bool const & ot1, bool const & sc, + bool const & osf, int const & scale) +{ + if (ot1 && !ot1package_.empty()) + return string(); + + ostringstream os; + if (sc && osf && providesOSF() && providesSC()) { + if (!osfscoption_.empty()) + os << to_ascii(osfscoption_); + else + os << to_ascii(osfoption_) << ',' << to_ascii(scoption_); + } else if (osf && providesOSF()) + os << to_ascii(osfoption_); + else if (sc && providesSC()) + os << to_ascii(scoption_); + if (scale != 100 && !scaleoption_.empty()) { + if (!os.str().empty()) + os << ','; + os << subst(to_ascii(scaleoption_), "$$val", + convert<std::string>(float(scale) / 100)); + } + return os.str(); +} + + +bool LaTeXFont::readFont(Lexer & lex) +{ + enum LaTeXFontTags { + LF_ALT_PACKAGES = 1, + LF_COMPLETE_PACKAGE, + LF_END, + LF_FAMILY, + LF_GUINAME, + LF_OSFOPTION, + LF_OSFPACKAGE, + LF_OSFSCOPTION, + LF_OT1_PACKAGE, + LF_PACKAGE, + LF_REQUIRES, + LF_SCALEOPTION, + LF_SCOPTION, + LF_SWITCHDEFAULT + }; + + // Keep these sorted alphabetically! + LexerKeyword latexFontTags[] = { + { "altpackages", LF_ALT_PACKAGES }, + { "completepackage", LF_COMPLETE_PACKAGE }, + { "endfont", LF_END }, + { "family", LF_FAMILY }, + { "guiname", LF_GUINAME }, + { "osfoption", LF_OSFOPTION }, + { "osfpackage", LF_OSFPACKAGE }, + { "osfscoption", LF_OSFSCOPTION }, + { "ot1package", LF_OT1_PACKAGE }, + { "package", LF_PACKAGE }, + { "requires", LF_REQUIRES }, + { "scaleoption", LF_SCALEOPTION }, + { "scoption", LF_SCOPTION }, + { "switchdefault", LF_SWITCHDEFAULT } + }; + + bool error = false; + bool finished = false; + lex.pushTable(latexFontTags); + // parse style section + while (!finished && lex.isOK() && !error) { + int le = lex.lex(); + // See comment in LyXRC.cpp. + switch (le) { + case Lexer::LEX_FEOF: + continue; + + case Lexer::LEX_UNDEF: // parse error + lex.printError("Unknown LaTeXFont tag `$$Token'"); + error = true; + continue; + + default: + break; + } + switch (static_cast<LaTeXFontTags>(le)) { + case LF_END: // end of structure + finished = true; + break; + case LF_ALT_PACKAGES: { + docstring altp; + lex >> altp; + altpackages_ = getVectorFromString(altp); + break; + } + case LF_COMPLETE_PACKAGE: + lex >> completepackage_; + break; + case LF_FAMILY: + lex >> family_; + break; + case LF_GUINAME: + lex >> guiname_; + break; + case LF_OSFOPTION: + lex >> osfoption_; + break; + case LF_OSFPACKAGE: + lex >> osfpackage_; + break; + case LF_OSFSCOPTION: + lex >> osfscoption_; + break; + case LF_OT1_PACKAGE: + lex >> ot1package_; + break; + case LF_PACKAGE: + lex >> package_; + break; + case LF_REQUIRES: + lex >> requires_; + break; + case LF_SCALEOPTION: + lex >> scaleoption_; + break; + case LF_SCOPTION: + lex >> scoption_; + break; + case LF_SWITCHDEFAULT: + lex >> switchdefault_; + break; + } + } + if (!finished) { + lex.printError("No End tag found for LaTeXFont tag `$$Token'"); + return false; + } + lex.popTable(); + return finished && !error; +} + + +bool LaTeXFont::read(Lexer & lex) +{ + switchdefault_ = 0; + + if (!lex.next()) { + lex.printError("No name given for LaTeX font: `$$Token'."); + return false; + } + + name_ = lex.getDocString(); + LYXERR(Debug::INFO, "Reading LaTeX font " << name_); + if (!readFont(lex)) { + LYXERR0("Error parsing LaTeX font `" << name_ << '\''); + 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; +} + + +void LaTeXFonts::readLaTeXFonts() +{ + // Read latexfonts file + FileName filename = libFileSearch(string(), "latexfonts"); + if (filename.empty()) { + LYXERR0("Error: latexfonts file not found!"); + return; + } + Lexer lex; + lex.setFile(filename); + lex.setContext("LaTeXFeatures::readLaTeXFonts"); + while (lex.isOK()) { + int le = lex.lex(); + switch (le) { + case Lexer::LEX_FEOF: + continue; + + default: + break; + } + if (lex.getString() != "Font") { + lex.printError("Unknown LaTeXFont tag `$$Token'"); + continue; + } + LaTeXFont f; + f.read(lex); + if (!lex) + break; + + texfontmap_[f.name()] = f; + } +} + + +LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts() +{ + if (texfontmap_.empty()) + readLaTeXFonts(); + return texfontmap_; +} + + +LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name) +{ + if (texfontmap_.empty()) + readLaTeXFonts(); + return texfontmap_[name]; +} + + +} // namespace lyx diff --git a/src/LaTeXFonts.h b/src/LaTeXFonts.h new file mode 100644 index 0000000..19dfe10 --- /dev/null +++ b/src/LaTeXFonts.h @@ -0,0 +1,136 @@ +// -*- C++ -*- +/** + * \file LaTeXFonts.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jürgen Spitzmüller + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef LATEXFONTS_H +#define LATEXFONTS_H + +#include "support/docstring.h" + +#include <map> +#include <vector> + + +namespace lyx { + +class Lexer; + +/// LaTeX Font definition +class LaTeXFont { +public: + /// TeX font + LaTeXFont() : switchdefault_(false) {} + /// The font name + docstring const & name() { return name_; } + /// The name to appear in the document dialog + docstring const & guiname() { return guiname_; } + /// Font family (rm, sf, tt) + docstring const & family() { return family_; } + /// The package that provides this font + docstring const & package() { return package_; } + /// Alternative packages if package() is not available + std::vector<docstring> const & altpackages() { return altpackages_; } + /// A package that provides all families + docstring const & completepackage() { return completepackage_; } + /// A package specifically needed for OT1 font encoding + docstring const & ot1package() { return ot1package_; } + /// A package that provides Old Style Figures for this font + docstring const & osfpackage() { return osfpackage_; } + /// A package option for Old Style Figures + docstring const & osfoption() { return osfoption_; } + /// A package option for true SmallCaps + docstring const & scoption() { return scoption_; } + /// A package option for both Old Style Figures and SmallCaps + docstring const & osfscoption() { return osfscoption_; } + /// A package option for font scaling + docstring const & scaleoption() { return scaleoption_; } + /// Alternative requirement to test for + docstring const & requires() { return requires_; } + /// Issue the familydefault switch + bool switchdefault() const { return switchdefault_; } + /// Is this font available? + bool available(bool ot1 = false) const; + /// Does this font provide Old Style Figures? + bool providesOSF(bool ot1 = false) const; + /// Does this font provide optional true SmallCaps? + bool providesSC(bool ot1 = false) const; + /// Does this font provide scaling? + bool providesScale(bool ot1 = false) const; + /// Return the preferred available package + std::string const getAvailablePackage(bool ot1 = false, bool complete = false); + /// Return the package options + std::string const getPackageOptions(bool const & ot1, + bool const & sc, + bool const & osf, + int const & scale = 100); + /// + bool read(Lexer & lex); + /// + bool readFont(Lexer & lex); +private: + /// + docstring name_; + /// + docstring guiname_; + /// + docstring family_; + /// + docstring package_; + /// + std::vector<docstring> altpackages_; + /// + docstring completepackage_; + /// + docstring ot1package_; + /// + docstring osfpackage_; + /// + docstring osfoption_; + /// + docstring scoption_; + /// + docstring osfscoption_; + /// + docstring scaleoption_; + /// + docstring requires_; + /// + bool switchdefault_; + /// + bool available_; + /// + bool available_ot1_; +}; + + +/** The list of available LaTeX fonts + */ +class LaTeXFonts { +public: + /// + typedef std::map<docstring, LaTeXFont> TexFontMap; + /// Get all LaTeXFonts + TexFontMap getLaTeXFonts(); + /// Get a specific LaTeXFont \p name + LaTeXFont getLaTeXFont(docstring const & name); +private: + /// + void readLaTeXFonts(); + /// + TexFontMap texfontmap_; +}; + +/// Implementation is in LyX.cpp +extern LaTeXFonts & theLaTeXFonts(); + + +} // namespace lyx + +#endif diff --git a/src/LyX.cpp b/src/LyX.cpp index cd1354b..6d8a98a 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -34,6 +34,7 @@ #include "HunspellChecker.h" #include "KeyMap.h" #include "Language.h" +#include "LaTeXFonts.h" #include "LayoutFile.h" #include "Lexer.h" #include "LyX.h" @@ -139,12 +140,13 @@ void reconfigureUserLyXDir() /// The main application class private implementation. struct LyX::Impl { - Impl() : spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0) + Impl() : latexfonts_(0), spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0) { } ~Impl() { + delete latexfonts_; delete apple_spell_checker_; delete aspell_checker_; delete enchant_checker_; @@ -187,6 +189,9 @@ struct LyX::Impl bool first_start; /// the parsed command line batch command if any vector<string> batch_commands; + + /// + LaTeXFonts * latexfonts_; /// SpellChecker * spell_checker_; @@ -1387,6 +1392,15 @@ Session & theSession() } +LaTeXFonts & theLaTeXFonts() +{ + LASSERT(singleton_, /**/); + if (!singleton_->pimpl_->latexfonts_) + singleton_->pimpl_->latexfonts_ = new LaTeXFonts; + return *singleton_->pimpl_->latexfonts_; +} + + CmdDef & theTopLevelCmdDef() { LASSERT(singleton_, /**/); diff --git a/src/LyX.h b/src/LyX.h index bc898d6..af43edc 100644 --- a/src/LyX.h +++ b/src/LyX.h @@ -28,6 +28,7 @@ class ErrorItem; class FuncRequest; class FuncStatus; class KeyMap; +class LaTeXFonts; class Messages; class Mover; class Movers; @@ -148,6 +149,7 @@ private: friend Movers & theSystemMovers(); friend frontend::Application * theApp(); friend Session & theSession(); + friend LaTeXFonts & theLaTeXFonts(); friend CmdDef & theTopLevelCmdDef(); friend SpellChecker * theSpellChecker(); friend void setSpellChecker(); diff --git a/src/Makefile.am b/src/Makefile.am index 02a878d..4a45f07 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -85,6 +85,8 @@ lyx_SOURCES = \ $(ENCHANT) \ $(HUNSPELL) \ $(PWL) \ + LaTeXFonts.cpp \ + LaTeXFonts.h \ PrinterParams.cpp \ PrinterParams.h \ Thesaurus.cpp \ diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index dd07083..ee39809 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -38,6 +38,7 @@ #include "IndicesList.h" #include "Language.h" #include "LaTeXFeatures.h" +#include "LaTeXFonts.h" #include "Layout.h" #include "LayoutModuleList.h" #include "LyXRC.h" @@ -115,51 +116,6 @@ char const * const tex_graphics_gui[] = }; -char const * const tex_fonts_roman[] = -{ - "default", "cmr", "lmodern", "ae", "times", "palatino", - "charter", "newcent", "bookman", "utopia", "beraserif", - "ccfonts", "chancery", "" -}; - - -char const * tex_fonts_roman_gui[] = -{ - N_("Default"), N_("Computer Modern Roman"), N_("Latin Modern Roman"), - N_("AE (Almost European)"), N_("Times Roman"), N_("Palatino"), - N_("Bitstream Charter"), N_("New Century Schoolbook"), N_("Bookman"), - N_("Utopia"), N_("Bera Serif"), N_("Concrete Roman"), N_("Zapf Chancery"), - "" -}; - - -char const * const tex_fonts_sans[] = -{ - "default", "cmss", "lmss", "helvet", "avant", "berasans", "cmbr", "" -}; - - -char const * tex_fonts_sans_gui[] = -{ - N_("Default"), N_("Computer Modern Sans"), N_("Latin Modern Sans"), - N_("Helvetica"), N_("Avant Garde"), N_("Bera Sans"), N_("CM Bright"), "" -}; - - -char const * const tex_fonts_monospaced[] = -{ - "default", "cmtt", "lmtt", "courier", "beramono", "luximono", "cmtl", "" -}; - - -char const * tex_fonts_monospaced_gui[] = -{ - N_("Default"), N_("Computer Modern Typewriter"), - N_("Latin Modern Typewriter"), N_("Courier"), N_("Bera Mono"), - N_("LuxiMono"), N_("CM Typewriter Light"), "" -}; - - char const * backref_opts[] = { "false", "section", "slide", "page", "" @@ -209,6 +165,10 @@ char const * packages_gui[][4] = vector<string> engine_types_; vector<pair<string, QString> > pagestyles; +QMap<QString, QString> rmfonts_; +QMap<QString, QString> sffonts_; +QMap<QString, QString> ttfonts_; + } // anonymous namespace @@ -890,9 +850,9 @@ GuiDocument::GuiDocument(GuiView & lv) fontModule->fontsizeCO->addItem(qt_("11")); fontModule->fontsizeCO->addItem(qt_("12")); - fontModule->fontencCO->addItem(qt_("Default")); - fontModule->fontencCO->addItem(qt_("Custom")); - fontModule->fontencCO->addItem(qt_("None (no fontenc)")); + fontModule->fontencCO->addItem(qt_("Default"), QString("global")); + fontModule->fontencCO->addItem(qt_("Custom"), QString("custom")); + fontModule->fontencCO->addItem(qt_("None (no fontenc)"), QString("default")); for (int n = 0; GuiDocument::fontfamilies_gui[n][0]; ++n) fontModule->fontsDefaultCO->addItem( @@ -1808,28 +1768,39 @@ void GuiDocument::osFontsChanged(bool nontexfonts) fontModule->fontsDefaultLA->setEnabled(tex_fonts); fontModule->cjkFontLE->setEnabled(tex_fonts); fontModule->cjkFontLA->setEnabled(tex_fonts); - string font; + + updateFontOptions(); + + fontModule->fontencLA->setEnabled(tex_fonts); + fontModule->fontencCO->setEnabled(tex_fonts); + if (!tex_fonts) + fontModule->fontencLE->setEnabled(false); + else + fontencChanged(fontModule->fontencCO->currentIndex()); +} + + +void GuiDocument::updateFontOptions() +{ + bool const tex_fonts = !fontModule->osFontsCB->isChecked(); + QString font; if (tex_fonts) - font = tex_fonts_sans[fontModule->fontsSansCO->currentIndex()]; + font = fontModule->fontsSansCO->itemData( + fontModule->fontsSansCO->currentIndex()).toString(); bool scaleable = providesScale(font); fontModule->scaleSansSB->setEnabled(scaleable); fontModule->scaleSansLA->setEnabled(scaleable); if (tex_fonts) - font = tex_fonts_monospaced[fontModule->fontsTypewriterCO->currentIndex()]; + font = fontModule->fontsTypewriterCO->itemData( + fontModule->fontsTypewriterCO->currentIndex()).toString(); scaleable = providesScale(font); fontModule->scaleTypewriterSB->setEnabled(scaleable); fontModule->scaleTypewriterLA->setEnabled(scaleable); if (tex_fonts) - font = tex_fonts_roman[fontModule->fontsRomanCO->currentIndex()]; + font = fontModule->fontsRomanCO->itemData( + fontModule->fontsRomanCO->currentIndex()).toString(); fontModule->fontScCB->setEnabled(providesSC(font)); fontModule->fontOsfCB->setEnabled(providesOSF(font)); - - fontModule->fontencLA->setEnabled(tex_fonts); - fontModule->fontencCO->setEnabled(tex_fonts); - if (!tex_fonts) - fontModule->fontencLE->setEnabled(false); - else - fontencChanged(fontModule->fontencCO->currentIndex()); } @@ -1851,6 +1822,40 @@ void GuiDocument::updateFontsize(string const & items, string const & sel) } +bool GuiDocument::ot1() const +{ + QString const fontenc = + fontModule->fontencCO->itemData(fontModule->fontencCO->currentIndex()).toString(); + return (fontenc == "default" + || (fontenc == "global" && (lyxrc.fontenc == "default" || lyxrc.fontenc == "OT1")) + || (fontenc == "custom" && fontModule->fontencLE->text() == "OT1")); +} + + +void GuiDocument::updateTexFonts() +{ + LaTeXFonts::TexFontMap texfontmap = theLaTeXFonts().getLaTeXFonts(); + + LaTeXFonts::TexFontMap::const_iterator it = texfontmap.begin(); + LaTeXFonts::TexFontMap::const_iterator end = texfontmap.end(); + for (; it != end; ++it) { + LaTeXFont lf = it->second; + if (lf.name().empty()) + return; + docstring const family = lf.family(); + docstring guiname = translateIfPossible(lf.guiname()); + if (!lf.available(ot1())) + guiname += _(" (not installed)"); + if (family == "rm") + rmfonts_.insert(toqstr(guiname), toqstr(it->first)); + else if (family == "sf") + sffonts_.insert(toqstr(guiname), toqstr(it->first)); + else if (family == "tt") + ttfonts_.insert(toqstr(guiname), toqstr(it->first)); + } +} + + void GuiDocument::updateFontlist() { fontModule->fontsRomanCO->clear(); @@ -1873,30 +1878,39 @@ void GuiDocument::updateFontlist() return; } - for (int n = 0; tex_fonts_roman[n][0]; ++n) { - QString font = qt_(tex_fonts_roman_gui[n]); - if (!isFontAvailable(tex_fonts_roman[n])) - font += qt_(" (not installed)"); - fontModule->fontsRomanCO->addItem(font, qt_(tex_fonts_roman[n])); + if (rmfonts_.empty()) + updateTexFonts(); + + fontModule->fontsRomanCO->addItem(qt_("Default"), QString("default")); + QMap<QString, QString>::const_iterator rmi = rmfonts_.constBegin(); + while (rmi != rmfonts_.constEnd()) { + fontModule->fontsRomanCO->addItem(rmi.key(), rmi.value()); + ++rmi; } - for (int n = 0; tex_fonts_sans[n][0]; ++n) { - QString font = qt_(tex_fonts_sans_gui[n]); - if (!isFontAvailable(tex_fonts_sans[n])) - font += qt_(" (not installed)"); - fontModule->fontsSansCO->addItem(font, qt_(tex_fonts_sans[n])); + + fontModule->fontsSansCO->addItem(qt_("Default"), QString("default")); + QMap<QString, QString>::const_iterator sfi = sffonts_.constBegin(); + while (sfi != sffonts_.constEnd()) { + fontModule->fontsSansCO->addItem(sfi.key(), sfi.value()); + ++sfi; } - for (int n = 0; tex_fonts_monospaced[n][0]; ++n) { - QString font = qt_(tex_fonts_monospaced_gui[n]); - if (!isFontAvailable(tex_fonts_monospaced[n])) - font += qt_(" (not installed)"); - fontModule->fontsTypewriterCO->addItem(font, qt_(tex_fonts_monospaced[n])); + + fontModule->fontsTypewriterCO->addItem(qt_("Default"), QString("default")); + QMap<QString, QString>::const_iterator tti = ttfonts_.constBegin(); + while (tti != ttfonts_.constEnd()) { + fontModule->fontsTypewriterCO->addItem(tti.key(), tti.value()); + ++tti; } } void GuiDocument::fontencChanged(int item) { - fontModule->fontencLE->setEnabled(item == 1); + fontModule->fontencLE->setEnabled( + fontModule->fontencCO->itemData(item).toString() == "custom"); + // The availability of TeX fonts depends on the font encoding + updateTexFonts(); + updateFontOptions(); } @@ -1904,7 +1918,8 @@ void GuiDocument::romanChanged(int item) { if (fontModule->osFontsCB->isChecked()) return; - string const font = tex_fonts_roman[item]; + QString const font = + fontModule->fontsRomanCO->itemData(item).toString(); fontModule->fontScCB->setEnabled(providesSC(font)); fontModule->fontOsfCB->setEnabled(providesOSF(font)); } @@ -1914,7 +1929,8 @@ void GuiDocument::sansChanged(int item) { if (fontModule->osFontsCB->isChecked()) return; - string const font = tex_fonts_sans[item]; + QString const font = + fontModule->fontsSansCO->itemData(item).toString(); bool scaleable = providesScale(font); fontModule->scaleSansSB->setEnabled(scaleable); fontModule->scaleSansLA->setEnabled(scaleable); @@ -1925,7 +1941,8 @@ void GuiDocument::ttChanged(int item) { if (fontModule->osFontsCB->isChecked()) return; - string const font = tex_fonts_monospaced[item]; + QString const font = + fontModule->fontsTypewriterCO->itemData(item).toString(); bool scaleable = providesScale(font); fontModule->scaleTypewriterSB->setEnabled(scaleable); fontModule->scaleTypewriterLA->setEnabled(scaleable); @@ -2680,12 +2697,12 @@ void GuiDocument::applyView() fromqstr(fontModule->fontsTypewriterCO-> itemData(fontModule->fontsTypewriterCO->currentIndex()).toString()); - if (fontModule->fontencCO->currentIndex() == 0) - bp_.fontenc = "global"; - else if (fontModule->fontencCO->currentIndex() == 1) + QString const fontenc = + fontModule->fontencCO->itemData(fontModule->fontencCO->currentIndex()).toString(); + if (fontenc == "custom") bp_.fontenc = fromqstr(fontModule->fontencLE->text()); - else if (fontModule->fontencCO->currentIndex() == 2) - bp_.fontenc = "default"; + else + bp_.fontenc = fromqstr(fontenc); bp_.fonts_cjk = fromqstr(fontModule->cjkFontLE->text()); @@ -3136,11 +3153,9 @@ void GuiDocument::paramsToDialog() if (nn >= 0) fontModule->fontsDefaultCO->setCurrentIndex(nn); - if (bp_.fontenc == "global") { - fontModule->fontencCO->setCurrentIndex(0); - fontModule->fontencLE->setEnabled(false); - } else if (bp_.fontenc == "default") { - fontModule->fontencCO->setCurrentIndex(2); + if (bp_.fontenc == "global" || bp_.fontenc == "default") { + fontModule->fontencCO->setCurrentIndex( + fontModule->fontencCO->findData(toqstr(bp_.fontenc))); fontModule->fontencLE->setEnabled(false); } else { fontModule->fontencCO->setCurrentIndex(1); @@ -3599,61 +3614,29 @@ void GuiDocument::saveAsDefault() const } -bool GuiDocument::isFontAvailable(string const & font) const -{ - if (font == "default" || font == "cmr" - || font == "cmss" || font == "cmtt") - // these are standard - return true; - if (font == "lmodern" || font == "lmss" || font == "lmtt") - return LaTeXFeatures::isAvailable("lmodern"); - if (font == "times" || font == "palatino" - || font == "helvet" || font == "courier") - return LaTeXFeatures::isAvailable("psnfss"); - if (font == "cmbr" || font == "cmtl") - return LaTeXFeatures::isAvailable("cmbright"); - if (font == "utopia") - return LaTeXFeatures::isAvailable("utopia") - || LaTeXFeatures::isAvailable("fourier"); - if (font == "beraserif" || font == "berasans" - || font == "beramono") - return LaTeXFeatures::isAvailable("bera"); - return LaTeXFeatures::isAvailable(font); -} - - -bool GuiDocument::providesOSF(string const & font) const +bool GuiDocument::providesOSF(QString const & font) const { if (fontModule->osFontsCB->isChecked()) // FIXME: we should check if the fonts really // have OSF support. But how? return true; - if (font == "cmr") - return isFontAvailable("eco"); - if (font == "palatino") - return isFontAvailable("mathpazo"); - return false; + return theLaTeXFonts().getLaTeXFont(qstring_to_ucs4(font)).providesOSF(ot1()); } -bool GuiDocument::providesSC(string const & font) const +bool GuiDocument::providesSC(QString const & font) const { if (fontModule->osFontsCB->isChecked()) return false; - if (font == "palatino") - return isFontAvailable("mathpazo"); - if (font == "utopia") - return isFontAvailable("fourier"); - return false; + return theLaTeXFonts().getLaTeXFont(qstring_to_ucs4(font)).providesSC(ot1()); } -bool GuiDocument::providesScale(string const & font) const +bool GuiDocument::providesScale(QString const & font) const { if (fontModule->osFontsCB->isChecked()) return true; - return font == "helvet" || font == "luximono" - || font == "berasans" || font == "beramono"; + return theLaTeXFonts().getLaTeXFont(qstring_to_ucs4(font)).providesScale(ot1()); } diff --git a/src/frontends/qt4/GuiDocument.h b/src/frontends/qt4/GuiDocument.h index cb89b20..24353a7 100644 --- a/src/frontends/qt4/GuiDocument.h +++ b/src/frontends/qt4/GuiDocument.h @@ -228,14 +228,12 @@ private: void setLanguage() const; /// void saveAsDefault() const; - /// - bool isFontAvailable(std::string const & font) const; /// does this font provide Old Style figures? - bool providesOSF(std::string const & font) const; + bool providesOSF(QString const & font) const; /// does this font provide true Small Caps? - bool providesSC(std::string const & font) const; + bool providesSC(QString const & font) const; /// does this font provide size adjustment? - bool providesScale(std::string const & font) const; + bool providesScale(QString const & font) const; /// void executeBranchRenaming() const; /// @@ -246,6 +244,12 @@ private: /// void updateUnknownBranches(); /// + void updateTexFonts(); + /// + void updateFontOptions(); + /// + bool ot1() const; + /// BufferParams bp_; /// List of names of available modules std::list<modInfoStruct> moduleNames_; ----------------------------------------------------------------------- Summary of changes: development/qmake/lyx.pro | 2 + lib/Makefile.am | 2 +- lib/latexfonts | 242 ++++++++++++++++++++++++++ po/Rules-lyx | 3 + po/lyx_pot.py | 25 +++- src/BufferParams.cpp | 146 +++++------------ src/LaTeXFonts.cpp | 335 +++++++++++++++++++++++++++++++++++++ src/LaTeXFonts.h | 136 +++++++++++++++ src/LyX.cpp | 16 ++- src/LyX.h | 2 + src/Makefile.am | 2 + src/frontends/qt4/GuiDocument.cpp | 235 ++++++++++++-------------- src/frontends/qt4/GuiDocument.h | 14 +- 13 files changed, 921 insertions(+), 239 deletions(-) create mode 100644 lib/latexfonts create mode 100644 src/LaTeXFonts.cpp create mode 100644 src/LaTeXFonts.h hooks/post-receive -- The LyX Source Repository