From 926abae7536ad564072163057bf8a95758d0be27 Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Sat, 17 Nov 2007 11:27:03 +0000 Subject: [PATCH] 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 --- src/BufferView.cpp | 89 ++++++++++++------------------- src/BufferView.h | 6 --- src/MetricsInfo.h | 33 +----------- src/ParagraphMetrics.cpp | 11 ++-- src/ParagraphMetrics.h | 2 +- src/Row.cpp | 15 +----- src/Row.h | 6 +-- src/Text3.cpp | 11 +--- src/TextMetrics.cpp | 39 +++++++------- src/frontends/qt4/GuiWorkArea.cpp | 11 +--- src/rowpainter.h | 1 - 11 files changed, 72 insertions(+), 152 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 124303a1b6..83ce588a8b 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -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 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 firstpm = tm.first(); - std::pair 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 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; } diff --git a/src/BufferView.h b/src/BufferView.h index 9dfe5568cf..426e8cf8a0 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -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(); diff --git a/src/MetricsInfo.h b/src/MetricsInfo.h index f1583d193c..e091dc7830 100644 --- a/src/MetricsInfo.h +++ b/src/MetricsInfo.h @@ -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 Changer { public: diff --git a/src/ParagraphMetrics.cpp b/src/ParagraphMetrics.cpp index 483620a8e7..f8901ecfc7 100644 --- a/src/ParagraphMetrics.cpp +++ b/src/ParagraphMetrics.cpp @@ -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(); } diff --git a/src/ParagraphMetrics.h b/src/ParagraphMetrics.h index 43dbd74748..53f5f4379a 100644 --- a/src/ParagraphMetrics.h +++ b/src/ParagraphMetrics.h @@ -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_; } diff --git a/src/Row.cpp b/src/Row.cpp index c965210e7a..5b3a8fc762 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -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; } diff --git a/src/Row.h b/src/Row.h index 5b67abba5e..cb25a4dcd9 100644 --- a/src/Row.h +++ b/src/Row.h @@ -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 diff --git a/src/Text3.cpp b/src/Text3.cpp index 6808b3d78e..4f68567993 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -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; diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 9b576e2a92..c54fe0e121 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -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 diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 66654b45ba..d25e9d626b 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -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(); diff --git a/src/rowpainter.h b/src/rowpainter.h index 14fe013ebb..c9bcafb723 100644 --- a/src/rowpainter.h +++ b/src/rowpainter.h @@ -31,7 +31,6 @@ class ParagraphMetrics; class Row; class Text; class TextMetrics; -class ViewMetricsInfo; namespace frontend { class Painter; } -- 2.39.5