]> git.lyx.org Git - lyx.git/blobdiff - src/BufferParams.cpp
avoid float-conversion warning and simplify size computation
[lyx.git] / src / BufferParams.cpp
index 49c55aaa511d6f52249d29b709a176d042a7c31a..8b193e00ecaa08525350c6501ab0d6a434104408 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"
@@ -52,6 +53,7 @@
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/Messages.h"
+#include "support/mutex.h"
 #include "support/Translator.h"
 #include "support/lstrings.h"
 
@@ -416,6 +418,7 @@ BufferParams::BufferParams()
        html_math_output = MathML;
        html_math_img_scale = 1.0;
        html_css_as_file = false;
+       display_pixel_ratio = 1.0;
 
        output_sync = false;
        use_refstyle = true;
@@ -446,10 +449,16 @@ void BufferParams::use_package(std::string const & p, BufferParams::Package u)
 
 map<string, string> const & BufferParams::auto_packages()
 {
-       // FIXME THREAD
-       // It is extremely unlikely that there could be a problem here, but...
        static map<string, string> packages;
        if (packages.empty()) {
+               // We could have a race condition here that two threads
+               // discover an empty map at the same time and want to fill
+               // it, but that is no problem, since the same contents is
+               // filled in twice then. Having the locker inside the
+               // packages.empty() condition has the advantage that we
+               // don't need the mutex overhead for simple reading.
+               static Mutex mutex;
+               Mutex::Locker locker(&mutex);
                // adding a package here implies a file format change!
                packages["amsmath"] =
                        N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
@@ -593,6 +602,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();
@@ -601,13 +612,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()) {
@@ -626,8 +655,11 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                                                 "See section 3.1.2.2 (Class Availability) of the\n"
                                                 "User's Guide for more information."), desc, prereqs);
                        frontend::Alert::warning(_("Document class not available"),
-                                      msg);
+                                      msg, true);
                }
+       } else if (token == "\\origin") {
+               lex.eatLine();
+               origin = lex.getString();
        } else if (token == "\\begin_preamble") {
                readPreamble(lex);
        } else if (token == "\\begin_local_layout") {
@@ -650,6 +682,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") {
@@ -928,17 +973,22 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                return token;
        }
 
-       return string();
+       return result;
 }
 
 
-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
 
+       // the document directory
+       os << "\\origin " << buf->filePath() << '\n';
+
        // the textclass
-       os << "\\textclass " << baseClass()->name() << '\n';
+       os << "\\textclass " << buf->includedFilePath(addName(buf->layoutPos(),
+                                               baseClass()->name()), "layout")
+          << '\n';
 
        // then the preamble
        if (!preamble.empty()) {
@@ -1318,6 +1368,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";
 
@@ -1483,32 +1538,16 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                   << from_ascii(fonts_default_family) << "}\n";
 
        // set font encoding
-       // for arabic_arabi and farsi we also need to load the LAE and
-       // LFE encoding
-       // XeTeX and LuaTeX (with OS fonts) work without fontenc
-       if (font_encoding() != "default" && language->lang() != "japanese"
-           && !useNonTeXFonts && !features.isProvided("fontenc")) {
-               docstring extra_encoding;
-               if (features.mustProvide("textgreek"))
-                       extra_encoding += from_ascii("LGR");
-               if (features.mustProvide("textcyr")) {
-                       if (!extra_encoding.empty())
-                               extra_encoding.push_back(',');
-                       extra_encoding += from_ascii("T2A");
-               }
-               if (!extra_encoding.empty() && !font_encoding().empty())
-                       extra_encoding.push_back(',');
-               size_t fars = language_options.str().find("farsi");
-               size_t arab = language_options.str().find("arabic");
-               if (language->lang() == "arabic_arabi"
-                       || language->lang() == "farsi" || fars != string::npos
-                       || arab != string::npos) {
-                       os << "\\usepackage[" << extra_encoding
-                          << from_ascii(font_encoding())
-                          << ",LFE,LAE]{fontenc}\n";
-               } else {
-                       os << "\\usepackage[" << extra_encoding
-                          << from_ascii(font_encoding())
+       // XeTeX and LuaTeX (with OS fonts) do not need fontenc
+       if (!useNonTeXFonts && !features.isProvided("fontenc")
+           && font_encoding() != "default") {
+               // get main font encodings
+               vector<string> fontencs = font_encodings();
+               // get font encodings of secondary languages
+               features.getFontEncodings(fontencs);
+               if (!fontencs.empty()) {
+                       os << "\\usepackage["
+                          << from_ascii(getStringFromVector(fontencs))
                           << "]{fontenc}\n";
                }
        }
@@ -1768,6 +1807,9 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                        lyxpreamble += "\\synctex=-1\n";
        }
 
+       // The package options (via \PassOptionsToPackage)
+       lyxpreamble += from_ascii(features.getPackageOptions());
+
        // due to interferences with babel and hyperref, the color package has to
        // be loaded (when it is not already loaded) before babel when hyperref
        // is used with the colorlinks option, see
@@ -1884,6 +1926,13 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                        "User specified LaTeX commands.\n"
                        + from_utf8(preamble) + '\n';
 
+       // footmisc must be loaded after setspace
+       // Load it here to avoid clashes with footmisc loaded in the user
+       // preamble. For that reason we also pass the options via
+       // \PassOptionsToPackage in getPreamble() and not here.
+       if (features.mustProvide("footmisc"))
+               atlyxpreamble += "\\usepackage{footmisc}\n";
+
        // subfig loads internally the LaTeX package "caption". As
        // caption is a very popular package, users will load it in
        // the preamble. Therefore we must load subfig behind the
@@ -1940,7 +1989,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                        + atlyxpreamble + "\\makeatother\n\n";
 
        // We try to load babel late, in case it interferes with other packages.
-       // Jurabib, hyperref, varioref and listings (bug 8995) have to be
+       // Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be
        // called after babel, though.
        if (use_babel && !features.isRequired("jurabib")
            && !features.isRequired("hyperref")
@@ -1953,6 +2002,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                                                   features.needBabelLangOptions())) + '\n';
                lyxpreamble += from_utf8(features.getBabelPostsettings());
        }
