]> git.lyx.org Git - lyx.git/blobdiff - src/BufferParams.cpp
Merge branch 'master' of git.lyx.org:lyx
[lyx.git] / src / BufferParams.cpp
index 53ebf0129c1859832fbd9b7c725b6dacdef324e0..373eee5dd0d0d98359ab47944e18cb75d341a46d 100644 (file)
@@ -20,6 +20,7 @@
 #include "Author.h"
 #include "LayoutFile.h"
 #include "BranchList.h"
+#include "Buffer.h"
 #include "buffer_funcs.h"
 #include "Bullet.h"
 #include "Color.h"
@@ -53,6 +54,7 @@
 #include "support/gettext.h"
 #include "support/Messages.h"
 #include "support/mutex.h"
+#include "support/Package.h"
 #include "support/Translator.h"
 #include "support/lstrings.h"
 
@@ -353,6 +355,8 @@ BufferParams::BufferParams()
        : pimpl_(new Impl)
 {
        setBaseClass(defaultBaseclass());
+       cite_engine_.push_back("basic");
+       cite_engine_type_ = ENGINE_TYPE_DEFAULT;
        makeDocumentClass();
        paragraph_separation = ParagraphIndentSeparation;
        quotes_language = InsetQuotes::EnglishQuotes;
@@ -362,11 +366,10 @@ BufferParams::BufferParams()
        papersize = PAPER_DEFAULT;
        orientation = ORIENTATION_PORTRAIT;
        use_geometry = false;
-       cite_engine_.push_back("basic");
-       cite_engine_type_ = ENGINE_TYPE_DEFAULT;
        biblio_style = "plain";
        use_bibtopic = false;
        use_indices = false;
+       save_transient_properties = true;
        track_changes = false;
        output_changes = false;
        use_default_options = true;
@@ -375,16 +378,23 @@ BufferParams::BufferParams()
        tocdepth = 3;
        language = default_language;
        fontenc = "global";
-       fonts_roman = "default";
-       fonts_sans = "default";
-       fonts_typewriter = "default";
-       fonts_math = "auto";
+       fonts_roman[0] = "default";
+       fonts_roman[1] = "default";
+       fonts_sans[0] = "default";
+       fonts_sans[1] = "default";
+       fonts_typewriter[0] = "default";
+       fonts_typewriter[1] = "default";
+       fonts_math[0] = "auto";
+       fonts_math[1] = "auto";
        fonts_default_family = "default";
        useNonTeXFonts = false;
+       use_microtype = false;
        fonts_expert_sc = false;
        fonts_old_figures = false;
-       fonts_sans_scale = 100;
-       fonts_typewriter_scale = 100;
+       fonts_sans_scale[0] = 100;
+       fonts_sans_scale[1] = 100;
+       fonts_typewriter_scale[0] = 100;
+       fonts_typewriter_scale[1] = 100;
        inputenc = "auto";
        lang_package = "default";
        graphics_driver = "default";
@@ -421,6 +431,9 @@ BufferParams::BufferParams()
 
        output_sync = false;
        use_refstyle = true;
+
+       // map current author
+       author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
 }
 
 
@@ -496,6 +509,12 @@ AuthorList const & BufferParams::authors() const
 }
 
 
