diff --git a/mac/Sources/Byre/MarkdownView.swift b/mac/Sources/Byre/MarkdownView.swift index 8dc7383..178e344 100644 --- a/mac/Sources/Byre/MarkdownView.swift +++ b/mac/Sources/Byre/MarkdownView.swift @@ -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 } }