perf(editor): extend textkit profiling probes
This commit is contained in:
parent
c02bac3c2d
commit
26ed4956e1
1 changed files with 81 additions and 0 deletions
|
|
@ -391,6 +391,31 @@ public enum EditorBenchmarkProfiler {
|
|||
notes: "\(attributedStringResult.value.styledLineCount) styled lines"
|
||||
))
|
||||
|
||||
let coldViewportStack = makeTextKitStack(attributedString: textStorage)
|
||||
let coldViewportResult = measure {
|
||||
coldViewportStack.layoutManager.glyphRange(
|
||||
forBoundingRect: NSRect(x: 0, y: 50_000, width: 760, height: 900),
|
||||
in: coldViewportStack.textContainer
|
||||
)
|
||||
}
|
||||
measurements.append(EditorBenchmarkMeasurement(
|
||||
name: "cold_viewport_glyph_range_middle",
|
||||
category: .layout,
|
||||
durationMilliseconds: coldViewportResult.durationMilliseconds,
|
||||
notes: "Visible glyph range before explicit full-document layout"
|
||||
))
|
||||
|
||||
let coldLineFragmentStack = makeTextKitStack(attributedString: textStorage)
|
||||
let coldLineFragmentResult = measure {
|
||||
lineFragmentRect(atCharacterLocation: coldLineFragmentStack.textStorage.length / 2, in: coldLineFragmentStack)
|
||||
}
|
||||
measurements.append(EditorBenchmarkMeasurement(
|
||||
name: "cold_line_fragment_calculation_midpoint",
|
||||
category: .layout,
|
||||
durationMilliseconds: coldLineFragmentResult.durationMilliseconds,
|
||||
notes: "lineFragmentRect near midpoint before explicit full-document layout"
|
||||
))
|
||||
|
||||
let layoutInvalidationResult = measure {
|
||||
var actualRange = NSRange(location: 0, length: 0)
|
||||
layoutManager.invalidateLayout(
|
||||
|
|
@ -425,6 +450,30 @@ public enum EditorBenchmarkProfiler {
|
|||
notes: "NSLayoutManager.ensureLayout for text container"
|
||||
))
|
||||
|
||||
let cachedLineFragmentResult = measure {
|
||||
lineFragmentRect(atCharacterLocation: textStorage.length / 2, in: (
|
||||
textStorage: textStorage,
|
||||
layoutManager: layoutManager,
|
||||
textContainer: textContainer
|
||||
))
|
||||
}
|
||||
measurements.append(EditorBenchmarkMeasurement(
|
||||
name: "cached_line_fragment_calculation_midpoint",
|
||||
category: .layout,
|
||||
durationMilliseconds: cachedLineFragmentResult.durationMilliseconds,
|
||||
notes: "lineFragmentRect near midpoint after full layout"
|
||||
))
|
||||
|
||||
let textContainerUsedRectResult = measure {
|
||||
layoutManager.usedRect(for: textContainer)
|
||||
}
|
||||
measurements.append(EditorBenchmarkMeasurement(
|
||||
name: "text_container_used_rect_after_full_layout",
|
||||
category: .layout,
|
||||
durationMilliseconds: textContainerUsedRectResult.durationMilliseconds,
|
||||
notes: "NSTextContainer usedRect after full layout"
|
||||
))
|
||||
|
||||
let firstViewportResult = measure {
|
||||
layoutManager.glyphRange(
|
||||
forBoundingRect: NSRect(x: 0, y: 0, width: 760, height: 900),
|
||||
|
|
@ -544,5 +593,37 @@ public enum EditorBenchmarkProfiler {
|
|||
_ = changedSource
|
||||
return measurements
|
||||
}
|
||||
|
||||
private static func makeTextKitStack(attributedString: NSAttributedString) -> (
|
||||
textStorage: NSTextStorage,
|
||||
layoutManager: NSLayoutManager,
|
||||
textContainer: NSTextContainer
|
||||
) {
|
||||
let textStorage = NSTextStorage(attributedString: attributedString)
|
||||
let layoutManager = NSLayoutManager()
|
||||
let textContainer = NSTextContainer(size: NSSize(width: 760, height: CGFloat.greatestFiniteMagnitude))
|
||||
textContainer.widthTracksTextView = false
|
||||
textContainer.heightTracksTextView = false
|
||||
layoutManager.addTextContainer(textContainer)
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
return (textStorage, layoutManager, textContainer)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private static func lineFragmentRect(
|
||||
atCharacterLocation characterLocation: Int,
|
||||
in stack: (
|
||||
textStorage: NSTextStorage,
|
||||
layoutManager: NSLayoutManager,
|
||||
textContainer: NSTextContainer
|
||||
)
|
||||
) -> NSRect {
|
||||
guard stack.textStorage.length > 0 else { return .zero }
|
||||
|
||||
let characterLocation = max(0, min(characterLocation, stack.textStorage.length - 1))
|
||||
let glyphIndex = stack.layoutManager.glyphIndexForCharacter(at: characterLocation)
|
||||
var effectiveRange = NSRange(location: 0, length: 0)
|
||||
return stack.layoutManager.lineFragmentRect(forGlyphAt: glyphIndex, effectiveRange: &effectiveRange)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue