]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
In the no-draw phase, do not cache the positions of not visible insets
[lyx.git] / src / TextMetrics.cpp
index 6fdcfe5aaf83ede405f4c43ef5fe8ed6c5dd089b..06e00f42201c90de2dfd876af30370a7ce2cdd0d 100644 (file)
@@ -520,18 +520,22 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
                        displayFont(pit, e.pos) : bufferfont;
                MacroContext mc(&buffer, parPos);
                MetricsInfo mi(bv_, font.fontInfo(), w, mc, e.pos == 0, tight_);
+               mi.base.outer_font = displayFont(pit, e.pos).fontInfo();
                e.inset->metrics(mi, dim);
-               /* FIXME: This is a kind of hack. This allows InsetMathHull to
-                * state that it needs some elbow room beyond its width, in
-                * order to fit the numbering and/or the left margin (with
-                * left alignment), which are outside of the inset itself.
+               /* FIXME: This is a hack. This allows InsetMathHull to state
+                * that it needs some elbow room beyond its width, in order to
+                * fit the numbering and/or the left margin (with left
+                * alignment), which are outside of the inset itself.
                 *
                 * To this end, InsetMathHull::metrics() sets a value in
-                * MetricsInfo::extrawidth and this value is recorded later in
-                * the corresponding row element's `extra' field. See ticket
-                * #12320 for details.
+                * MetricsInfo::extrawidth and this value is added later to
+                * the width of the row that contains the inset (when this row
+                * is tight or shorter than the max allowed width).
+                *
+                * See ticket #12320 for details.
                */
                extrawidths[e.inset] = mi.extrawidth;
+
                if (!insetCache.has(e.inset) || insetCache.dim(e.inset) != dim) {
                        insetCache.add(e.inset, dim);
                        changed = true;
@@ -539,14 +543,16 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
        }
 
        // Transform the paragraph into a single row containing all the elements.
-       Row bigrow = tokenizeParagraph(pit);
-       // Add the needed extra width to the row elements of the insets
-       for (auto & e : bigrow)
-               if (e.type == Row::INSET)
-                       e.extra = extrawidths[e.inset];
+       Row const bigrow = tokenizeParagraph(pit);
        // Split the row in several rows fitting in available width
        pm.rows() = breakParagraph(bigrow);
 
