]> git.lyx.org Git - lyx.git/commitdiff
Fix up a4d9315b: handle metrics of not visible paragraphs
authorJean-Marc Lasgouttes <lasgouttes@lyx.org>
Fri, 17 May 2024 13:42:08 +0000 (15:42 +0200)
committerJean-Marc Lasgouttes <lasgouttes@lyx.org>
Fri, 17 May 2024 15:39:09 +0000 (17:39 +0200)
The code is not ready for situations where some paragraphs that are
not visible have metrics available. This has been made visible by
a4d9315b, which removes a couple of full metrics updates: the screen
was not correctly scrolled after a scrollToCursor() call.

In PararagraphMetrics, some methods are added to be able to handle the
fact that paragraphs have or do not have a position.

In TextMetrics, a new method returns the first visible paragraph.

Finally, in BufferView::updateMetrics, the paragraphs' positions are
reset (in the case where everything is not cleared) and some care is
taken to skip the ones that are not relevant.

The assumption outside of this method is that all the paragraphs that
are in the TextMetrics are visible (we are talking about top-level
TextMetrics here). This could be changed (in order to avoid
recomputing paragraph metrics), but the cost is high in terms of
complexity and it is not clear that the gain in terms of performance
would be important.

src/BufferView.cpp
src/ParagraphMetrics.cpp
src/ParagraphMetrics.h
src/TextMetrics.cpp
src/TextMetrics.h

index 800801c2643ae159ebb64050fbe0630cecd8b6a0..755e2f7b4e1802defb1b6afc4517e181a0dcf22d 100644 (file)
@@ -3211,6 +3211,7 @@ void BufferView::updateMetrics(bool force)
                d->text_metrics_.clear();
        }
 
+       // This should not be moved earlier
        TextMetrics & tm = textMetrics(&buftext);
 
        // make sure inline completion pointer is ok
@@ -3226,14 +3227,16 @@ void BufferView::updateMetrics(bool force)
 
        // Check that the end of the document is not too high
        int const min_visible = lyxrc.scroll_below_document ? minVisiblePart() : height_;
