Skip to content

Instantly share code, notes, and snippets.

@jweinberg
Created March 14, 2011 20:54
Show Gist options
  • Save jweinberg/869860 to your computer and use it in GitHub Desktop.
Save jweinberg/869860 to your computer and use it in GitHub Desktop.
for (id p in self.lines)
{
//if (i >= self.numberOfLines && self.numberOfLines)
// break;
CGPoint origin = self.lineOrigins[i++];
CGContextSetTextPosition(ctx, origin.x , origin.y);
CTLineRef line = (CTLineRef)p;
CGFloat ascent, descent, leading;
CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
NSArray *runs = (NSArray*)CTLineGetGlyphRuns(line);
for (id r in runs)
{
CGContextSaveGState(ctx);
CTRunRef run = (CTRunRef)r;
NSDictionary *attributes = (id)CTRunGetAttributes(run);
CGSize shadowOffset = [[attributes valueForKey:kRAShadowOffsetName] CGSizeValue];
CGColorRef shadowColor = (CGColorRef)[attributes valueForKey:kRAShadowColorName];
CGContextSetShadowWithColor(ctx, shadowOffset, 0, shadowColor);
NSInteger superscript = [[attributes valueForKey:(id)kCTSuperscriptAttributeName] integerValue];
CGContextSaveGState(ctx);
if (superscript != 0)
{
if (superscript > 0)
CGContextConcatCTM(ctx, CGAffineTransformMakeTranslation(0, ascent * .4f));
else
CGContextConcatCTM(ctx, CGAffineTransformMakeTranslation(0, ascent * -.16f));
}
CTRunDraw(run, ctx, CFRangeMake(0, 0));
CGContextRestoreGState(ctx);
CGFloat width = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL);
NSUInteger underlineStyle = [[attributes valueForKey:(id)kCTUnderlineStyleAttributeName] unsignedIntegerValue];
if (underlineStyle)
{
NSUInteger underlineHeight = MAX(floor(descent / 4.0f), 1);
CGFloat underlineY = floor(origin.y - underlineHeight * 3);
underlineY += (underlineHeight % 2) > 0.0f ? .5f : 0;
if (underlineStyle & kCTUnderlineStyleThick)
underlineHeight *= 2.0f;
UIBezierPath *path = [UIBezierPath bezierPath];
if (underlineStyle & 0x8) //Double
{
underlineY += underlineHeight;
[path moveToPoint:CGPointMake(origin.x, underlineY)];
[path addLineToPoint:CGPointMake(ceil(origin.x + width), underlineY)];
[path closePath];
[path moveToPoint:CGPointMake(origin.x, underlineY - underlineHeight * 2)];
[path addLineToPoint:CGPointMake(ceil(origin.x + width), underlineY - underlineHeight * 2)];
[path closePath];
}
else
{
[path moveToPoint:CGPointMake(origin.x, underlineY)];
[path addLineToPoint:CGPointMake(ceil(origin.x + width), underlineY)];
}
CGContextSetStrokeColorWithColor(ctx, (CGColorRef)[attributes valueForKey:(id)kCTUnderlineColorAttributeName]);
CGContextSetLineWidth(ctx, underlineHeight);
CGContextAddPath(ctx, [path CGPath]);
CGFloat width = ascent;
if ((underlineStyle & ~0xFF) == kCTUnderlinePatternDash)
CGContextSetLineDash(ctx, origin.x, (CGFloat[]){width,width/2}, 2);
else if ((underlineStyle & ~0xFF) == kCTUnderlinePatternDot)
CGContextSetLineDash(ctx, origin.x, (CGFloat[]){width/4,width/4}, 2);
else if ((underlineStyle & ~0xFF) == kCTUnderlinePatternDashDot)
CGContextSetLineDash(ctx, origin.x, (CGFloat[]){width,width/4,width/4,width/4}, 4);
else if ((underlineStyle & ~0xFF) == kCTUnderlinePatternDashDotDot)
CGContextSetLineDash(ctx, origin.x, (CGFloat[]){width,width/4,width/4,width/4,width/4,width/4}, 6);
CGContextStrokePath(ctx);
}
origin.x += width;
origin.x = ceil(origin.x);
CGContextRestoreGState(ctx);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment