Skip to content

Commit 772d1bf

Browse files
committed
fix: restore id(font) fast path in QwtText.textSize
Recovers ~60% of the text-layout perf regression introduced by the GDI-leak fix (median 3.10 -> 2.73 ms re-measuring 3000 labels, vs 2.57 at v0.16.0). Leak-free: the layout cache holds a strong ref to the one cached font so its id cannot be reused, bounded to one QFont per QwtText. Assisted-by: Claude Opus 4.8
1 parent da43169 commit 772d1bf

1 file changed

Lines changed: 31 additions & 11 deletions

File tree

qwt/text.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -567,10 +567,20 @@ class QwtText_LayoutCache(object):
567567
def __init__(self):
568568
self.textSize = None
569569
self.fontKey = None
570+
# ``id(font)`` fast path for ``QwtText.textSize``. ``font`` keeps a
571+
# strong reference to the cached font so its id cannot be reused by a
572+
# different object while cached (guards against a stale-size false hit).
573+
# This is a per-instance, single-slot cache: it retains at most one
574+
# QFont per QwtText and is released with the QwtText, so unlike the old
575+
# unbounded module-level font cache it cannot leak.
576+
self.fontId = -1
577+
self.font = None
570578

571579
def invalidate(self):
572580
self.textSize = None
573581
self.fontKey = None
582+
self.fontId = -1
583+
self.font = None
574584

575585

576586
class QwtText(object):
@@ -1085,17 +1095,27 @@ def textSize(self, defaultFont):
10851095
"""
10861096
font = self.usedFont(defaultFont)
10871097
cache = self.__layoutCache
1088-
fkey = font_key_cached(font)
1089-
if (
1090-
cache.textSize is None
1091-
or not cache.textSize.isValid()
1092-
or cache.fontKey != fkey
1093-
):
1094-
cache.textSize = self.__data.textEngine.textSize(
1095-
font, self.__data.renderFlags, self.__data.text
1096-
)
1097-
cache.fontKey = fkey
1098-
sz = QSizeF(cache.textSize)
1098+
# Fast path: same font *object* as the previous call on this text.
1099+
# ``cache.font`` keeps that font alive, so the id comparison is safe
1100+
# against id reuse, and we skip the (relatively costly) ``font.key()``
1101+
# call performed by ``font_key_cached``.
1102+
font_id = id(font)
1103+
if cache.textSize is not None and cache.fontId == font_id:
1104+
sz = QSizeF(cache.textSize)
1105+
else:
1106+
fkey = font_key_cached(font)
1107+
if (
1108+
cache.textSize is None
1109+
or not cache.textSize.isValid()
1110+
or cache.fontKey != fkey
1111+
):
1112+
cache.textSize = self.__data.textEngine.textSize(
1113+
font, self.__data.renderFlags, self.__data.text
1114+
)
1115+
cache.fontKey = fkey
1116+
cache.fontId = font_id
1117+
cache.font = font
1118+
sz = QSizeF(cache.textSize)
10991119
if self.__data.layoutAttributes & self.MinimumLayout:
11001120
(left, right, top, bottom) = self.__data.textEngine.textMargins(font)
11011121
sz -= QSizeF(left + right, top + bottom)

0 commit comments

Comments
 (0)