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
This commit is contained in:
Angus Leeming 2002-07-15 11:08:46 +00:00
parent a674f70d4a
commit 16b928088f
13 changed files with 395 additions and 117 deletions

View File

@ -1,3 +1,18 @@
2002-07-12 Angus Leeming <leeming@lyx.org>
* 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 <moz@compsoc.man.ac.uk>
* GraphicsCache.C: remove init_graphics()

View File

@ -17,10 +17,15 @@
#include "GraphicsCacheItem.h"
#include "GraphicsImage.h"
#include "GraphicsParams.h"
#include "GraphicsSupport.h"
#include "frontends/Timeout.h"
#include <boost/bind.hpp>
#include <boost/signals/trackable.hpp>
#include <list>
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<Inset const *> 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<VisibleParagraph> const & vps) : vps_(vps) {}
bool operator()(Inset const * inset_ptr)
{
if (!inset_ptr)
return false;
return isInsetVisible(*inset_ptr, vps_);
}
private:
std::list<VisibleParagraph> 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<VisibleParagraph> 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

View File

@ -31,6 +31,9 @@
#include <boost/signals/signal0.hpp>
#include <boost/scoped_ptr.hpp>
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;

View File

@ -0,0 +1,102 @@
/**
* \file GraphicsSupport.C
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming <leeming@lyx.org>
*/
#include <config.h>
#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<VisibleParagraph> 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;
}

View File

@ -0,0 +1,50 @@
// -*- C++ -*-
/**
* \file GraphicsSupport.h
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming <leeming@lyx.org>
*/
#ifndef GRAPHICSSUPPORT_H
#define GRAPHICSSUPPORT_H
#ifdef __GNUG__
#pragma interface
#endif
#include "support/types.h"
#include <list>
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<VisibleParagraph> 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<VisibleParagraph> const &);
#endif // GRAPHICSSUPPORT_H

View File

@ -23,6 +23,8 @@ libgraphics_la_SOURCES = \
GraphicsLoader.C \
$(GRAPHICSIMAGEXPM) GraphicsParams.C \
GraphicsParams.h \
GraphicsSupport.h \
GraphicsSupport.C \
GraphicsTypes.h \
PreviewImage.h \
PreviewImage.C \

View File

@ -3,7 +3,7 @@
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming <a.leeming@ic.ac.uk>
* \author Angus Leeming <leeming@lyx.org>
*/
#include <config.h>
@ -17,8 +17,6 @@
#include "GraphicsImage.h"
#include "GraphicsLoader.h"
#include "debug.h"
#include "support/lyxlib.h"
#include <boost/bind.hpp>
@ -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<Loader> 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;
}

View File

@ -4,7 +4,7 @@
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming <a.leeming@ic.ac.uk>
* \author Angus Leeming <leeming@lyx.org>
*/
#ifndef PREVIEWIMAGE_H
@ -17,6 +17,9 @@
#include "LString.h"
#include <boost/scoped_ptr.hpp>
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.

View File

@ -3,7 +3,7 @@
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming <a.leeming@ic.ac.uk>
* \author Angus Leeming <leeming@lyx.org>
*/
#include <config.h>
@ -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<PreviewImagePtr> 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<PreviewImagePtr>::const_iterator nit = newimages.begin();
std::list<PreviewImagePtr>::const_iterator nend = newimages.end();
for (; nit != nend; ++nit) {
parent_.imageReady(*nit->get());
}
}

View File

@ -1,3 +1,8 @@
2002-07-12 Angus Leeming <leeming@lyx.org>
* insetgraphics.C: use the new smart loading capabilities of the image
loader.
2002-07-13 Dekel Tsur <dekelts@tau.ac.il>
* insettabular.C (edit): Move into correct cell when entering a

View File

@ -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,

View File

@ -1,3 +1,7 @@
2002-07-12 Angus Leeming <leeming@lyx.org>
* formula.C: use the new smart loading capabilities of the image loader.
2002-07-14 John Levon <moz@compsoc.man.ac.uk>
* mathformula.C: use Lsstream.h not sstream

View File

@ -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);
}