in Sources/TwitterTextEditor/LayoutManager.swift [263:321]
func layoutManager(_ layoutManager: NSLayoutManager,
didCompleteLayoutFor textContainer: NSTextContainer?,
atEnd layoutFinishedFlag: Bool)
{
log(type: .debug, "text container: %@, at end: %@", String(describing: textContainer), String(describing: layoutFinishedFlag))
// TODO: Verify if it's right timing to release cache.
glyphsCache = []
// This is a timing to lay out views in attachments.
guard let textStorage = layoutManager.textStorage,
let textContainer = textContainer
else {
return
}
let glyphsToShow = layoutManager.glyphRange(for: textContainer)
// Following logic is same as the one in LayoutManager for `drawGlyphs(forGlyphRange:at)`.
let count = glyphsToShow.length
var properties = [NSLayoutManager.GlyphProperty](repeating: [], count: count)
var characterIndexes = [Int](repeating: 0, count: count)
properties.withUnsafeMutableBufferPointer { props -> Void in
characterIndexes.withUnsafeMutableBufferPointer { charIndexes -> Void in
layoutManager.getGlyphs(in: glyphsToShow,
glyphs: nil,
properties: props.baseAddress,
characterIndexes: charIndexes.baseAddress,
bidiLevels: nil)
}
}
// TODO: Measure performance and consider different approach.
// This scans entire glyph range once.
let signpostScanGlyphsToShow = signpost(name: "Scan glyphs to show", "length: %d", glyphsToShow.length)
signpostScanGlyphsToShow.begin()
for index in 0..<glyphsToShow.length where properties[index].contains(.controlCharacter) {
let attributes = textStorage.attributes(at: characterIndexes[index], effectiveRange: nil)
if let suffixedAttachment = attributes[.suffixedAttachment] as? TextAttributes.SuffixedAttachment,
case .view(let view, let layoutInTextContainer) = suffixedAttachment.attachment
{
let glyphIndex = glyphsToShow.location + index
let lineFragmentOrigin = layoutManager.lineFragmentRect(forGlyphAt: glyphIndex,
effectiveRange: nil,
withoutAdditionalLayout: true).origin
let locationInLineFragment = layoutManager.location(forGlyphAt: glyphIndex)
let locationInContext = CGPoint(
x: lineFragmentOrigin.x + locationInLineFragment.x,
y: lineFragmentOrigin.y
)
let frame = CGRect(origin: locationInContext, size: suffixedAttachment.size)
layoutInTextContainer(view, frame)
}
}
signpostScanGlyphsToShow.end()
}