Roll src/third_party/WebKit be01d6f:ffb483a (svn 183313:183317)
[chromium-blink-merge.git] / third_party / molokocacao / NSBezierPath+MCAdditions.m
blob3b006ed01126fab940d77ffbf07a81aa59559b0c
1 //
2 //  NSBezierPath+MCAdditions.m
3 //
4 //  Created by Sean Patrick O'Brien on 4/1/08.
5 //  Copyright 2008 MolokoCacao. All rights reserved.
6 //
8 #import "NSBezierPath+MCAdditions.h"
10 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+CGPath.h"
12 // remove/comment out this line of you don't want to use undocumented functions
13 #define MCBEZIER_USE_PRIVATE_FUNCTION
15 #ifdef MCBEZIER_USE_PRIVATE_FUNCTION
16 extern CGPathRef CGContextCopyPath(CGContextRef context);
17 #endif
19 static void CGPathCallback(void *info, const CGPathElement *element)
21         NSBezierPath *path = info;
22         CGPoint *points = element->points;
24         switch (element->type) {
25                 case kCGPathElementMoveToPoint:
26                 {
27                         [path moveToPoint:NSMakePoint(points[0].x, points[0].y)];
28                         break;
29                 }
30                 case kCGPathElementAddLineToPoint:
31                 {
32                         [path lineToPoint:NSMakePoint(points[0].x, points[0].y)];
33                         break;
34                 }
35                 case kCGPathElementAddQuadCurveToPoint:
36                 {
37                         // NOTE: This is untested.
38                         NSPoint currentPoint = [path currentPoint];
39                         NSPoint interpolatedPoint = NSMakePoint((currentPoint.x + 2*points[0].x) / 3, (currentPoint.y + 2*points[0].y) / 3);
40                         [path curveToPoint:NSMakePoint(points[1].x, points[1].y) controlPoint1:interpolatedPoint controlPoint2:interpolatedPoint];
41                         break;
42                 }
43                 case kCGPathElementAddCurveToPoint:
44                 {
45                         [path curveToPoint:NSMakePoint(points[2].x, points[2].y) controlPoint1:NSMakePoint(points[0].x, points[0].y) controlPoint2:NSMakePoint(points[1].x, points[1].y)];
46                         break;
47                 }
48                 case kCGPathElementCloseSubpath:
49                 {
50                         [path closePath];
51                         break;
52                 }
53         }
56 @implementation NSBezierPath (MCAdditions)
58 + (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)pathRef
60         NSBezierPath *path = [NSBezierPath bezierPath];
61         CGPathApply(pathRef, path, CGPathCallback);
62         
63         return path;
66 - (NSBezierPath *)pathWithStrokeWidth:(CGFloat)strokeWidth
68 #ifdef MCBEZIER_USE_PRIVATE_FUNCTION
69         NSBezierPath *path = [self copy];
70         CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
71         CGPathRef pathRef = [path gtm_CGPath];
72         [path release];
73         
74         CGContextSaveGState(context);
75                 
76         CGContextBeginPath(context);
77         CGContextAddPath(context, pathRef);
78         CGContextSetLineWidth(context, strokeWidth);
79         CGContextReplacePathWithStrokedPath(context);
80         CGPathRef strokedPathRef = CGContextCopyPath(context);
81         CGContextBeginPath(context);
82         NSBezierPath *strokedPath = [NSBezierPath bezierPathWithCGPath:strokedPathRef];
83         
84         CGContextRestoreGState(context);
85         
86         CFRelease(pathRef);
87         CFRelease(strokedPathRef);
88         
89         return strokedPath;
90 #else
91         return nil;
92 #endif  // MCBEZIER_USE_PRIVATE_FUNCTION
95 - (void)fillWithInnerShadow:(NSShadow *)shadow
97         [NSGraphicsContext saveGraphicsState];
98         
99         NSSize offset = shadow.shadowOffset;
100         NSSize originalOffset = offset;
101         CGFloat radius = shadow.shadowBlurRadius;
102         NSRect bounds = NSInsetRect(self.bounds, -(ABS(offset.width) + radius), -(ABS(offset.height) + radius));
104         // The context's user transform isn't automatically applied to shadow offsets.
105         offset.height += bounds.size.height;
106         shadow.shadowOffset = offset;
107         NSAffineTransform *transform = [NSAffineTransform transform];
108         if ([[NSGraphicsContext currentContext] isFlipped])
109                 [transform translateXBy:0 yBy:bounds.size.height];
110         else
111                 [transform translateXBy:0 yBy:-bounds.size.height];
112         
113         NSBezierPath *drawingPath = [NSBezierPath bezierPathWithRect:bounds];
114         [drawingPath setWindingRule:NSEvenOddWindingRule];
115         [drawingPath appendBezierPath:self];
116         [drawingPath transformUsingAffineTransform:transform];
117         
118         [self addClip];
119         [shadow set];
120         [[NSColor blackColor] set];
121         [drawingPath fill];
122         
123         shadow.shadowOffset = originalOffset;
124         
125         [NSGraphicsContext restoreGraphicsState];
128 - (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius
130         NSRect bounds = NSInsetRect(self.bounds, -radius, -radius);
131         NSShadow *shadow = [[NSShadow alloc] init];
132         shadow.shadowOffset = NSMakeSize(0, bounds.size.height);
133         shadow.shadowBlurRadius = radius;
134         shadow.shadowColor = color;
135         NSBezierPath *path = [self copy];
136         NSAffineTransform *transform = [NSAffineTransform transform];
137         if ([[NSGraphicsContext currentContext] isFlipped])
138                 [transform translateXBy:0 yBy:bounds.size.height];
139         else
140                 [transform translateXBy:0 yBy:-bounds.size.height];
141         [path transformUsingAffineTransform:transform];
142         
143         [NSGraphicsContext saveGraphicsState];
144         
145         [shadow set];
146         [[NSColor blackColor] set];
147         NSRectClip(bounds);
148         [path fill];
149         
150         [NSGraphicsContext restoreGraphicsState];
151         
152         [path release];
153         [shadow release];
156 // Credit for the next two methods goes to Matt Gemmell
157 - (void)strokeInside
159     /* Stroke within path using no additional clipping rectangle. */
160     [self strokeInsideWithinRect:NSZeroRect];
163 - (void)strokeInsideWithinRect:(NSRect)clipRect
165     NSGraphicsContext *thisContext = [NSGraphicsContext currentContext];
166     float lineWidth = [self lineWidth];
167     
168     /* Save the current graphics context. */
169     [thisContext saveGraphicsState];
170     
171     /* Double the stroke width, since -stroke centers strokes on paths. */
172     [self setLineWidth:(lineWidth * 2.0)];
173     
174     /* Clip drawing to this path; draw nothing outwith the path. */
175     [self setClip];
176     
177     /* Further clip drawing to clipRect, usually the view's frame. */
178     if (clipRect.size.width > 0.0 && clipRect.size.height > 0.0) {
179         [NSBezierPath clipRect:clipRect];
180     }
181     
182     /* Stroke the path. */
183     [self stroke];
184     
185     /* Restore the previous graphics context. */
186     [thisContext restoreGraphicsState];
187     [self setLineWidth:lineWidth];
190 @end