1 /*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
 
     2     http://developer.apple.com/samplecode/GeekGameBoard/
 
     3     Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
 
     5     Redistribution and use in source and binary forms, with or without modification, are permitted
 
     6     provided that the following conditions are met:
 
     8     * Redistributions of source code must retain the above copyright notice, this list of conditions
 
     9       and the following disclaimer.
 
    10     * Redistributions in binary form must reproduce the above copyright notice, this list of
 
    11       conditions and the following disclaimer in the documentation and/or other materials provided
 
    12       with the distribution.
 
    14     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 
    15     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
 
    16     FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
 
    17     BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
    18     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 
    19     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 
    20     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
 
    21     THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
    23 #import "QuartzUtils.h"
 
    24 #import <QuartzCore/QuartzCore.h>
 
    27 CGColorRef kBlackColor, kWhiteColor, 
 
    28            kTranslucentGrayColor, kTranslucentLightGrayColor,
 
    29            kAlmostInvisibleWhiteColor,
 
    33 __attribute__((constructor))        // Makes this function run when the app loads
 
    34 static void InitQuartzUtils()
 
    36     kBlackColor = CreateGray(0.0, 1.0);
 
    37     kWhiteColor = CreateGray(1.0, 1.0);
 
    38     kTranslucentGrayColor = CreateGray(0.0, 0.5);
 
    39     kTranslucentLightGrayColor = CreateGray(0.0, 0.25);
 
    40     kAlmostInvisibleWhiteColor = CreateGray(1, 0.05);
 
    41     kHighlightColor = CreateRGB(1, 1, 0, 0.5);
 
    46 CGColorRef CreateGray(CGFloat gray, CGFloat alpha)
 
    48     CGColorSpaceRef graySpace = CGColorSpaceCreateDeviceGray();
 
    49     CGFloat components[2] = {gray,alpha};
 
    50     CGColorRef color = CGColorCreate(graySpace, components);
 
    51     CGColorSpaceRelease(graySpace);
 
    55 CGColorRef CreateRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha)
 
    57     CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
 
    58     CGFloat components[4] = {red,green,blue,alpha};
 
    59     CGColorRef color = CGColorCreate(rgbSpace, components);
 
    60     CGColorSpaceRelease(rgbSpace);
 
    66 void ChangeSuperlayer( CALayer *layer, CALayer *newSuperlayer, int index )
 
    68     // Disable actions, else the layer will move to the wrong place and then back!
 
    69     [CATransaction flush];
 
    70     [CATransaction begin];
 
    71     [CATransaction setValue:(id)kCFBooleanTrue
 
    72                      forKey:kCATransactionDisableActions];
 
    74     CGPoint pos = [newSuperlayer convertPoint: layer.position 
 
    75                       fromLayer: layer.superlayer];
 
    77     [layer removeFromSuperlayer];
 
    79         [newSuperlayer insertSublayer: layer atIndex: index];
 
    81         [newSuperlayer addSublayer: layer];
 
    85     [CATransaction commit];
 
    89 void RemoveImmediately( CALayer *layer )
 
    91     [CATransaction flush];
 
    92     [CATransaction begin];
 
    93     [CATransaction setValue:(id)kCFBooleanTrue
 
    94                      forKey:kCATransactionDisableActions];
 
    95     [layer removeFromSuperlayer];
 
    96     [CATransaction commit];
 
   100 CGImageRef CreateCGImageFromFile( NSString *path )
 
   103     UIImage *uiImage = [UIImage imageWithContentsOfFile: path];
 
   104     if(!uiImage) NSLog(@"Warning: UIImage imageWithContentsOfFile failed on file %@",path);
 
   105     return CGImageRetain(uiImage.CGImage);
 
   107     CGImageRef image = NULL;
 
   108     CFURLRef url = (CFURLRef) [NSURL fileURLWithPath: path];
 
   109     CGImageSourceRef src = CGImageSourceCreateWithURL(url, NULL);
 
   111         image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
 
   113         if(!image) NSLog(@"Warning: CGImageSourceCreateImageAtIndex failed on file %@ (ptr size=%u)",path,sizeof(void*));
 
   120 CGImageRef GetCGImageNamed( NSString *name )
 
   123     name = name.lastPathComponent;
 
   124     UIImage *uiImage = [UIImage imageNamed: name];
 
   125     NSCAssert1(uiImage,@"Couldn't find bundle image resource '%@'",name);
 
   126     return uiImage.CGImage;
 
   128     // For efficiency, loaded images are cached in a dictionary by name.
 
   129     static NSMutableDictionary *sMap;
 
   131         sMap = [[NSMutableDictionary alloc] init];
 
   133     CGImageRef image = (CGImageRef) [sMap objectForKey: name];
 
   135         // Hasn't been cached yet, so load it:
 
   137         if( [name hasPrefix: @"/"] )
 
   140             path = [[NSBundle mainBundle] pathForResource: name ofType: nil];
 
   141             NSCAssert1(path,@"Couldn't find bundle image resource '%@'",name);
 
   143         image = CreateCGImageFromFile(path);
 
   144         NSCAssert1(image,@"Failed to load image from %@",path);
 
   145         [sMap setObject: (id)image forKey: name];
 
   146         CGImageRelease(image);
 
   153 CGColorRef GetCGPatternNamed( NSString *name )         // can be resource name or abs. path
 
   155     // For efficiency, loaded patterns are cached in a dictionary by name.
 
   156     static NSMutableDictionary *sMap;
 
   158         sMap = [[NSMutableDictionary alloc] init];
 
   160     CGColorRef pattern = (CGColorRef) [sMap objectForKey: name];
 
   162         pattern = CreatePatternColor( GetCGImageNamed(name) );
 
   163         [sMap setObject: (id)pattern forKey: name];
 
   164         CGColorRelease(pattern);
 
   170 #if ! TARGET_OS_ASPEN
 
   171 CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb )
 
   173     CGImageSourceRef src = NULL;
 
   174     NSArray *paths = [pb propertyListForType: NSFilenamesPboardType];
 
   175     if( paths.count==1 ) {
 
   176         // If a file is being dragged, read it:
 
   177         CFURLRef url = (CFURLRef) [NSURL fileURLWithPath: [paths objectAtIndex: 0]];
 
   178         src = CGImageSourceCreateWithURL(url, NULL);
 
   180         // Else look for an image type:
 
   181         NSString *type = [pb availableTypeFromArray: [NSImage imageUnfilteredPasteboardTypes]];
 
   183             NSData *data = [pb dataForType: type];
 
   184             src = CGImageSourceCreateWithData((CFDataRef)data, NULL);
 
   188         CGImageRef image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
 
   197 float GetPixelAlpha( CGImageRef image, CGSize imageSize, CGPoint pt )
 
   200     // iPhone uses "flipped" (i.e. normal) coords, so images are wrong-way-up
 
   201     pt.y = imageSize.height - pt.y;
 
   205     if( pt.x<0 || pt.x>=imageSize.width || pt.y<0 || pt.y>=imageSize.height )
 
   208     // sTinyContext is a 1x1 CGBitmapContext whose pixmap stores only alpha.
 
   209     static UInt8 sPixel[1];
 
   210     static CGContextRef sTinyContext;
 
   211     if( ! sTinyContext ) {
 
   212         sTinyContext = CGBitmapContextCreate(sPixel, 1, 1, 
 
   213                                              8, 1,     // bpp, rowBytes
 
   216         CGContextSetBlendMode(sTinyContext, kCGBlendModeCopy);
 
   219     // Draw the image into sTinyContext, positioned so the desired point is at
 
   220     // (0,0), then examine the alpha value in the pixmap:
 
   221     CGContextDrawImage(sTinyContext, 
 
   222                        CGRectMake(-pt.x,-pt.y, imageSize.width,imageSize.height),
 
   224     return sPixel[0] / 255.0;
 
   229 #pragma mark PATTERNS:
 
   232 // callback for CreateImagePattern.
 
   233 static void drawPatternImage (void *info, CGContextRef ctx)
 
   235     CGImageRef image = (CGImageRef) info;
 
   236     CGContextDrawImage(ctx, 
 
   237                        CGRectMake(0,0, CGImageGetWidth(image),CGImageGetHeight(image)),
 
   241 // callback for CreateImagePattern.
 
   242 static void releasePatternImage( void *info )
 
   244     CGImageRelease( (CGImageRef)info );
 
   248 CGPatternRef CreateImagePattern( CGImageRef image )
 
   250     NSCParameterAssert(image);
 
   251     int width = CGImageGetWidth(image);
 
   252     int height = CGImageGetHeight(image);
 
   253     static const CGPatternCallbacks callbacks = {0, &drawPatternImage, &releasePatternImage};
 
   254     return CGPatternCreate (image,
 
   255                             CGRectMake (0, 0, width, height),
 
   256                             CGAffineTransformMake (1, 0, 0, 1, 0, 0),
 
   259                             kCGPatternTilingConstantSpacing,
 
   265 CGColorRef CreatePatternColor( CGImageRef image )
 
   267     CGPatternRef pattern = CreateImagePattern(image);
 
   268     CGColorSpaceRef space = CGColorSpaceCreatePattern(NULL);
 
   269     CGFloat components[1] = {1.0};
 
   270     CGColorRef color = CGColorCreateWithPattern(space, pattern, components);
 
   271     CGColorSpaceRelease(space);
 
   272     CGPatternRelease(pattern);
 
   281 void AddRoundRect( CGContextRef ctx, CGRect rect, CGFloat radius )
 
   283     radius = MIN(radius, floorf(rect.size.width/2));
 
   284     float x0 = CGRectGetMinX(rect), y0 = CGRectGetMinY(rect),
 
   285     x1 = CGRectGetMaxX(rect), y1 = CGRectGetMaxY(rect);
 
   287     CGContextBeginPath(ctx);
 
   288     CGContextMoveToPoint(ctx,x0+radius,y0);
 
   289     CGContextAddArcToPoint(ctx,x1,y0, x1,y1, radius);
 
   290     CGContextAddArcToPoint(ctx,x1,y1, x0,y1, radius);
 
   291     CGContextAddArcToPoint(ctx,x0,y1, x0,y0, radius);
 
   292     CGContextAddArcToPoint(ctx,x0,y0, x1,y0, radius);
 
   293     CGContextClosePath(ctx);