Transfer ParagraphMetrics::rowChangeStatus() to Row::changed(). Prepare for fine grained row redrawing.

^ Row:
- changed_: new boolean to inform change status at draw time.
- crc_: new crc_ signature
- inline pos() and endpos()
- replace width(), ascent() and descent() direct access with dimension().

* ParagraphMetrics
- do not maintain row_signature_ anymore
- rename calculateRowSignature() to computeRowSignature() and make it public

* TextMetrics
- redoParagraph(): don't clear the ParagraphMetrics row list, reuse and update it.
- rowHeight(), rowWidth(), rowBreakPoint(): take first/end positions instead of Row.





git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19895 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-08-29 21:03:41 +00:00
parent 8a947f63da
commit 8175971041
6 changed files with 114 additions and 120 deletions

View File

@ -94,7 +94,7 @@ void ParagraphMetrics::reset(Paragraph const & par)
}
size_type ParagraphMetrics::calculateRowSignature(Row const & row,
void ParagraphMetrics::computeRowSignature(Row & row,
BufferParams const & bparams)
{
boost::crc_32_type crc;
@ -107,22 +107,7 @@ size_type ParagraphMetrics::calculateRowSignature(Row const & row,
crc.process_bytes(b, 1);
}
}
return crc.checksum();
}
void ParagraphMetrics::updateRowChangeStatus(BufferParams const & bparams)
{
size_t const size = rows_.size();
row_change_status_.resize(size);
row_signature_.resize(size);
for (size_t i = 0; i != size; ++i) {
// Row signature; has row changed since last update?
size_type const row_sig = calculateRowSignature(rows_[i], bparams);
row_change_status_[i] = row_signature_[i] != row_sig;
row_signature_[i] = row_sig;
}
row.setCrc(crc.checksum());
}

View File

@ -40,9 +40,6 @@ public:
ParagraphMetrics(Paragraph const & par);
/// Copy operator.
/// Important note: We don't copy \c row_change_status_ and
/// \c row_signature_ because those are updated externally with
/// \c updateRowChangeStatus() in TextMetrics::redoParagraph().
ParagraphMetrics & operator=(ParagraphMetrics const &);
void reset(Paragraph const & par);
@ -69,11 +66,6 @@ public:
RowList & rows() { return rows_; }
/// The painter and others use this
RowList const & rows() const { return rows_; }
/// The painter and others use this
std::vector<bool> const & rowChangeStatus() const
{ return row_change_status_; }
///
void updateRowChangeStatus(BufferParams const & bparams);
///
int rightMargin(Buffer const & buffer) const;
///
@ -81,18 +73,12 @@ public:
/// dump some information to lyxerr
void dump() const;
///
void computeRowSignature(Row &, BufferParams const & bparams);
private:
///
typedef std::vector<size_type> RowSignature;
///
size_type calculateRowSignature(Row const &, BufferParams const & bparams);
///
mutable RowList rows_;
///
RowSignature row_signature_;
///
std::vector<bool> row_change_status_;
/// cached dimensions of paragraph
Dimension dim_;
///

View File

