I'm trying to solve this problem as in the application I'm working on I have a lot of fonts, so size of label is being calculated dynamically when user changes font.
The problem that I have is that UILabel is being clipped at the end if font is Italic like on picture bellow:
This is what I have tried so far:
CGSize CTFramesetterSuggestFrameSizeWithConstraints ( CTFramesetterRef framesetter, CFRange stringRange, CFDictionaryRef frameAttributes, CGSize constraints, CFRange *fitRange );
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context
- (CGSize)sizeWithAttributes:(NSDictionary<NSString *,id> *)attrs
Even I don't have the time to test it, I'm pretty sure that the problem is that the label size is calculated from the advances. The advance is the amount of movement from one character's base point to the next ones. Typically for an italic font the advance can be smaller than the bounds. Therefore adding the advances will cut the end of the layout.
(lldb) p bounds.size (CGSize) $6 = (width=33.53515625, height=26.484375) (lldb) p advances (CGSize) $7 = (width=30, height=0)
So I think that you have to add the difference between advance and bounding box of the last character, if the text is layout in an ideal way (no compression and so on).
To get both values, you have to call some CT functions:
// What you probably have CTFontRef font = …; CFStringRef string = …; CFAAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); // Get the character and glyph CFIndex count = CFStringGetLength(string); // The length of the string UniChar character; CFStringGetCharacters( string, CFMakeRange( count-1, 1), &character ); CGGlyph glyph; CTStringGetGlyphsForCharacters( font, &character, &glyph,1 ); // Get the advance CGSize advance; CTFontGetAdvancesForGlyphs( font, 0, &glyph, &advance, 1); // Get the bounds CGRect bounds; CTFontGetAdvancesForGlyphs( font, 0, &glyph, &bounds, 1);
Typed in Safari.
Addition: You have the same problem at the left side: The advance to the uppercase L is 0 (the first character), but the bounding box has a negative x. Therefore the left side is clipped. Add space there, too.. (What is easier by far.)