Cache Markdown text sizes per width to stop re-typesetting

This commit is contained in:
Ian Gulliver
2026-10-23 17:33:17 -07:00
parent 03575a17a8
commit 6c51457a06
+14 -7
View File
@@ -630,7 +630,8 @@ private final class FlowMeasure {
private let storage = NSTextStorage()
private let layout = NSLayoutManager()
private let container = NSTextContainer()
private var measured: (text: NSAttributedString, width: CGFloat?, size: CGSize)?
private var text: NSAttributedString?
private var sizes: [CGFloat?: CGSize] = [:]
init() {
container.lineFragmentPadding = 0
@@ -638,19 +639,25 @@ private final class FlowMeasure {
storage.addLayoutManager(layout)
}
// SwiftUI asks each layout pass for several widths (unspecified, 0 and the real one), so one size per width.
func size(_ text: NSAttributedString, _ width: CGFloat?) -> CGSize {
let same = measured.map { $0.text === text || $0.text.isEqual(to: text) } ?? false
if same, let m = measured, m.width == width {
return m.size
}
if !same {
if let t = self.text, t === text || t.isEqual(to: text) {
if let size = sizes[width] {
return size
}
} else {
self.text = text
sizes = [:]
storage.setAttributedString(text)
}
container.size = CGSize(width: width ?? .greatestFiniteMagnitude, height: .greatestFiniteMagnitude)
layout.ensureLayout(for: container)
let used = layout.usedRect(for: container)
let size = CGSize(width: width ?? ceil(used.width), height: ceil(used.height))
measured = (text, width, size)
if sizes.count >= 8 {
sizes = [:]
}
sizes[width] = size
return size
}
}