]> git.lyx.org Git - features.git/commitdiff
Improve support for on screen length calculation
authorJean-Marc Lasgouttes <lasgouttes@lyx.org>
Thu, 26 Mar 2015 15:55:19 +0000 (16:55 +0100)
committerJean-Marc Lasgouttes <lasgouttes@lyx.org>
Thu, 26 Mar 2015 16:10:15 +0000 (17:10 +0100)
The computation of length on screen depend in particular of the computation of the size of an em. Many places of the code used to rely on the width of the M character, which is not really correct:
http://en.wikipedia.org/wiki/Em_%28typography%29

In digital typography, the best value to use is the point size of the font.

* Implement FontMetrics::em(), which returns the value in pixels of the EM unit.
 Convert code to use it.

* Introduce Length::inPixel(MetricsBase const &), which takes the textwidth and em information from the MetricsBase object. Convert code to use it.

* Fix several places where Length::inPixel is used without a proper em value.

* add mathed_font_em() helper function. It should eventually be removed like some other functions in MathSupport.

* Add dummy implementation of FontMetrics to tex2lyx for linking purposes.

20 files changed:
src/BufferView.cpp
src/Length.cpp
src/Length.h
src/TextMetrics.cpp
src/frontends/FontMetrics.h
src/frontends/qt4/GuiFontMetrics.cpp
src/frontends/qt4/GuiFontMetrics.h
src/insets/InsetBox.cpp
src/insets/InsetLine.cpp
src/insets/InsetSpace.cpp
src/insets/InsetSpecialChar.cpp
src/insets/InsetTabular.cpp
src/mathed/InsetMathChar.cpp
src/mathed/InsetMathGrid.cpp
src/mathed/InsetMathKern.cpp
src/mathed/InsetMathSpace.cpp
src/mathed/InsetMathSymbol.cpp
src/mathed/MathSupport.cpp
src/mathed/MathSupport.h
src/tex2lyx/dummy_impl.cpp

index 77750d87e3111e898f2f4ad8948e6b507f153e70..8948b73d2de8b2d082807652a7069d802625336c 100644 (file)
@@ -3000,7 +3000,7 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi)
 
        // Horizontal scroll offset of the cursor row in pixels
        int offset = d->horiz_scroll_offset_;
-       int const MARGIN = Length(2, Length::EM).inPixels(workWidth());
+       int const MARGIN = Length(2, Length::EM).inPixels(pi.base);
        if (cur_x < offset + MARGIN) {
                // scroll right
                offset = cur_x - MARGIN;
index 0deed7481c915f3e2e70b6f2f100c80d7d993d64..2463be8f66c889d37810e907fddbc37d67b5f842 100644 (file)
@@ -17,6 +17,9 @@
 
 #include "Length.h"
 #include "LyXRC.h"
+#include "MetricsInfo.h"
+
+#include "frontends/FontMetrics.h"
 
 #include "support/docstream.h"
 
@@ -197,7 +200,7 @@ int Length::inPixels(int text_width, int em_width_base) const
                ? em_width_base
                : 10*(dpi/72.27)*zoom;
        // A different estimate for em_width is
-       // theFontMetrics(FontInfo(sane_font)).width('M')
+       // theFontMetrics(FontInfo(sane_font)).em()
        // but this estimate might not be more accurate as the screen font
        // is different then the latex font.
 
@@ -288,6 +291,12 @@ int Length::inPixels(int text_width, int em_width_base) const
 }
 
 