+void BufferParams::addAuthor(Author a)
+{
+       author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
+}
+
+
 BranchList & BufferParams::branchlist()
 {
        return pimpl_->branchlist;
@@ -601,6 +620,8 @@ void BufferParams::setDefSkip(VSpace const & vs)
 string BufferParams::readToken(Lexer & lex, string const & token,
        FileName const & filepath)
 {
+       string result;
+
        if (token == "\\textclass") {
                lex.next();
                string const classname = lex.getString();
@@ -609,13 +630,31 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                // be available.
                string tcp;
                LayoutFileList & bcl = LayoutFileList::get();
-               if (!filepath.empty())
-                       tcp = bcl.addLocalLayout(classname, filepath.absFileName());
+               if (!filepath.empty()) {
+                       // If classname is an absolute path, the document is
+                       // using a local layout file which could not be accessed
+                       // by a relative path. In this case the path is correct
+                       // even if the document was moved to a different
+                       // location. However, we will have a problem if the
+                       // document was generated on a different platform.
+                       bool isabsolute = FileName::isAbsolute(classname);
+                       string const classpath = onlyPath(classname);
+                       string const path = isabsolute ? classpath
+                               : FileName(addPath(filepath.absFileName(),
+                                               classpath)).realPath();
+                       string const oldpath = isabsolute ? string()
+                               : FileName(addPath(origin, classpath)).realPath();
+                       tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
+               }
                // that returns non-empty if a "local" layout file is found.
-               if (!tcp.empty())
-                       setBaseClass(tcp);
-               else
-                       setBaseClass(classname);
+               if (!tcp.empty()) {
+                       result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
+                                               from_utf8(filepath.absFileName())));
+                       if (result.empty())
+                               result = ".";
+                       setBaseClass(onlyFileName(tcp));
+               } else
+                       setBaseClass(onlyFileName(classname));
                // We assume that a tex class exists for local or unknown
                // layouts so this warning, will only be given for system layouts.
                if (!baseClass()->isTeXClassAvailable()) {
@@ -636,6 +675,16 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                        frontend::Alert::warning(_("Document class not available"),
                                       msg, true);
                }
+       } else if (token == "\\save_transient_properties") {
+               lex >> save_transient_properties;
+       } else if (token == "\\origin") {
+               lex.eatLine();
+               origin = lex.getString();
+               string const sysdirprefix = "/systemlyxdir/";
+               if (prefixIs(origin, sysdirprefix)) {
+                       origin.replace(0, sysdirprefix.length() - 1,
+                               package().system_support().absFileName());
+               }
        } else if (token == "\\begin_preamble") {
                readPreamble(lex);
        } else if (token == "\\begin_local_layout") {
@@ -658,6 +707,19 @@ string BufferParams::readToken(Lexer & lex, string const & token,
        } else if (token == "\\master") {
                lex.eatLine();
                master = lex.getString();
+               if (!filepath.empty() && FileName::isAbsolute(origin)) {
+                       bool const isabs = FileName::isAbsolute(master);
+                       FileName const abspath(isabs ? master : origin + master);
+                       bool const moved = filepath != FileName(origin);
+                       if (moved && abspath.exists()) {
+                               docstring const path = isabs
+                                       ? from_utf8(master)
+                                       : from_utf8(abspath.realPath());
+                               docstring const refpath =
+                                       from_utf8(filepath.absFileName());
+                               master = to_utf8(makeRelPath(path, refpath));
+                       }
+               }
        } else if (token == "\\suppress_date") {
                lex >> suppress_date;
        } else if (token == "\\justification") {
@@ -683,17 +745,17 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                lex.eatLine();
                fontenc = lex.getString();
        } else if (token == "\\font_roman") {
-               lex.eatLine();
-               fonts_roman = lex.getString();
+               lex >> fonts_roman[0];
+               lex >> fonts_roman[1];
        } else if (token == "\\font_sans") {
-               lex.eatLine();
-               fonts_sans = lex.getString();
+               lex >> fonts_sans[0];
+               lex >> fonts_sans[1];
        } else if (token == "\\font_typewriter") {
-               lex.eatLine();
-               fonts_typewriter = lex.getString();
+               lex >> fonts_typewriter[0];
+               lex >> fonts_typewriter[1];
        } else if (token == "\\font_math") {
-               lex.eatLine();
-               fonts_math = lex.getString();
+               lex >> fonts_math[0];
+               lex >> fonts_math[1];
        } else if (token == "\\font_default_family") {
                lex >> fonts_default_family;
        } else if (token == "\\use_non_tex_fonts") {
@@ -703,11 +765,15 @@ string BufferParams::readToken(Lexer & lex, string const & token,
        } else if (token == "\\font_osf") {
                lex >> fonts_old_figures;
        } else if (token == "\\font_sf_scale") {
-               lex >> fonts_sans_scale;
+               lex >> fonts_sans_scale[0];
+               lex >> fonts_sans_scale[1];
        } else if (token == "\\font_tt_scale") {
-               lex >> fonts_typewriter_scale;
+               lex >> fonts_typewriter_scale[0];
+               lex >> fonts_typewriter_scale[1];
        } else if (token == "\\font_cjk") {
                lex >> fonts_cjk;
+       } else if (token == "\\use_microtype") {
+               lex >> use_microtype;
        } else if (token == "\\paragraph_separation") {
                string parsep;
                lex >> parsep;
@@ -825,7 +891,7 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                istringstream ss(lex.getString());
                Author a;
                ss >> a;
-               author_map[a.bufferId()] = pimpl_->authorlist.record(a);
+               addAuthor(a);
        } else if (token == "\\paperorientation") {
                string orient;
                lex >> orient;
@@ -936,17 +1002,46 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                return token;
        }
 
-       return string();
+       return result;
+}
+
+
+namespace {
+       // Quote argument if it contains spaces
+       string quoteIfNeeded(string const & str) {
+               if (contains(str, ' '))
+                       return "\"" + str + "\"";
+               return str;
+       }
 }
 
 
-void BufferParams::writeFile(ostream & os) const
+void BufferParams::writeFile(ostream & os, Buffer const * buf) const
 {
        // The top of the file is written by the buffer.
        // Prints out the buffer info into the .lyx file given by file
 
+       os << "\\save_transient_properties "
+          << convert<string>(save_transient_properties) << '\n';
+
+       // the document directory (must end with a path separator)
+       // realPath() is used to resolve symlinks, while addPath(..., "")
+       // ensures a trailing path separator.
+       string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
+       string const sysdir = addPath(package().system_support().realPath(), "");
+       string const relpath =
+               to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
+       if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
+               filepath = addPath("/systemlyxdir", relpath);
+       else if (!save_transient_properties || !lyxrc.save_origin)
+               filepath = "unavailable";
+       os << "\\origin " << quoteIfNeeded(filepath) << '\n';
+
        // the textclass
-       os << "\\textclass " << baseClass()->name() << '\n';
+       os << "\\textclass "
+          << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
+                                               baseClass()->name()), "layout"))
+          << '\n';
 
        // then the preamble
        if (!preamble.empty()) {
@@ -1027,20 +1122,27 @@ void BufferParams::writeFile(ostream & os) const
        os << "\\language_package " << lang_package
           << "\n\\inputencoding " << inputenc
           << "\n\\fontencoding " << fontenc
-          << "\n\\font_roman " << fonts_roman
-          << "\n\\font_sans " << fonts_sans
-          << "\n\\font_typewriter " << fonts_typewriter
-          << "\n\\font_math " << fonts_math
+          << "\n\\font_roman \"" << fonts_roman[0]
+          << "\" \"" << fonts_roman[1] << '"'
+          << "\n\\font_sans \"" << fonts_sans[0]
+          << "\" \"" << fonts_sans[1] << '"'
+          << "\n\\font_typewriter \"" << fonts_typewriter[0]
+          << "\" \"" << fonts_typewriter[1] << '"'
+          << "\n\\font_math \"" << fonts_math[0]
+          << "\" \"" << fonts_math[1] << '"'
           << "\n\\font_default_family " << fonts_default_family
           << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
           << "\n\\font_sc " << convert<string>(fonts_expert_sc)
           << "\n\\font_osf " << convert<string>(fonts_old_figures)
-          << "\n\\font_sf_scale " << fonts_sans_scale
-          << "\n\\font_tt_scale " << fonts_typewriter_scale
+          << "\n\\font_sf_scale " << fonts_sans_scale[0]
+          << ' ' << fonts_sans_scale[1]
+          << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
+          << ' ' << fonts_typewriter_scale[1]
           << '\n';
        if (!fonts_cjk.empty()) {
                os << "\\font_cjk " << fonts_cjk << '\n';
        }
+       os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
        os << "\\graphics " << graphics_driver << '\n';
        os << "\\default_output_format " << default_output_format << '\n';
        os << "\\output_sync " << output_sync << '\n';
@@ -1181,9 +1283,15 @@ void BufferParams::writeFile(ostream & os) const
                }
        }
 
-       os << "\\tracking_changes " << convert<string>(track_changes) << '\n'
-          << "\\output_changes " << convert<string>(output_changes) << '\n'
-          << "\\html_math_output " << html_math_output << '\n'
+       os << "\\tracking_changes "
+          << (save_transient_properties ? convert<string>(track_changes) : "false")
+          << '\n';
+
+       os << "\\output_changes "
+          << (save_transient_properties ? convert<string>(output_changes) : "false")
+          << '\n';
+
+       os << "\\html_math_output " << html_math_output << '\n'
           << "\\html_css_as_file " << html_css_as_file << '\n'
           << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
 
@@ -1302,13 +1410,14 @@ void BufferParams::validate(LaTeXFeatures & features) const
        }
 
        // some languages are only available via polyglossia
-       if (features.runparams().flavor == OutputParams::XETEX
-           && (features.hasPolyglossiaExclusiveLanguages()
-               || useNonTeXFonts))
-               features.require("polyglossia");
+       if (features.hasPolyglossiaExclusiveLanguages())
+          features.require("polyglossia");
 
-       if (useNonTeXFonts && fonts_math != "auto")
+       if (useNonTeXFonts && fontsMath() != "auto")
                features.require("unicode-math");
+       
+       if (use_microtype)
+               features.require("microtype");
 
        if (!language->requires().empty())
                features.require(language->requires());