-       if (tm.last().first == lastpit && tm.last().second->bottom() < min_visible) {
+       if (tm.last().first == lastpit && tm.last().second->hasPosition()
+            && tm.last().second->bottom() < min_visible) {
                d->anchor_ypos_ += min_visible - tm.last().second->bottom();
                LYXERR(Debug::SCROLLING, "Too high, adjusting anchor ypos to " << d->anchor_ypos_);
                tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
        }
 
        // Check that the start of the document is not too low
-       if (tm.first().first == 0 && tm.first().second->top() > 0) {
+       if (tm.first().first == 0 && tm.first().second->hasPosition()
+            && tm.first().second->top() > 0) {
                d->anchor_ypos_ -= tm.first().second->top();
                LYXERR(Debug::SCROLLING, "Too low, adjusting anchor ypos to " << d->anchor_ypos_);
                tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
@@ -3246,11 +3249,11 @@ void BufferView::updateMetrics(bool force)
         * extra paragraphs are removed
         */
        // Remove paragraphs that are outside of screen
-       while(tm.first().second->bottom() <= 0) {
+       while(!tm.first().second->hasPosition() || tm.first().second->bottom() <= 0) {
                //LYXERR0("Forget pit: " << tm.first().first);
                tm.forget(tm.first().first);
        }
-       while(tm.last().second->top() > height_) {
+       while(!tm.last().second->hasPosition() || tm.last().second->top() > height_) {
                //LYXERR0("Forget pit: " << tm.first().first);
                tm.forget(tm.last().first);
        }
index 31b31a2d0158a156117835fb3af784369c398acd..e1284b0e80b81c6daced3d87cf0dcb23b318621b 100644 (file)
@@ -40,9 +40,10 @@ using namespace lyx::support;
 
 namespace lyx {
 
+const int pm_npos = -10000;
 
 ParagraphMetrics::ParagraphMetrics(Paragraph const & par) :
-       position_(-1), id_(par.id()), par_(&par)
+       position_(pm_npos), id_(par.id()), par_(&par)
 {}
 
 
@@ -61,7 +62,14 @@ void ParagraphMetrics::reset(Paragraph const & par)
 {
        par_ = &par;
        dim_ = Dimension();
-       //position_ = -1;
+       //position_ = pm_npos;
+}
+
+
+int ParagraphMetrics::position() const
+{
+       LASSERT(hasPosition(), return pm_npos);
+       return position_;
 }
 
 
@@ -71,6 +79,18 @@ void ParagraphMetrics::setPosition(int position)
 }
 
 
+void ParagraphMetrics::resetPosition()
+{
+       position_ = pm_npos;
+}
+
+
+bool ParagraphMetrics::hasPosition() const
+{
+       return position_ != pm_npos;
+}
+
+
 Row const & ParagraphMetrics::getRow(pos_type pos, bool boundary) const
 {
        LBUFERR(!rows().empty());
index 805d056541cb6e8ceb0a8168f05a2a782ecadc0f..a82ebaa0416a434dfdac7bba67a91ed2fd6716c5 100644 (file)
@@ -70,8 +70,12 @@ public:
        bool hfillExpansion(Row const & row, pos_type pos) const;
 
        /// The vertical position of the baseline of the first line of the paragraph
-       int position() const { return position_; }
+       int position() const;
        void setPosition(int position);
+       /// Set poistion to unknown
+       void resetPosition();
+       /// Return true when the position of the paragraph is known
+       bool hasPosition() const;
        /// The vertical position of the top of the paragraph
        int top() const { return position_ - dim_.ascent(); }
        /// The vertical position of the bottom of the paragraph
index fe8aa4d73a71c59cda952903541bda8ec7f2008d..766f0aae24427129a9185a3e0d5a76935a80de05 100644 (file)
@@ -131,6 +131,17 @@ pair<pit_type, ParagraphMetrics const *> TextMetrics::first() const
 }
 
 
+pair<pit_type, ParagraphMetrics const *> TextMetrics::firstVisible() const
+{
+       // This only works in the main text, I think (bottom > 0)
+       LASSERT(text_->isMainText(), return first());
+       auto it = find_if(par_metrics_.begin(), par_metrics_.end(),
+                         [] (ParMetricsCache::value_type const & p) {
+                             return p.second.hasPosition() && p.second.bottom() > 0;
+                         });
+       return make_pair(it->first, &it->second);
+}
+
 pair<pit_type, ParagraphMetrics const *> TextMetrics::last() const
 {
        LBUFERR(!par_metrics_.empty());
@@ -220,7 +231,10 @@ void TextMetrics::updateMetrics(pit_type const anchor_pit, int const anchor_ypos
                                 int const bv_height)
 {
        LASSERT(text_->isMainText(), return);
-       pit_type const npit = pit_type(text_->paragraphs().size());
+
+       // Forget existing positions
+       for (auto & pm_pair : par_metrics_)
+               pm_pair.second.resetPosition();
 
        if (!contains(anchor_pit))
                // Rebreak anchor paragraph.
@@ -246,6 +260,7 @@ void TextMetrics::updateMetrics(pit_type const anchor_pit, int const anchor_ypos
        int y2 = anchor_ypos + anchor_pm.descent();
        // We are now just below the anchor paragraph.
        pit_type pit2 = anchor_pit + 1;
+       pit_type const npit = pit_type(text_->paragraphs().size());
        for (; pit2 < npit && y2 < bv_height; ++pit2) {
                if (!contains(pit2))
                        redoParagraph(pit2);
index d5606b610a396661046fd56f1a89d5d71acf895f..1a19b4293901a62da0443857be0ee17e9b908dc9 100644 (file)
@@ -50,6 +50,8 @@ public:
        ///
        std::pair<pit_type, ParagraphMetrics const *> first() const;
        ///
+       std::pair<pit_type, ParagraphMetrics const *> firstVisible() const;
+       ///
        std::pair<pit_type, ParagraphMetrics const *> last() const;
        /// is this row the last in the text?
        bool isLastRow(Row const & row) const;