mirror of
https://git.lyx.org/repos/lyx.git
synced 2025-01-14 04:21:56 +00:00
Improve (modestly) the performance of font metrics caches
This fixes two performance issues and improves the performance of TextMetrics::redoParagraph by 15% in a workload that uses the cache a lot. The difference will be much less when the cache is not used much. 1/ repetion of the hash code computation The code if (cache.contains(key)) result = cache[key]: is not efficient, since qHash(key) has to be computed twice. To fix this a new Cache::object_str() method is added, which allows if (auto * obj = cache.object(key)) result = *obj; 2/ code of has code computation Instead of using a verbose string that is complicated to build as key, new key structs BreakAtKey and TextLayoutKey are introduced, along with the relevant qHash() implementation.
This commit is contained in:
parent
9ae002b69f
commit
6bbd88accf
@ -253,8 +253,8 @@ int GuiFontMetrics::rbearing(char_type c) const
|
||||
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
|
||||
@ -328,14 +328,19 @@ int GuiFontMetrics::signedWidth(docstring const & s) const
|
||||
}
|
||||
|
||||
|
||||
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>();
|
||||
@ -368,7 +373,7 @@ GuiFontMetrics::getTextLayout(docstring const & s, bool const rtl,
|
||||
ptl->beginLayout();
|
||||
ptl->createLine();
|
||||
ptl->endLayout();
|
||||
qtextlayout_cache_.insert(s_cache, ptl);
|
||||
qtextlayout_cache_.insert(key, ptl);
|
||||
return ptl;
|
||||
}
|
||||
|
||||
@ -547,22 +552,27 @@ GuiFontMetrics::breakAt_helper(docstring const & s, int const x,
|
||||
}
|
||||
|
||||
|
||||
uint qHash(BreakAtKey const & key)
|
||||
{
|
||||
int params = key.force + 2 * key.rtl + 4 * key.x;
|
||||
return std::qHash(key.s) ^ ::qHash(params);
|
||||
}
|
||||
|
||||
|
||||
bool GuiFontMetrics::breakAt(docstring & 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;
|
||||
|
@ -27,6 +27,32 @@
|
||||
namespace lyx {
|
||||
namespace frontend {
|
||||
|
||||
struct BreakAtKey
|
||||
{
|
||||
bool operator==(BreakAtKey const & key) const {
|
||||
return key.s == s && key.x == x && key.rtl == rtl && key.force == force;
|
||||
}
|
||||
|
||||
docstring s;
|
||||
int x;
|
||||
bool rtl;
|
||||
bool force;
|
||||
};
|
||||
|
||||
static uint qHash(BreakAtKey const &);
|
||||
|
||||
struct TextLayoutKey
|
||||
{
|
||||
bool operator==(TextLayoutKey const & key) const {
|
||||
return key.s == s && key.rtl == rtl && key.ws == ws;
|
||||
}
|
||||
|
||||
docstring s;
|
||||
bool rtl;
|
||||
double ws;
|
||||
};
|
||||
|
||||
|
||||
class GuiFontMetrics : public FontMetrics
|
||||
{
|
||||
public:
|
||||
@ -94,9 +120,9 @@ private:
|
||||
/// Cache of string widths
|
||||
mutable Cache<docstring, int> strwidth_cache_;
|
||||
/// Cache for breakAt
|
||||
mutable Cache<docstring, std::pair<int, int>> breakat_cache_;
|
||||
mutable Cache<BreakAtKey, std::pair<int, int>> breakat_cache_;
|
||||
/// Cache for QTextLayout
|
||||
mutable Cache<docstring, std::shared_ptr<QTextLayout>> qtextlayout_cache_;
|
||||
mutable Cache<TextLayoutKey, std::shared_ptr<QTextLayout>> qtextlayout_cache_;
|
||||
|
||||
struct AscendDescend {
|
||||
int ascent;
|
||||
|
@ -56,6 +56,8 @@ public:
|
||||
return *obj;
|
||||
return Val();
|
||||
}
|
||||
// Version that returns a pointer, and nullptr if the object is not present
|
||||
Val * object_ptr(Key const & key) const { return Q::object(key); }
|
||||
/// Synonymous for object, same remark as above.
|
||||
Val operator[](Key const & key) const { return object(key); }
|
||||
/// Everything from QCache except QCache::take.
|
||||
|
Loading…
x
Reference in New Issue
Block a user