+       // Add the needed extra width to the rows that contain the insets that request it
+       for (Row & row : pm.rows())
+               for (Row::Element & e : row)
+                       if (e.type == Row::INSET && (row.width() < max_width_ || tight_))
+                               row.dim().wid += extrawidths[e.inset];
+
        /* If there is more than one row, expand the text to the full
         * allowable width. This setting here is needed for the
         * setRowAlignment() below. We do nothing when tight insets are
@@ -1150,7 +1156,7 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
                // pile, or the place when we were in main row
                Row::Element elt = *fcit;
                Row::Elements tail;
-               elt.splitAt(width - rows.back().width(), next_width, false, tail);
+               elt.splitAt(width - rows.back().width(), next_width, Row::FIT, tail);
                Row & rb = rows.back();
                if (elt.type == Row::MARGINSPACE)
                        elt.dim.wid = max(elt.dim.wid, leftMargin(bigrow.pit()) - rb.width());
@@ -1175,6 +1181,9 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
                // Last row in paragraph is flushed
                rows.back().flushed(true);
                cleanupRow(rows.back(), true);
+               // Is there an end-of-paragraph change?
+               if (bigrow.needsChangeBar())
+                       rows.back().needsChangeBar(true);
        }
 
        return rows;
@@ -1286,20 +1295,39 @@ void TextMetrics::setRowHeight(Row & row) const
 {
        Paragraph const & par = text_->getPar(row.pit());
        Layout const & layout = par.layout();
-       double const spacing_val = layout.spacing.getValue() * text_->spacing(par);
+       // leading space (line spacing) factor based on current paragraph
+       double spacing_val = layout.spacing.getValue() * text_->spacing(par);
+
+       // if this is the first row but not the first paragraph, take into
+       // account the spacing of the previous paragraph.
+       if (row.pos() == 0 && row.pit() > 0) {
+               // for the first row in the paragraph,
+               // use previous paragraphs line spacing if it is larger
+               Paragraph const & previousPar = text_->getPar(row.pit() - 1);
+               Layout const & previousLayout = previousPar.layout();
+               // leading space factor based on previous paragraph
+               double const previous_spacing_val
+                       = previousLayout.spacing.getValue() * text_->spacing(previousPar);
+               if (previous_spacing_val > spacing_val)
+                       spacing_val = previous_spacing_val;
+       }
 
        // Initial value for ascent (useful if row is empty).
        Font const font = displayFont(row.pit(), row.pos());
        FontMetrics const & fm = theFontMetrics(font);
-       int maxasc = int(fm.maxAscent() * spacing_val);
-       int maxdes = int(fm.maxDescent() * spacing_val);
+       int maxasc = int(fm.maxAscent()
+               // add leading space
+               + fm.maxHeight() * (spacing_val - 1));
+       int maxdes = int(fm.maxDescent());
 
        // Take label string into account (useful if labelfont is large)
        if (row.pos() == 0 && layout.labelIsInline()) {
                FontInfo const labelfont = text_->labelFont(par);
                FontMetrics const & lfm = theFontMetrics(labelfont);
-               maxasc = max(maxasc, int(lfm.maxAscent() * spacing_val));
-               maxdes = max(maxdes, int(lfm.maxDescent() * spacing_val));
+               maxasc = max(maxasc, int(lfm.maxAscent()
+                       // add leading space
+                       + lfm.maxHeight() * (spacing_val - 1)));
+               maxdes = max(maxdes, int(lfm.maxDescent()));
        }
 
        // Find the ascent/descent of the row contents
@@ -1309,8 +1337,10 @@ void TextMetrics::setRowHeight(Row & row) const
                        maxdes = max(maxdes, e.dim.descent());
                } else {
                        FontMetrics const & fm2 = theFontMetrics(e.font);
-                       maxasc = max(maxasc, int(fm2.maxAscent() * spacing_val));
-                       maxdes = max(maxdes, int(fm2.maxDescent() * spacing_val));
+                       maxasc = max(maxasc, int(fm2.maxAscent()
+                               // add leading space
+                               + fm2.maxHeight() * (spacing_val - 1)));
+                       maxdes = max(maxdes, int(fm2.maxDescent()));
                }
        }
 
@@ -1426,7 +1456,7 @@ pit_type TextMetrics::getPitNearY(int y)
 {
        LASSERT(!text_->paragraphs().empty(), return -1);
        LASSERT(!par_metrics_.empty(), return -1);
-       LYXERR(Debug::DEBUG, "y: " << y << " cache size: " << par_metrics_.size());
+       LYXERR(Debug::PAINTING, "y: " << y << " cache size: " << par_metrics_.size());
 
        // look for highest numbered paragraph with y coordinate less than given y
        pit_type pit = -1;
@@ -1467,7 +1497,7 @@ pit_type TextMetrics::getPitNearY(int y)
        }
 
        for (; it != et; ++it) {
-               LYXERR(Debug::DEBUG, "examining: pit: " << it->first
+               LYXERR(Debug::PAINTING, "examining: pit: " << it->first
                        << " y: " << it->second.position());
 
                ParagraphMetrics const & pm2 = par_metrics_[it->first];
@@ -1478,7 +1508,7 @@ pit_type TextMetrics::getPitNearY(int y)
                }
        }
 
-       LYXERR(Debug::DEBUG, "found best y: " << yy << " for pit: " << pit);
+       LYXERR(Debug::PAINTING, "found best y: " << yy << " for pit: " << pit);
 
        return pit;
 }
@@ -1592,7 +1622,7 @@ void TextMetrics::setCursorFromCoordinates(Cursor & cur, int const x, int const
        ParagraphMetrics const & pm = par_metrics_[pit];
 
        int yy = pm.position() - pm.rows().front().ascent();
-       LYXERR(Debug::DEBUG, "x: " << x << " y: " << y <<
+       LYXERR(Debug::PAINTING, "x: " << x << " y: " << y <<
                " pit: " << pit << " yy: " << yy);
 
        int r = 0;
@@ -1606,13 +1636,13 @@ void TextMetrics::setCursorFromCoordinates(Cursor & cur, int const x, int const
 
        Row const & row = pm.rows()[r];
 
-       LYXERR(Debug::DEBUG, "row " << r << " from pos: " << row.pos());
+       LYXERR(Debug::PAINTING, "row " << r << " from pos: " << row.pos());
 
        bool bound = false;
        int xx = x;
        pos_type const pos = getPosNearX(row, xx, bound);
 
-       LYXERR(Debug::DEBUG, "setting cursor pit: " << pit << " pos: " << pos);
+       LYXERR(Debug::PAINTING, "setting cursor pit: " << pit << " pos: " << pos);
 
        text_->setCursor(cur, pit, pos, true, bound);
        // remember new position.
@@ -1626,18 +1656,18 @@ InsetList::Element * TextMetrics::checkInsetHit(pit_type pit, int x, int y)
        Paragraph const & par = text_->paragraphs()[pit];
        CoordCache::Insets const & insetCache = bv_->coordCache().getInsets();
 
-       LYXERR(Debug::DEBUG, "x: " << x << " y: " << y << "  pit: " << pit);
+       LYXERR(Debug::PAINTING, "x: " << x << " y: " << y << "  pit: " << pit);
 
        for (InsetList::Element const & e : par.insetList()) {
-               LYXERR(Debug::DEBUG, "examining inset " << e.inset);
+               LYXERR(Debug::PAINTING, "examining inset " << e.inset);
 
                if (insetCache.covers(e.inset, x, y)) {
-                       LYXERR(Debug::DEBUG, "Hit inset: " << e.inset);
+                       LYXERR(Debug::PAINTING, "Hit inset: " << e.inset);
                        return const_cast<InsetList::Element *>(&e);
                }
        }
 
-       LYXERR(Debug::DEBUG, "No inset hit. ");
+       LYXERR(Debug::PAINTING, "No inset hit. ");
        return nullptr;
 }
 
@@ -1970,6 +2000,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
        if (pm.rows().empty())
                return;
        size_t const nrows = pm.rows().size();
+       int const wh = bv_->workHeight();
        // Remember left and right margin for drawing math numbers
        Changer changeleft = changeVar(pi.leftx, x + leftMargin(pit));
        Changer changeright = changeVar(pi.rightx, x + width() - rightMargin(pit));
@@ -1984,15 +2015,17 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
                        if (i)
                                y += row.ascent();
 
-                       RowPainter rp(pi, *text_, row, row_x, y);
-
-                       rp.paintOnlyInsets();
+                       // It is not needed to draw on screen if we are not inside
+                       bool const inside = (y + row.descent() >= 0 && y - row.ascent() < wh);
+                       if (inside) {
+                               RowPainter rp(pi, *text_, row, row_x, y);
+                               rp.paintOnlyInsets();
+                       }
                        y += row.descent();
                }
                return;
        }
 
-       int const ww = bv_->workHeight();
        Cursor const & cur = bv_->cursor();
        DocIterator sel_beg = cur.selectionBegin();
        DocIterator sel_end = cur.selectionEnd();
@@ -2035,7 +2068,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
 
                // It is not needed to draw on screen if we are not inside.
                bool const inside = (y + row.descent() >= 0
-                       && y - row.ascent() < ww);
+                       && y - row.ascent() < wh);
                if (!inside) {
                        // Inset positions have already been set in nodraw stage.
                        y += row.descent();