X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fgraphics%2FPreviewLoader.cpp;h=198d6d96abb3be104608bad7c55ca1640e2fbb76;hb=3695b631c6c16d1d87c646d25143c416e7358bad;hp=f38c157e7ecc7eca387557a459a8af90a2ed5593;hpb=cd046f0e0cdea5aae064284790e4e17f0c60bd03;p=lyx.git diff --git a/src/graphics/PreviewLoader.cpp b/src/graphics/PreviewLoader.cpp index f38c157e7e..198d6d96ab 100644 --- a/src/graphics/PreviewLoader.cpp +++ b/src/graphics/PreviewLoader.cpp @@ -19,30 +19,30 @@ #include "Converter.h" #include "Encoding.h" #include "Format.h" -#include "InsetIterator.h" -#include "LaTeXFeatures.h" #include "LyXRC.h" #include "output.h" #include "OutputParams.h" #include "TexRow.h" +#include "texstream.h" #include "frontends/Application.h" // hexName -#include "insets/Inset.h" - #include "support/convert.h" #include "support/debug.h" #include "support/FileName.h" #include "support/filetools.h" #include "support/ForkedCalls.h" #include "support/lstrings.h" +#include "support/os.h" -#include "support/bind.h" #include "support/TempFile.h" -#include +#include #include #include +#include +#include +#include #include @@ -70,35 +70,6 @@ FileName const unique_tex_filename(FileName const & bufferpath) } -lyx::Converter const * setConverter(string const & from) -{ - typedef vector FmtList; - typedef lyx::graphics::Cache GCache; - FmtList const & loadableFormats = GCache::get().loadableFormats(); - FmtList::const_iterator it = loadableFormats.begin(); - FmtList::const_iterator const end = loadableFormats.end(); - - for (; it != end; ++it) { - string const to = *it; - if (from == to) - continue; - - lyx::Converter const * ptr = lyx::theConverters().getConverter(from, to); - if (ptr) - return ptr; - } - - // FIXME THREAD - static bool first = true; - if (first) { - first = false; - LYXERR0("PreviewLoader::startLoading()\n" - << "No converter from \"" << from << "\" format has been defined."); - } - return 0; -} - - void setAscentFractions(vector & ascent_fractions, FileName const & metrics_file) { @@ -150,14 +121,10 @@ void setAscentFractions(vector & ascent_fractions, } -class FindFirst +std::function FindFirst(string const & comp) { -public: - FindFirst(string const & comp) : comp_(comp) {} - bool operator()(SnippetPair const & sp) const { return sp.first == comp_; } -private: - string const comp_; -}; + return [&comp](SnippetPair const & sp) { return sp.first == comp; }; +} /// Store info on a currently executing, forked process. @@ -172,28 +139,27 @@ public: /// Remove any files left lying around and kill the forked process. void stop() const; - /// - pid_t pid; /// string command; /// FileName metrics_file; /// BitmapFile snippets; + /// + pid_t pid; }; typedef map InProgressProcesses; typedef InProgressProcesses::value_type InProgressProcess; -} // namespace anon - +} // namespace namespace lyx { namespace graphics { -class PreviewLoader::Impl : public boost::signals::trackable { +class PreviewLoader::Impl { public: /// Impl(PreviewLoader & p, Buffer const & b); @@ -214,22 +180,24 @@ public: void refreshPreviews(); /// Emit this signal when an image is ready for display. - boost::signal imageReady; + signal imageReady; Buffer const & buffer() const { return buffer_; } + lyx::Converter const * setConverter(string const & from); + private: /// Called by the ForkedCall process that generated the bitmap files. void finishedGenerating(pid_t, int); /// - void dumpPreamble(otexstream &, OutputParams::FLAVOR) const; + void dumpPreamble(otexstream &, Flavor) const; /// void dumpData(odocstream &, BitmapFile const &) const; /** cache_ allows easy retrieval of already-generated images * using the LaTeX snippet as the identifier. */ - typedef shared_ptr PreviewImagePtr; + typedef std::shared_ptr PreviewImagePtr; /// typedef map Cache; /// @@ -242,7 +210,6 @@ private: /** in_progress_ stores all forked processes so that we can proceed * thereafter. - The map uses the conversion commands as its identifiers. */ InProgressProcesses in_progress_; @@ -253,12 +220,17 @@ private: /// mutable int font_scaling_factor_; /// + mutable int fg_color_; + /// + mutable int bg_color_; + /// QTimer * delay_refresh_; /// bool finished_generating_; /// We don't own this static lyx::Converter const * pconverter_; + }; @@ -270,16 +242,10 @@ lyx::Converter const * PreviewLoader::Impl::pconverter_; // PreviewLoader::PreviewLoader(Buffer const & b) - : pimpl_(new Impl(*this, b)) + : pimpl_(make_shared(*this, b)) {} -PreviewLoader::~PreviewLoader() -{ - delete pimpl_; -} - - PreviewImage const * PreviewLoader::preview(string const & latex_snippet) const { return pimpl_->preview(latex_snippet); @@ -316,7 +282,7 @@ void PreviewLoader::refreshPreviews() } -boost::signals::connection PreviewLoader::connect(slot_type const & slot) const +connection PreviewLoader::connect(slot const & slot) const { return pimpl_->imageReady.connect(slot); } @@ -353,9 +319,8 @@ public: { ostringstream os; os << base_ << counter_++ << '.' << to_format_; - string const file = os.str(); - - return make_pair(snippet, FileName(file)); + string const file_name = os.str(); + return make_pair(snippet, FileName(file_name)); } private: @@ -368,9 +333,8 @@ private: InProgress::InProgress(string const & filename_base, PendingSnippets const & pending, string const & to_format) - : pid(0), - metrics_file(filename_base + ".metrics"), - snippets(pending.size()) + : metrics_file(filename_base + ".metrics"), + snippets(pending.size()), pid(0) { PendingSnippets::const_iterator pit = pending.begin(); PendingSnippets::const_iterator pend = pending.end(); @@ -397,7 +361,7 @@ void InProgress::stop() const } } -} // namespace anon +} // namespace namespace lyx { @@ -407,6 +371,13 @@ PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b) : parent_(p), buffer_(b), finished_generating_(true) { font_scaling_factor_ = int(buffer_.fontScalingFactor()); + if (theApp()) { + fg_color_ = convert(theApp()->hexName(foregroundColor()), 16); + bg_color_ = convert(theApp()->hexName(backgroundColor()), 16); + } else { + fg_color_ = 0x0; + bg_color_ = 0xffffff; + } if (!pconverter_) pconverter_ = setConverter("lyxpreview"); @@ -417,6 +388,35 @@ PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b) } +lyx::Converter const * PreviewLoader::Impl::setConverter(string const & from) +{ + typedef vector FmtList; + FmtList const & loadableFormats = graphics::Cache::get().loadableFormats(); + FmtList::const_iterator it = loadableFormats.begin(); + FmtList::const_iterator const end = loadableFormats.end(); + + for (; it != end; ++it) { + string const to = *it; + if (from == to) + continue; + + lyx::Converter const * ptr = lyx::theConverters().getConverter(from, to); + if (ptr) + return ptr; + } + + // Show the error only once. This is thread-safe. + static nullptr_t no_conv = [&]{ + LYXERR0("PreviewLoader::startLoading()\n" + << "No converter from \"" << from + << "\" format has been defined."); + return nullptr; + } (); + + return no_conv; +} + + PreviewLoader::Impl::~Impl() { delete delay_refresh_; @@ -433,17 +433,26 @@ PreviewImage const * PreviewLoader::Impl::preview(string const & latex_snippet) const { int fs = int(buffer_.fontScalingFactor()); - if (font_scaling_factor_ != fs) { - // Schedule refresh of all previews on zoom changes. + int fg = 0x0; + int bg = 0xffffff; + if (theApp()) { + fg = convert(theApp()->hexName(foregroundColor()), 16); + bg = convert(theApp()->hexName(backgroundColor()), 16); + } + if (font_scaling_factor_ != fs || fg_color_ != fg || bg_color_ != bg) { + // Schedule refresh of all previews on zoom or color changes. // The previews are regenerated only after the zoom factor // has not been changed for about 1 second. + fg_color_ = fg; + bg_color_ = bg; delay_refresh_->start(1000); } // Don't try to access the cache until we are done. if (delay_refresh_->isActive() || !finished_generating_) - return 0; + return nullptr; + Cache::const_iterator it = cache_.find(latex_snippet); - return (it == cache_.end()) ? 0 : it->second.get(); + return (it == cache_.end()) ? nullptr : it->second.get(); } @@ -466,22 +475,17 @@ void PreviewLoader::Impl::refreshPreviews() namespace { -class FindSnippet { -public: - FindSnippet(string const & s) : snippet_(s) {} - bool operator()(InProgressProcess const & process) const - { +std::function FindSnippet(string const & s) +{ + return [&s](InProgressProcess const & process) { BitmapFile const & snippets = process.second.snippets; BitmapFile::const_iterator beg = snippets.begin(); BitmapFile::const_iterator end = snippets.end(); - return find_if(beg, end, FindFirst(snippet_)) != end; - } - -private: - string const snippet_; -}; + return find_if(beg, end, FindFirst(s)) != end; + }; +} -} // namespace anon +} // namespace PreviewLoader::Status PreviewLoader::Impl::status(string const & latex_snippet) const @@ -525,25 +529,20 @@ void PreviewLoader::Impl::add(string const & latex_snippet) namespace { -class EraseSnippet { -public: - EraseSnippet(string const & s) : snippet_(s) {} - void operator()(InProgressProcess & process) - { +std::function EraseSnippet(string const & s) +{ + return [&s](InProgressProcess & process) { BitmapFile & snippets = process.second.snippets; BitmapFile::iterator it = snippets.begin(); BitmapFile::iterator end = snippets.end(); - it = find_if(it, end, FindFirst(snippet_)); + it = find_if(it, end, FindFirst(s)); if (it != end) snippets.erase(it, it+1); - } - -private: - string const & snippet_; -}; + }; +} -} // namespace anon +} // namespace void PreviewLoader::Impl::remove(string const & latex_snippet) @@ -605,11 +604,7 @@ void PreviewLoader::Impl::startLoading(bool wait) return; } - TexRow texrow; - otexstream os(of, texrow); - OutputParams runparams(&enc); - LaTeXFeatures features(buffer_, buffer_.params(), runparams); - + otexstream os(of); if (!openFileWrite(of, latexfile)) return; @@ -620,48 +615,48 @@ void PreviewLoader::Impl::startLoading(bool wait) } of << "\\batchmode\n"; - LYXERR(Debug::LATEX, "Format = " << buffer_.params().getDefaultOutputFormat()); + LYXERR(Debug::OUTFILE, "Format = " << buffer_.params().getDefaultOutputFormat()); string latexparam = ""; bool docformat = !buffer_.params().default_output_format.empty() && buffer_.params().default_output_format != "default"; // Use LATEX flavor if the document does not specify a specific // output format (see bug 9371). - OutputParams::FLAVOR flavor = docformat + Flavor flavor = docformat ? buffer_.params().getOutputFlavor() - : OutputParams::LATEX; + : Flavor::LaTeX; if (buffer_.params().encoding().package() == Encoding::japanese) { latexparam = " --latex=platex"; - flavor = OutputParams::LATEX; + flavor = Flavor::LaTeX; } else if (buffer_.params().useNonTeXFonts) { - if (flavor == OutputParams::LUATEX) + if (flavor == Flavor::LuaTeX) latexparam = " --latex=lualatex"; else { - flavor = OutputParams::XETEX; + flavor = Flavor::XeTeX; latexparam = " --latex=xelatex"; } } else { switch (flavor) { - case OutputParams::PDFLATEX: + case Flavor::PdfLaTeX: latexparam = " --latex=pdflatex"; break; - case OutputParams::XETEX: + case Flavor::XeTeX: latexparam = " --latex=xelatex"; break; - case OutputParams::LUATEX: + case Flavor::LuaTeX: latexparam = " --latex=lualatex"; break; - case OutputParams::DVILUATEX: + case Flavor::DviLuaTeX: latexparam = " --latex=dvilualatex"; break; default: - flavor = OutputParams::LATEX; + flavor = Flavor::LaTeX; } } dumpPreamble(os, flavor); // handle inputenc etc. - // I think, this is already hadled by dumpPreamble(): Kornel + // I think this is already handled by dumpPreamble(): Kornel // buffer_.params().writeEncodingPreamble(os, features); of << "\n\\begin{document}\n"; dumpData(of, inprogress.snippets); @@ -675,26 +670,21 @@ void PreviewLoader::Impl::startLoading(bool wait) // The conversion command. ostringstream cs; - cs << pconverter_->command() + cs << subst(pconverter_->command(), "$${python}", os::python()) << " " << quoteName(latexfile.toFilesystemEncoding()) << " --dpi " << font_scaling_factor_; - // FIXME XHTML + // FIXME XHTML // The colors should be customizable. if (!buffer_.isExporting()) { ColorCode const fg = PreviewLoader::foregroundColor(); ColorCode const bg = PreviewLoader::backgroundColor(); - cs << " --fg " << theApp()->hexName(fg) + cs << " --fg " << theApp()->hexName(fg) << " --bg " << theApp()->hexName(bg); } cs << latexparam; - if (buffer_.params().bibtex_command != "default") - cs << " --bibtex=" << quoteName(buffer_.params().bibtex_command); - else if (buffer_.params().encoding().package() == Encoding::japanese) - cs << " --bibtex=" << quoteName(lyxrc.jbibtex_command); - else - cs << " --bibtex=" << quoteName(lyxrc.bibtex_command); + cs << " --bibtex=" << quoteName(buffer_.params().bibtexCommand()); if (buffer_.params().bufferFormat() == "lilypond-book") cs << " --lilypond"; @@ -703,8 +693,8 @@ void PreviewLoader::Impl::startLoading(bool wait) if (wait) { ForkedCall call(buffer_.filePath(), buffer_.layoutPos()); int ret = call.startScript(ForkedProcess::Wait, command); - // FIXME THREAD - static int fake = (2^20) + 1; + // PID_MAX_LIMIT is 2^22 so we start one after that + static atomic_int fake((1 << 22) + 1); int pid = fake++; inprogress.pid = pid; inprogress.command = command; @@ -714,9 +704,13 @@ void PreviewLoader::Impl::startLoading(bool wait) } // Initiate the conversion from LaTeX to bitmap images files. - ForkedCall::SignalTypePtr - convert_ptr(new ForkedCall::SignalType); - convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2)); + ForkedCall::sigPtr convert_ptr = make_shared(); + weak_ptr this_ = parent_.pimpl_; + convert_ptr->connect([this_](pid_t pid, int retval){ + if (auto p = this_.lock()) { + p->finishedGenerating(pid, retval); + } + }); ForkedCall call(buffer_.filePath()); int ret = call.startScript(command, convert_ptr); @@ -772,7 +766,7 @@ void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval) list newimages; - int metrics_counter = 0; + size_t metrics_counter = 0; for (; it != end; ++it, ++metrics_counter) { string const & snip = it->first; FileName const & file = it->second; @@ -801,13 +795,14 @@ void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval) imageReady(*nit->get()); } finished_generating_ = true; + buffer_.scheduleRedrawWorkAreas(); } -void PreviewLoader::Impl::dumpPreamble(otexstream & os, OutputParams::FLAVOR flavor) const +void PreviewLoader::Impl::dumpPreamble(otexstream & os, Flavor flavor) const { // Dump the preamble only. - LYXERR(Debug::LATEX, "dumpPreamble, flavor == " << flavor); + LYXERR(Debug::OUTFILE, "dumpPreamble, flavor == " << static_cast(flavor)); OutputParams runparams(&buffer_.params().encoding()); runparams.flavor = flavor; runparams.nice = true; @@ -817,11 +812,11 @@ void PreviewLoader::Impl::dumpPreamble(otexstream & os, OutputParams::FLAVOR fla buffer_.writeLaTeXSource(os, buffer_.filePath(), runparams, Buffer::OnlyPreamble); // FIXME! This is a HACK! The proper fix is to control the 'true' - // passed to WriteStream below: + // passed to TeXMathStream below: // int InsetMathNest::latex(Buffer const &, odocstream & os, // OutputParams const & runparams) const // { - // WriteStream wi(os, runparams.moving_arg, true); + // TeXMathStream wi(os, runparams.moving_arg, true); // par_->write(wi); // return wi.line(); // }