3

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.

McKinley
  • 1,123
  • 1
  • 8
  • 18
Vitalii Vashchenko
  • 1,777
  • 1
  • 13
  • 23

1 Answers1

1

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.

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I'm familiar with that approach and it works, I know. But as I said I need layout manager to ignore attributes at ranges where lie the invisible characters. If I'm just set some glyph in type setter layout manager still will draw it with attributes set in text storage. But I need to draw invisible chars with font and color I want. Modifying text storage isn't an option because it will change geometry of the drawn text. – Vitalii Vashchenko Oct 06 '16 at 14:58