From 16b928088fe3f9673df0b67a82aabd12f5de4582 Mon Sep 17 00:00:00 2001 From: Angus Leeming Date: Mon, 15 Jul 2002 11:08:46 +0000 Subject: [PATCH] Smart loading of image files for previews and for the graphics inset. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4638 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/graphics/ChangeLog | 15 +++ src/graphics/GraphicsLoader.C | 223 +++++++++++++++++++++++---------- src/graphics/GraphicsLoader.h | 8 ++ src/graphics/GraphicsSupport.C | 102 +++++++++++++++ src/graphics/GraphicsSupport.h | 50 ++++++++ src/graphics/Makefile.am | 2 + src/graphics/PreviewImage.C | 60 ++++----- src/graphics/PreviewImage.h | 17 ++- src/graphics/PreviewLoader.C | 14 ++- src/insets/ChangeLog | 5 + src/insets/insetgraphics.C | 2 +- src/mathed/ChangeLog | 4 + src/mathed/formula.C | 10 +- 13 files changed, 395 insertions(+), 117 deletions(-) create mode 100644 src/graphics/GraphicsSupport.C create mode 100644 src/graphics/GraphicsSupport.h diff --git a/src/graphics/ChangeLog b/src/graphics/ChangeLog index 23cf06e790..6bb09a9271 100644 --- a/src/graphics/ChangeLog +++ b/src/graphics/ChangeLog @@ -1,3 +1,18 @@ +2002-07-12 Angus Leeming + + * GraphicsLoader.[Ch]: smart loading of images. Images are loaded only + if visible 2 secs after the call to load them is first made. + + * GraphicsSupport.[Ch]: new files. isInsetVisible interrogates the + BufferView to ascertain whether the inset is visible or not. + + * Makefile.am: added GraphicsSupport.[Ch]. + + * PreviewImage.[Ch]: use this smart loader. + + * PreviewLoader.C: don't load generated image files indiscimminantly. + Instead emit the imageReady signal and allow the image owner to decide. + 2002-07-12 John Levon * GraphicsCache.C: remove init_graphics() diff --git a/src/graphics/GraphicsLoader.C b/src/graphics/GraphicsLoader.C index 9464960690..9644c5f245 100644 --- a/src/graphics/GraphicsLoader.C +++ b/src/graphics/GraphicsLoader.C @@ -17,10 +17,15 @@ #include "GraphicsCacheItem.h" #include "GraphicsImage.h" #include "GraphicsParams.h" +#include "GraphicsSupport.h" + +#include "frontends/Timeout.h" #include #include +#include + namespace grfx { struct Loader::Impl : boost::signals::trackable { @@ -35,6 +40,9 @@ struct Loader::Impl : boost::signals::trackable { /// void createPixmap(); + /// + void startLoading(Inset const &, BufferView const &); + /// The loading status of the image. ImageStatus status_; /** Must store a copy of the cached item to ensure that it is not @@ -47,19 +55,118 @@ struct Loader::Impl : boost::signals::trackable { private: /// void statusChanged(); + /// + void checkedLoading(); /// Params params_; /// Loader & parent_; + + /// + Timeout timer; + // Multiple Insets can share the same image + typedef std::list InsetList; + /// + InsetList insets; + /// + BufferView const * view; }; -Loader::Impl::Impl(Loader & parent, Params const & params) - : status_(WaitingToLoad), params_(params), parent_(parent) +Loader::Loader() + : pimpl_(new Impl(*this, Params())) {} +Loader::Loader(string const & file, DisplayType type) + : pimpl_(new Impl(*this, Params())) +{ + reset(file, type); +} + + +Loader::Loader(string const & file, Params const & params) + : pimpl_(new Impl(*this, params)) +{ + reset(file, params); +} + + +Loader::~Loader() +{} + + +void Loader::reset(string const & file, DisplayType type) +{ + Params params; + params.display = type; + pimpl_->resetParams(params); + + pimpl_->resetFile(file); + pimpl_->createPixmap(); +} + + +void Loader::reset(string const & file, Params const & params) +{ + pimpl_->resetParams(params); + pimpl_->resetFile(file); + pimpl_->createPixmap(); +} + + +void Loader::reset(Params const & params) +{ + pimpl_->resetParams(params); + pimpl_->createPixmap(); +} + + +void Loader::startLoading() +{ + if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get()) + return; + pimpl_->cached_item_->startLoading(); +} + + +void Loader::startLoading(Inset const & inset, BufferView const & bv) +{ + if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get()) + return; + pimpl_->startLoading(inset, bv); +} + + +string const & Loader::filename() const +{ + static string const empty; + return pimpl_->cached_item_.get() ? + pimpl_->cached_item_->filename() : empty; +} + + +ImageStatus Loader::status() const +{ + return pimpl_->status_; +} + + +Image const * Loader::image() const +{ + return pimpl_->image_.get(); +} + + +Loader::Impl::Impl(Loader & parent, Params const & params) + : status_(WaitingToLoad), params_(params), parent_(parent), + timer(2000, Timeout::ONETIME), view(0) +{ + timer.timeout.connect(boost::bind(&Impl::checkedLoading, this)); +} + + Loader::Impl::~Impl() { resetFile(string()); @@ -141,80 +248,58 @@ void Loader::Impl::createPixmap() } -Loader::Loader() - : pimpl_(new Impl(*this, Params())) -{} - - -Loader::Loader(string const & file, DisplayType type) - : pimpl_(new Impl(*this, Params())) +void Loader::Impl::startLoading(Inset const & inset, BufferView const & bv) { - reset(file, type); -} - - -Loader::Loader(string const & file, Params const & params) - : pimpl_(new Impl(*this, params)) -{ - reset(file, params); -} - - -Loader::~Loader() -{} - - -void Loader::reset(string const & file, DisplayType type) -{ - Params params; - params.display = type; - pimpl_->resetParams(params); - - pimpl_->resetFile(file); - pimpl_->createPixmap(); -} - - -void Loader::reset(string const & file, Params const & params) -{ - pimpl_->resetParams(params); - pimpl_->resetFile(file); - pimpl_->createPixmap(); -} - - -void Loader::reset(Params const & params) -{ - pimpl_->resetParams(params); - pimpl_->createPixmap(); -} - - -void Loader::startLoading() -{ - if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get()) + if (status_ != WaitingToLoad || timer.running()) return; - pimpl_->cached_item_->startLoading(); + + InsetList::const_iterator it = insets.begin(); + InsetList::const_iterator end = insets.end(); + it = std::find(it, end, &inset); + if (it == end) + insets.push_back(&inset); + view = &bv; + + timer.start(); } -string const & Loader::filename() const +namespace { + +struct FindVisibleInset { + + FindVisibleInset(std::list const & vps) : vps_(vps) {} + + bool operator()(Inset const * inset_ptr) + { + if (!inset_ptr) + return false; + return isInsetVisible(*inset_ptr, vps_); + } + +private: + std::list const & vps_; +}; + +} // namespace anon + + +void Loader::Impl::checkedLoading() { - static string const empty; - return pimpl_->cached_item_.get() ? - pimpl_->cached_item_->filename() : empty; + if (insets.empty() || !view) + return; + + std::list const vps = getVisibleParagraphs(*view); + + InsetList::const_iterator it = insets.begin(); + InsetList::const_iterator end = insets.end(); + + it = std::find_if(it, end, FindVisibleInset(vps)); + + // One of the insets is visible, so start loading the image. + if (it != end) + cached_item_->startLoading(); } -ImageStatus Loader::status() const -{ - return pimpl_->status_; -} - - -Image const * Loader::image() const -{ - return pimpl_->image_.get(); -} - } // namespace grfx diff --git a/src/graphics/GraphicsLoader.h b/src/graphics/GraphicsLoader.h index 3054b8cbaf..569e329864 100644 --- a/src/graphics/GraphicsLoader.h +++ b/src/graphics/GraphicsLoader.h @@ -31,6 +31,9 @@ #include #include +class Inset; +class BufferView; + namespace grfx { class Image; @@ -63,6 +66,11 @@ public: /// We are explicit about when we begin the loading process. void startLoading(); + /** starting loading of the image is conditional upon the + * inset being visible or not. + */ + void startLoading(Inset const &, BufferView const &); + /// How far have we got in loading the image? ImageStatus status() const; diff --git a/src/graphics/GraphicsSupport.C b/src/graphics/GraphicsSupport.C new file mode 100644 index 0000000000..de8cccd1d3 --- /dev/null +++ b/src/graphics/GraphicsSupport.C @@ -0,0 +1,102 @@ +/** + * \file GraphicsSupport.C + * Copyright 2002 the LyX Team + * Read the file COPYING + * + * \author Angus Leeming + */ + +#include + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include "GraphicsSupport.h" + +#include "BufferView.h" +#include "lyxtext.h" +#include "lyxrow.h" +#include "paragraph.h" +#include "frontends/Painter.h" + + +typedef std::list VPList; + + +VPList const getVisibleParagraphs(BufferView const & bv) +{ + // top_y is not const because it's reset by getRowNearY. + int top_y = bv.text->first_y; + Row const * row = bv.text->getRowNearY(top_y); + + int const bv_height = bv.painter().paperHeight(); + + VPList vps; + Row const * last_row = 0; + + for (int height = 0; row && height < bv_height; row = row->next()) { + height += row->height(); + + if (vps.empty() || vps.back().par != row->par()) { + vps.push_back(VisibleParagraph(row->par(), + row->pos(), + row->par()->size())); + } + + last_row = row; + } + + // If the end of the final paragraph is not visble, + // update vps.back().end + if (last_row && last_row->next() && + last_row->par() == last_row->next()->par()) { + vps.back().end = last_row->next()->pos(); + } + + return vps; +} + + +namespace { + +struct InsetVisibleInParagraph { + InsetVisibleInParagraph(Inset const & inset) : inset_(inset) {} + bool operator()(VisibleParagraph const & vp) + { + Paragraph * par = vp.par; + Paragraph::inset_iterator it = par->inset_iterator_begin(); + Paragraph::inset_iterator end = par->inset_iterator_end(); + + // Can't refactor this as a functor because we rely on the + // inset_iterator member function getPos(). + for (; it != end; ++it) { + lyx::pos_type const pos = it.getPos(); + if (pos >= vp.start && pos <= vp.end) { + if (*it == &inset_ || + it->getInsetFromID(inset_.id()) != 0) + return true; + } + } + return false; + } + +private: + Inset const & inset_; +}; + +} // namespace anon + + +bool isInsetVisible(Inset const & inset, VPList const & vps) +{ + if (vps.empty()) + return false; + + VPList::const_iterator it = vps.begin(); + VPList::const_iterator end = vps.end(); + + it = std::find_if(it, end, InsetVisibleInParagraph(inset)); + + return it != end; +} diff --git a/src/graphics/GraphicsSupport.h b/src/graphics/GraphicsSupport.h new file mode 100644 index 0000000000..72257b193b --- /dev/null +++ b/src/graphics/GraphicsSupport.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +/** + * \file GraphicsSupport.h + * Copyright 2002 the LyX Team + * Read the file COPYING + * + * \author Angus Leeming + */ + +#ifndef GRAPHICSSUPPORT_H +#define GRAPHICSSUPPORT_H + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "support/types.h" +#include + +class BufferView; +class Inset; +class Paragraph; + +/** A Paragraph * together with delimiters for the start and end positions + of visibility. + */ +struct VisibleParagraph { + /// + VisibleParagraph() : par(0), start(0), end(0) {} + /// + VisibleParagraph(Paragraph * p, lyx::pos_type s, lyx::pos_type e) + : par(p), start(s), end(e) {} + /// + Paragraph * par; + /// + lyx::pos_type start; + /// + lyx::pos_type end; +}; + + +/// Returns a list of all Paragraphs currently visible in bv. +std::list const getVisibleParagraphs(BufferView const & bv); + +/** Given this data, check whether inset lies within it and is, therefore, + * visible. + */ +bool isInsetVisible(Inset const & inset, std::list const &); + +#endif // GRAPHICSSUPPORT_H diff --git a/src/graphics/Makefile.am b/src/graphics/Makefile.am index 6c1c4c1afe..01e377553e 100644 --- a/src/graphics/Makefile.am +++ b/src/graphics/Makefile.am @@ -23,6 +23,8 @@ libgraphics_la_SOURCES = \ GraphicsLoader.C \ $(GRAPHICSIMAGEXPM) GraphicsParams.C \ GraphicsParams.h \ + GraphicsSupport.h \ + GraphicsSupport.C \ GraphicsTypes.h \ PreviewImage.h \ PreviewImage.C \ diff --git a/src/graphics/PreviewImage.C b/src/graphics/PreviewImage.C index 9bc6ba88c2..4be278aa61 100644 --- a/src/graphics/PreviewImage.C +++ b/src/graphics/PreviewImage.C @@ -3,7 +3,7 @@ * Copyright 2002 the LyX Team * Read the file COPYING * - * \author Angus Leeming + * \author Angus Leeming */ #include @@ -17,8 +17,6 @@ #include "GraphicsImage.h" #include "GraphicsLoader.h" -#include "debug.h" - #include "support/lyxlib.h" #include @@ -34,9 +32,7 @@ struct PreviewImage::Impl : public boost::signals::trackable { /// ~Impl(); /// - void startLoading(); - /// - Image const * image(); + Image const * image(Inset const &, BufferView const &); /// void statusChanged(); @@ -45,7 +41,7 @@ struct PreviewImage::Impl : public boost::signals::trackable { /// PreviewLoader & ploader_; /// - boost::scoped_ptr const iloader_; + Loader iloader_; /// string const snippet_; /// @@ -65,20 +61,15 @@ PreviewImage::~PreviewImage() {} -void PreviewImage::startLoading() -{ - return pimpl_->startLoading(); -} - - string const & PreviewImage::snippet() const { return pimpl_->snippet_; } + int PreviewImage::ascent() const { - Image const * const image = pimpl_->image(); + Image const * const image = pimpl_->iloader_.image(); if (!image) return 0; @@ -88,7 +79,7 @@ int PreviewImage::ascent() const int PreviewImage::descent() const { - Image const * const image = pimpl_->image(); + Image const * const image = pimpl_->iloader_.image(); if (!image) return 0; @@ -99,14 +90,15 @@ int PreviewImage::descent() const int PreviewImage::width() const { - Image const * const image = pimpl_->image(); + Image const * const image = pimpl_->iloader_.image(); return image ? image->getWidth() : 0; } -Image const * PreviewImage::image() const +Image const * PreviewImage::image(Inset const & inset, + BufferView const & bv) const { - return pimpl_->image(); + return pimpl_->image(inset, bv); } @@ -114,37 +106,33 @@ PreviewImage::Impl::Impl(PreviewImage & p, PreviewLoader & l, string const & s, string const & bf, double af) - : parent_(p), ploader_(l), iloader_(new Loader(bf)), + : parent_(p), ploader_(l), iloader_(bf), snippet_(s), ascent_frac_(af) -{} +{ + iloader_.statusChanged.connect( + boost::bind(&Impl::statusChanged, this)); +} PreviewImage::Impl::~Impl() { - lyx::unlink(iloader_->filename()); + lyx::unlink(iloader_.filename()); } -void PreviewImage::Impl::startLoading() +Image const * PreviewImage::Impl::image(Inset const & inset, + BufferView const & bv) { - if (iloader_->status() != WaitingToLoad) - return; + if (iloader_.status() == WaitingToLoad) + iloader_.startLoading(inset, bv); - iloader_->statusChanged.connect( - boost::bind(&Impl::statusChanged, this)); - iloader_->startLoading(); + return iloader_.image(); } -Image const * PreviewImage::Impl::image() -{ -// startLoading(); - return iloader_->image(); -} - void PreviewImage::Impl::statusChanged() { - switch (iloader_->status()) { + switch (iloader_.status()) { case WaitingToLoad: case Loading: case Converting: @@ -157,12 +145,12 @@ void PreviewImage::Impl::statusChanged() case ErrorLoading: case ErrorGeneratingPixmap: case ErrorUnknown: - //lyx::unlink(iloader_->filename()); + //lyx::unlink(iloader_.filename()); ploader_.remove(snippet_); break; case Ready: - lyx::unlink(iloader_->filename()); + lyx::unlink(iloader_.filename()); ploader_.imageReady(parent_); break; } diff --git a/src/graphics/PreviewImage.h b/src/graphics/PreviewImage.h index 67b67ed856..d0f2533f41 100644 --- a/src/graphics/PreviewImage.h +++ b/src/graphics/PreviewImage.h @@ -4,7 +4,7 @@ * Copyright 2002 the LyX Team * Read the file COPYING * - * \author Angus Leeming + * \author Angus Leeming */ #ifndef PREVIEWIMAGE_H @@ -17,6 +17,9 @@ #include "LString.h" #include +class Inset; +class BufferView; + namespace grfx { class PreviewLoader; @@ -34,9 +37,6 @@ public: /// ~PreviewImage(); - /// We are explicit about when we begin the loading process. - void startLoading(); - /// string const & snippet() const; /// @@ -45,8 +45,13 @@ public: int descent() const; /// int width() const; - /// - Image const * image() const; + + /** If the image is not yet loaded (WaitingToLoad), then this method + * triggers that. + * inset and bv are passed so we can choose to load only + * those insets that are visible. + */ + Image const * image(Inset const & inset, BufferView const & bv) const; private: /// Use the Pimpl idiom to hide the internals. diff --git a/src/graphics/PreviewLoader.C b/src/graphics/PreviewLoader.C index 79e6d866a4..887b7ccb92 100644 --- a/src/graphics/PreviewLoader.C +++ b/src/graphics/PreviewLoader.C @@ -3,7 +3,7 @@ * Copyright 2002 the LyX Team * Read the file COPYING * - * \author Angus Leeming + * \author Angus Leeming */ #include @@ -444,6 +444,7 @@ void PreviewLoader::Impl::finishedGenerating(string const & command, if (retval > 0) return; + // Paranoia check! InProgressMap::iterator git = in_progress_.find(command); if (git == in_progress_.end()) { lyxerr << "PreviewLoader::finishedGenerating(): unable to find " @@ -461,6 +462,8 @@ void PreviewLoader::Impl::finishedGenerating(string const & command, InProgressStore::const_iterator it = git->second.snippets.begin(); InProgressStore::const_iterator end = git->second.snippets.end(); + std::list newimages; + int metrics_counter = 0; for (; it != end; ++it, ++metrics_counter) { string const & snip = it->first; @@ -470,11 +473,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) { + parent_.imageReady(*nit->get()); + } } diff --git a/src/insets/ChangeLog b/src/insets/ChangeLog index 2cea2be72b..098c4d382b 100644 --- a/src/insets/ChangeLog +++ b/src/insets/ChangeLog @@ -1,3 +1,8 @@ +2002-07-12 Angus Leeming + + * insetgraphics.C: use the new smart loading capabilities of the image + loader. + 2002-07-13 Dekel Tsur * insettabular.C (edit): Move into correct cell when entering a diff --git a/src/insets/insetgraphics.C b/src/insets/insetgraphics.C index efa3112dd8..518924a72e 100644 --- a/src/insets/insetgraphics.C +++ b/src/insets/insetgraphics.C @@ -329,7 +329,7 @@ void InsetGraphics::draw(BufferView * bv, LyXFont const & font, x += lwidth; if (cache_->loader.status() == grfx::WaitingToLoad) { - cache_->loader.startLoading(); + cache_->loader.startLoading(*this, *bv); } // This will draw the graphics. If the graphics has not been loaded yet, diff --git a/src/mathed/ChangeLog b/src/mathed/ChangeLog index 38092b2a29..c814dfc410 100644 --- a/src/mathed/ChangeLog +++ b/src/mathed/ChangeLog @@ -1,3 +1,7 @@ +2002-07-12 Angus Leeming + + * formula.C: use the new smart loading capabilities of the image loader. + 2002-07-14 John Levon * mathformula.C: use Lsstream.h not sstream diff --git a/src/mathed/formula.C b/src/mathed/formula.C index d597380460..67108d39be 100644 --- a/src/mathed/formula.C +++ b/src/mathed/formula.C @@ -214,6 +214,10 @@ void InsetFormula::read(Buffer const *, LyXLex & lex) void InsetFormula::draw(BufferView * bv, LyXFont const & font, int y, float & xx, bool) const { + // This initiates the loading of the preview, so should come + // before the metrics are computed. + bool const use_preview = preview_->usePreview(); + int const x = int(xx); int const w = width(bv, font); int const d = descent(bv, font); @@ -222,9 +226,9 @@ void InsetFormula::draw(BufferView * bv, LyXFont const & font, MathPainterInfo pi(bv->painter()); - if (preview_->usePreview()) { + if (use_preview) { pi.pain.image(x + 1, y - a + 1, w - 2, h - 2, - *(preview_->pimage_->image())); + *(preview_->pimage_->image(*this, *bv))); } else { //pi.base.style = display() ? LM_ST_DISPLAY : LM_ST_TEXT; pi.base.style = LM_ST_TEXT; @@ -524,7 +528,7 @@ bool InsetFormula::PreviewImpl::usePreview() const if (!pimage_) return false; - return pimage_->image(); + return pimage_->image(parent_, *view); }