X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiFontMetrics.cpp;h=76ebd907064e088a442cdd03fb2097196c1a2f8e;hb=425d092204118ea6c24c28e85fdf03fcf2bb51a4;hp=d9e1348613f8d230e575a066d62d40e43d1c9704;hpb=f8175cca5eaf70bfdf5daa745afe5821d9ce9e6a;p=lyx.git diff --git a/src/frontends/qt4/GuiFontMetrics.cpp b/src/frontends/qt4/GuiFontMetrics.cpp index d9e1348613..76ebd90706 100644 --- a/src/frontends/qt4/GuiFontMetrics.cpp +++ b/src/frontends/qt4/GuiFontMetrics.cpp @@ -18,13 +18,36 @@ #include "Language.h" #include "Dimension.h" -#include "support/unicode.h" +#include "insets/Inset.h" -using std::string; +#include "support/lassert.h" + +using namespace std; namespace lyx { namespace frontend { +/** + * Convert a UCS4 character into a QChar. + * This is a hack (it does only make sense for the common part of the UCS4 + * and UTF16 encodings) and should not be used. + * This does only exist because of performance reasons (a real conversion + * using iconv is too slow on windows). + */ +static inline QChar const ucs4_to_qchar(char_type const ucs4) +{ + LASSERT(is_utf16(ucs4), /**/); + return QChar(static_cast(ucs4)); +} + + +// Caution: When using ucs4_to_qchar() in these methods, this is no +// real conversion but a simple cast in reality. This is the reason +// why this works well for symbol fonts used in mathed too, even though +// these are not real ucs4 characters. These are codepoints in the +// modern fonts used, nothing unicode related. +// See comment in QLPainter::text() for more explanation. + GuiFontMetrics::GuiFontMetrics(QFont const & font) : metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false) { @@ -56,30 +79,38 @@ int GuiFontMetrics::lbearing(char_type c) const if (!is_utf16(c)) // FIXME: QFontMetrics::leftBearingdoes not support the // full unicode range. Once it does, we could use: - //return metrics_.leftBearing(toqstr(docstring(1,c))); + //return metrics_.leftBearing(toqstr(docstring(1, c))); return 0; return metrics_.leftBearing(ucs4_to_qchar(c)); } +namespace { +int const outOfLimitMetric = -10000; +} + + int GuiFontMetrics::rbearing(char_type c) const { - if (!rbearing_cache_.contains(c)) { - // Qt rbearing is from the right edge of the char's width(). - int rb; - if (is_utf16(c)) { - QChar sc = ucs4_to_qchar(c); - rb = width(c) - metrics_.rightBearing(sc); - } else - // FIXME: QFontMetrics::leftBearingdoes not support the - // full unicode range. Once it does, we could use: - // metrics_.rightBearing(toqstr(docstring(1,c))); - rb = width(c); - - rbearing_cache_.insert(c, rb); + int value = rbearing_cache_.value(c, outOfLimitMetric); + if (value != outOfLimitMetric) + return value; + + // Qt rbearing is from the right edge of the char's width(). + if (is_utf16(c)) { + QChar sc = ucs4_to_qchar(c); + value = width(c) - metrics_.rightBearing(sc); + } else { + // FIXME: QFontMetrics::leftBearing does not support the + // full unicode range. Once it does, we could use: + // metrics_.rightBearing(toqstr(docstring(1, c))); + value = width(c); } - return rbearing_cache_.value(c); + + rbearing_cache_.insert(c, value); + + return value; } @@ -94,7 +125,7 @@ int GuiFontMetrics::smallcapsWidth(char_type c) const else return metrics_.width(qc); } else { - QString const s = toqstr(docstring(1,c)); + QString const s = toqstr(docstring(1, c)); QString const us = s.toUpper(); if (s != us) return smallcaps_metrics_.width(us); @@ -108,8 +139,21 @@ int GuiFontMetrics::width(docstring const & s) const { size_t ls = s.size(); int w = 0; - for (unsigned int i = 0; i < ls; ++i) + for (unsigned int i = 0; i < ls; ++i) { + //FIXME: we need to detect surrogate pairs and act accordingly + /** + if isSurrogateBase(s[i]) { + docstring c = s[i]; + if (smallcaps_shape_) + w += metrics_.width(toqstr(c + s[i + 1])); + else + w += smallcaps_metrics_.width(toqstr(c + s[i + 1])); + ++i; + } + else + */ w += width(s[i]); + } return w; } @@ -136,8 +180,9 @@ int GuiFontMetrics::signedWidth(docstring const & s) const void GuiFontMetrics::rectText(docstring const & str, int & w, int & ascent, int & descent) const { - static int const d = 2; - w = width(str) + d * 2 + 2; + static int const d = Inset::TEXT_TO_INSET_OFFSET / 2; + + w = width(str) + Inset::TEXT_TO_INSET_OFFSET; ascent = metrics_.ascent() + d; descent = metrics_.descent() + d; } @@ -147,10 +192,8 @@ void GuiFontMetrics::rectText(docstring const & str, void GuiFontMetrics::buttonText(docstring const & str, int & w, int & ascent, int & descent) const { - static int const d = 3; - w = width(str) + d * 2 + 2; - ascent = metrics_.ascent() + d; - descent = metrics_.descent() + d; + rectText(str, w, ascent, descent); + w += Inset::TEXT_TO_INSET_OFFSET; } @@ -166,18 +209,21 @@ Dimension const GuiFontMetrics::dimension(char_type c) const } -void GuiFontMetrics::fillMetricsCache(char_type c) const +GuiFontMetrics::AscendDescend const GuiFontMetrics::fillMetricsCache( + char_type c) const { QRect r; if (is_utf16(c)) r = metrics_.boundingRect(ucs4_to_qchar(c)); else - r = metrics_.boundingRect(toqstr(docstring(1,c))); + r = metrics_.boundingRect(toqstr(docstring(1, c))); AscendDescend ad = { -r.top(), r.bottom() + 1}; // We could as well compute the width but this is not really // needed for now as it is done directly in width() below. metrics_cache_.insert(c, ad); + + return ad; } @@ -186,33 +232,45 @@ int GuiFontMetrics::width(char_type c) const if (smallcaps_shape_) return smallcapsWidth(c); - if (!width_cache_.contains(c)) { - if (is_utf16(c)) - width_cache_.insert(c, metrics_.width(ucs4_to_qchar(c))); - else - width_cache_.insert(c, metrics_.width(toqstr(docstring(1,c)))); - } + int value = width_cache_.value(c, outOfLimitMetric); + if (value != outOfLimitMetric) + return value; + + if (is_utf16(c)) + value = metrics_.width(ucs4_to_qchar(c)); + else + value = metrics_.width(toqstr(docstring(1, c))); - return width_cache_.value(c); + width_cache_.insert(c, value); + + return value; } int GuiFontMetrics::ascent(char_type c) const { - if (!metrics_cache_.contains(c)) - fillMetricsCache(c); - - return metrics_cache_.value(c).ascent; + static AscendDescend const outOfLimitAD = + {outOfLimitMetric, outOfLimitMetric}; + AscendDescend value = metrics_cache_.value(c, outOfLimitAD); + if (value.ascent != outOfLimitMetric) + return value.ascent; + + value = fillMetricsCache(c); + return value.ascent; } int GuiFontMetrics::descent(char_type c) const { - if (!metrics_cache_.contains(c)) - fillMetricsCache(c); - - return metrics_cache_.value(c).descent; + static AscendDescend const outOfLimitAD = + {outOfLimitMetric, outOfLimitMetric}; + AscendDescend value = metrics_cache_.value(c, outOfLimitAD); + if (value.descent != outOfLimitMetric) + return value.descent; + + value = fillMetricsCache(c); + return value.descent; } -} // frontend -} // lyx +} // namespace frontend +} // namespace lyx