@@ -1326,6 +1435,11 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        // are doing!
        if (features.mustProvide("fix-cm"))
                os << "\\RequirePackage{fix-cm}\n";
+       // Likewise for fixltx2e. If other packages conflict with this policy,
+       // treat it as a package bug (and report it!)
+       // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
+       if (features.mustProvide("fixltx2e"))
+               os << "\\RequirePackage{fixltx2e}\n";
 
        os << "\\documentclass";
 
@@ -1469,7 +1583,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        string const ams = features.loadAMSPackages();
        bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
        bool const use_newtxmath =
-               theLaTeXFonts().getLaTeXFont(from_ascii(fonts_math)).getUsedPackage(
+               theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
                        ot1, false, false) == "newtxmath";
        if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
                os << from_ascii(ams);
@@ -1494,18 +1608,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        // XeTeX and LuaTeX (with OS fonts) do not need fontenc
        if (!useNonTeXFonts && !features.isProvided("fontenc")
            && font_encoding() != "default") {
-               vector<string> fontencs;
-               // primary language font encoding and default encoding
-               if (ascii_lowercase(language->fontenc()) != "none") {
-                       vector<string> fencs = getVectorFromString(font_encoding());
-                       fontencs.insert(fontencs.end(), fencs.begin(), fencs.end());
-                       fencs = getVectorFromString(language->fontenc());
-                       vector<string>::const_iterator fit = fencs.begin();
-                       for (; fit != fencs.end(); ++fit) {
-                               if (find(fontencs.begin(), fontencs.end(), *fit) == fontencs.end())
-                                       fontencs.push_back(*fit);
-                       }
-               }
+               // get main font encodings
+               vector<string> fontencs = font_encodings();
                // get font encodings of secondary languages
                features.getFontEncodings(fontencs);
                if (!fontencs.empty()) {
@@ -1883,11 +1987,55 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
 
        /* the user-defined preamble */
-       if (!containsOnly(preamble, " \n\t"))
+       if (!containsOnly(preamble, " \n\t")) {
                // FIXME UNICODE
                atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
-                       "User specified LaTeX commands.\n"
-                       + from_utf8(preamble) + '\n';
+                       "User specified LaTeX commands.\n";
+
+               // Check if the user preamble contains uncodable glyphs
+               docstring const u_preamble = from_utf8(preamble);
+               odocstringstream user_preamble;
+               docstring uncodable_glyphs;
+               Encoding const * const enc = features.runparams().encoding;
+               if (enc) {
+                       for (size_t n = 0; n < u_preamble.size(); ++n) {
+                               char_type c = u_preamble[n];
+                               if (!enc->encodable(c)) {
+                                       docstring const glyph(1, c);
+                                       LYXERR0("Uncodable character '"
+                                               << glyph
+                                               << "' in user preamble!");
+                                       uncodable_glyphs += glyph;
+                                       if (features.runparams().dryrun) {
+                                               user_preamble << "<" << _("LyX Warning: ")
+                                                  << _("uncodable character") << " '";
+                                               user_preamble.put(c);
+                                               user_preamble << "'>";
+                                       }
+                               } else
+                                       user_preamble.put(c);
+                       }
+               } else
+                       user_preamble << u_preamble;
+
+               // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
+               if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
+                       frontend::Alert::warning(
+                               _("Uncodable character in user preamble"),
+                               support::bformat(
+                                 _("The user preamble of your document contains glyphs "
+                                   "that are unknown in the current document encoding "
+                                   "(namely %1$s).\nThese glyphs are omitted "
+                                   " from the output, which may result in "
+                                   "incomplete output."
+                                   "\n\nPlease select an appropriate "
+                                   "document encoding\n"
+                                   "(such as utf8) or change the "
+                                   "preamble code accordingly."),
+                                 uncodable_glyphs));
+               }
+               atlyxpreamble += user_preamble.str() + '\n';
+       }
 
        // footmisc must be loaded after setspace
        // Load it here to avoid clashes with footmisc loaded in the user
@@ -2057,7 +2205,7 @@ bool BufferParams::hasClassDefaults() const
 
 DocumentClass const & BufferParams::documentClass() const
 {
-       return *doc_class_.get();
+       return *doc_class_;
 }
 
 
@@ -2202,7 +2350,7 @@ string BufferParams::bufferFormat() const
        string format = documentClass().outputFormat();
        if (format == "latex") {
                if (useNonTeXFonts)
-                       return "xetex";
+                       return "xetex"; // actually "xetex or luatex"
                if (encoding().package() == Encoding::japanese)
                        return "platex";
        }
@@ -2308,7 +2456,7 @@ OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
        else if (dformat == "lyx")
                result = OutputParams::LYX;
        else if (dformat == "pdflatex")
-               result = OutputParams::PDFLATEX;
+               result = OutputParams::PDFLATEX;
        else if (dformat == "xetex")
                result = OutputParams::XETEX;
        else if (dformat == "luatex")
@@ -2757,7 +2905,31 @@ string const BufferParams::dvips_options() const
 
 string const BufferParams::font_encoding() const
 {
-       return (fontenc == "global") ? lyxrc.fontenc : fontenc;
+       return font_encodings().empty() ? "default" : font_encodings().back();
+}
+
+
+vector<string> const BufferParams::font_encodings() const
+{
+       string doc_fontenc = (fontenc == "global") ? lyxrc.fontenc : fontenc;
+
+       vector<string> fontencs;
+
+       // "default" means "no explicit font encoding"
+       if (doc_fontenc != "default") {
+               fontencs = getVectorFromString(doc_fontenc);
+               if (!language->fontenc().empty()
+                   && ascii_lowercase(language->fontenc()) != "none") {
+                       vector<string> fencs = getVectorFromString(language->fontenc());
+                       vector<string>::const_iterator fit = fencs.begin();
+                       for (; fit != fencs.end(); ++fit) {
+                               if (find(fontencs.begin(), fontencs.end(), *fit) == fontencs.end())
+                                       fontencs.push_back(*fit);
+                       }
+               }
+       }
+
+       return fontencs;
 }
 
 
@@ -2798,30 +2970,26 @@ docstring BufferParams::getGraphicsDriver(string const & package) const
 void BufferParams::writeEncodingPreamble(otexstream & os,
                                         LaTeXFeatures & features) const
 {
-       // XeTeX does not need this
-       if (features.runparams().flavor == OutputParams::XETEX)
-               return;
-       // LuaTeX neither, but with tex fonts, we need to load
-       // the luainputenc package.
-       if (features.runparams().flavor == OutputParams::LUATEX
-               || features.runparams().flavor == OutputParams::DVILUATEX) {
-               if (!useNonTeXFonts && inputenc != "default"
-                   && ((inputenc == "auto" && language->encoding()->package() == Encoding::inputenc)
-                       || (inputenc != "auto" && encoding().package() == Encoding::inputenc))) {
-                       os << "\\usepackage[utf8]{luainputenc}\n";
-               }
+       // XeTeX/LuaTeX: (see also #9740)
+       // With Unicode fonts we use utf8-plain without encoding package.
+       // With TeX fonts, we cannot use utf8-plain, but "inputenc" fails.
+       // XeTeX must use ASCII encoding (see Buffer.cpp),
+       //  for LuaTeX, we load "luainputenc" (see below).
+       if (useNonTeXFonts || features.runparams().flavor == OutputParams::XETEX)
                return;
-       }
+
        if (inputenc == "auto") {
                string const doc_encoding =
                        language->encoding()->latexName();
                Encoding::Package const package =
                        language->encoding()->package();
 
-               // Create a list with all the input encodings used
-               // in the document
-               set<string> encodings =
-                       features.getEncodingSet(doc_encoding);
+               // Create list of inputenc options:
+               set<string> encodings;
+               // luainputenc fails with more than one encoding
+               if (!features.runparams().isFullUnicode()) // if we reach this point, this means LuaTeX with TeX fonts
+                       // list all input encodings used in the document
+                       encodings = features.getEncodingSet(doc_encoding);
 
                // If the "japanese" package (i.e. pLaTeX) is used,
                // inputenc must be omitted.
@@ -2843,7 +3011,11 @@ void BufferParams::writeEncodingPreamble(otexstream & os,
                                        os << ',';
                                os << from_ascii(doc_encoding);
                        }
-                       os << "]{inputenc}\n";
+                       if (features.runparams().flavor == OutputParams::LUATEX
+                           || features.runparams().flavor == OutputParams::DVILUATEX)
+                               os << "]{luainputenc}\n";
+                       else
+                               os << "]{inputenc}\n";
                }
                if (package == Encoding::CJK || features.mustProvide("CJK")) {
                        if (language->encoding()->name() == "utf8-cjk"
@@ -2863,8 +3035,12 @@ void BufferParams::writeEncodingPreamble(otexstream & os,
                        if (features.isRequired("japanese")
                            || features.isProvided("inputenc"))
                                break;
-                       os << "\\usepackage[" << from_ascii(encoding().latexName())
-                          << "]{inputenc}\n";
+                       os << "\\usepackage[" << from_ascii(encoding().latexName());
+                       if (features.runparams().flavor == OutputParams::LUATEX
+                           || features.runparams().flavor == OutputParams::DVILUATEX)
+                               os << "]{luainputenc}\n";
+                       else
+                               os << "]{inputenc}\n";
                        break;
                case Encoding::CJK:
                        if (encoding().name() == "utf8-cjk"
@@ -2900,9 +3076,9 @@ string const BufferParams::parseFontName(string const & name) const
 
 string const BufferParams::loadFonts(LaTeXFeatures & features) const
 {
-       if (fonts_roman == "default" && fonts_sans == "default"
-           && fonts_typewriter == "default"
-           && (fonts_math == "default" || fonts_math == "auto"))
+       if (fontsRoman() == "default" && fontsSans() == "default"
+           && fontsTypewriter() == "default"
+           && (fontsMath() == "default" || fontsMath() == "auto"))
                //nothing to do
                return string();
 
@@ -2931,28 +3107,28 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const
                string const texmapping =
                        (features.runparams().flavor == OutputParams::XETEX) ?
                        "Mapping=tex-text" : "Ligatures=TeX";
-               if (fonts_roman != "default") {
+               if (fontsRoman() != "default") {
                        os << "\\setmainfont[" << texmapping;
                        if (fonts_old_figures)
                                os << ",Numbers=OldStyle";
-                       os << "]{" << parseFontName(fonts_roman) << "}\n";
+                       os << "]{" << parseFontName(fontsRoman()) << "}\n";
                }
-               if (fonts_sans != "default") {
-                       string const sans = parseFontName(fonts_sans);
-                       if (fonts_sans_scale != 100)
+               if (fontsSans() != "default") {
+                       string const sans = parseFontName(fontsSans());
+                       if (fontsSansScale() != 100)
                                os << "\\setsansfont[Scale="
-                                  << float(fonts_sans_scale) / 100
+                                  << float(fontsSansScale()) / 100
                                   << "," << texmapping << "]{"
                                   << sans << "}\n";
                        else
                                os << "\\setsansfont[" << texmapping << "]{"
                                   << sans << "}\n";
                }
-               if (fonts_typewriter != "default") {
-                       string const mono = parseFontName(fonts_typewriter);
-                       if (fonts_typewriter_scale != 100)
+               if (fontsTypewriter() != "default") {
+                       string const mono = parseFontName(fontsTypewriter());
+                       if (fontsTypewriterScale() != 100)
                                os << "\\setmonofont[Scale="
-                                  << float(fonts_typewriter_scale) / 100
+                                  << float(fontsTypewriterScale()) / 100
                                   << "]{"
                                   << mono << "}\n";
                        else
@@ -2965,26 +3141,26 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const
        // Tex Fonts
        bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
        bool const dryrun = features.runparams().dryrun;
-       bool const complete = (fonts_sans == "default" && fonts_typewriter == "default");
-       bool const nomath = (fonts_math == "default");
+       bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
+       bool const nomath = (fontsMath() == "default");
 
        // ROMAN FONTS
-       os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_roman)).getLaTeXCode(
+       os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
                dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
                nomath);
 
        // SANS SERIF
-       os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_sans)).getLaTeXCode(
+       os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
                dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
-               nomath, fonts_sans_scale);
+               nomath, fontsSansScale());
 
        // MONOSPACED/TYPEWRITER
-       os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_typewriter)).getLaTeXCode(
+       os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
                dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
-               nomath, fonts_typewriter_scale);
+               nomath, fontsTypewriterScale());
 
        // MATH
-       os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_math)).getLaTeXCode(
+       os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
                dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
                nomath);
 
@@ -2994,11 +3170,13 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const
 
 Encoding const & BufferParams::encoding() const
 {
-       // FIXME: actually, we should check for the flavor
-       // or runparams.isFullyUnicode() here:
-       // This check will not work with XeTeX/LuaTeX and tex fonts.
-       // Thus we have to reset the encoding in Buffer::makeLaTeXFile
-       // (for export) and Buffer::writeLaTeXSource (for preview).
+       // Main encoding for LaTeX output.
+       // 
+       // Exception: XeTeX with 8-bit TeX fonts requires ASCII (see #9740).
+       // As the "flavor" is only known once export started, this
+       // cannot be handled here. Instead, runparams.encoding is set
+       // to ASCII in Buffer::makeLaTeXFile (for export)
+       // and Buffer::writeLaTeXSource (for preview).
        if (useNonTeXFonts)
                return *(encodings.fromLyXName("utf8-plain"));
        if (inputenc == "auto" || inputenc == "default")