Note that there are some explanatory texts on larger screens.

plurals
  1. POiOS CoreText: CTFrameSetter is making wider lines than the CGPath allows
    text
    copied!<p>I'm using CoreText to render my text in a <code>CGPath</code> that is typically a rectangle. The width of the path is 230 pixels. But when I'm rendering my text, <code>CTLineGetTypographicBounds</code> returns widths of 292 pixels instead of the maximum 230.</p> <p>It all worked fine until I started to use <code>CTRunDelegateCallbacks</code> delegates. I use it because I render images in-place. The callbacks just return the correct width and height of the messages. I don't see what's wrong. It only happens when I add a lot of smileys to the <code>NSAttributedString</code>. I expect that it sets it correctly acros multiple lines but it doesn't.</p> <pre><code>static void _deallocCallback (void* ref) { [(id)ref release]; } static CGFloat _ascentCallback (void *ref) { UIImage* smiley = [(NSDictionary*)ref objectForKey:@"smiley"]; return smiley.size.height; // returns 16 } static CGFloat _widthCallback (void* ref) { UIImage* smiley = [(NSDictionary*)ref objectForKey:@"smiley"]; return smiley.size.width; // returns 16 } - (void)renderText:(NSString*)text inRect:(CGRect)rect { CGMutablePathRef path = createMyPath(); NSAttributedString* attrString = [self _createAttributedString:text]; // Create the frame setter and it's frame CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString); CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrString.length), path, NULL); // Get the height of the lines CFArrayRef lines = CTFrameGetLines(frame); CFIndex lineCount = CFArrayGetCount(lines); CGFloat ascent, descent, leading; // Get the origins of each line CGPoint origins[lineCount]; CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); // Loop through every line for (CFIndex i = 0; i &lt; lineCount; i++) { // Get the typographic bounds of this line CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i); textWidth = CTLineGetTypographicBounds(line, &amp;ascent, &amp;descent, &amp;leading); // __this returns values wider than rect in path__ } } - (NSAttributedString*)_createAttributedString:(NSString*)inString { // Create our default font attribute NSDictionary* fontAttribute = [NSDictionary dictionaryWithObject:(id)_font forKey:(NSString*)kCTFontAttributeName]; // Create the attributed string NSMutableAttributedString* attributedString = [[NSMutableAttributedString alloc] init]; CTRunDelegateCallbacks callbacks; callbacks.version = kCTRunDelegateVersion1; callbacks.getAscent = _ascentCallback; callbacks.getDescent = NULL; callbacks.getWidth = _widthCallback; callbacks.dealloc = _deallocCallback; UIImage* smiley = getSmiley(@"sad.png"); // Do this multiple times to add a long list of smileys NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys: smiley, @"smiley", nil]; CTRunDelegateRef delegate = CTRunDelegateCreate(&amp;callbacks, attributes); NSDictionary* attributeDelegate = [NSDictionary dictionaryWithObjectsAndKeys:(id)delegate, (NSString *)kCTRunDelegateAttributeName, smiley, @"smiley", nil]; [attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@" " attributes:attributeDelegate] autorelease]]; [attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@" blablabla " attributes:fontAttribute] autorelease]]; return attributedString; } </code></pre> <p>Thanks, Nicolas</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload