X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fgraphics%2FPreviewLoader.C;h=5eb37010644edb289abdabada41b42da36cc3ee2;hb=3aa7e91a827fa15b3e0906b975c4755a2dcdb76d;hp=de8110f73a1af777c42267e32bb42332e28d89a4;hpb=a0003fb2a80f594c965236eda8e178514c12127b;p=lyx.git diff --git a/src/graphics/PreviewLoader.C b/src/graphics/PreviewLoader.C index de8110f73a..5eb3701064 100644 --- a/src/graphics/PreviewLoader.C +++ b/src/graphics/PreviewLoader.C @@ -1,9 +1,10 @@ -/* +/** * \file PreviewLoader.C - * Copyright 2002 the LyX Team * Read the file COPYING * - * \author Angus Leeming + * \author Angus Leeming + * + * Full author contact details available in file CREDITS */ #include @@ -16,11 +17,9 @@ #include "PreviewImage.h" #include "buffer.h" -#include "bufferparams.h" #include "converter.h" #include "debug.h" #include "lyxrc.h" -#include "lyxtextclasslist.h" #include "LColor.h" #include "insets/inset.h" @@ -64,12 +63,11 @@ namespace { typedef pair StrPair; -typedef list PendingStore; - -typedef vector InProgressStore; +// A list of alll snippets to be converted to previews +typedef list PendingSnippets; - -double setFontScalingFactor(Buffer &); +// Each item in the vector is a pair. +typedef vector BitmapFile; string const unique_filename(string const bufferpath); @@ -95,19 +93,22 @@ struct InProgress { InProgress() : pid(0) {} /// InProgress(string const & filename_base, - PendingStore const & pending, + PendingSnippets const & pending, string const & to_format); - /// Remove any files left lying around and kill the forked process. + /// Remove any files left lying around and kill the forked process. void stop() const; /// pid_t pid; /// string metrics_file; - /// Each item in the vector is a pair. - InProgressStore snippets; + /// + BitmapFile snippets; }; +typedef map InProgressProcesses; + +typedef InProgressProcesses::value_type InProgressProcess; } // namespace anon @@ -130,13 +131,18 @@ struct PreviewLoader::Impl : public boost::signals::trackable { /// void startLoading(); + /// Emit this signal when an image is ready for display. + boost::signal1 imageReady; + + Buffer const & buffer() const { return buffer_; } + private: /// Called by the Forkedcall process that generated the bitmap files. void finishedGenerating(string const &, pid_t, int); /// void dumpPreamble(ostream &) const; /// - void dumpData(ostream &, InProgressStore const &) const; + void dumpData(ostream &, BitmapFile const &) const; /** cache_ allows easy retrieval of already-generated images * using the LaTeX snippet as the identifier. @@ -150,15 +156,13 @@ private: /** pending_ stores the LaTeX snippets in anticipation of them being * sent to the converter. */ - PendingStore pending_; + PendingSnippets pending_; /** in_progress_ stores all forked processes so that we can proceed * thereafter. The map uses the conversion commands as its identifiers. */ - typedef map InProgressMap; - /// - InProgressMap in_progress_; + InProgressProcesses in_progress_; /// PreviewLoader & parent_; @@ -168,7 +172,7 @@ private: double font_scaling_factor_; /// We don't own this - static Converter const * pconverter_; + static Converter const * pconverter_; }; @@ -198,23 +202,41 @@ PreviewLoader::Status PreviewLoader::status(string const & latex_snippet) const } -void PreviewLoader::add(string const & latex_snippet) +void PreviewLoader::add(string const & latex_snippet) const { pimpl_->add(latex_snippet); } -void PreviewLoader::remove(string const & latex_snippet) +void PreviewLoader::remove(string const & latex_snippet) const { pimpl_->remove(latex_snippet); } -void PreviewLoader::startLoading() +void PreviewLoader::startLoading() const { pimpl_->startLoading(); } + +boost::signals::connection PreviewLoader::connect(slot_type const & slot) const +{ + return pimpl_->imageReady.connect(slot); +} + + +void PreviewLoader::emitSignal(PreviewImage const & pimage) const +{ + pimpl_->imageReady(pimage); +} + + +Buffer const & PreviewLoader::buffer() const +{ + return pimpl_->buffer(); +} + } // namespace grfx @@ -223,27 +245,41 @@ void PreviewLoader::startLoading() namespace { +struct IncrementedFileName { + IncrementedFileName(string const & to_format, + string const & filename_base) + : to_format_(to_format), base_(filename_base), counter_(1) + {} + + StrPair const operator()(string const & snippet) + { + ostringstream os; + os << base_ << counter_++ << "." << to_format_; + string const file = os.str().c_str(); + + return make_pair(snippet, file); + } + +private: + string const & to_format_; + string const & base_; + int counter_; +}; + + InProgress::InProgress(string const & filename_base, - PendingStore const & pending, + PendingSnippets const & pending, string const & to_format) : pid(0), metrics_file(filename_base + ".metrics"), snippets(pending.size()) { - InProgressStore::iterator sit = snippets.begin(); - PendingStore::const_iterator pit = pending.begin(); - PendingStore::const_iterator pend = pending.end(); + PendingSnippets::const_iterator pit = pending.begin(); + PendingSnippets::const_iterator pend = pending.end(); + BitmapFile::iterator sit = snippets.begin(); - int counter = 1; // file numbers start at 1 - for (; pit != pend; ++pit, ++sit, ++counter) { - ostringstream os; - os << filename_base - << setfill('0') << setw(3) << counter - << "." << to_format; - string const file = os.str().c_str(); - - *sit = make_pair(*pit, file); - } + std::transform(pit, pend, sit, + IncrementedFileName(to_format, filename_base)); } @@ -255,14 +291,14 @@ void InProgress::stop() const if (!metrics_file.empty()) lyx::unlink(metrics_file); - InProgressStore::const_iterator vit = snippets.begin(); - InProgressStore::const_iterator vend = snippets.end(); + BitmapFile::const_iterator vit = snippets.begin(); + BitmapFile::const_iterator vend = snippets.end(); for (; vit != vend; ++vit) { if (!vit->second.empty()) lyx::unlink(vit->second); } } - + } // namespace anon @@ -271,7 +307,8 @@ namespace grfx { PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b) : parent_(p), buffer_(b), font_scaling_factor_(0.0) { - font_scaling_factor_ = setFontScalingFactor(const_cast(b)); + font_scaling_factor_ = 0.01 * lyxrc.dpi * lyxrc.zoom * + lyxrc.preview_scale_factor; lyxerr[Debug::GRAPHICS] << "The font scaling factor is " << font_scaling_factor_ << endl; @@ -283,8 +320,8 @@ PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b) PreviewLoader::Impl::~Impl() { - InProgressMap::iterator ipit = in_progress_.begin(); - InProgressMap::iterator ipend = in_progress_.end(); + InProgressProcesses::iterator ipit = in_progress_.begin(); + InProgressProcesses::iterator ipend = in_progress_.end(); for (; ipit != ipend; ++ipit) { ipit->second.stop(); @@ -300,6 +337,25 @@ PreviewLoader::Impl::preview(string const & latex_snippet) const } +namespace { + +struct FindSnippet { + FindSnippet(string const & s) : snippet_(s) {} + bool operator()(InProgressProcess const & process) + { + BitmapFile const & snippets = process.second.snippets; + BitmapFile::const_iterator it = snippets.begin(); + BitmapFile::const_iterator end = snippets.end(); + it = find_if(it, end, FindFirst(snippet_)); + return it != end; + } + +private: + string const & snippet_; +}; + +} // namespace anon + PreviewLoader::Status PreviewLoader::Impl::status(string const & latex_snippet) const { @@ -307,25 +363,19 @@ PreviewLoader::Impl::status(string const & latex_snippet) const if (cit != cache_.end()) return Ready; - PendingStore::const_iterator pit = pending_.begin(); - PendingStore::const_iterator pend = pending_.end(); - pit = find(pit, pend, latex_snippet); + PendingSnippets::const_iterator pit = pending_.begin(); + PendingSnippets::const_iterator pend = pending_.end(); + pit = find(pit, pend, latex_snippet); if (pit != pend) return InQueue; - InProgressMap::const_iterator ipit = in_progress_.begin(); - InProgressMap::const_iterator ipend = in_progress_.end(); + InProgressProcesses::const_iterator ipit = in_progress_.begin(); + InProgressProcesses::const_iterator ipend = in_progress_.end(); - for (; ipit != ipend; ++ipit) { - InProgressStore const & snippets = ipit->second.snippets; - InProgressStore::const_iterator sit = snippets.begin(); - InProgressStore::const_iterator send = snippets.end(); - sit = find_if(sit, send, FindFirst(latex_snippet)); - - if (sit != send) - return Processing; - } + ipit = find_if(ipit, ipend, FindSnippet(latex_snippet)); + if (ipit != ipend) + return Processing; return NotFound; } @@ -336,41 +386,57 @@ void PreviewLoader::Impl::add(string const & latex_snippet) if (!pconverter_ || status(latex_snippet) != NotFound) return; - pending_.push_back(latex_snippet); + string const snippet = trim(latex_snippet); + if (snippet.empty()) + return; + + lyxerr[Debug::GRAPHICS] << "adding snippet:\n" << snippet << endl; + + pending_.push_back(snippet); } +namespace { + +struct EraseSnippet { + EraseSnippet(string const & s) : snippet_(s) {} + void operator()(InProgressProcess & process) + { + BitmapFile & snippets = process.second.snippets; + BitmapFile::iterator it = snippets.begin(); + BitmapFile::iterator end = snippets.end(); + + it = find_if(it, end, FindFirst(snippet_)); + if (it != end) + snippets.erase(it, it+1); + } + +private: + string const & snippet_; +}; + +} // namespace anon + + void PreviewLoader::Impl::remove(string const & latex_snippet) { Cache::iterator cit = cache_.find(latex_snippet); if (cit != cache_.end()) cache_.erase(cit); - PendingStore::iterator pit = pending_.begin(); - PendingStore::iterator pend = pending_.end(); - pit = find(pit, pend, latex_snippet); - - if (pit != pend) { - PendingStore::iterator first = pit++; - pending_.erase(first, pit); - } - - InProgressMap::iterator ipit = in_progress_.begin(); - InProgressMap::iterator ipend = in_progress_.end(); + PendingSnippets::iterator pit = pending_.begin(); + PendingSnippets::iterator pend = pending_.end(); - while (ipit != ipend) { - InProgressMap::iterator curr = ipit; - ++ipit; + pending_.erase(std::remove(pit, pend, latex_snippet), pend); - InProgressStore & snippets = curr->second.snippets; - InProgressStore::iterator sit = snippets.begin(); - InProgressStore::iterator send = snippets.end(); - sit = find_if(sit, send, FindFirst(latex_snippet)); + InProgressProcesses::iterator ipit = in_progress_.begin(); + InProgressProcesses::iterator ipend = in_progress_.end(); - if (sit != send) - snippets.erase(sit, sit+1); + std::for_each(ipit, ipend, EraseSnippet(latex_snippet)); - if (snippets.empty()) + for (; ipit != ipend; ++ipit) { + InProgressProcesses::iterator curr = ipit++; + if (curr->second.snippets.empty()) in_progress_.erase(curr); } } @@ -407,9 +473,9 @@ void PreviewLoader::Impl::startLoading() // The conversion command. ostringstream cs; cs << pconverter_->command << " " << latexfile << " " - << font_scaling_factor_; + << int(font_scaling_factor_) << " " << pconverter_->to; - string const command = cs.str().c_str(); + string const command = "sh " + LibScriptSearch(cs.str().c_str()); // Initiate the conversion from LaTeX to bitmap images files. Forkedcall::SignalTypePtr convert_ptr; @@ -444,7 +510,8 @@ void PreviewLoader::Impl::finishedGenerating(string const & command, if (retval > 0) return; - InProgressMap::iterator git = in_progress_.find(command); + // Paranoia check! + InProgressProcesses::iterator git = in_progress_.find(command); if (git == in_progress_.end()) { lyxerr << "PreviewLoader::finishedGenerating(): unable to find " "data for\n" @@ -458,8 +525,10 @@ void PreviewLoader::Impl::finishedGenerating(string const & command, // Add these newly generated bitmap files to the cache and // start loading them into LyX. - InProgressStore::const_iterator it = git->second.snippets.begin(); - InProgressStore::const_iterator end = git->second.snippets.end(); + BitmapFile::const_iterator it = git->second.snippets.begin(); + BitmapFile::const_iterator end = git->second.snippets.end(); + + std::list newimages; int metrics_counter = 0; for (; it != end; ++it, ++metrics_counter) { @@ -470,11 +539,18 @@ void PreviewLoader::Impl::finishedGenerating(string const & command, PreviewImagePtr ptr(new PreviewImage(parent_, snip, file, af)); cache_[snip] = ptr; - ptr->startLoading(); + newimages.push_back(ptr); } // Remove the item from the list of still-executing processes. in_progress_.erase(git); + + // Tell the outside world + std::list::const_iterator nit = newimages.begin(); + std::list::const_iterator nend = newimages.end(); + for (; nit != nend; ++nit) { + imageReady(*nit->get()); + } } @@ -483,17 +559,15 @@ void PreviewLoader::Impl::dumpPreamble(ostream & os) const // Why on earth is Buffer::makeLaTeXFile a non-const method? Buffer & tmp = const_cast(buffer_); // Dump the preamble only. - tmp.makeLaTeXFile(os, string(), true, false, true); + tmp.makeLaTeXFile(os, buffer_.filePath(), true, false, true); // Loop over the insets in the buffer and dump all the math-macros. Buffer::inset_iterator it = buffer_.inset_const_iterator_begin(); Buffer::inset_iterator end = buffer_.inset_const_iterator_end(); - for (; it != end; ++it) { - if ((*it)->lyxCode() == Inset::MATHMACRO_CODE) { - (*it)->latex(&buffer_, os, true, true); - } - } + for (; it != end; ++it) + if (it->lyxCode() == Inset::MATHMACRO_CODE) + it->latex(&buffer_, os, true, true); // All equation lables appear as "(#)" + preview.sty's rendering of // the label name @@ -503,7 +577,7 @@ void PreviewLoader::Impl::dumpPreamble(ostream & os) const // Use the preview style file to ensure that each snippet appears on a // fresh page. os << "\n" - << "\\usepackage[active,delayed,dvips,tightpage,showlabels]{preview}\n" + << "\\usepackage[active,delayed,dvips,tightpage,showlabels,lyx]{preview}\n" << "\n"; // This piece of PostScript magic ensures that the foreground and @@ -522,13 +596,13 @@ void PreviewLoader::Impl::dumpPreamble(ostream & os) const void PreviewLoader::Impl::dumpData(ostream & os, - InProgressStore const & vec) const + BitmapFile const & vec) const { if (vec.empty()) return; - InProgressStore::const_iterator it = vec.begin(); - InProgressStore::const_iterator end = vec.end(); + BitmapFile::const_iterator it = vec.begin(); + BitmapFile::const_iterator end = vec.end(); for (; it != end; ++it) { os << "\\begin{preview}\n" @@ -552,8 +626,6 @@ string const unique_filename(string const bufferpath) Converter const * setConverter() { - Converter const * converter = 0; - string const from = "lyxpreview"; Formats::FormatList::const_iterator it = formats.begin(); @@ -577,68 +649,8 @@ Converter const * setConverter() "defined." << endl; } - - return 0; -} - -double setFontScalingFactor(Buffer & buffer) -{ - double scale_factor = 0.01 * lyxrc.dpi * lyxrc.zoom * - lyxrc.preview_scale_factor; - - // Has the font size been set explicitly? - string const & fontsize = buffer.params.fontsize; - lyxerr[Debug::GRAPHICS] << "PreviewLoader::scaleToFitLyXView()\n" - << "font size is " << fontsize << endl; - - if (isStrUnsignedInt(fontsize)) - return 10.0 * scale_factor / strToDbl(fontsize); - - // No. We must extract it from the LaTeX class file. - LyXTextClass const & tclass = textclasslist[buffer.params.textclass]; - string const textclass(tclass.latexname() + ".cls"); - string const classfile(findtexfile(textclass, "cls")); - - lyxerr[Debug::GRAPHICS] << "text class is " << textclass << '\n' - << "class file is " << classfile << endl; - - ifstream ifs(classfile.c_str()); - if (!ifs.good()) { - lyxerr[Debug::GRAPHICS] << "Unable to open class file!" << endl; - return scale_factor; - } - - string str; - double scaling = scale_factor; - - while (ifs.good()) { - getline(ifs, str); - // To get the default font size, look for a line like - // "\ExecuteOptions{letterpaper,10pt,oneside,onecolumn,final}" - if (!prefixIs(frontStrip(str), "\\ExecuteOptions")) - continue; - - // str contains just the options of \ExecuteOptions - string const tmp = split(str, '{'); - split(tmp, str, '}'); - - int count = 0; - string tok = token(str, ',', count++); - while (!isValidLength(tok) && !tok.empty()) - tok = token(str, ',', count++); - - if (!tok.empty()) { - lyxerr[Debug::GRAPHICS] - << "Extracted default font size from " - "LaTeX class file successfully!" << endl; - LyXLength fsize(tok); - scaling *= 10.0 / fsize.value(); - break; - } - } - - return scaling; + return 0; } @@ -651,36 +663,72 @@ void setAscentFractions(vector & ascent_fractions, vector::iterator end = ascent_fractions.end(); fill(it, end, 0.5); - ifstream ifs(metrics_file.c_str()); - if (!ifs.good()) { - lyxerr[Debug::GRAPHICS] << "setAscentFractions(" - << metrics_file << ")\n" - << "Unable to open file!" - << endl; + ifstream in(metrics_file.c_str()); + if (!in.good()) { + lyxerr[Debug::GRAPHICS] + << "setAscentFractions(" << metrics_file << ")\n" + << "Unable to open file!" << endl; return; } - for (; it != end; ++it) { - string page; - string page_id; - int dummy; - int ascent; - int descent; - - ifs >> page >> page_id >> dummy >> dummy >> dummy >> dummy - >> ascent >> descent >> dummy; - - if (!ifs.good() || - page != "%%Page" || - !isStrUnsignedInt(strip(page_id, ':'))) { - lyxerr[Debug::GRAPHICS] << "setAscentFractions(" - << metrics_file << ")\n" - << "Error reading file!" - << endl; + bool error = false; + + // Tightpage dimensions affect all subsequent dimensions + int tp_ascent; + int tp_descent; + + int snippet_counter = 0; + while (!in.eof()) { + // Expecting lines of the form + // Preview: Tightpage tp_bl_x tp_bl_y tp_tr_x tp_tr_y + // Preview: Snippet id ascent descent width + string preview; + string type; + in >> preview >> type; + + if (!in.good()) + // eof after all + break; + + error = preview != "Preview:" + || (type != "Tightpage" && type != "Snippet"); + if (error) break; + + if (type == "Tightpage") { + int dummy; + in >> dummy >> tp_descent >> dummy >> tp_ascent; + + error = !in.good(); + if (error) + break; + + } else { + int dummy; + int snippet_id; + int ascent; + int descent; + in >> snippet_id >> ascent >> descent >> dummy; + + error = !in.good() || ++snippet_counter != snippet_id; + if (error) + break; + + double const a = ascent + tp_ascent; + double const d = descent - tp_descent; + + if (!lyx::float_equal(a + d, 0, 0.1)) + *it = a / (a + d); + + if (++it == end) + break; } - - *it = ascent / (ascent + descent); + } + + if (error) { + lyxerr[Debug::GRAPHICS] + << "setAscentFractions(" << metrics_file << ")\n" + << "Error reading file!\n" << endl; } }