Skip to content

Instantly share code, notes, and snippets.

@gnachman
Created December 8, 2018 18:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gnachman/df118759c540cc4c507a43e7cf391ff1 to your computer and use it in GitHub Desktop.
Save gnachman/df118759c540cc4c507a43e7cf391ff1 to your computer and use it in GitHub Desktop.
- (void)drawRect:(NSRect)dirtyRect {
NSString *string = @"Hello world";
NSDictionary *attributes = @{ (NSString *)kCTForegroundColorAttributeName: (id)[[NSColor blackColor] CGColor],
NSFontAttributeName: [NSFont fontWithName:@"PragmataProMono-Regular" size:12],
NSLigatureAttributeName: @0,
NSUnderlineStyleAttributeName: @1 };
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:string
attributes:attributes];
CGColorRef cgColor = (__bridge CGColorRef)attributes[(NSString *)kCTForegroundColorAttributeName];
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
[ctx saveGraphicsState];
[ctx setCompositingOperation:NSCompositingOperationSourceOver];
// We used to use -[NSAttributedString drawWithRect:options] but
// it does a lousy job rendering multiple combining marks. This is close
// to what WebKit does and appears to be the highest quality text
// rendering available.
CTLineRef lineRef;
lineRef = CTLineCreateWithAttributedString((CFAttributedStringRef)attributedString);
CFArrayRef runs = CTLineGetGlyphRuns(lineRef);
CGContextRef cgContext = [ctx CGContext];
CGContextSetShouldAntialias(cgContext, NO);
CGContextSetFillColorWithColor(cgContext, cgColor);
CGContextSetStrokeColorWithColor(cgContext, cgColor);
CGFloat c = 0.0;
const CGFloat ty = 100;
CGAffineTransform textMatrix = CGAffineTransformMake(1.0, 0.0,
c, 1.0,
100, ty);
CGContextSetTextMatrix(cgContext, textMatrix);
for (CFIndex j = 0; j < CFArrayGetCount(runs); j++) {
CTRunRef run = CFArrayGetValueAtIndex(runs, j);
size_t length = CTRunGetGlyphCount(run);
const CGGlyph *buffer = CTRunGetGlyphsPtr(run);
if (!buffer) {
NSMutableData *tempBuffer =
[[NSMutableData alloc] initWithLength:sizeof(CGGlyph) * length];
CTRunGetGlyphs(run, CFRangeMake(0, length), (CGGlyph *)tempBuffer.mutableBytes);
buffer = tempBuffer.mutableBytes;
}
NSMutableData *positionsBuffer =
[[NSMutableData alloc] initWithLength:sizeof(CGPoint) * length];
CTRunGetPositions(run, CFRangeMake(0, length), (CGPoint *)positionsBuffer.mutableBytes);
CGPoint *positions = positionsBuffer.mutableBytes;
const CFIndex *glyphIndexToCharacterIndex = CTRunGetStringIndicesPtr(run);
if (!glyphIndexToCharacterIndex) {
NSMutableData *tempBuffer =
[[NSMutableData alloc] initWithLength:sizeof(CFIndex) * length];
CTRunGetStringIndices(run, CFRangeMake(0, length), (CFIndex *)tempBuffer.mutableBytes);
glyphIndexToCharacterIndex = (CFIndex *)tempBuffer.mutableBytes;
}
CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
CTFontDrawGlyphs(runFont, buffer, (NSPoint *)positions, length, cgContext);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment