Skip to content

Instantly share code, notes, and snippets.

@umurgdk
Created February 21, 2022 22:01
Show Gist options
  • Save umurgdk/030d5c22ac3c91718c38c1a5655e0810 to your computer and use it in GitHub Desktop.
Save umurgdk/030d5c22ac3c91718c38c1a5655e0810 to your computer and use it in GitHub Desktop.
TextRendering CoreText
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
CGContextRef ctx = [NSGraphicsContext currentContext].CGContext;
[NSColor.blackColor setFill];
CGContextFillRect(ctx, CGRectMake(0, self.label.frame.size.height, self.label.frame.size.width, self.label.frame.size.height));
CFIndex stringLen = CFStringGetLength(text);
CTFontRef font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, 24.0f, nil);
// MARK: - Get Glyph Rects
UniChar *characters = (UniChar *)malloc(sizeof(UniChar) * stringLen);
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * stringLen);
CGRect *glyphRects = (CGRect *)malloc(sizeof(CGRect) * stringLen);
CFStringGetCharacters(text, CFRangeMake(0, stringLen), characters);
CTFontGetGlyphsForCharacters(font, characters, glyphs, stringLen);
CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationDefault, glyphs, glyphRects, stringLen);
// MARK: - Draw Glyph Rects
CFMutableAttributedStringRef attributedString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString(attributedString, CFRangeMake(0, 0), text);
CFAttributedStringSetAttribute(attributedString, CFRangeMake(0, CFAttributedStringGetLength(attributedString)), kCTFontAttributeName, font);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributedString);
CFRange fitRange;
CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(self.bounds.size.width, CGFLOAT_MAX), &fitRange);
[NSColor.redColor setStroke];
CGContextTranslateCTM(ctx, 0, self.label.frame.size.height);
CGContextStrokeRect(ctx, CGRectMake(0, 0, frameSize.width, frameSize.height));
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString(attributedString);
CTLineRef line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, stringLen));
CFArrayRef runs = CTLineGetGlyphRuns(line);
[NSColor.greenColor setStroke];
[NSColor.labelColor setFill];
for (int i = 0; i < CFArrayGetCount(runs); i++) {
CTRunRef run = CFArrayGetValueAtIndex(runs, i);
CFIndex glyphCount = CTRunGetGlyphCount(run);
CGGlyph *glyphs = malloc(sizeof(CGGlyph) * glyphCount);
CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs);
CGPoint *glyphPositions = malloc(sizeof(CGSize) * glyphCount);
CTRunGetPositions(run, CFRangeMake(0, 0), glyphPositions);
CGRect *glyphRects = malloc(sizeof(CGRect) * glyphCount);
CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationDefault, glyphs, glyphRects, glyphCount);
for (int j = 0; j < glyphCount; j++) {
CGRect rect = CGRectOffset(glyphRects[j], glyphPositions[j].x, glyphPositions[j].y);
rect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeScale(1, -1));
rect = CGRectOffset(rect, 0, frameSize.height);
CGContextStrokeRect(ctx, rect);
CGAffineTransform glyphTransform = CGAffineTransformMakeTranslation(glyphPositions[j].x, glyphPositions[j].y + frameSize.height);
glyphTransform = CGAffineTransformScale(glyphTransform, 1, -1);
CGPathRef glyphPath = CTFontCreatePathForGlyph(font, glyphs[j], &glyphTransform);
CGContextSaveGState(ctx);
// CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y);
// CGContextScaleCTM(ctx, 1, -1);
CGContextAddPath(ctx, glyphPath);
CGContextFillPath(ctx);
CGContextRestoreGState(ctx);
CGPathRelease(glyphPath);
}
free(glyphRects);
free(glyphPositions);
free(glyphs);
}
CFRelease(line);
CFRelease(typesetter);
CFRelease(framesetter);
CFRelease(attributedString);
free(characters);
free(glyphs);
CFRelease(font);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment