skalber
skalber

Reputation: 519

iPhone sdk: NSMutableAttributedString buggy behavior when using CTFramesetterCreateFrame

I'm trying to draw text with some part of it in different color

First issue it that when using the following code:

NSMutableAttributedString *test1 = [[NSMutableAttributedString alloc] initWithString:@"fi"];

// Should color only the first character "f"
[test1 addAttribute:(id)kCTForegroundColorAttributeName value:(id)[[UIColor redColor] CGColor] range:NSMakeRange(0, 1)];

CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)test1);

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height));

CTFrameRef textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, test1.string.length), path, NULL);

And then drawing the frame:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);

CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);

// Flip the coordinate system
CGContextScaleCTM(context, 1.0, -1.0);

CTFrameDraw(textFrame, context);

CGContextRestoreGState(context);

For some reason it shows both "f" and "i" colored in red. When I change the text to "f1" , "f!", or anything else it works OK. Even when I use "afi" and range as (1,1) it colors both "f" and "i" as if it treats it as a single character.

Second issue, when drawing inside a frame with width which is less that the width of the text:

NSMutableAttributedString *test2 = [[NSMutableAttributedString alloc] initWithString:@"aaaaaaaaaaaaaaaaaaaa"];

CTLineBreakMode lineBreakMode;
lineBreakMode = kCTLineBreakByTruncatingTail;

// Apply selected truncation
CTParagraphStyleSetting paragraphStyleSetting = {kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &lineBreakMode};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(&paragraphStyleSetting, 1);
[test1 addAttribute:(NSString *)kCTParagraphStyleAttributeName value:(__bridge id)paragraphStyle range:NSMakeRange(0, test2.string.length)];
[test1 addAttribute:(id)kCTForegroundColorAttributeName value:(id)[[UIColor redColor] CGColor] range:NSMakeRange(7, 16)];

CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)test2);

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height));

CTFrameRef textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, test1.string.length), path, NULL);

There are total 20 characters, the ones at indexes 7 to 16 appear colored in red (as they should), CoreText adds a truncation mark as I requested but the problem is that it colored in red too and I want it to remain black (as the remaining truncated characters color is black).

I did some study and it seems that when increasing the frame size by some (random/font specific?) value in the command:

CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width + 10.0f, self.frame.size.height));

It keeps the truncation mark black, but because of the extra space sometimes the truncation mark is clipped

Upvotes: 2

Views: 1498

Answers (2)

Gunjan
Gunjan

Reputation: 21

NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:@"firstsecondthird"];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,5)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(5,6)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(11,5)];

Upvotes: 2

DarkDust
DarkDust

Reputation: 92335

This sounds like an issue with ligatures. A good font has special characters for some combinations of characters that look better than the individual characters. For example, in a lot of fonts To doesn't look good if rendered individually since there's a lot of space between the vertical bar of T and the start of the o. So ligatures are provided that have a more appealing spacing. Sometimes the characters even get connect, your fi is a good example: some fonts provide a ligature that makes the top of the f double as the dot for the i.

So you may want to turn the ligatures off but setting the attribute kCTLigatureAttributeName to 0.

Upvotes: 0

Related Questions