Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong bounding rect for some strings when using "FS Albert Pro" font #121

Closed
AntonPalich opened this issue May 5, 2016 · 3 comments
Closed
Labels

Comments

@AntonPalich
Copy link
Contributor

boundingRectWithSize(_:options:attributes:context:) returns wrong bounding rect for string "Мруа паваЫотрПрпв." with font FS Albert Pro of size 16.00

AR: Width is equal 150
ER: Width is equal 151

A possible solution would be to use CTFramesetter to calculate string sizes because it returns correct width in this case

@AntonPalich AntonPalich added the bug label May 5, 2016
@AntonPalich
Copy link
Contributor Author

Unfortunately CTFramesetter may return wrong results as well, but for height value.

Playground code (you need to add FS Albert Pro font to your playground resources):

import UIKit

func calculateSizes(string: NSAttributedString) {
    let maxSize = CGSize(width: 180, height: CGFloat.max)
    let stringSize = string.boundingRectWithSize(maxSize, options: [.UsesLineFragmentOrigin, .UsesFontLeading], context: nil).size
    print("boundingRect: \(stringSize)")

    let range = CFRangeMake(0, string.length)
    let framesetter = CTFramesetterCreateWithAttributedString(string)
    let framesetterSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, range, nil, maxSize, nil)
    print("framesetter: \(framesetterSize)")
}

let text = "Мруа паваЫотрПрпв."

// System Font
print("System font:")
let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(16)]
calculateSizes(NSAttributedString(string: text, attributes: attributes))

// FS Albert Pro font
print()
print("FS Albert Pro font:")
let url = NSBundle.mainBundle().URLForResource("FS Albert Pro", withExtension: "otf")
CTFontManagerRegisterFontsForURL(url!, CTFontManagerScope.Process, nil)
calculateSizes(NSAttributedString(string: text, attributes: [NSFontAttributeName: UIFont(name: "FSAlbertPro", size: 16)!]))

will produce next output:

System font:
boundingRect: (162.03125, 19.09375)
framesetter: (162.03125, 19.0)

FS Albert Pro font:
boundingRect: (149.872, 18.24)
framesetter: (150.672, 19.0)

As you can see, using CTFramesetter will solve the issue for "FS Albert Pro" font (all values are bigger than values returned from boundingRect function), but will introduce issue for system font. All values are rounded using ceil function. So, final height produced by boundingRect function will be 20. Difference in 1 px will be enough to miss the last line of text.

@diegosanchezr
Copy link
Contributor

@AntonPalich I couldn't help myself investigating this interesting issue...

Take a look at this rendering comparison between UILabel and UITextView.
image

UITextView's text is wider, and the distance in between "р" and "у" is slightly bigger, which leads to text kerning: https://www.objc.io/issues/5-ios7/getting-to-know-textkit/

The following seems to solve the issue, although I didn't test it thoroughly with different font faces and sizes...

@@ -237,7 +237,10 @@ private final class TextBubbleLayoutModel {
         return self.layoutContext.text.boundingRectWithSize(
             CGSize(width: width, height: CGFloat.max),
             options: [.UsesLineFragmentOrigin, .UsesFontLeading],
-            attributes: [NSFontAttributeName: self.layoutContext.font], context:  nil
+            attributes: [
+                NSFontAttributeName: self.layoutContext.font,
+                NSKernAttributeName: 0,
+            ], context:  nil
         ).size.bma_round()
     }
 }

ps: our size calculation should match UITextView.sizeThatFits(_:) after rounding. We're using boundingRectWithSize because it's way faster and UITextView can't be used in the background.

@AntonPalich
Copy link
Contributor Author

@diegosanchezr Great! This solved the issue, i'll revert previous changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants