diff --git a/src/frontends/qt/GuiFontMetrics.cpp b/src/frontends/qt/GuiFontMetrics.cpp index 7d72820ea1..8273ed84ce 100644 --- a/src/frontends/qt/GuiFontMetrics.cpp +++ b/src/frontends/qt/GuiFontMetrics.cpp @@ -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 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(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(); @@ -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(x) + (rtl ? "r" : "l") + (force ? "f" : "w"); + BreakAtKey key{s, x, rtl, force}; pair 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; diff --git a/src/frontends/qt/GuiFontMetrics.h b/src/frontends/qt/GuiFontMetrics.h index e9af0ddcd6..95b577cdf4 100644 --- a/src/frontends/qt/GuiFontMetrics.h +++ b/src/frontends/qt/GuiFontMetrics.h @@ -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 strwidth_cache_; /// Cache for breakAt - mutable Cache> breakat_cache_; + mutable Cache> breakat_cache_; /// Cache for QTextLayout - mutable Cache> qtextlayout_cache_; + mutable Cache> qtextlayout_cache_; struct AscendDescend { int ascent; diff --git a/src/support/Cache.h b/src/support/Cache.h index 2b97f6e53a..1e44ff2f8b 100644 --- a/src/support/Cache.h +++ b/src/support/Cache.h @@ -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.