168 lines
5.6 KiB
Objective-C
168 lines
5.6 KiB
Objective-C
//
|
|
// IJSVGRadialGradient.m
|
|
// IJSVGExample
|
|
//
|
|
// Created by Curtis Hard on 03/09/2014.
|
|
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
|
//
|
|
|
|
#import "IJSVGRadialGradient.h"
|
|
|
|
@implementation IJSVGRadialGradient
|
|
|
|
@synthesize cx;
|
|
@synthesize cy;
|
|
@synthesize fx;
|
|
@synthesize fy;
|
|
@synthesize radius;
|
|
|
|
- (void)dealloc
|
|
{
|
|
[cx release], cx = nil;
|
|
[cy release], cy = nil;
|
|
[fx release], fx = nil;
|
|
[fy release], fy = nil;
|
|
[radius release], radius = nil;
|
|
[super dealloc];
|
|
}
|
|
|
|
- (id)copyWithZone:(NSZone *)zone
|
|
{
|
|
IJSVGRadialGradient * grad = [super copyWithZone:zone];
|
|
grad.fx = self.fx;
|
|
grad.fy = self.fy;
|
|
grad.cx = self.cx;
|
|
grad.cy = self.cy;
|
|
grad.radius = self.radius;
|
|
return grad;
|
|
}
|
|
|
|
|
|
+ (NSGradient *)parseGradient:(NSXMLElement *)element
|
|
gradient:(IJSVGRadialGradient *)gradient
|
|
{
|
|
// cx defaults to 50% if not specified
|
|
NSDictionary * kv = @{@"cx":@"cx",
|
|
@"cy":@"cy",
|
|
@"r":@"radius"};
|
|
|
|
for(NSString * key in kv.allKeys) {
|
|
NSString * str = [element attributeForName:key].stringValue;
|
|
IJSVGUnitLength * unit = nil;
|
|
if(str != nil) {
|
|
unit = [IJSVGUnitLength unitWithString:str];
|
|
} else {
|
|
unit = [IJSVGUnitLength unitWithPercentageFloat:.5f];
|
|
}
|
|
[gradient setValue:unit
|
|
forKey:kv[key]];
|
|
}
|
|
|
|
gradient.fx = gradient.cx;
|
|
gradient.fy = gradient.cy;
|
|
|
|
// needs fixing
|
|
NSString * fx = [element attributeForName:@"fx"].stringValue;
|
|
if(fx != nil) {
|
|
if(fx.floatValue < 1.f) {
|
|
gradient.fx = [IJSVGUnitLength unitWithPercentageString:fx];
|
|
} else {
|
|
gradient.fx = [IJSVGUnitLength unitWithString:fx];
|
|
}
|
|
}
|
|
|
|
NSString * fy = [element attributeForName:@"fy"].stringValue;
|
|
if(fx != nil) {
|
|
if(fx.floatValue < 1.f) {
|
|
gradient.fy = [IJSVGUnitLength unitWithPercentageString:fy];
|
|
} else {
|
|
gradient.fy = [IJSVGUnitLength unitWithString:fy];
|
|
}
|
|
}
|
|
|
|
if( gradient.gradient != nil ) {
|
|
return nil;
|
|
}
|
|
|
|
NSArray * colors = nil;
|
|
CGFloat * colorStops = [[self class] computeColorStopsFromString:element colors:&colors];
|
|
NSGradient * ret = [[[NSGradient alloc] initWithColors:colors
|
|
atLocations:colorStops
|
|
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
|
|
free(colorStops);
|
|
return ret;
|
|
}
|
|
|
|
- (void)drawInContextRef:(CGContextRef)ctx
|
|
objectRect:(NSRect)objectRect
|
|
absoluteTransform:(CGAffineTransform)absoluteTransform
|
|
viewPort:(CGRect)viewBox
|
|
{
|
|
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
|
|
CGFloat radius = self.radius.value;
|
|
CGPoint startPoint = CGPointZero;
|
|
CGPoint gradientStartPoint = CGPointZero;
|
|
CGPoint gradientEndPoint = CGPointZero;
|
|
|
|
// transforms
|
|
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
|
|
|
|
#pragma mark User Space On Use
|
|
if(inUserSpace == YES) {
|
|
CGFloat rad = radius*2.f;
|
|
startPoint = CGPointMake(self.cx.value, self.cy.value);
|
|
|
|
// work out the new radius
|
|
CGRect rect = CGRectMake(startPoint.x, startPoint.y, rad, rad);
|
|
rect = CGRectApplyAffineTransform(rect, selfTransform);
|
|
rect = CGRectApplyAffineTransform(rect, absoluteTransform);
|
|
radius = CGRectGetHeight(rect)/2.f;
|
|
|
|
gradientStartPoint = startPoint;
|
|
gradientEndPoint = CGPointMake(self.fx.value, self.fy.value);
|
|
|
|
// apply the absolute position
|
|
CGContextConcatCTM(ctx, absoluteTransform);
|
|
} else {
|
|
#pragma mark Object Bounding Box
|
|
// compute size based on percentages
|
|
CGFloat x = [self.cx computeValue:CGRectGetWidth(objectRect)];
|
|
CGFloat y = [self.cy computeValue:CGRectGetHeight(objectRect)];
|
|
startPoint = CGPointMake(x, y);
|
|
CGFloat val = MIN(CGRectGetWidth(objectRect), CGRectGetHeight(objectRect));
|
|
radius = [self.radius computeValue:val];
|
|
|
|
CGFloat ex = [self.fx computeValue:CGRectGetWidth(objectRect)];
|
|
CGFloat ey = [self.fy computeValue:CGRectGetHeight(objectRect)];
|
|
|
|
gradientEndPoint = CGPointMake(ex, ey);
|
|
gradientStartPoint = startPoint;
|
|
|
|
// transform if width or height is not equal
|
|
if(CGRectGetWidth(objectRect) != CGRectGetHeight(objectRect)) {
|
|
CGAffineTransform tr = CGAffineTransformMakeTranslation(gradientStartPoint.x,
|
|
gradientStartPoint.y);
|
|
if(CGRectGetWidth(objectRect) > CGRectGetHeight(objectRect)) {
|
|
tr = CGAffineTransformScale(tr, CGRectGetWidth(objectRect)/CGRectGetHeight(objectRect), 1);
|
|
} else {
|
|
tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(objectRect)/CGRectGetWidth(objectRect));
|
|
}
|
|
tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y);
|
|
selfTransform = CGAffineTransformConcat(tr, selfTransform);
|
|
}
|
|
}
|
|
|
|
#pragma mark Default drawing
|
|
// transform the context
|
|
CGContextConcatCTM(ctx, selfTransform);
|
|
|
|
// draw the gradient
|
|
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation|
|
|
kCGGradientDrawsAfterEndLocation;
|
|
CGContextDrawRadialGradient(ctx, self.CGGradient,
|
|
gradientEndPoint, 0, gradientStartPoint,
|
|
radius, options);
|
|
}
|
|
|
|
@end
|