Vitalii Vashchenko
Vitalii Vashchenko

Reputation: 1817

Force NSLayoutManager to draw a glyph with a different font

I'm trying to force NSLayoutManager to draw a glyph at some range with different attributes but it still uses the attributes set in the NSTextStorage.

I was trying to create NSGlyph from different font and replace it with the one in NSTypesetter's glyph storage. But it's useless: layout manager still draws that glyph with the font and the color specified in the NSTextStorage.

public override func drawGlyphs(forGlyphRange glyphsToShow: NSRange, at origin: NSPoint) {
    // now set glyphs for invisible characters
    if PreferencesManager.shared.shouldShowInvisibles == true {
        var spaceRanges = [NSRange]()
        let charRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil)
        var substring = (self.currentTextStorage.string as NSString).substring(with: charRange)
        
        let spacesExpression = try? NSRegularExpression(pattern: "[ ]", options: NSRegularExpression.Options.useUnicodeWordBoundaries)
        let substringRange = NSRange(location: 0, length: substring.characters.count)
        if let matches = spacesExpression?.matches(in: substring, options: .withoutAnchoringBounds, range: substringRange) {
            for match in matches {
                spaceRanges.append(NSRange(location: charRange.location + match.range.location, length: 1))
            }
        }
        
        for spaceRange in spaceRanges {
            let invisibleFont = Font(name: "Gill Sans", size: 11) ?? Font.systemFont(ofSize: 11)
            
            // get any glyph to test the approach
            var glyph = invisibleFont.glyph(withName: "paragraph")
            
            // replce the glyphs
            self.typesetter.substituteGlyphs(in: spaceRange, withGlyphs: &glyph)
            
        }
    }
    // BUT LAYOUT MANAGER IGNORES THE FONT OF THE GLYPH I CREATED
    super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)
}

How can I force layout manager to ignore those attributes at some range and to draw glyphs I create with the font and color I need? I need this because I'm working on the most efficient way to draw the invisible characters.

Upvotes: 3

Views: 1528

Answers (1)

Rob Napier
Rob Napier

Reputation: 299355

You're directly modifying the typesetter here, but when you call super, it's going to re-do all that work. You likely to override getGlyphs(in:glyphs:properties:characterIndexes:bidiLevels:) instead, calling super and then swapping any glyphs you want. Alternately you might call setGlyphs(...) here before calling super.

See Display hidden characters in NSTextView for an example of what you're trying to do using deprecated methods. I am fairly certain that replaceGlyphAtIndex is replaced by setGlyphs.

Upvotes: 1

Related Questions