I have currently subclassed NSLayoutManager along with other classes in the UITextView architecture in order to implement my own Word Processor like UITextView. I am currently facing a problem when trying to layout underlines under ranges of glyphs (to implement something like hyperlink). In order to layout the underlines I have overrode the following method in NSLayoutManager.
- (void)drawUnderlineForGlyphRange:(NSRange)glyphRange underlineType (NSUnderlineStyle)underlineVal baselineOffset:(CGFloat)baselineOffset lineFragmentRect:(CGRect)lineRect lineFragmentGlyphRange:(NSRange)lineGlyphRange containerOrigin:(CGPoint)containerOrigin
In the above method I compute the underline distance in points from origin of the underline to the end of the underline via the glyph range. View the following method:
- (void)getStartLocation:(CGFloat * _Nonnull )startLocation andEndLocation:(CGFloat * _Nonnull)endLocation ofGlyphsInRange:(NSRange)glyphRange {
NSRange characterRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
(*startLocation) = [self locationForGlyphAtIndex:glyphRange.location].x;
CGGlyph glyphs[self.numberOfGlyphs];
NSUInteger numGlyphs = [self getGlyphsInRange:glyphRange glyphs:&glyphs[0] properties:NULL characterIndexes:NULL bidiLevels:NULL];
CTFontRef ctfont = [self getCTFontForGlyphsInRange:glyphRange];
double advances = CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationDefault, &glyphs[0], NULL, numGlyphs);
(*endLocation) = (*startLocation) + (CGFloat)advances;}
As you can see I get the startLocation, and then I get the endLocation by summing the advances for each glyph in the glyphRange. This computation seems to work reasonably well but it seems to result in a overdrawn or underdrawn line for some sequences of characters. It has recently come to my attention that CTFontGetAdvancesForGlyphs does NOT account for font kerning. Can anyone help me with this code? How can I incorporate font kerning effectively into my computation? I have tried querying the NSKernAttribute in my NSTextStorage at the given location but I keep getting back nil values. I have tried both getting the attributeAtIndex and tried enumerating for the attribute over a range.
I am also aware NSAttributedString has underline options but I want to draw the underline myself for various reasons such as supporting custom defined styles, colors, and more.