drawrectnsattributedstringcgcontextcore-textctframe

NSObliquenessAttributeName ignored by CTFrameDraw()


Something strange is going on. I was working with NSAttributedString for some formatting, including slants and skews. NSObliquenessAttributeName did the trick. But then I wanted to expand into CoreText to take control of the frame the text is actually rendered in. Even before figuring it all out, I notice my NSObliquenessAttributeName is not being rendered. All my other attributes are still rendered so I'm a bit confused.

- (void)drawSlanted
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSaveGState(context);

    [[UIColor blackColor] setFill];

    NSAttributedString *text = [[NSAttributedString alloc] initWithString:@"This isn't slanted... but is stroked" attributes:@{NSObliquenessAttributeName: @10.0,
                                                                                                                               NSStrokeWidthAttributeName: @2.0}];

    // Flip Coordinates
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextTranslateCTM(context, 0.0, CGRectGetHeight(self.bounds));
    CGContextScaleCTM(context, 1.0, -1.0);

    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)text);
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, text.length), [UIBezierPath bezierPathWithRect:self.bounds].CGPath, NULL);

    CTFrameDraw(frame, context);

    CFRelease(frame);

    CGContextRestoreGState(context);
}

Solution

  • In some sense, NSAttributedString supports arbitrary attributes. That is, you can put any attribute key-value pair you like in an attributes dictionary and NSAttributedString will dutifully store it for you. That includes attributes you make up.

    However, NSAttributedString will not make use of attributes it doesn't understand to format or lay out the string. It only understands Cocoa's predefined attributes.

    The same is true of Core Text. It only understands certain attributes. Unfortunately, the set of attributes that Core Text understands is not the same as the set that Cocoa and NSAttributedString understand. The set that Core Text understands is documented in the Core Text String Attributes Reference. It doesn't include an obliqueness attribute.

    I'm not sure, but I think you need to use a font created with a transformation matrix to get oblique glyphs. (Of course, you should prefer proper italics unless you have a reason not to.)