+int Length::inPixels(MetricsBase const & base) const
+{
+       return inPixels(base.textwidth, theFontMetrics(base.font).em());
+}
+
+
 int Length::inBP() const
 {
        // return any Length value as a one with
index 435eea053576ab397c2d620edbee03102340e01d..ef17bac760671d55c933f27e92451cc19064eee7 100644 (file)
@@ -20,6 +20,8 @@
 
 namespace lyx {
 
+class MetricsBase;
+
 // Solaris/x86 version 9 and earlier define these
 #undef PC
 #undef SP
@@ -87,8 +89,18 @@ public:
        std::string const asLatexString() const;
        /// return string representation for HTML
        std::string const asHTMLString() const;
-       /// return the on-screen size of this length
+       /** return the on-screen size of this length.
+        *
+        *      If the second argument is not provided, then the unit EM will
+        *      only be approximated. It is better if possible to use
+        *      FontMetrics::em() to get this value.
+        */
        int inPixels(int text_width, int em_width = 0) const;
+       /** return the on-screen size of this length
+        *
+        *  This version of the function uses the right EM definition.
+        */
+       int inPixels(MetricsBase const &) const;
        /// return the value in Big Postscript points.
        int inBP() const;
 
index afc7f4ebdc99e774f1171aee7654f37cd49def82..33baa8cafd0940c49d3dd1bb9fd6ed94489cd73e 100644 (file)
@@ -1736,7 +1736,7 @@ int TextMetrics::leftMargin(int max_width,
        }
 
        if (!par.params().leftIndent().zero())
-               l_margin += par.params().leftIndent().inPixels(max_width);
+               l_margin += par.params().leftIndent().inPixels(max_width, labelfont_metrics.em());
 
        LyXAlignment align;
 
index 56e47eaeabbbc5473958332c6d3f841306cb67a9..53f57a2880075b513d35aff12fd674f2319b7c6e 100644 (file)
@@ -63,6 +63,9 @@ public:
        /// return default dimension of the font.
        /// \warning \c width is set to zero.
        virtual Dimension const defaultDimension() const = 0;
+       /// return the em size
+       virtual int em() const = 0;
+
        /// return the width of the char in the font
        virtual int width(char_type c) const = 0;
        /// return the ascent of the char in the font
index f3a4c0fab79999a6ea63371e4fb65e0ce1fbd5fc..b488b684eb70702216fd85204e8a398acd3b6e51 100644 (file)
@@ -72,6 +72,12 @@ int GuiFontMetrics::maxDescent() const
 }
 
 
+int GuiFontMetrics::em() const
+{
+       return QFontInfo(font_).pixelSize();
+}
+
+
 int GuiFontMetrics::lbearing(char_type c) const
 {
        if (!is_utf16(c))
index ac1e71419d126df186f879ae5c0ccc7be95ea6f9..7555929c9b14da3319e985e3c82f7a4e954d5c11 100644 (file)
@@ -35,6 +35,7 @@ public:
        virtual int maxAscent() const;
        virtual int maxDescent() const;
        virtual Dimension const defaultDimension() const;
+       virtual int em() const;
        virtual int width(char_type c) const;
        virtual int ascent(char_type c) const;
        virtual int descent(char_type c) const;
index c96a7c9e7d11375d5a2fac0ec9537743a63fe0c1..de1c7fd5823a1d66b495637a0fca38691e0691b2 100644 (file)
@@ -171,7 +171,7 @@ void InsetBox::metrics(MetricsInfo & m, Dimension & dim) const
        // back up textwidth.
        int textwidth_backup = m.base.textwidth;
        if (hasFixedWidth())
-               m.base.textwidth = params_.width.inPixels(m.base.textwidth);
+               m.base.textwidth = params_.width.inPixels(m.base);
        InsetCollapsable::metrics(m, dim);
        // retore textwidth.
        m.base.textwidth = textwidth_backup;
index 82960b262e338ffa118bed2d04c035fac6aaefb1..8b80f0d3ecbd29d96ae02bf665e030ae4e0109a1 100644 (file)
@@ -111,7 +111,7 @@ void InsetLine::metrics(MetricsInfo & mi, Dimension & dim) const
        int const max_width = mi.base.textwidth;
 
        Length const width(to_ascii(getParam("width")));
-       dim.wid = width.inPixels(max_width, fm.width(char_type('M')));
+       dim.wid = width.inPixels(mi.base);
 
        // assure that the line inset is not outside of the window
        // check that it doesn't exceed the outer boundary
@@ -123,11 +123,11 @@ void InsetLine::metrics(MetricsInfo & mi, Dimension & dim) const
        dim.wid = max(minw, abs(dim.wid));
 
        Length height = Length(to_ascii(getParam("height")));
-       height_ = height.inPixels(max_width, fm.width(char_type('M')));
+       height_ = height.inPixels(mi.base);
 
        // get the length of the parameters in pixels
        Length offset = Length(to_ascii(getParam("offset")));
-       offset_ = offset.inPixels(max_width, fm.width(char_type('M')));
+       offset_ = offset.inPixels(mi.base);
 
        dim.asc = max(fm.maxAscent(), offset_ + height_);
        dim.des = max(fm.maxDescent(), - offset_);
index 8f746f5e310f7f36590626969c41e4b04383d522..839ccc917b194e64b7f9912bb22c418744772d0d 100644 (file)
@@ -209,19 +209,20 @@ void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
        frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
        dim.asc = fm.maxAscent();
        dim.des = fm.maxDescent();
+       int const em = fm.em();
 
        switch (params_.kind) {
                case InsetSpaceParams::THIN:
                case InsetSpaceParams::NEGTHIN:
-                       dim.wid = fm.width(char_type('M')) / 6;
+                       dim.wid = em / 6;
                        break;
                case InsetSpaceParams::MEDIUM:
                case InsetSpaceParams::NEGMEDIUM:
-                       dim.wid = fm.width(char_type('M')) / 4;
+                       dim.wid = em / 4;
                        break;
                case InsetSpaceParams::THICK:
                case InsetSpaceParams::NEGTHICK:
-                       dim.wid = fm.width(char_type('M')) / 2;
+                       dim.wid = em / 2;
                        break;
                case InsetSpaceParams::PROTECTED:
                case InsetSpaceParams::VISIBLE:
@@ -229,20 +230,19 @@ void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
                        dim.wid = fm.width(char_type(' '));
                        break;
                case InsetSpaceParams::QUAD:
-                       dim.wid = fm.width(char_type('M'));
+                       dim.wid = em;
                        break;
                case InsetSpaceParams::QQUAD:
-                       dim.wid = 2 * fm.width(char_type('M'));
+                       dim.wid = 2 * em;
                        break;
                case InsetSpaceParams::ENSPACE:
                case InsetSpaceParams::ENSKIP:
-                       dim.wid = int(0.5 * fm.width(char_type('M')));
+                       dim.wid = int(0.5 * em);
                        break;
                case InsetSpaceParams::CUSTOM:
                case InsetSpaceParams::CUSTOM_PROTECTED: {
                        int const w =
-                               params_.length.len().inPixels(mi.base.textwidth,
-                                                       fm.width(char_type('M')));
+                               params_.length.len().inPixels(mi.base);
                        int const minw = (w < 0) ? 3 * arrow_size : 4;
                        dim.wid = max(minw, abs(w));
                        break;
index 8a52f166fc011cac31b0f2c34324c572cc23df76..99ac836916e69ffe20fcba5bb89042181f930779 100644 (file)
@@ -47,7 +47,7 @@ namespace {
 
 int logoWidth(FontInfo const & font, InsetSpecialChar::Kind kind) {
        frontend::FontMetrics const & fm = theFontMetrics(font);
-       int const em = fm.width('M');
+       int const em = fm.em();
        int width = 0;
        // See drawlogo() below to understand what this does.
        switch (kind) {
@@ -137,9 +137,7 @@ namespace {
 
 void drawLogo(PainterInfo & pi, InsetSpecialChar::Kind kind, int & x, int & y) {
        FontInfo const & font = pi.base.font;
-       // FIXME: this definition of em is bogus, but there is a need
-       // for a big refactoring of the code around this issue anyway.
-       int const em = theFontMetrics(font).width('M');
+       int const em = theFontMetrics(font).em();
        switch (kind) {
        case InsetSpecialChar::PHRASE_LYX:
                /** Reference macro:
index d39cf7f2638e8907095c3c76e5ec74fb7a03b2fb..1566836770ac317963ef93dcbd6d91ed7399c214 100644 (file)
@@ -3591,7 +3591,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                        MetricsInfo m = mi;
                        Length const p_width = tabular.getPWidth(cell);
                        if (!p_width.zero())
-                               m.base.textwidth = p_width.inPixels(mi.base.textwidth);
+                               m.base.textwidth = p_width.inPixels(mi.base);
                        tabular.cellInset(cell)->metrics(m, dim);
                        if (!p_width.zero())
                                dim.wid = m.base.textwidth;
@@ -3652,11 +3652,11 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                }
                int const top_space = tabular.row_info[r].top_space_default ?
                        default_line_space :
-                       tabular.row_info[r].top_space.inPixels(mi.base.textwidth);
+                       tabular.row_info[r].top_space.inPixels(mi.base);
                tabular.setRowAscent(r, maxasc + ADD_TO_HEIGHT + top_space);
                int const bottom_space = tabular.row_info[r].bottom_space_default ?
                        default_line_space :
-                       tabular.row_info[r].bottom_space.inPixels(mi.base.textwidth);
+                       tabular.row_info[r].bottom_space.inPixels(mi.base);
                tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space);
        }
 
index 03bda07cf60475c4ebaae4584ea401c613fccc12..724bad43fd1b086503433e609bf7c2d8a1159713 100644 (file)
@@ -75,7 +75,7 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
                dim = fm.dimension(char_);
                kerning_ = fm.rbearing(char_) - dim.wid;
        }
-       int const em = mathed_char_width(mi.base.font, 'M');
+       int const em = mathed_font_em(mi.base.font);
        if (isBinaryOp(char_))
                dim.wid += static_cast<int>(0.5*em+0.5);
        else if (char_ == '\'')
@@ -93,7 +93,7 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
 void InsetMathChar::draw(PainterInfo & pi, int x, int y) const
 {
        //lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << endl;
-       int const em = mathed_char_width(pi.base.font, 'M');
+       int const em = mathed_font_em(pi.base.font);
        if (isBinaryOp(char_))
                x += static_cast<int>(0.25*em+0.5);
        else if (char_ == '\'')
index 07f0b2ce79d1efc099b57bfb129228addad6bae3..d3eb677197dcd2535d717745dae7c2caf3f5f7ba 100644 (file)
@@ -28,7 +28,6 @@
 #include "FuncRequest.h"
 
 #include "frontends/Clipboard.h"
-#include "frontends/FontMetrics.h"
 #include "frontends/Painter.h"
 
 #include "support/debug.h"
@@ -98,9 +97,7 @@ InsetMathGrid::RowInfo::RowInfo()
 
 int InsetMathGrid::RowInfo::skipPixels(MetricsInfo const & mi) const
 {
-       frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
-       return crskip_.inPixels(mi.base.textwidth,
-                               fm.width(char_type('M')));
+       return crskip_.inPixels(mi.base);
 }
 
 
index 7f990f996842ff99068b19794feb5d72186a6695..80e3243ae615b9fb047ee9bc1ebd2b080e534f2f 100644 (file)
@@ -47,7 +47,7 @@ void InsetMathKern::metrics(MetricsInfo & mi, Dimension & dim) const
 {
        dim.asc = 0;
        dim.des = 0;
-       dim.wid = wid_.inPixels(0, mathed_char_width(mi.base.font, 'M'));
+       dim.wid = wid_.inPixels(mi.base);
 }
 
 
index 2a3b6f45cb477657a4e988da12b4991e14d0be46..c84bc771d82251124497a0c325a7e35abc1d4cfe 100644 (file)
@@ -123,9 +123,7 @@ void InsetMathSpace::metrics(MetricsInfo & mi, Dimension & dim) const
        dim.asc = 4;
        dim.des = 0;
        if (space_info[space_].custom)
-               dim.wid = abs(length_.inPixels(
-                               mi.base.textwidth,
-                               mathed_char_width(mi.base.font, 'M')));
+               dim.wid = abs(length_.inPixels(mi.base));
        else
                dim.wid = space_info[space_].width;
 }
index 8b2d1a2f723051bec9f4345f7d48f7db6349e712..352352bdd66d2c937a9feff31fd4d17cef48015e 100644 (file)
@@ -67,7 +67,7 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
                                         sym_->extra == "mathalpha" &&
                                         mi.base.fontname == "mathit";
        std::string const font = italic_upcase_greek ? "cmm" : sym_->inset;
-       int const em = mathed_char_width(mi.base.font, 'M');
+       int const em = mathed_font_em(mi.base.font);
        FontSetChanger dummy(mi.base, from_ascii(font));
        mathed_string_dim(mi.base.font, sym_->draw, dim);
        docstring::const_reverse_iterator rit = sym_->draw.rbegin();
@@ -104,7 +104,7 @@ void InsetMathSymbol::draw(PainterInfo & pi, int x, int y) const
                                         sym_->extra == "mathalpha" &&
                                         pi.base.fontname == "mathit";
        std::string const font = italic_upcase_greek ? "cmm" : sym_->inset;
-       int const em = mathed_char_width(pi.base.font, 'M');
+       int const em = mathed_font_em(pi.base.font);
        if (isRelOp())
                x += static_cast<int>(0.25*em+0.5);
        else
index 7d15c42672f2357c0a053af1b642ec9b6b8a49a1..1f90873fec10dae82647e76511081f2d3ce9951a 100644 (file)
@@ -501,6 +501,12 @@ deco_struct const * search_deco(docstring const & name)
 } // namespace anon
 
 
+int mathed_font_em(FontInfo const & font)
+{
+       return theFontMetrics(font).em();
+}
+
+
 int mathed_char_width(FontInfo const & font, char_type c)
 {
        return theFontMetrics(font).width(c);
index dc0087f915b88d84327176de0aafe589545ea3ed..aa5ef2adc2a56f7de8e43364a47c8394551004f9 100644 (file)
@@ -27,6 +27,8 @@ class MathAtom;
 class InsetMath;
 
 
+int mathed_font_em(FontInfo const &);
+
 int mathed_char_width(FontInfo const &, char_type c);
 
 int mathed_char_kerning(FontInfo const &, char_type c);
index 6fb1a84b7611a68e0b91dc8613e54a06b90c579c..9e9c3107292c563fc7286b4d3d2db4f9dc1aa10b 100644 (file)
@@ -121,6 +121,22 @@ string alignmentToCSS(LyXAlignment)
        return string();
 }
 
+//
+// Dummy FontMetrics (needed by Length)
+//
+
+
+class FontMetrics {
+       int em() const { return 0; };
+};
+
+class FontInfo;
+
+FontMetrics const & theFontMetrics(FontInfo const &) {
+       static FontMetrics dummy;
+       return dummy;
+}
+
 //
 // Keep the linker happy on Windows
 //