@ -24,39 +24,45 @@ namespace lyx {
Row::Row()
: pos_(0), end_(0), separator(0), hfill(0), label_hfill(0), x(0)
: changed_(false), crc_(0), pos_(0), end_(0), separator(0), hfill(0),
label_hfill(0), x(0)
{}
Row::Row(pos_type pos)
: pos_(pos), end_(0), separator(0), hfill(0), label_hfill(0), x(0)
: changed_(false), crc_(0), pos_(pos), end_(0), separator(0), hfill(0),
label_hfill(0), x(0)
{}
void Row::setCrc(size_type crc)
{
changed_ |= crc != crc_;
crc_ = crc;
}
void Row::setDimension(Dimension const & dim)
{
changed_ |= dim != dim_;
dim_ = dim;
}
void Row::pos(pos_type p)
{
changed_ |= p != pos_;
pos_ = p;
}
pos_type Row::pos() const
{
return pos_;
}
void Row::endpos(pos_type p)
{
changed_ |= p != end_;
end_ = p;
}
pos_type Row::endpos() const
{
return end_;
}
void Row::dump(const char * s) const
{
lyxerr << s << " pos: " << pos_ << " end: " << end_

View File

@ -34,29 +34,30 @@ public:
///
Row(pos_type pos);
///
bool changed() const { return changed_; }
///
void setCrc(size_type crc);
///
void pos(pos_type p);
///
pos_type pos() const;
pos_type pos() const { return pos_; }
///
void endpos(pos_type p);
///
pos_type endpos() const;
pos_type endpos() const { return end_; }
///
void setDimension(Dimension const & dim);
///
Dimension const & dimension() const { return dim_; }
///
int height() const { return dim_.height(); }
///
void width(int w) { dim_.wid = w; }
///
int width() const { return dim_.wid; }
///
void ascent(int a) { dim_.asc = a; }
///
int ascent() const { return dim_.asc; }
///
void descent(int d) { dim_.des = d; }
///
int descent() const { return dim_.des; }
/// current debugging only
void dump(const char * = "") const;
@ -70,6 +71,10 @@ public:
double x;
private:
/// has the Row appearance changed since last drawing?
bool changed_;
/// CRC of row contents.
size_type crc_;
/// first pos covered by this row
pos_type pos_;
/// one behind last pos covered by this row

View File

@ -193,6 +193,7 @@ 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;
@ -234,31 +235,45 @@ bool TextMetrics::redoParagraph(pit_type const pit)
}
par.setBeginOfBody();
pos_type z = 0;
pos_type first = 0;
size_t row_index = 0;
// maximum pixel width of a row
int width = max_width_ - right_margin; // - leftMargin(buffer, max_width_, pit, row);
do {
Row row(z);
rowBreakPoint(width, pit, row);
setRowWidth(right_margin, pit, row);
setHeightOfRow(pit, row);
Dimension dim;
pos_type end = rowBreakPoint(width, pit, first);
dim.wid = rowWidth(right_margin, pit, first, end);
boost::tie(dim.asc, dim.des) = rowHeight(pit, first, end);
if (row_index == pm.rows().size())
pm.rows().push_back(Row());
Row & row = pm.rows()[row_index];
row.pos(first);
row.endpos(end);
row.setDimension(dim);
computeRowMetrics(pit, row);
pm.rows().push_back(row);
pm.dim().wid = std::max(pm.dim().wid, row.width());
pm.dim().des += row.height();
z = row.endpos();
} while (z < par.size());
pm.computeRowSignature(row, bparams);
first = end;
++row_index;
pm.dim().wid = std::max(pm.dim().wid, dim.wid);
pm.dim().des += dim.height();
} while (first < par.size());
// Make sure that if a par ends in newline, there is one more row
// under it
if (z > 0 && par.isNewline(z - 1)) {
Row row(z);
row.endpos(z);
setRowWidth(right_margin, pit, row);
setHeightOfRow(pit, row);
if (first > 0 && par.isNewline(first - 1)) {
Dimension dim;
dim.wid = rowWidth(right_margin, pit, first, first);
boost::tie(dim.asc, dim.des) = rowHeight(pit, first, first);
if (row_index == pm.rows().size())
pm.rows().push_back(Row());
Row & row = pm.rows()[row_index];
row.pos(first);
row.endpos(first);
row.setDimension(dim);
computeRowMetrics(pit, row);
pm.rows().push_back(row);
pm.dim().des += row.height();
pm.computeRowSignature(row, bparams);
pm.dim().des += dim.height();
}
pm.dim().asc += pm.rows()[0].ascent();
@ -266,10 +281,6 @@ bool TextMetrics::redoParagraph(pit_type const pit)
changed |= old_dim.height() != pm.dim().height();
// Update the row change statuses. The painter will need that info
// in order to know which row has to be repainted.
pm.updateRowChangeStatus(bv_->buffer().params());
return changed;
}
@ -451,30 +462,20 @@ int TextMetrics::labelEnd(pit_type const pit) const
}
void TextMetrics::rowBreakPoint(int width, pit_type const pit,
Row & row) const
pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
pit_type pos) const
{
Buffer & buffer = bv_->buffer();
ParagraphMetrics const & pm = par_metrics_[pit];
Paragraph const & par = text_->getPar(pit);
pos_type const end = par.size();
pos_type const pos = row.pos();
if (pos == end) {
row.endpos(end);
return;
}
if (width < 0) {
row.endpos(end);
return;
}
if (pos == end || width < 0)
return end;
LayoutPtr const & layout = par.layout();
if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
row.endpos(addressBreakPoint(pos, par));
return;
}
if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX)
return addressBreakPoint(pos, par);
pos_type const body_pos = par.beginOfBody();
@ -563,23 +564,22 @@ void TextMetrics::rowBreakPoint(int width, pit_type const pit,
if (body_pos && point < body_pos)
point = body_pos;
row.endpos(point);
return point;
}
void TextMetrics::setRowWidth(int right_margin,
pit_type const pit, Row & row) const
int TextMetrics::rowWidth(int right_margin, pit_type const pit,
pos_type const first, pos_type const end) const
{
Buffer & buffer = bv_->buffer();
// get the pure distance
pos_type const end = row.endpos();
ParagraphMetrics const & pm = par_metrics_[pit];
Paragraph const & par = text_->getPar(pit);
int w = text_->leftMargin(buffer, max_width_, pit, row.pos());
int w = text_->leftMargin(buffer, max_width_, pit, first);
int label_end = labelEnd(pit);
pos_type const body_pos = par.beginOfBody();
pos_type i = row.pos();
pos_type i = first;
if (i < end) {
FontIterator fi = FontIterator(buffer, *text_, par, i);
@ -605,12 +605,12 @@ void TextMetrics::setRowWidth(int right_margin,
w = max(w, label_end);
}
row.width(w + right_margin);
return w + right_margin;
}
void TextMetrics::setHeightOfRow(pit_type const pit,
Row & row)
boost::tuple<int, int> TextMetrics::rowHeight(pit_type const pit, pos_type const first,
pos_type const end) const
{
Paragraph const & par = text_->getPar(pit);
// get the maximum ascent and the maximum descent
@ -628,7 +628,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
// start with so we don't have to do the assignment below too
// often.
Buffer const & buffer = bv_->buffer();
Font font = text_->getFont(buffer, par, row.pos());
Font font = text_->getFont(buffer, par, first);
Font::FONT_SIZE const tmpsize = font.size();
font = text_->getLayoutFont(buffer, pit);
Font::FONT_SIZE const size = font.size();
@ -650,7 +650,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
InsetList::const_iterator ii = par.insetlist.begin();
InsetList::const_iterator iend = par.insetlist.end();
for ( ; ii != iend; ++ii) {
if (ii->pos >= row.pos() && ii->pos < row.endpos()) {
if (ii->pos >= first && ii->pos < end) {
maxasc = max(maxasc, ii->inset->ascent());
maxdesc = max(maxdesc, ii->inset->descent());
}
@ -660,10 +660,9 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
// This is not completely correct, but we can live with the small,
// cosmetic error for now.
int labeladdon = 0;
pos_type const pos_end = row.endpos();
Font::FONT_SIZE maxsize =
par.highestFontInRange(row.pos(), pos_end, size);
par.highestFontInRange(first, end, size);
if (maxsize > font.size()) {
// use standard paragraph font with the maximal size
Font maxfont = font;
@ -677,11 +676,10 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
++maxasc;
++maxdesc;
row.ascent(maxasc);
ParagraphList const & pars = text_->paragraphs();
// is it a top line?
if (row.pos() == 0) {
if (first == 0) {
BufferParams const & bufparams = buffer.params();
// some parskips VERY EASY IMPLEMENTATION
if (bufparams.paragraph_separation
@ -734,7 +732,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
&& prevpar.getLabelWidthString()
== par.getLabelWidthString()) {
layoutasc = layout->itemsep * dh;
} else if (pit != 0 || row.pos() != 0) {
} else if (pit != 0 || first != 0) {
if (layout->topsep > 0)
layoutasc = layout->topsep * dh;
}
@ -752,7 +750,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
}
// is it a bottom line?
if (row.endpos() >= par.size()) {
if (end >= par.size()) {
// add the layout spaces, for example before and after
// a section, or between the items of a itemize or enumerate
// environment
@ -788,16 +786,15 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
// main Text. The following test is thus bogus.
// Top and bottom margin of the document (only at top-level)
if (main_text_) {
if (pit == 0 && row.pos() == 0)
if (pit == 0 && first == 0)
maxasc += 20;
if (pit + 1 == pit_type(pars.size()) &&
row.endpos() == par.size() &&
!(row.endpos() > 0 && par.isNewline(row.endpos() - 1)))
end == par.size() &&
!(end > 0 && par.isNewline(end - 1)))
maxdesc += 20;
}
row.ascent(maxasc + labeladdon);
row.descent(maxdesc);
return boost::make_tuple(maxasc + labeladdon, maxdesc);
}
@ -997,11 +994,10 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y,
Bidi bidi;
y -= rb->ascent();
size_type rowno = 0;
for (RowList::const_iterator rit = rb; rit != re; ++rit, ++rowno) {
for (RowList::const_iterator rit = rb; rit != re; ++rit) {
y += rit->ascent();
// Row signature; has row changed since last paint?
bool row_has_changed = pm.rowChangeStatus()[rowno];
bool row_has_changed = rit->changed();
// Paint the row if a full repaint has been requested or it has
// changed.

View File

@ -18,6 +18,9 @@
#include "support/types.h"
#include <boost/utility.hpp>
#include <boost/tuple/tuple.hpp>
#include <map>
@ -91,13 +94,26 @@ private:
/// sets row.end to the pos value *after* which a row should break.
/// for example, the pos after which isNewLine(pos) == true
void rowBreakPoint(int width, pit_type const pit, Row & row) const;
pit_type rowBreakPoint(
int width,
pit_type const pit,
pit_type first
) const;
/// sets row.width to the minimum space a row needs on the screen in pixel
void setRowWidth(int right_margin, pit_type const pit, Row & row) const;
int rowWidth(
int right_margin,
pit_type const pit,
pos_type const first,
pos_type const end
) const;
/// Calculate and set the height of the row
void setHeightOfRow(pit_type, Row & row);
boost::tuple<int, int> rowHeight(
pit_type const pit,
pos_type const first,
pos_type const end
) const;
// Temporary public:
public: