Permalink
Browse files

Optimize Shadow drawing

- Related to #345
- for text with no shadow only the glyph run is drawn
- for text with 1 shadow this is set and the glyph run is drawn
- for text with more than 1 shadow an area is clipped, 100 pixel wider in all directions
  - then the text position is moved outside that area and the shadow gets an additional offset in the other direction
  - this way only the shadow is drawn
  - except for the very last shadow, there the text position is moved back and the glyph run is drawn together with the last shadow
  • Loading branch information...
1 parent f6db538 commit 536321e1cf30e99fb364e3a86c3819efcef3c757 @odrobnik odrobnik committed Mar 15, 2013
Showing with 52 additions and 12 deletions.
  1. +52 −12 Core/Source/DTCoreTextLayoutFrame.m
@@ -704,12 +704,16 @@ - (NSArray *)linesContainedInRect:(CGRect)rect
#pragma mark Drawing
-- (void)_setShadowInContext:(CGContextRef)context fromDictionary:(NSDictionary *)dictionary
+- (void)_setShadowInContext:(CGContextRef)context fromDictionary:(NSDictionary *)dictionary additionalOffset:(CGSize)additionalOffset
{
DTColor *color = [dictionary objectForKey:@"Color"];
CGSize offset = [[dictionary objectForKey:@"Offset"] CGSizeValue];
CGFloat blur = [[dictionary objectForKey:@"Blur"] floatValue];
+ // add extra offset
+ offset.width += additionalOffset.width;
+ offset.height += additionalOffset.height;
+
CGFloat scaleFactor = 1.0;
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
{
@@ -731,7 +735,6 @@ - (void)_setShadowInContext:(CGContextRef)context fromDictionary:(NSDictionary *
}
}
- offset.width -= 10000;
CGContextSetShadowWithColor(context, offset, blur, color.CGColor);
}
@@ -1138,23 +1141,60 @@ - (void)drawInContext:(CGContextRef)context drawImages:(BOOL)drawImages drawLink
if (shadows)
{
CGContextSaveGState(context);
-
- // Move the text 10000pt away from the current position so that on the shadow is visisble
- CGContextSetTextPosition(context, textPosition.x + 10000, textPosition.y);
- for (NSDictionary *shadowDict in shadows)
+ NSUInteger numShadows = [shadows count];
+
+ if (numShadows == 1)
{
- [self _setShadowInContext:context fromDictionary:shadowDict];
+ // single shadow, we only draw the glyph run with the shadow, no clipping magic
+ NSDictionary *singleShadow = [shadows objectAtIndex:0];
+ [self _setShadowInContext:context fromDictionary:singleShadow additionalOffset:CGSizeZero];
[oneRun drawInContext:context];
}
-
- CGContextSetTextPosition(context, textPosition.x, textPosition.y);
+ else // multiple shadows, we shift the text away and then draw a single glyph run over it
+ {
+ // get the run bounds, Core Text has bottom left 0,0 so we flip it
+ CGRect runBoundsFlipped = oneRun.frame;
+ runBoundsFlipped.origin.y = self.frame.size.height - runBoundsFlipped.origin.y - runBoundsFlipped.size.height;
+
+ // assume that shadows would never be more than 100 pixels away from glyph run frame or outside of frame
+ CGRect clipRect = CGRectIntersection(CGRectInset(runBoundsFlipped, -100, -100), self.frame);
+
+ // clip to the rect
+ CGContextAddRect(context, clipRect);
+ CGContextClipToRect(context, clipRect);
+
+ // Move the text outside of the clip rect so that only the shadow is visisble
+ CGContextSetTextPosition(context, textPosition.x + clipRect.size.width, textPosition.y);
+
+ // draw each shadow
+ [shadows enumerateObjectsUsingBlock:^(NSDictionary *shadowDict, NSUInteger idx, BOOL *stop) {
+ BOOL isLastShadow = (idx == (numShadows-1));
+
+ if (isLastShadow)
+ {
+ // last shadow draws the original text
+ [self _setShadowInContext:context fromDictionary:shadowDict additionalOffset:CGSizeZero];
+
+ // ... so we put text position back
+ CGContextSetTextPosition(context, textPosition.x, textPosition.y);
+ }
+ else
+ {
+ [self _setShadowInContext:context fromDictionary:shadowDict additionalOffset:CGSizeMake(-clipRect.size.width, 0)];
+ }
+
+ [oneRun drawInContext:context];
+ }];
+ }
+
CGContextRestoreGState(context);
}
-
- // regular text
- [oneRun drawInContext:context];
+ else // no shadows
+ {
+ [oneRun drawInContext:context];
+ }
}
}
}

0 comments on commit 536321e

Please sign in to comment.