commit 66fa801e74e1775b31008df548332436ce79e2e1
Author: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date:   Thu Mar 26 16:55:19 2015 +0100

    Improve support for on screen length calculation
    
    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.

diff --git a/src/BufferView.cpp b/src/BufferView.cpp
index 77750d8..8948b73 100644
--- a/src/BufferView.cpp
+++ b/src/BufferView.cpp
@@ -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;
diff --git a/src/Length.cpp b/src/Length.cpp
index 0deed74..2463be8 100644
--- a/src/Length.cpp
+++ b/src/Length.cpp
@@ -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
diff --git a/src/Length.h b/src/Length.h
index 435eea0..ef17bac 100644
--- a/src/Length.h
+++ b/src/Length.h
@@ -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;
 
diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp
index afc7f4e..33baa8c 100644
--- a/src/TextMetrics.cpp
+++ b/src/TextMetrics.cpp
@@ -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;
 
diff --git a/src/frontends/FontMetrics.h b/src/frontends/FontMetrics.h
index 56e47ea..53f57a2 100644
--- a/src/frontends/FontMetrics.h
+++ b/src/frontends/FontMetrics.h
@@ -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
diff --git a/src/frontends/qt4/GuiFontMetrics.cpp 
b/src/frontends/qt4/GuiFontMetrics.cpp
index f3a4c0f..b488b68 100644
--- a/src/frontends/qt4/GuiFontMetrics.cpp
+++ b/src/frontends/qt4/GuiFontMetrics.cpp
@@ -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))
diff --git a/src/frontends/qt4/GuiFontMetrics.h 
b/src/frontends/qt4/GuiFontMetrics.h
index ac1e714..7555929 100644
--- a/src/frontends/qt4/GuiFontMetrics.h
+++ b/src/frontends/qt4/GuiFontMetrics.h
@@ -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;
diff --git a/src/insets/InsetBox.cpp b/src/insets/InsetBox.cpp
index c96a7c9..de1c7fd 100644
--- a/src/insets/InsetBox.cpp
+++ b/src/insets/InsetBox.cpp
@@ -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;
diff --git a/src/insets/InsetLine.cpp b/src/insets/InsetLine.cpp
index 82960b2..8b80f0d 100644
--- a/src/insets/InsetLine.cpp
+++ b/src/insets/InsetLine.cpp
@@ -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_);
diff --git a/src/insets/InsetSpace.cpp b/src/insets/InsetSpace.cpp
index 8f746f5..839ccc9 100644
--- a/src/insets/InsetSpace.cpp
+++ b/src/insets/InsetSpace.cpp
@@ -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;
diff --git a/src/insets/InsetSpecialChar.cpp b/src/insets/InsetSpecialChar.cpp
index 8a52f16..99ac836 100644
--- a/src/insets/InsetSpecialChar.cpp
+++ b/src/insets/InsetSpecialChar.cpp
@@ -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:
diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp
index d39cf7f..1566836 100644
--- a/src/insets/InsetTabular.cpp
+++ b/src/insets/InsetTabular.cpp
@@ -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);
        }
 
diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp
index 03bda07..724bad4 100644
--- a/src/mathed/InsetMathChar.cpp
+++ b/src/mathed/InsetMathChar.cpp
@@ -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_ == '\'')
diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp
index 07f0b2c..d3eb677 100644
--- a/src/mathed/InsetMathGrid.cpp
+++ b/src/mathed/InsetMathGrid.cpp
@@ -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);
 }
 
 
diff --git a/src/mathed/InsetMathKern.cpp b/src/mathed/InsetMathKern.cpp
index 7f990f9..80e3243 100644
--- a/src/mathed/InsetMathKern.cpp
+++ b/src/mathed/InsetMathKern.cpp
@@ -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);
 }
 
 
diff --git a/src/mathed/InsetMathSpace.cpp b/src/mathed/InsetMathSpace.cpp
index 2a3b6f4..c84bc77 100644
--- a/src/mathed/InsetMathSpace.cpp
+++ b/src/mathed/InsetMathSpace.cpp
@@ -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;
 }
diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp
index 8b2d1a2..352352b 100644
--- a/src/mathed/InsetMathSymbol.cpp
+++ b/src/mathed/InsetMathSymbol.cpp
@@ -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
diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp
index 7d15c42..1f90873 100644
--- a/src/mathed/MathSupport.cpp
+++ b/src/mathed/MathSupport.cpp
@@ -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);
diff --git a/src/mathed/MathSupport.h b/src/mathed/MathSupport.h
index dc0087f..aa5ef2a 100644
--- a/src/mathed/MathSupport.h
+++ b/src/mathed/MathSupport.h
@@ -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);
diff --git a/src/tex2lyx/dummy_impl.cpp b/src/tex2lyx/dummy_impl.cpp
index 6fb1a84..9e9c310 100644
--- a/src/tex2lyx/dummy_impl.cpp
+++ b/src/tex2lyx/dummy_impl.cpp
@@ -122,6 +122,22 @@ string alignmentToCSS(LyXAlignment)
 }
 
 //
+// 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
 //
 

Reply via email to