+       if (features.isRequired("bicaption"))
+               lyxpreamble += "\\usepackage{bicaption}\n";
        if (!listings_params.empty() || features.isRequired("listings"))
                lyxpreamble += "\\usepackage{listings}\n";
        if (!listings_params.empty()) {
@@ -2273,7 +2324,7 @@ vector<string> BufferParams::backends() const
 }
 
 
-OutputParams::FLAVOR BufferParams::getOutputFlavor(string const format) const
+OutputParams::FLAVOR BufferParams::getOutputFlavor(string const format) const
 {
        string const dformat = (format.empty() || format == "default") ?
                getDefaultOutputFormat() : format;
@@ -2294,7 +2345,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")
@@ -2355,7 +2406,7 @@ Font const BufferParams::getFont() const
 }
 
 
-InsetQuotes::QuoteLanguage BufferParams::getQuoteStyle(string const qs) const
+InsetQuotes::QuoteLanguage BufferParams::getQuoteStyle(string const qs) const
 {
        return quoteslangtranslator().find(qs);
 }
@@ -2743,7 +2794,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;
 }
 
 
@@ -2813,7 +2888,8 @@ void BufferParams::writeEncodingPreamble(otexstream & os,
                // inputenc must be omitted.
                // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
                if ((!encodings.empty() || package == Encoding::inputenc)
-                   && !features.isRequired("japanese")) {
+                   && !features.isRequired("japanese")
+                   && !features.isProvided("inputenc")) {
                        os << "\\usepackage[";
                        set<string>::const_iterator it = encodings.begin();
                        set<string>::const_iterator const end = encodings.end();
@@ -2844,7 +2920,9 @@ void BufferParams::writeEncodingPreamble(otexstream & os,
                        break;
                case Encoding::inputenc:
                        // do not load inputenc if japanese is used
-                       if (features.isRequired("japanese"))
+                       // or if the class provides inputenc
+                       if (features.isRequired("japanese")
+                           || features.isProvided("inputenc"))
                                break;
                        os << "\\usepackage[" << from_ascii(encoding().latexName())
                           << "]{inputenc}\n";
@@ -2980,7 +3058,8 @@ 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.
+       // Thus we have to reset the encoding in Buffer::makeLaTeXFile
+       // (for export) and Buffer::writeLaTeXSource (for preview).
        if (useNonTeXFonts)
                return *(encodings.fromLyXName("utf8-plain"));
        if (inputenc == "auto" || inputenc == "default")