#include "support/convert.h"
#include "support/lassert.h"
#include "support/lyxlib.h"
+#include "support/debug.h"
#define DISABLE_PMPROF
#include "support/pmprof.h"
#include <QByteArray>
+#include <QRawFont>
+#include <QtEndian>
+
+#if QT_VERSION >= 0x050100
+#include <QtMath>
+#else
+#define qDegreesToRadians(degree) (degree * (M_PI / 180))
+#endif
using namespace std;
using namespace lyx::support;
# error "Define at least one of BIDI_USE_OVERRIDE or BIDI_USE_FLAG"
#endif
+
+#if QT_VERSION < 0x050000
+inline uint qHash(double key)
+{
+ return qHash(QByteArray(reinterpret_cast<char const *>(&key), sizeof(key)));
+}
+#endif
+
+
namespace std {
/*
breakat_cache_(cache_metrics_breakat_size),
qtextlayout_cache_(cache_metrics_qtextlayout_size)
{
+ // Determine italic slope
+ double const defaultSlope = tan(qDegreesToRadians(19.0));
+ QRawFont raw = QRawFont::fromFont(font);
+ QByteArray post(raw.fontTable("post"));
+ if (post.length() == 0) {
+ slope_ = defaultSlope;
+ LYXERR(Debug::FONT, "Screen font doesn't have 'post' table.");
+ } else {
+ // post table description:
+ // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
+ int32_t italicAngle = qFromBigEndian(*reinterpret_cast<int32_t *>(post.data() + 4));
+ double angle = italicAngle / 65536.0; // Fixed-point 16.16 to floating-point
+ slope_ = -tan(qDegreesToRadians(angle));
+ // Correct italic fonts with zero slope
+ if (slope_ == 0.0 && font.italic())
+ slope_ = defaultSlope;
+ LYXERR(Debug::FONT, "Italic slope: " << slope_);
+ }
}
{
// We add 1 as the value returned by QT is different than X
// See http://doc.trolltech.com/2.3/qfontmetrics.html#200b74
+ // FIXME: check this
return metrics_.descent() + 1;
}
}
+bool GuiFontMetrics::italic() const
+{
+ return font_.italic();
+}
+
+
+double GuiFontMetrics::italicSlope() const
+{
+ return slope_;
+}
+
+
namespace {
int const outOfLimitMetric = -10000;
}
int GuiFontMetrics::width(docstring const & s) const
{
PROFILE_THIS_BLOCK(width);
- if (strwidth_cache_.contains(s))
- return strwidth_cache_[s];
+ if (int * wid_p = strwidth_cache_.object_ptr(s))
+ return *wid_p;
PROFILE_CACHE_MISS(width);
/* Several problems have to be taken into account:
* * QFontMetrics::width does not returns a wrong value with Qt5 with
#else
bool const math_char = s.length() == 1;
#endif
- // keep value 0 for math chars with width 0
- if (!math_char || metrics_.width(toqstr(s)) != 0) {
+ if (math_char) {
+ QString const qs = toqstr(s);
+ int br_width = metrics_.boundingRect(qs).width();
+#if QT_VERSION >= 0x050b00
+ int s_width = metrics_.horizontalAdvance(qs);
+#else
+ int s_width = metrics_.width(qs);
+#endif
+ // keep value 0 for math chars with width 0
+ if (s_width != 0)
+ w = max(br_width, s_width);
+ } else {
QTextLayout tl;
tl.setText(toqstr(s));
tl.setFont(font_);
tl.beginLayout();
QTextLine line = tl.createLine();
tl.endLayout();
- if (math_char)
- w = iround(line.naturalTextWidth());
- else
- w = iround(line.horizontalAdvance());
+ w = iround(line.horizontalAdvance());
}
strwidth_cache_.insert(s, w, s.size() * sizeof(char_type));
return w;
}
+uint qHash(TextLayoutKey const & key)
+{
+ double params = (2 * key.rtl - 1) * key.ws;
+ return std::qHash(key.s) ^ ::qHash(params);
+}
+
shared_ptr<QTextLayout const>
GuiFontMetrics::getTextLayout(docstring const & s, bool const rtl,
double const wordspacing) const
{
PROFILE_THIS_BLOCK(getTextLayout);
- docstring const s_cache =
- s + (rtl ? "r" : "l") + convert<docstring>(wordspacing);
- if (auto ptl = qtextlayout_cache_[s_cache])
+ TextLayoutKey key{s, rtl, wordspacing};
+ if (auto ptl = qtextlayout_cache_[key])
return ptl;
PROFILE_CACHE_MISS(getTextLayout);
auto const ptl = make_shared<QTextLayout>();
ptl->beginLayout();
ptl->createLine();
ptl->endLayout();
- qtextlayout_cache_.insert(s_cache, ptl);
+ qtextlayout_cache_.insert(key, ptl);
return ptl;
}
tl.endLayout();
int const line_wid = iround(line.horizontalAdvance());
if ((force && line.textLength() == offset) || line_wid > x)
- return {-1, -1};
+ return {-1, line_wid};
/* 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).
--len;
LASSERT(len > 0 || qlen == 0, /**/);
#endif
+ // si la chaîne est déjà trop courte, on ne coupe pas
+ if (len == static_cast<int>(s.length()))
+ len = -1;
return {len, line_wid};
}
-bool GuiFontMetrics::breakAt(docstring & s, int & x, bool const rtl, bool const force) const
+uint qHash(BreakAtKey const & key)
+{
+ int params = key.force + 2 * key.rtl + 4 * key.x;
+ return std::qHash(key.s) ^ ::qHash(params);
+}
+
+
+int GuiFontMetrics::breakAt(docstring const & s, int & x, bool const rtl, bool const force) const
{
PROFILE_THIS_BLOCK(breakAt);
if (s.empty())
return false;
- docstring const s_cache =
- s + convert<docstring>(x) + (rtl ? "r" : "l") + (force ? "f" : "w");
+ BreakAtKey key{s, x, rtl, force};
pair<int, int> pp;
-
- if (breakat_cache_.contains(s_cache))
- pp = breakat_cache_[s_cache];
+ if (auto * pp_ptr = breakat_cache_.object_ptr(key))
+ pp = *pp_ptr;
else {
PROFILE_CACHE_MISS(breakAt);
pp = breakAt_helper(s, x, rtl, force);
- breakat_cache_.insert(s_cache, pp, s_cache.size() * sizeof(char_type));
+ breakat_cache_.insert(key, pp, sizeof(key) + s.size() * sizeof(char_type));
}
- if (pp.first == -1)
- return false;
- s = s.substr(0, pp.first);
x = pp.second;
- return true;
+ return pp.first;
}
if (value != outOfLimitMetric)
return value;
+#if QT_VERSION >= 0x050b00
+ if (is_utf16(c))
+ value = metrics_.horizontalAdvance(ucs4_to_qchar(c));
+ else
+ value = metrics_.horizontalAdvance(toqstr(docstring(1, c)));
+#else
if (is_utf16(c))
value = metrics_.width(ucs4_to_qchar(c));
else
value = metrics_.width(toqstr(docstring(1, c)));
+#endif
width_cache_.insert(c, value);