2006-10-07 16:15:06 +00:00
|
|
|
/**
|
2007-04-26 03:53:02 +00:00
|
|
|
* \file GuiFontMetrics.cpp
|
2006-10-07 16:15:06 +00:00
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
*
|
|
|
|
* \author unknown
|
|
|
|
* \author John Levon
|
|
|
|
*
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "GuiFontMetrics.h"
|
|
|
|
|
|
|
|
#include "qt_helpers.h"
|
|
|
|
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Dimension.h"
|
2008-02-14 08:49:45 +00:00
|
|
|
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
#include "support/convert.h"
|
2008-04-30 08:26:40 +00:00
|
|
|
#include "support/lassert.h"
|
2017-08-28 12:05:35 +02:00
|
|
|
#include "support/lyxlib.h"
|
2007-11-08 00:09:58 +00:00
|
|
|
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
#define DISABLE_PMPROF
|
|
|
|
#include "support/pmprof.h"
|
|
|
|
|
|
|
|
#include <QByteArray>
|
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
using namespace std;
|
2014-05-23 18:59:53 +02:00
|
|
|
using namespace lyx::support;
|
2006-10-07 16:15:06 +00:00
|
|
|
|
2020-01-27 18:38:21 +01:00
|
|
|
/* Define what mechanism is used to enforce text direction. Different
|
|
|
|
* methods work with different Qt versions. Here we try to use both
|
|
|
|
* methods together.
|
|
|
|
*/
|
|
|
|
// Define to use unicode override characters to force direction
|
|
|
|
#define BIDI_USE_OVERRIDE
|
|
|
|
// Define to use flag to force direction
|
|
|
|
#define BIDI_USE_FLAG
|
|
|
|
|
|
|
|
#ifdef BIDI_USE_OVERRIDE
|
|
|
|
# define BIDI_OFFSET 1
|
|
|
|
#else
|
|
|
|
# define BIDI_OFFSET 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(BIDI_USE_OVERRIDE) && !defined(BIDI_USE_FLAG)
|
|
|
|
# error "Define at least one of BIDI_USE_OVERRIDE or BIDI_USE_FLAG"
|
|
|
|
#endif
|
|
|
|
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
namespace std {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Argument-dependent lookup implies that this function shall be
|
|
|
|
* declared in the namespace of its argument. But this is std
|
|
|
|
* namespace, since lyx::docstring is just std::basic_string<wchar_t>.
|
|
|
|
*/
|
|
|
|
uint qHash(lyx::docstring const & s)
|
|
|
|
{
|
|
|
|
return qHash(QByteArray(reinterpret_cast<char const *>(s.data()),
|
|
|
|
s.size() * sizeof(lyx::docstring::value_type)));
|
|
|
|
}
|
|
|
|
|
2017-07-23 13:11:54 +02:00
|
|
|
} // namespace std
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
|
2006-10-07 16:15:06 +00:00
|
|
|
namespace lyx {
|
|
|
|
namespace frontend {
|
|
|
|
|
2017-02-20 23:59:24 +01:00
|
|
|
|
2017-02-21 06:50:48 +01:00
|
|
|
/*
|
|
|
|
* Limit (strwidth|breakat)_cache_ size to 512kB of string data.
|
|
|
|
* Limit qtextlayout_cache_ size to 500 elements (we do not know the
|
|
|
|
* size of the QTextLayout objects anyway).
|
|
|
|
* Note that all these numbers are arbitrary.
|
|
|
|
* Also, setting size to 0 is tantamount to disabling the cache.
|
|
|
|
*/
|
2017-02-20 23:59:24 +01:00
|
|
|
int cache_metrics_width_size = 1 << 19;
|
|
|
|
int cache_metrics_breakat_size = 1 << 19;
|
|
|
|
// Qt 5.x already has its own caching of QTextLayout objects
|
2017-04-18 14:02:31 +02:00
|
|
|
// but it does not seem to work well on MacOS X.
|
|
|
|
#if (QT_VERSION < 0x050000) || defined(Q_OS_MAC)
|
2017-02-20 23:59:24 +01:00
|
|
|
int cache_metrics_qtextlayout_size = 500;
|
|
|
|
#else
|
|
|
|
int cache_metrics_qtextlayout_size = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2010-11-17 22:00:42 +00:00
|
|
|
namespace {
|
2007-11-08 00:09:58 +00:00
|
|
|
/**
|
|
|
|
* 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).
|
2010-11-17 22:00:42 +00:00
|
|
|
*
|
|
|
|
* 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
|
2012-12-15 13:02:40 +01:00
|
|
|
* computer modern fonts used, nothing unicode related.
|
2014-05-23 18:59:53 +02:00
|
|
|
* See comment in GuiPainter::text() for more explanation.
|
2014-05-07 12:06:56 +02:00
|
|
|
**/
|
2010-11-17 22:00:42 +00:00
|
|
|
inline QChar const ucs4_to_qchar(char_type const ucs4)
|
2007-11-08 00:09:58 +00:00
|
|
|
{
|
2013-04-25 17:27:10 -04:00
|
|
|
LATTEST(is_utf16(ucs4));
|
2007-11-08 00:09:58 +00:00
|
|
|
return QChar(static_cast<unsigned short>(ucs4));
|
|
|
|
}
|
2017-07-23 13:11:54 +02:00
|
|
|
} // namespace
|
2007-11-08 00:09:58 +00:00
|
|
|
|
|
|
|
|
2015-11-09 10:11:57 +01:00
|
|
|
GuiFontMetrics::GuiFontMetrics(QFont const & font)
|
2017-02-20 23:59:24 +01:00
|
|
|
: font_(font), metrics_(font, 0),
|
|
|
|
strwidth_cache_(cache_metrics_width_size),
|
|
|
|
breakat_cache_(cache_metrics_breakat_size),
|
|
|
|
qtextlayout_cache_(cache_metrics_qtextlayout_size)
|
2006-10-07 16:15:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::maxAscent() const
|
|
|
|
{
|
|
|
|
return metrics_.ascent();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::maxDescent() const
|
|
|
|
{
|
|
|
|
// We add 1 as the value returned by QT is different than X
|
|
|
|
// See http://doc.trolltech.com/2.3/qfontmetrics.html#200b74
|
|
|
|
return metrics_.descent() + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-26 16:55:19 +01:00
|
|
|
int GuiFontMetrics::em() const
|
|
|
|
{
|
|
|
|
return QFontInfo(font_).pixelSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-19 22:16:40 +02:00
|
|
|
int GuiFontMetrics::xHeight() const
|
|
|
|
{
|
|
|
|
// LATTEST(metrics_.xHeight() == ascent('x'));
|
|
|
|
return metrics_.xHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-14 15:22:11 +02:00
|
|
|
int GuiFontMetrics::lineWidth() const
|
|
|
|
{
|
|
|
|
return metrics_.lineWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::underlinePos() const
|
|
|
|
{
|
|
|
|
return metrics_.underlinePos();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::strikeoutPos() const
|
|
|
|
{
|
|
|
|
return metrics_.strikeOutPos();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-20 10:56:16 +01:00
|
|
|
namespace {
|
|
|
|
int const outOfLimitMetric = -10000;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-07 16:15:06 +00:00
|
|
|
int GuiFontMetrics::lbearing(char_type c) const
|
|
|
|
{
|
2019-03-20 10:56:16 +01:00
|
|
|
int value = lbearing_cache_.value(c, outOfLimitMetric);
|
|
|
|
if (value != outOfLimitMetric)
|
|
|
|
return value;
|
|
|
|
|
|
|
|
if (is_utf16(c))
|
|
|
|
value = metrics_.leftBearing(ucs4_to_qchar(c));
|
|
|
|
else {
|
2015-04-14 15:22:11 +02:00
|
|
|
// FIXME: QFontMetrics::leftBearing does not support the
|
2007-05-31 12:48:42 +00:00
|
|
|
// full unicode range. Once it does, we could use:
|
2019-03-20 10:56:16 +01:00
|
|
|
// metrics_.leftBearing(toqstr(docstring(1, c)));
|
|
|
|
value = 0;
|
|
|
|
}
|
2006-10-07 16:15:06 +00:00
|
|
|
|
2019-03-20 10:56:16 +01:00
|
|
|
lbearing_cache_.insert(c, value);
|
2006-10-07 16:15:06 +00:00
|
|
|
|
2019-03-20 10:56:16 +01:00
|
|
|
return value;
|
2007-08-13 13:56:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-07 16:15:06 +00:00
|
|
|
int GuiFontMetrics::rbearing(char_type c) const
|
|
|
|
{
|
2007-08-13 13:56:54 +00:00
|
|
|
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);
|
2007-11-13 23:00:36 +00:00
|
|
|
} else {
|
|
|
|
// FIXME: QFontMetrics::leftBearing does not support the
|
2007-08-13 13:56:54 +00:00
|
|
|
// full unicode range. Once it does, we could use:
|
2008-09-08 01:18:33 +00:00
|
|
|
// metrics_.rightBearing(toqstr(docstring(1, c)));
|
2007-08-13 13:56:54 +00:00
|
|
|
value = width(c);
|
2007-11-13 23:00:36 +00:00
|
|
|
}
|
2007-08-13 13:56:54 +00:00
|
|
|
|
|
|
|
rbearing_cache_.insert(c, value);
|
|
|
|
|
|
|
|
return value;
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-26 15:13:08 +00:00
|
|
|
int GuiFontMetrics::width(docstring const & s) const
|
2006-10-07 16:15:06 +00:00
|
|
|
{
|
2017-02-20 23:59:24 +01:00
|
|
|
PROFILE_THIS_BLOCK(width);
|
|
|
|
if (strwidth_cache_.contains(s))
|
|
|
|
return strwidth_cache_[s];
|
|
|
|
PROFILE_CACHE_MISS(width);
|
2018-02-17 16:55:22 +01:00
|
|
|
/* Several problems have to be taken into account:
|
|
|
|
* * QFontMetrics::width does not returns a wrong value with Qt5 with
|
|
|
|
* some arabic text, since the glyph-shaping operations are not
|
|
|
|
* done (documented in Qt5).
|
|
|
|
* * QTextLayout is broken for single characters with null width
|
|
|
|
* (like \not in mathed).
|
|
|
|
* * While QTextLine::horizontalAdvance is the right thing to use
|
|
|
|
* for text strings, it does not give a good result with some
|
|
|
|
* characters like the \int (gyph 4) of esint.
|
|
|
|
|
2020-07-24 12:32:24 +02:00
|
|
|
* The metrics of some of our math fonts (eg. esint) are such that
|
|
|
|
* QTextLine::horizontalAdvance leads, more or less, in the middle
|
|
|
|
* of a symbol. This is the horizontal position where a subscript
|
|
|
|
* should be drawn, so that the superscript has to be moved rightward.
|
|
|
|
* This is done when the kerning() method of the math insets returns
|
|
|
|
* a positive value. The problem with this choice is that navigating
|
|
|
|
* a formula becomes weird. For example, a selection extends only over
|
|
|
|
* about half of the symbol. In order to avoid this, with our math
|
|
|
|
* fonts we use QTextLine::naturalTextWidth, so that a superscript can
|
|
|
|
* be drawn right after the symbol, and move the subscript leftward by
|
|
|
|
* recording a negative value for the kerning.
|
2017-01-20 10:32:40 +01:00
|
|
|
*/
|
|
|
|
int w = 0;
|
2018-02-17 16:55:22 +01:00
|
|
|
// is the string a single character from a math font ?
|
2017-01-20 10:32:40 +01:00
|
|
|
#if QT_VERSION >= 0x040800
|
2018-02-17 16:55:22 +01:00
|
|
|
bool const math_char = s.length() == 1 || font_.styleName() == "LyX";
|
|
|
|
#else
|
|
|
|
bool const math_char = s.length() == 1;
|
2017-01-20 10:32:40 +01:00
|
|
|
#endif
|
2018-02-17 16:55:22 +01:00
|
|
|
// keep value 0 for math chars with width 0
|
|
|
|
if (!math_char || metrics_.width(toqstr(s)) != 0) {
|
2017-01-20 10:32:40 +01:00
|
|
|
QTextLayout tl;
|
|
|
|
tl.setText(toqstr(s));
|
|
|
|
tl.setFont(font_);
|
|
|
|
tl.beginLayout();
|
|
|
|
QTextLine line = tl.createLine();
|
|
|
|
tl.endLayout();
|
2018-02-17 16:55:22 +01:00
|
|
|
if (math_char)
|
|
|
|
w = iround(line.naturalTextWidth());
|
|
|
|
else
|
|
|
|
w = iround(line.horizontalAdvance());
|
2017-01-20 10:32:40 +01:00
|
|
|
}
|
2017-02-20 23:59:24 +01:00
|
|
|
strwidth_cache_.insert(s, w, s.size() * sizeof(char_type));
|
2006-10-27 21:27:03 +00:00
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::width(QString const & ucs2) const
|
|
|
|
{
|
2007-05-31 12:48:42 +00:00
|
|
|
return width(qstring_to_ucs4(ucs2));
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::signedWidth(docstring const & s) const
|
|
|
|
{
|
2006-11-08 11:32:33 +00:00
|
|
|
if (s.empty())
|
|
|
|
return 0;
|
|
|
|
|
2006-10-07 16:15:06 +00:00
|
|
|
if (s[0] == '-')
|
2007-02-26 15:13:08 +00:00
|
|
|
return -width(s.substr(1, s.size() - 1));
|
2006-10-07 16:15:06 +00:00
|
|
|
else
|
2007-02-26 15:13:08 +00:00
|
|
|
return width(s);
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
|
|
|
|
2015-12-07 10:32:34 +01:00
|
|
|
|
2017-02-20 23:59:24 +01:00
|
|
|
shared_ptr<QTextLayout const>
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
GuiFontMetrics::getTextLayout(docstring const & s, bool const rtl,
|
|
|
|
double const wordspacing) const
|
2015-12-11 16:33:34 +01:00
|
|
|
{
|
2017-02-20 23:59:24 +01:00
|
|
|
PROFILE_THIS_BLOCK(getTextLayout);
|
|
|
|
docstring const s_cache =
|
|
|
|
s + (rtl ? "r" : "l") + convert<docstring>(wordspacing);
|
|
|
|
if (auto ptl = qtextlayout_cache_[s_cache])
|
|
|
|
return ptl;
|
|
|
|
PROFILE_CACHE_MISS(getTextLayout);
|
|
|
|
auto const ptl = make_shared<QTextLayout>();
|
|
|
|
ptl->setCacheEnabled(true);
|
|
|
|
QFont copy = font_;
|
|
|
|
copy.setWordSpacing(wordspacing);
|
|
|
|
ptl->setFont(copy);
|
2020-01-27 18:38:21 +01:00
|
|
|
|
|
|
|
#ifdef BIDI_USE_FLAG
|
|
|
|
/* Use undocumented flag to enforce drawing direction
|
|
|
|
* FIXME: This does not work with Qt 5.11 (ticket #11284).
|
|
|
|
*/
|
|
|
|
ptl->setFlags(rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BIDI_USE_OVERRIDE
|
2018-11-03 15:55:33 +00:00
|
|
|
/* Use unicode override characters to enforce drawing direction
|
|
|
|
* Source: http://www.iamcal.com/understanding-bidirectional-text/
|
|
|
|
*/
|
|
|
|
if (rtl)
|
|
|
|
// Right-to-left override: forces to draw text right-to-left
|
|
|
|
ptl->setText(QChar(0x202E) + toqstr(s));
|
|
|
|
else
|
|
|
|
// Left-to-right override: forces to draw text left-to-right
|
|
|
|
ptl->setText(QChar(0x202D) + toqstr(s));
|
|
|
|
#else
|
|
|
|
ptl->setText(toqstr(s));
|
|
|
|
#endif
|
2020-01-27 18:38:21 +01:00
|
|
|
|
2017-02-20 23:59:24 +01:00
|
|
|
ptl->beginLayout();
|
|
|
|
ptl->createLine();
|
|
|
|
ptl->endLayout();
|
|
|
|
qtextlayout_cache_.insert(s_cache, ptl);
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
return ptl;
|
2014-05-14 17:46:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-20 15:39:28 +01:00
|
|
|
int GuiFontMetrics::pos2x(docstring const & s, int pos, bool const rtl,
|
2015-07-19 01:22:10 +02:00
|
|
|
double const wordspacing) const
|
2014-05-14 17:46:43 +02:00
|
|
|
{
|
2016-12-06 16:06:03 +01:00
|
|
|
if (pos <= 0)
|
2017-02-20 15:39:28 +01:00
|
|
|
pos = 0;
|
2017-02-20 23:59:24 +01:00
|
|
|
shared_ptr<QTextLayout const> tl = getTextLayout(s, rtl, wordspacing);
|
2016-11-02 17:42:56 +01:00
|
|
|
/* Since QString is UTF-16 and docstring is UCS-4, the offsets may
|
|
|
|
* not be the same when there are high-plan unicode characters
|
|
|
|
* (bug #10443).
|
|
|
|
*/
|
2020-01-27 18:38:21 +01:00
|
|
|
// BIDI_OFFSET accounts for a possible direction override
|
2018-11-03 15:55:33 +00:00
|
|
|
// character in front of the string.
|
2020-01-27 18:38:21 +01:00
|
|
|
int const qpos = toqstr(s.substr(0, pos)).length() + BIDI_OFFSET;
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
return static_cast<int>(tl->lineForTextPosition(qpos).cursorToX(qpos));
|
2014-05-14 17:46:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-19 01:22:10 +02:00
|
|
|
int GuiFontMetrics::x2pos(docstring const & s, int & x, bool const rtl,
|
|
|
|
double const wordspacing) const
|
2014-05-14 17:46:43 +02:00
|
|
|
{
|
2017-02-20 23:59:24 +01:00
|
|
|
shared_ptr<QTextLayout const> tl = getTextLayout(s, rtl, wordspacing);
|
2017-03-31 16:56:06 +02:00
|
|
|
QTextLine const & tline = tl->lineForTextPosition(0);
|
|
|
|
int qpos = tline.xToCursor(x);
|
|
|
|
int newx = static_cast<int>(tline.cursorToX(qpos));
|
|
|
|
// The value of qpos may be wrong in rtl text (see ticket #10569).
|
|
|
|
// To work around this, let's have a look at adjacent positions to
|
|
|
|
// see whether we find closer matches.
|
|
|
|
if (rtl && newx < x) {
|
|
|
|
while (qpos > 0) {
|
|
|
|
int const xm = static_cast<int>(tline.cursorToX(qpos - 1));
|
|
|
|
if (abs(xm - x) < abs(newx - x)) {
|
|
|
|
--qpos;
|
|
|
|
newx = xm;
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (rtl && newx > x) {
|
|
|
|
while (qpos < tline.textLength()) {
|
|
|
|
int const xp = static_cast<int>(tline.cursorToX(qpos + 1));
|
|
|
|
if (abs(xp - x) < abs(newx - x)) {
|
|
|
|
++qpos;
|
|
|
|
newx = xp;
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-05-14 17:46:43 +02:00
|
|
|
// correct x value to the actual cursor position.
|
2017-03-31 16:56:06 +02:00
|
|
|
x = newx;
|
|
|
|
|
2016-11-02 17:42:56 +01:00
|
|
|
/* Since QString is UTF-16 and docstring is UCS-4, the offsets may
|
|
|
|
* not be the same when there are high-plan unicode characters
|
|
|
|
* (bug #10443).
|
|
|
|
*/
|
|
|
|
#if QT_VERSION < 0x040801 || QT_VERSION >= 0x050100
|
2018-11-03 15:55:33 +00:00
|
|
|
int pos = qstring_to_ucs4(tl->text().left(qpos)).length();
|
|
|
|
// there may be a direction override character in front of the string.
|
2020-01-27 18:38:21 +01:00
|
|
|
return max(pos - BIDI_OFFSET, 0);
|
2016-11-02 17:42:56 +01:00
|
|
|
#else
|
|
|
|
/* Due to QTBUG-25536 in 4.8.1 <= Qt < 5.1.0, the string returned
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
* by QString::toUcs4 (used by qstring_to_ucs4) may have wrong
|
2016-11-02 17:42:56 +01:00
|
|
|
* length. We work around the problem by trying all docstring
|
|
|
|
* positions until the right one is found. This is slow only if
|
|
|
|
* there are many high-plane Unicode characters. It might be
|
|
|
|
* worthwhile to implement a dichotomy search if this shows up
|
|
|
|
* under a profiler.
|
|
|
|
*/
|
2018-11-03 15:55:33 +00:00
|
|
|
// there may be a direction override character in front of the string.
|
2020-01-27 18:38:21 +01:00
|
|
|
qpos = max(qpos - BIDI_OFFSET, 0);
|
2016-11-02 17:42:56 +01:00
|
|
|
int pos = min(qpos, static_cast<int>(s.length()));
|
|
|
|
while (pos >= 0 && toqstr(s.substr(0, pos)).length() != qpos)
|
|
|
|
--pos;
|
|
|
|
LASSERT(pos > 0 || qpos == 0, /**/);
|
2014-05-14 17:46:43 +02:00
|
|
|
return pos;
|
2016-11-02 17:42:56 +01:00
|
|
|
#endif
|
2014-05-14 17:46:43 +02:00
|
|
|
}
|
|
|
|
|
2006-10-07 16:15:06 +00:00
|
|
|
|
2016-08-13 19:03:02 +01:00
|
|
|
int GuiFontMetrics::countExpanders(docstring const & str) const
|
|
|
|
{
|
|
|
|
// Numbers of characters that are expanded by inter-word spacing. These
|
|
|
|
// characters are spaces, except for characters 09-0D which are treated
|
|
|
|
// specially. (From a combination of testing with the notepad found in qt's
|
|
|
|
// examples, and reading the source code.) In addition, consecutive spaces
|
|
|
|
// only count as one expander.
|
|
|
|
bool wasspace = false;
|
|
|
|
int nexp = 0;
|
|
|
|
for (char_type c : str)
|
|
|
|
if (c > 0x0d && QChar(c).isSpace()) {
|
|
|
|
if (!wasspace) {
|
|
|
|
++nexp;
|
|
|
|
wasspace = true;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
wasspace = false;
|
|
|
|
return nexp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-20 23:59:24 +01:00
|
|
|
pair<int, int>
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
GuiFontMetrics::breakAt_helper(docstring const & s, int const x,
|
|
|
|
bool const rtl, bool const force) const
|
2015-07-19 01:22:10 +02:00
|
|
|
{
|
|
|
|
QTextLayout tl;
|
2016-01-19 12:02:43 +01:00
|
|
|
/* Qt will not break at a leading or trailing space, and we need
|
|
|
|
* that sometimes, see http://www.lyx.org/trac/ticket/9921.
|
|
|
|
*
|
|
|
|
* To work around the problem, we enclose the string between
|
|
|
|
* zero-width characters so that the QTextLayout algorithm will
|
|
|
|
* agree to break the text at these extremal spaces.
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
*/
|
2016-01-19 12:02:43 +01:00
|
|
|
// Unicode character ZERO WIDTH NO-BREAK SPACE
|
|
|
|
QChar const zerow_nbsp(0xfeff);
|
2016-11-02 17:42:56 +01:00
|
|
|
QString qs = zerow_nbsp + toqstr(s) + zerow_nbsp;
|
2020-01-27 18:38:21 +01:00
|
|
|
#ifdef BIDI_USE_FLAG
|
|
|
|
/* Use undocumented flag to enforce drawing direction
|
|
|
|
* FIXME: This does not work with Qt 5.11 (ticket #11284).
|
|
|
|
*/
|
|
|
|
tl.setFlags(rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BIDI_USE_OVERRIDE
|
2016-10-23 20:52:01 +02:00
|
|
|
/* Use unicode override characters to enforce drawing direction
|
|
|
|
* Source: http://www.iamcal.com/understanding-bidirectional-text/
|
|
|
|
*/
|
|
|
|
if (rtl)
|
|
|
|
// Right-to-left override: forces to draw text right-to-left
|
2016-11-02 17:42:56 +01:00
|
|
|
qs = QChar(0x202E) + qs;
|
2016-10-23 20:52:01 +02:00
|
|
|
else
|
|
|
|
// Left-to-right override: forces to draw text left-to-right
|
2016-11-02 17:42:56 +01:00
|
|
|
qs = QChar(0x202D) + qs;
|
2016-10-23 20:52:01 +02:00
|
|
|
#endif
|
2020-01-27 18:38:21 +01:00
|
|
|
int const offset = 1 + BIDI_OFFSET;
|
2016-10-23 20:52:01 +02:00
|
|
|
|
2016-11-02 17:42:56 +01:00
|
|
|
tl.setText(qs);
|
2016-10-23 20:52:01 +02:00
|
|
|
tl.setFont(font_);
|
2015-07-19 01:22:10 +02:00
|
|
|
QTextOption to;
|
2016-11-06 15:14:29 +01:00
|
|
|
to.setWrapMode(force ? QTextOption::WrapAtWordBoundaryOrAnywhere
|
|
|
|
: QTextOption::WordWrap);
|
2015-07-19 01:22:10 +02:00
|
|
|
tl.setTextOption(to);
|
|
|
|
tl.beginLayout();
|
|
|
|
QTextLine line = tl.createLine();
|
|
|
|
line.setLineWidth(x);
|
|
|
|
tl.createLine();
|
|
|
|
tl.endLayout();
|
2017-08-28 12:05:35 +02:00
|
|
|
int const line_wid = iround(line.horizontalAdvance());
|
|
|
|
if ((force && line.textLength() == offset) || line_wid > x)
|
2017-02-20 23:59:24 +01:00
|
|
|
return {-1, -1};
|
2016-11-02 17:42:56 +01:00
|
|
|
/* Since QString is UTF-16 and docstring is UCS-4, the offsets may
|
|
|
|
* not be the same when there are high-plan unicode characters
|
|
|
|
* (bug #10443).
|
|
|
|
*/
|
|
|
|
// The variable `offset' is here to account for the extra leading characters.
|
|
|
|
// The ending character zerow_nbsp has to be ignored if the line is complete.
|
|
|
|
int const qlen = line.textLength() - offset - (line.textLength() == qs.length());
|
|
|
|
#if QT_VERSION < 0x040801 || QT_VERSION >= 0x050100
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
int len = qstring_to_ucs4(qs.mid(offset, qlen)).length();
|
2016-11-02 17:42:56 +01:00
|
|
|
#else
|
|
|
|
/* Due to QTBUG-25536 in 4.8.1 <= Qt < 5.1.0, the string returned
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
* by QString::toUcs4 (used by qstring_to_ucs4) may have wrong
|
2016-11-02 17:42:56 +01:00
|
|
|
* length. We work around the problem by trying all docstring
|
|
|
|
* positions until the right one is found. This is slow only if
|
|
|
|
* there are many high-plane Unicode characters. It might be
|
|
|
|
* worthwhile to implement a dichotomy search if this shows up
|
|
|
|
* under a profiler.
|
|
|
|
*/
|
|
|
|
int len = min(qlen, static_cast<int>(s.length()));
|
|
|
|
while (len >= 0 && toqstr(s.substr(0, len)).length() != qlen)
|
|
|
|
--len;
|
|
|
|
LASSERT(len > 0 || qlen == 0, /**/);
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
#endif
|
2017-08-28 12:05:35 +02:00
|
|
|
return {len, line_wid};
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool GuiFontMetrics::breakAt(docstring & s, int & x, bool const rtl, bool const force) const
|
|
|
|
{
|
2017-02-20 23:59:24 +01:00
|
|
|
PROFILE_THIS_BLOCK(breakAt);
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
if (s.empty())
|
|
|
|
return false;
|
|
|
|
|
2017-02-20 23:59:24 +01:00
|
|
|
docstring const s_cache =
|
|
|
|
s + convert<docstring>(x) + (rtl ? "r" : "l") + (force ? "f" : "w");
|
|
|
|
pair<int, int> pp;
|
|
|
|
|
|
|
|
if (breakat_cache_.contains(s_cache))
|
|
|
|
pp = breakat_cache_[s_cache];
|
|
|
|
else {
|
|
|
|
PROFILE_CACHE_MISS(breakAt);
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
pp = breakAt_helper(s, x, rtl, force);
|
|
|
|
breakat_cache_.insert(s_cache, pp, s_cache.size() * sizeof(char_type));
|
|
|
|
}
|
2017-02-20 23:59:24 +01:00
|
|
|
if (pp.first == -1)
|
Add caching for the QTextLayout objects we use
The QTextLayout handling is terribly slow on Qt 4.8.7, but some
caching has been added in Qt5 that makes it much faster. For some
reason, it is not that slow with Qt 4.8.1.
Caches are introduced for the three following methods
* width(doctring), controlled by CACHE_METRICS_WIDTH. This cache already
existed, but the code has been cleaned up
* getTextLayout, controlled by CACHE_METRICS_QTEXTLAYOUT (disabled by
default on Qt5, which does its own caching). This is used for pos2x
and x2pos and now for drawing of text too. The previous code used a
trivial caching scheme of the last used QTextLayout, but now they
are properly kept in a QCache. Moreover, the cacheEnabled() property
is enabled for these QTextLayout object (not sure what this does).
* breakAt, controlled by CACHE_METRICS_BREAKAT. This is the only user
of QTextLayout which did not have some kind of caching already.
For some weird reasons related to Argument-dependent look-up, the
qHash(docstring) function has to be defined in std namespace, since
lyx::docstring is actually std::basic_string<wchar_t>.
[NOTE: this version has profiling hooks, enabled by commenting out the line
#define DISABLE_PMPROF
that should eventually be removed.]
2016-07-05 14:06:22 +02:00
|
|
|
return false;
|
2017-02-20 23:59:24 +01:00
|
|
|
s = s.substr(0, pp.first);
|
|
|
|
x = pp.second;
|
2015-07-19 01:22:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-07 16:15:06 +00:00
|
|
|
void GuiFontMetrics::rectText(docstring const & str,
|
|
|
|
int & w, int & ascent, int & descent) const
|
|
|
|
{
|
2017-06-15 15:30:23 +02:00
|
|
|
// FIXME: let offset depend on font (this is Inset::TEXT_TO_OFFSET)
|
|
|
|
int const offset = 4;
|
2008-03-02 10:20:13 +00:00
|
|
|
|
2017-06-15 15:30:23 +02:00
|
|
|
w = width(str) + offset;
|
|
|
|
ascent = metrics_.ascent() + offset / 2;
|
|
|
|
descent = metrics_.descent() + offset / 2;
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-15 15:30:23 +02:00
|
|
|
void GuiFontMetrics::buttonText(docstring const & str, const int offset,
|
2006-10-07 16:15:06 +00:00
|
|
|
int & w, int & ascent, int & descent) const
|
|
|
|
{
|
2008-02-14 09:44:12 +00:00
|
|
|
rectText(str, w, ascent, descent);
|
2017-06-15 15:30:23 +02:00
|
|
|
w += offset;
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
|
|
|
|
2006-12-01 16:12:24 +00:00
|
|
|
|
2006-12-04 10:09:22 +00:00
|
|
|
Dimension const GuiFontMetrics::defaultDimension() const
|
2006-10-07 16:15:06 +00:00
|
|
|
{
|
2006-12-04 10:45:43 +00:00
|
|
|
return Dimension(0, maxAscent(), maxDescent());
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
|
|
|
|
2006-12-01 16:12:24 +00:00
|
|
|
|
2006-12-04 10:09:22 +00:00
|
|
|
Dimension const GuiFontMetrics::dimension(char_type c) const
|
2006-12-01 16:12:24 +00:00
|
|
|
{
|
2006-12-04 10:45:43 +00:00
|
|
|
return Dimension(width(c), ascent(c), descent(c));
|
2006-12-01 16:12:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-13 13:56:54 +00:00
|
|
|
GuiFontMetrics::AscendDescend const GuiFontMetrics::fillMetricsCache(
|
|
|
|
char_type c) const
|
2006-12-01 16:12:24 +00:00
|
|
|
{
|
2007-05-31 12:48:42 +00:00
|
|
|
QRect r;
|
|
|
|
if (is_utf16(c))
|
|
|
|
r = metrics_.boundingRect(ucs4_to_qchar(c));
|
|
|
|
else
|
2008-09-08 01:18:33 +00:00
|
|
|
r = metrics_.boundingRect(toqstr(docstring(1, c)));
|
2007-05-31 12:48:42 +00:00
|
|
|
|
2006-12-02 15:54:49 +00:00
|
|
|
AscendDescend ad = { -r.top(), r.bottom() + 1};
|
2006-12-01 16:12:24 +00:00
|
|
|
// We could as well compute the width but this is not really
|
|
|
|
// needed for now as it is done directly in width() below.
|
2006-12-02 15:54:49 +00:00
|
|
|
metrics_cache_.insert(c, ad);
|
2007-08-13 13:56:54 +00:00
|
|
|
|
|
|
|
return ad;
|
2006-12-01 16:12:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::width(char_type c) const
|
|
|
|
{
|
2007-08-13 13:56:54 +00:00
|
|
|
int value = width_cache_.value(c, outOfLimitMetric);
|
|
|
|
if (value != outOfLimitMetric)
|
|
|
|
return value;
|
|
|
|
|
|
|
|
if (is_utf16(c))
|
|
|
|
value = metrics_.width(ucs4_to_qchar(c));
|
|
|
|
else
|
2007-11-08 00:09:58 +00:00
|
|
|
value = metrics_.width(toqstr(docstring(1, c)));
|
2007-08-13 13:56:54 +00:00
|
|
|
|
|
|
|
width_cache_.insert(c, value);
|
2006-12-01 16:12:24 +00:00
|
|
|
|
2007-08-13 13:56:54 +00:00
|
|
|
return value;
|
2006-12-01 16:12:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::ascent(char_type c) const
|
|
|
|
{
|
2014-05-07 12:06:56 +02:00
|
|
|
static AscendDescend const outOfLimitAD =
|
2007-08-13 13:56:54 +00:00
|
|
|
{outOfLimitMetric, outOfLimitMetric};
|
|
|
|
AscendDescend value = metrics_cache_.value(c, outOfLimitAD);
|
|
|
|
if (value.ascent != outOfLimitMetric)
|
|
|
|
return value.ascent;
|
2006-12-01 16:12:24 +00:00
|
|
|
|
2007-08-13 13:56:54 +00:00
|
|
|
value = fillMetricsCache(c);
|
|
|
|
return value.ascent;
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
2006-12-01 16:12:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
int GuiFontMetrics::descent(char_type c) const
|
|
|
|
{
|
2014-05-07 12:06:56 +02:00
|
|
|
static AscendDescend const outOfLimitAD =
|
2007-08-13 13:56:54 +00:00
|
|
|
{outOfLimitMetric, outOfLimitMetric};
|
|
|
|
AscendDescend value = metrics_cache_.value(c, outOfLimitAD);
|
|
|
|
if (value.descent != outOfLimitMetric)
|
|
|
|
return value.descent;
|
2006-12-01 16:12:24 +00:00
|
|
|
|
2007-08-13 13:56:54 +00:00
|
|
|
value = fillMetricsCache(c);
|
|
|
|
return value.descent;
|
2006-10-07 16:15:06 +00:00
|
|
|
}
|
2006-12-01 16:12:24 +00:00
|
|
|
|
2007-11-13 23:00:36 +00:00
|
|
|
} // namespace frontend
|
|
|
|
} // namespace lyx
|