]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
Rename TextMetrics::dimension() to dim()
[lyx.git] / src / TextMetrics.cpp
index a10633842189cae9284d969b4ccdc7b54455bce9..89f8d92075d5cd99a89a43a37456a921015200f7 100644 (file)
@@ -48,6 +48,7 @@
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/lassert.h"
+#include "support/lyxlib.h"
 
 #include <stdlib.h>
 #include <cmath>
@@ -61,6 +62,10 @@ using frontend::FontMetrics;
 
 namespace {
 
+// the somewhat arbitrary leading added between rows. This is 20% of
+// the characters height, inluding the possible leading of the font.
+// 20% is a standard value used by LaTeX and word processors.
+double const extra_leading = 0.2;
 
 int numberOfLabelHfills(Paragraph const & par, Row const & row)
 {
@@ -182,13 +187,21 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width,
        bool changed = false;
        unsigned int h = 0;
        for (pit_type pit = 0; pit != npar; ++pit) {
-               changed |= redoParagraph(pit);
+               // create rows, but do not set alignment yet
+               changed |= redoParagraph(pit, false);
                ParagraphMetrics const & pm = par_metrics_[pit];
                h += pm.height();
                if (dim_.wid < pm.width())
                        dim_.wid = pm.width();
        }
 
+       // Now set alignment for all rows (the width might not have been known before).
+       for (pit_type pit = 0; pit != npar; ++pit) {
+               ParagraphMetrics & pm = par_metrics_[pit];
+               for (Row & row : pm.rows())
+                       setRowAlignment(row, dim_.wid);
+       }
+
        dim_.asc = par_metrics_[0].ascent();
        dim_.des = h - dim_.asc;
        //lyxerr << "dim_.wid " << dim_.wid << endl;
@@ -354,7 +367,7 @@ bool TextMetrics::isRTLBoundary(pit_type pit, pos_type pos,
 }
 
 
-bool TextMetrics::redoParagraph(pit_type const pit)
+bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
 {
        Paragraph & par = text_->getPar(pit);
        // IMPORTANT NOTE: We pass 'false' explicitly in order to not call
@@ -474,14 +487,14 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                        /* If there is more than one row or the row has been
                         * broken by a display inset or a newline, expand the text
                         * to the full allowable width. This setting here is
-                        * needed for the computeRowMetrics() below.
+                        * needed for the setRowAlignment() below.
                         * We do nothing when inside a table cell.
                         */
                        if (dim_.wid < max_width_)
                                dim_.wid = max_width_;
                }
-               int const max_row_width = max(dim_.wid, row.width());
-               computeRowMetrics(row, max_row_width);
+               if (align_rows)
+                       setRowAlignment(row, max(dim_.wid, row.width()));
                first = row.endpos();
                ++row_index;
 
@@ -499,7 +512,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                // original value was 20px, which is 0.2in at 100dpi
                int const margin = bv_->zoomedPixels(20);
                if (pit == 0) {
-                       pm.rows().front().dimension().asc += margin;
+                       pm.rows().front().dim().asc += margin;
                        /* coverity thinks that we should update pm.dim().asc
                         * below, but all the rows heights are actually counted as
                         * part of the paragraph metric descent see loop above).
@@ -509,16 +522,16 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                }
                ParagraphList const & pars = text_->paragraphs();
                if (pit + 1 == pit_type(pars.size())) {
-                       pm.rows().back().dimension().des += margin;
+                       pm.rows().back().dim().des += margin;
                        pm.dim().des += margin;
                }
        }
 
        // The space above and below the paragraph.
        int const top = parTopSpacing(pit);
-       pm.rows().front().dimension().asc += top;
+       pm.rows().front().dim().asc += top;
        int const bottom = parBottomSpacing(pit);
-       pm.rows().back().dimension().des += bottom;
+       pm.rows().back().dim().des += bottom;
        pm.dim().des += top + bottom;
 
        pm.dim().asc += pm.rows()[0].ascent();
@@ -588,7 +601,7 @@ LyXAlignment TextMetrics::getAlign(Paragraph const & par, Row const & row) const
 }
 
 
-void TextMetrics::computeRowMetrics(Row & row, int width) const
+void TextMetrics::setRowAlignment(Row & row, int width) const
 {
        row.label_hfill = 0;
        row.separator = 0;
@@ -641,28 +654,28 @@ void TextMetrics::computeRowMetrics(Row & row, int width) const
                        if (!row.setExtraWidth(w) && row.isRTL()) {
                                // Justification failed and the text is RTL: align to the right
                                row.left_margin += w;
-                               row.dimension().wid += w;
+                               row.dim().wid += w;
                        }
                        break;
                case LYX_ALIGN_LEFT:
                        // a displayed inset that is flushed
                        if (Inset const * inset = par.getInset(row.pos())) {
                                row.left_margin += inset->indent(*bv_);
-                               row.dimension().wid += inset->indent(*bv_);
+                               row.dim().wid += inset->indent(*bv_);
                        }
                        break;
                case LYX_ALIGN_RIGHT:
                        if (Inset const * inset = par.getInset(row.pos())) {
                                int const new_w = max(w - inset->indent(*bv_), 0);
                                row.left_margin += new_w;
-                               row.dimension().wid += new_w;
+                               row.dim().wid += new_w;
                        } else {
                                row.left_margin += w;
-                               row.dimension().wid += w;
+                               row.dim().wid += w;
                        }
                        break;
                case LYX_ALIGN_CENTER:
-                       row.dimension().wid += w / 2;
+                       row.dim().wid += w / 2;
                        row.left_margin += w / 2;
                        break;
                case LYX_ALIGN_NONE:
@@ -677,7 +690,7 @@ void TextMetrics::computeRowMetrics(Row & row, int width) const
        // Case nh > 0. There are hfill separators.
        hfill = w / nh;
        hfill_rem = w % nh;
-       row.dimension().wid += w;
+       row.dim().wid += w;
        // Set size of hfill insets
        pos_type const endpos = row.endpos();
        pos_type body_pos = par.beginOfBody();
@@ -833,7 +846,7 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const
                swap(row.left_margin, row.right_margin);
        // Remember that the row width takes into account the left_margin
        // but not the right_margin.
-       row.dimension().wid = row.left_margin;
+       row.dim().wid = row.left_margin;
        // the width available for the row.
        int const width = max_width_ - row.right_margin;
 
@@ -1080,27 +1093,19 @@ void TextMetrics::setRowHeight(Row & row) const
        // 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 = fm.maxAscent() + fm.leading();
+       int maxdes = fm.maxDescent();
 
        // Find the ascent/descent of the row contents
        for (Row::Element const & e : row) {
-               if (e.inset) {
-                       maxasc = max(maxasc, e.dim.ascent());
-                       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, e.dim.ascent());
+               maxdes = max(maxdes, e.dim.descent());
        }
 
-       // This is nicer with box insets
-       ++maxasc;
-       ++maxdes;
-
-       row.dimension().asc = maxasc;
-       row.dimension().des = maxdes;
+       // Add some leading (split between before and after)
+       int const leading = support::iround(extra_leading * (maxasc + maxdes));
+       row.dim().asc = int((maxasc + leading - leading / 2) * spacing_val);
+       row.dim().des = int((maxdes + leading / 2) * spacing_val);
 }
 
 
@@ -1929,15 +1934,11 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
                rp.paintDepthBar();
                if (row.needsChangeBar())
                        rp.paintChangeBar();
-               if (i == 0 && !row.isRTL())
+               if (i == 0)
                        rp.paintFirst();
-               if (i == nrows - 1 && row.isRTL())
+               if (i == nrows - 1)
                        rp.paintLast();
                rp.paintText();
-               if (i == nrows - 1 && !row.isRTL())
-                       rp.paintLast();
-               if (i == 0 && row.isRTL())
-                       rp.paintFirst();
                rp.paintTooLargeMarks(row_x + row.left_x() < 0,
                                      row_x + row.right_x() > bv_->workWidth());
                y += row.descent();
@@ -1982,7 +1983,7 @@ void TextMetrics::completionPosAndDim(Cursor const & cur, int & x, int & y,
        row.pos(wordStart.pos());
        row.endpos(bvcur.pos());
        setRowHeight(row);
-       dim = row.dimension();
+       dim = row.dim();
 
        // get position on screen of the word start and end
        //FIXME: Is it necessary to explicitly set this to false?
@@ -2001,7 +2002,8 @@ void TextMetrics::completionPosAndDim(Cursor const & cur, int & x, int & y,
 
 int defaultRowHeight()
 {
-       return int(theFontMetrics(sane_font).maxHeight() *  1.2);
+       FontMetrics const & fm = theFontMetrics(sane_font);
+       return support::iround(fm.maxHeight() * (1 + extra_leading) + fm.leading());
 }
 
 } // namespace lyx