Simplify single par drawing:

* ParagraphMetrics::computeRowSignature(): Integrate row's dimensions and selection status in the row signature.
* TextMetrics::drawParagraph(): compute the row signature here and rely on that to decide if a redraw is needed or not.
* BufferView::Private: get rid of the ViewMetricsInfo member. Just keep the ScreenUpdateStrategy.
* BufferView::draw(): full screen update even for singlePar case because the row signature will detect if something needs to be redrawn.
* Text3.cpp: get rid of hack following architecture update.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21650 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-11-17 11:27:03 +00:00
parent fd34bd3914
commit 926abae753
11 changed files with 72 additions and 152 deletions

View File

@ -210,6 +210,13 @@ void gotoInset(BufferView * bv, InsetCode code, bool same_content)
/// A map from a Text to the associated text metrics
typedef std::map<Text const *, TextMetrics> TextMetricsCache;
enum ScreenUpdateStrategy {
NoScreenUpdate,
SingleParUpdate,
FullScreenUpdate,
DecorationUpdate
};
} // anon namespace
@ -229,7 +236,7 @@ struct BufferView::Private
///
ScrollbarParameters scrollbarParameters_;
///
ViewMetricsInfo metrics_info_;
ScreenUpdateStrategy update_strategy_;
///
CoordCache coord_cache_;
@ -375,12 +382,12 @@ void BufferView::processUpdateFlags(Update::flags flags)
// Case when no explicit update is requested.
if (!flags) {
// no need to redraw anything.
d->metrics_info_.update_strategy = NoScreenUpdate;
d->update_strategy_ = NoScreenUpdate;
return;
}
if (flags == Update::Decoration) {
d->metrics_info_.update_strategy = DecorationUpdate;
d->update_strategy_ = DecorationUpdate;
buffer_.changed();
return;
}
@ -395,12 +402,12 @@ void BufferView::processUpdateFlags(Update::flags flags)
return;
}
if (flags & Update::Decoration) {
d->metrics_info_.update_strategy = DecorationUpdate;
d->update_strategy_ = DecorationUpdate;
buffer_.changed();
return;
}
// no screen update is needed.
d->metrics_info_.update_strategy = NoScreenUpdate;
d->update_strategy_ = NoScreenUpdate;
return;
}
@ -1176,7 +1183,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
//FIXME: updateMetrics() does not update paragraph position
// This is done at draw() time. So we need a redraw!
// But no screen update is needed.
d->metrics_info_.update_strategy = NoScreenUpdate;
d->update_strategy_ = NoScreenUpdate;
buffer_.changed();
p = getPos(cur, cur.boundary());
}
@ -1205,7 +1212,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
}
// FIXME: we need to do a redraw again because of the selection
// But no screen update is needed.
d->metrics_info_.update_strategy = NoScreenUpdate;
d->update_strategy_ = NoScreenUpdate;
buffer_.changed();
updateFlags = Update::Force | Update::FitCursor;
break;
@ -1334,23 +1341,10 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
if (!need_redraw)
return;
// if last metrics update was in singlepar mode, WorkArea::redraw() will
// not expose the button for redraw. We adjust here the metrics dimension
// to enable a full redraw in any case as this is not costly.
TextMetrics & tm = d->text_metrics_[&buffer_.text()];
std::pair<pit_type, ParagraphMetrics const *> firstpm = tm.first();
std::pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
int y1 = firstpm.second->position() - firstpm.second->ascent();
int y2 = lastpm.second->position() + lastpm.second->descent();
d->metrics_info_ = ViewMetricsInfo(firstpm.first, lastpm.first, y1, y2,
FullScreenUpdate, buffer_.text().paragraphs().size());
// Reinitialize anchor to first pit.
d->anchor_ref_ = firstpm.first;
d->offset_ref_ = -y1;
LYXERR(Debug::PAINTING,
"Mouse hover detected at: (" << cmd.x << ", " << cmd.y << ")"
<< "\nTriggering redraw: y1: " << y1 << " y2: " << y2
<< " pit1: " << firstpm.first << " pit2: " << lastpm.first);
LYXERR(Debug::PAINTING, "Mouse hover detected at: ("
<< cmd.x << ", " << cmd.y << ")");
d->update_strategy_ = DecorationUpdate;
// This event (moving without mouse click) is not passed further.
// This should be changed if it is further utilized.
@ -1629,12 +1623,6 @@ pit_type BufferView::anchor_ref() const
}
ViewMetricsInfo const & BufferView::viewMetricsInfo()
{
return d->metrics_info_;
}
bool BufferView::singleParUpdate()
{
Text & buftext = buffer_.text();
@ -1653,13 +1641,11 @@ bool BufferView::singleParUpdate()
// the singlePar optimisation.
return false;
int y1 = pm.position() - pm.ascent();
int y2 = pm.position() + pm.descent();
d->metrics_info_ = ViewMetricsInfo(bottom_pit, bottom_pit, y1, y2,
SingleParUpdate, buftext.paragraphs().size());
d->update_strategy_ = SingleParUpdate;
LYXERR(Debug::PAINTING, BOOST_CURRENT_FUNCTION
<< "\ny1: " << y1
<< " y2: " << y2
<< "\ny1: " << pm.position() - pm.ascent()
<< " y2: " << pm.position() + pm.descent()
<< " pit: " << bottom_pit
<< " singlepar: 1");
return true;
@ -1741,8 +1727,7 @@ void BufferView::updateMetrics()
<< " npit: " << npit
<< " singlepar: 0");
d->metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2,
FullScreenUpdate, npit);
d->update_strategy_ = FullScreenUpdate;
if (lyxerr.debugging(Debug::WORKAREA)) {
LYXERR(Debug::WORKAREA, "BufferView::updateMetrics");
@ -1928,11 +1913,10 @@ void BufferView::draw(frontend::Painter & pain)
LYXERR(Debug::PAINTING, "\t\t*** START DRAWING ***");
Text & text = buffer_.text();
TextMetrics const & tm = d->text_metrics_[&text];
int const y = d->metrics_info_.y1
+ tm.parMetrics(d->metrics_info_.p1).ascent();
int const y = - d->offset_ref_ + tm.parMetrics(d->anchor_ref_).ascent();
PainterInfo pi(this, pain);
switch (d->metrics_info_.update_strategy) {
switch (d->update_strategy_) {
case NoScreenUpdate:
// If no screen painting is actually needed, only some the different
@ -1943,9 +1927,11 @@ void BufferView::draw(frontend::Painter & pain)
break;
case SingleParUpdate:
// Only the current outermost paragraph will be redrawn.
pi.full_repaint = false;
tm.drawParagraph(pi, d->metrics_info_.p1, 0, y);
// In general, only the current row of the outermost paragraph
// will be redrawn. Particular cases where selection spans
// multiple paragraph are correctly detected in TextMetrics.
tm.draw(pi, 0, y);
break;
case DecorationUpdate:
@ -1957,21 +1943,16 @@ void BufferView::draw(frontend::Painter & pain)
// The whole screen, including insets, will be refreshed.
pi.full_repaint = true;
// Clear background (if not delegated to rows)
pain.fillRectangle(0, d->metrics_info_.y1, width_,
d->metrics_info_.y2 - d->metrics_info_.y1,
// Clear background.
pain.fillRectangle(0, 0, width_, height_,
buffer_.inset().backgroundColor());
tm.draw(pi, 0, y);
// and grey out above (should not happen later)
if (d->metrics_info_.y1 > 0)
pain.fillRectangle(0, 0, width_,
d->metrics_info_.y1, Color_bottomarea);
// and possibly grey out below
if (d->metrics_info_.y2 < height_)
pain.fillRectangle(0, d->metrics_info_.y2, width_,
height_ - d->metrics_info_.y2, Color_bottomarea);
std::pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
int const y2 = lastpm.second->position() + lastpm.second->descent();
if (y2 < height_)
pain.fillRectangle(0, y2, width_, height_ - y2, Color_bottomarea);
break;
}

View File

@ -41,7 +41,6 @@ class ParagraphMetrics;
class Point;
class Text;
class TextMetrics;
class ViewMetricsInfo;
enum CursorStatus {
CUR_INSIDE,
@ -195,11 +194,6 @@ public:
void putSelectionAt(DocIterator const & cur,
int length, bool backwards);
/// return the internal \c ViewMetricsInfo.
/// This is used specifically by the \c Workrea.
/// \sa WorkArea
/// \sa ViewMetricsInfo
ViewMetricsInfo const & viewMetricsInfo();
/// update the internal \c ViewMetricsInfo.
void updateMetrics();

View File

@ -112,38 +112,9 @@ public:
class TextMetricsInfo {};
enum ScreenUpdateStrategy {
NoScreenUpdate,
SingleParUpdate,
FullScreenUpdate,
DecorationUpdate
};
class ViewMetricsInfo
{
public:
ViewMetricsInfo()
: p1(0), p2(0), y1(0), y2(0),
update_strategy(FullScreenUpdate), size(0)
{}
ViewMetricsInfo(pit_type p1, pit_type p2, int y1, int y2,
ScreenUpdateStrategy updatestrategy, pit_type size)
: p1(p1), p2(p2), y1(y1), y2(y2),
update_strategy(updatestrategy), size(size)
{}
pit_type p1;
pit_type p2;
int y1;
int y2;
ScreenUpdateStrategy update_strategy;
pit_type size;
};
// Generic base for temporarily changing things.
// The original state gets restored when the Changer is destructed.
/// Generic base for temporarily changing things.
/// The original state gets restored when the Changer is destructed.
template <class Struct, class Temp = Struct>
class Changer {
public:

View File

@ -97,8 +97,8 @@ void ParagraphMetrics::reset(Paragraph const & par)
}
void ParagraphMetrics::computeRowSignature(Row & row,
BufferParams const & bparams)
size_t ParagraphMetrics::computeRowSignature(Row const & row,
BufferParams const & bparams) const
{
boost::crc_32_type crc;
for (pos_type i = row.pos(); i < row.endpos(); ++i) {
@ -110,7 +110,12 @@ void ParagraphMetrics::computeRowSignature(Row & row,
crc.process_bytes(b, 1);
}
}
row.setCrc(crc.checksum());
Dimension const & d = row.dimension();
char_type const b[] = { row.sel_beg, row.sel_end, d.wid, d.asc, d.des};
crc.process_bytes(b, 5);
return crc.checksum();
}

View File

@ -87,7 +87,7 @@ public:
bool hfillExpansion(Row const & row, pos_type pos) const;
///
void computeRowSignature(Row &, BufferParams const & bparams);
size_t computeRowSignature(Row const &, BufferParams const & bparams) const;
///
int position() const { return position_; }

View File

@ -35,16 +35,15 @@ Row::Row(pos_type pos)
{}
void Row::setCrc(size_type crc)
void Row::setCrc(size_type crc) const
{
changed_ |= crc != crc_;
changed_ = crc != crc_;
crc_ = crc;
}
void Row::setDimension(Dimension const & dim)
{
changed_ |= dim != dim_;
dim_ = dim;
}
@ -63,7 +62,6 @@ void Row::endpos(pos_type p)
void Row::setSelection(pos_type beg, pos_type end)
{
pos_type sel_beg_b = sel_beg;
if (pos_ >= beg && pos_ <= end)
sel_beg = pos_;
else if (beg > pos_ && beg <= end_)
@ -71,21 +69,12 @@ void Row::setSelection(pos_type beg, pos_type end)
else
sel_beg = -1;
pos_type sel_end_b = sel_end;
if (end_ >= beg && end_ <= end)
sel_end = end_;
else if (end < end_ && end >= pos_)
sel_end = end;
else
sel_end = -1;
/*
&& ((rit->pos() >= beg.pos() && rit->pos() <= end.pos())
|| (rit->endpos() >= beg.pos() && rit->endpos() <= end.pos())
|| (beg.pos() >= rit->pos() && beg.pos() <= rit->endpos())
|| (end.pos() >= rit->pos() && end.pos() <= rit->endpos()));
*/
changed_ |= sel_beg_b != sel_beg;
changed_ |= sel_end_b != sel_end;
}

View File

@ -38,7 +38,7 @@ public:
///
void setChanged(bool c) { changed_ = c; }
///
void setCrc(size_type crc);
void setCrc(size_type crc) const;
///
void setSelection(pos_type sel_beg, pos_type sel_end);
@ -80,9 +80,9 @@ public:
pos_type sel_end;
private:
/// has the Row appearance changed since last drawing?
bool changed_;
mutable bool changed_;
/// CRC of row contents.
size_type crc_;
mutable size_type crc_;
/// first pos covered by this row
pos_type pos_;
/// one behind last pos covered by this row

View File

@ -1203,17 +1203,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
// "auto_region_delete", which defaults to
// true (on).
if (lyxrc.auto_region_delete && cur.selection()) {
pit_type const begpit = cur.selBegin().pit();
pit_type const endpit = cur.selEnd().pit();
if (lyxrc.auto_region_delete && cur.selection())
cutSelection(cur, false, false);
// When a selection spans multiple paragraphs, the metrics update
// mechanism sometimes fail to detect that a full update is needed.
// In this case, we force the full update:
// (see http://bugzilla.lyx.org/show_bug.cgi?id=4317)
if (isMainText(cur.bv().buffer()) && begpit != endpit)
cur.updateFlags(Update::Force);
}
cur.clearSelection();
Font const old_font = cur.real_current_font;

View File

@ -359,7 +359,6 @@ bool TextMetrics::redoParagraph(pit_type const pit)
pm.reset(par);
Buffer & buffer = bv_->buffer();
BufferParams const & bparams = buffer.params();
main_text_ = (text_ == &buffer.text());
bool changed = false;
@ -477,7 +476,6 @@ bool TextMetrics::redoParagraph(pit_type const pit)
row.setDimension(dim);
int const max_row_width = max(dim_.wid, dim.wid);
computeRowMetrics(pit, row, max_row_width);
pm.computeRowSignature(row, bparams);
first = end;
++row_index;
@ -502,7 +500,6 @@ bool TextMetrics::redoParagraph(pit_type const pit)
row.setDimension(dim);
int const max_row_width = max(dim_.wid, dim.wid);
computeRowMetrics(pit, row, max_row_width);
pm.computeRowSignature(row, bparams);
pm.dim().des += dim.height();
}
@ -1862,7 +1859,6 @@ int TextMetrics::singleWidth(pit_type pit, pos_type pos) const
}
// only used for inset right now. should also be used for main text
void TextMetrics::draw(PainterInfo & pi, int x, int y) const
{
if (par_metrics_.empty())
@ -1888,6 +1884,7 @@ void TextMetrics::draw(PainterInfo & pi, int x, int y) const
void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) const
{
BufferParams const & bparams = bv_->buffer().params();
ParagraphMetrics const & pm = par_metrics_[pit];
if (pm.rows().empty())
return;
@ -1910,26 +1907,27 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
RowPainter rp(pi, *text_, pit, row, bidi, x, y);
// Row signature; has row changed since last paint?
row.setCrc(pm.computeRowSignature(row, bparams));
bool row_has_changed = row.changed();
bool row_selection = row.sel_beg != -1 && row.sel_end != -1;
if (!row_selection && !pi.full_repaint && !row_has_changed) {
// Paint the only the insets if the text itself is
// Don't paint the row if a full repaint has not been requested
// or if it has not changed.
if (!pi.full_repaint && !row_has_changed) {
// Paint only the insets if the text itself is
// unchanged.
rp.paintOnlyInsets();
y += row.descent();
continue;
}
// Paint the row if a full repaint has been requested or it has
// changed.
// Clear background of this row
// (if paragraph background was not cleared)
if (row_selection || (!pi.full_repaint && row_has_changed)) {
// Clear background of this row if paragraph background was not
// already cleared because of a full repaint.
if (!pi.full_repaint && row_has_changed) {
pi.pain.fillRectangle(x, y - row.ascent(),
width(), row.height(), pi.background_color);
}
bool row_selection = row.sel_beg != -1 && row.sel_end != -1;
if (row_selection) {
DocIterator beg = bv_->cursor().selectionBegin();
DocIterator end = bv_->cursor().selectionEnd();
@ -1944,13 +1942,14 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
// Instrumentation for testing row cache (see also
// 12 lines lower):
if (lyxerr.debugging(Debug::PAINTING)) {
if (text_->isMainText(bv_->buffer()))
LYXERR(Debug::PAINTING, "\n{" << inside <<
pi.full_repaint << row_has_changed << "}");
else
LYXERR(Debug::PAINTING, "[" << inside <<
pi.full_repaint << row_has_changed << "]");
if (lyxerr.debugging(Debug::PAINTING) && inside
&& (row_selection || pi.full_repaint || row_has_changed)) {
std::string const foreword = text_->isMainText(bv_->buffer()) ?
"main text redraw " : "inset text redraw: ";
LYXERR(Debug::PAINTING, foreword << "pit=" << pit << " row=" << i
<< " row_selection=" << row_selection
<< " full_repaint=" << pi.full_repaint
<< " row_has_changed=" << row_has_changed);
}
// Backup full_repaint status and force full repaint

View File

@ -320,18 +320,9 @@ void GuiWorkArea::redraw()
showCursor();
}
ViewMetricsInfo const & vi = buffer_view_->viewMetricsInfo();
LYXERR(Debug::WORKAREA, "WorkArea::redraw screen");
int const ymin = std::max(vi.y1, 0);
int const ymax = vi.p2 < vi.size - 1 ? vi.y2 : viewport()->height();
updateScreen();
update(0, ymin, viewport()->width(), ymax - ymin);
//LYXERR(Debug::WORKAREA, " ymin = " << ymin << " width() = " << width()
// << " ymax-ymin = " << ymax-ymin);
update(0, 0, viewport()->width(), viewport()->height());
if (lyxerr.debugging(Debug::WORKAREA))
buffer_view_->coordCache().dump();

View File

@ -31,7 +31,6 @@ class ParagraphMetrics;
class Row;
class Text;
class TextMetrics;
class ViewMetricsInfo;
namespace frontend { class Painter; }