diff --git a/IJSVG.m b/IJSVG.m index 37befa4..320b94c 100644 --- a/IJSVG.m +++ b/IJSVG.m @@ -43,8 +43,11 @@ static NSColor * _baseColor = nil; { NSBundle * bundle = [NSBundle mainBundle]; NSString * str = nil; + NSString * ext = [string pathExtension]; + if( ext == nil || ext.length == 0 ) + ext = @"svg"; if( ( str = [bundle pathForResource:[string stringByDeletingPathExtension] - ofType:[string pathExtension]] ) ) + ofType:ext] ) ) return [[[self alloc] initWithFile:str delegate:delegate] autorelease]; return nil; diff --git a/IJSVGCache.m b/IJSVGCache.m index 932e233..ece4f62 100644 --- a/IJSVGCache.m +++ b/IJSVGCache.m @@ -7,6 +7,7 @@ // #import "IJSVGCache.h" +#import @implementation IJSVGCache @@ -34,20 +35,11 @@ static BOOL _enabled = YES; + (void)cacheSVG:(IJSVG *)svg fileURL:(NSURL *)aURL { - NSFileManager * fm = [NSFileManager defaultManager]; - NSDictionary * atts = [fm attributesOfItemAtPath:[aURL path] - error:nil]; - - // cache is nil ... for some reason..? - if( _cache == nil ) - { - _cache = [[NSCache alloc] init]; - [_cache setTotalCostLimit:MAX_CACHE_SIZE]; - } - + // use the malloc size for the object size, + // is this correct? [_cache setObject:svg forKey:aURL - cost:[atts fileSize]+sizeof(svg)]; + cost:malloc_size(svg)]; } + (void)setEnabled:(BOOL)flag diff --git a/IJSVGDef.h b/IJSVGDef.h index 8975bba..b41c4be 100644 --- a/IJSVGDef.h +++ b/IJSVGDef.h @@ -16,4 +16,6 @@ } +- (void)addDef:(IJSVGNode *)aDef; + @end diff --git a/IJSVGDef.m b/IJSVGDef.m index 17d060a..6e137cb 100644 --- a/IJSVGDef.m +++ b/IJSVGDef.m @@ -25,8 +25,10 @@ return self; } -- (void)addDef:(IJSVGDef *)aDef +- (void)addDef:(IJSVGNode *)aDef { + if( aDef.identifier == nil ) + return; [_dict setObject:aDef forKey:aDef.identifier]; } diff --git a/IJSVGExample/IJSVGExample.xcodeproj/project.pbxproj b/IJSVGExample/IJSVGExample.xcodeproj/project.pbxproj index 48e8885..488f192 100644 --- a/IJSVGExample/IJSVGExample.xcodeproj/project.pbxproj +++ b/IJSVGExample/IJSVGExample.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ 59A0E7A519B7334F001BA157 /* IJSVGDef.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A0E7A419B7334F001BA157 /* IJSVGDef.m */; }; 59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59B93C6C19B7D1840063E823 /* paperplane.svg */; }; 59B93C6F19B7D32C0063E823 /* products.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59B93C6E19B7D32C0063E823 /* products.svg */; }; + 59F799E219B880CE00096CB7 /* htc_one.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59F799E119B880CE00096CB7 /* htc_one.svg */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -128,6 +129,7 @@ 59A0E7A419B7334F001BA157 /* IJSVGDef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGDef.m; path = ../../IJSVGDef.m; sourceTree = ""; }; 59B93C6C19B7D1840063E823 /* paperplane.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = paperplane.svg; sourceTree = ""; }; 59B93C6E19B7D32C0063E823 /* products.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = products.svg; sourceTree = ""; }; + 59F799E119B880CE00096CB7 /* htc_one.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = htc_one.svg; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -184,6 +186,7 @@ 5956657A19B62F4600D805FF /* Supporting Files */ = { isa = PBXGroup; children = ( + 59F799E119B880CE00096CB7 /* htc_one.svg */, 59B93C6E19B7D32C0063E823 /* products.svg */, 59B93C6C19B7D1840063E823 /* paperplane.svg */, 595665DD19B6309C00D805FF /* test.svg */, @@ -356,6 +359,7 @@ 59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */, 5956658219B62F4600D805FF /* Images.xcassets in Resources */, 595665DE19B6309C00D805FF /* test.svg in Resources */, + 59F799E219B880CE00096CB7 /* htc_one.svg in Resources */, 59B93C6F19B7D32C0063E823 /* products.svg in Resources */, 5956658519B62F4600D805FF /* MainMenu.xib in Resources */, ); diff --git a/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate b/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate index 4e5ba85..1c016ff 100644 Binary files a/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate and b/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/IJSVGExample/IJSVGExample/SVGView.m b/IJSVGExample/IJSVGExample/SVGView.m index ea54627..4037a00 100644 --- a/IJSVGExample/IJSVGExample/SVGView.m +++ b/IJSVGExample/IJSVGExample/SVGView.m @@ -20,7 +20,7 @@ { if( ( self = [super initWithCoder:aDecoder] ) != nil ) { - svg = [[IJSVG svgNamed:@"paperplane.svg"] retain]; + svg = [[IJSVG svgNamed:@"test"] retain]; } return self; } diff --git a/IJSVGExample/IJSVGExample/htc_one.svg b/IJSVGExample/IJSVGExample/htc_one.svg new file mode 100644 index 0000000..87f291c --- /dev/null +++ b/IJSVGExample/IJSVGExample/htc_one.svg @@ -0,0 +1,274 @@ + + + htc one + Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IJSVGGroup.h b/IJSVGGroup.h index 27f3cc4..7d67a97 100644 --- a/IJSVGGroup.h +++ b/IJSVGGroup.h @@ -18,5 +18,6 @@ - (void)addChild:(id)child; - (NSArray *)children; +- (void)purgeChildren; @end diff --git a/IJSVGGroup.m b/IJSVGGroup.m index e2c4b7d..eaf99ee 100644 --- a/IJSVGGroup.m +++ b/IJSVGGroup.m @@ -25,6 +25,23 @@ return self; } +- (id)copyWithZone:(NSZone *)zone +{ + IJSVGGroup * node = [[self class] allocWithZone:zone]; + for( IJSVGNode * childNode in self.children ) + { + childNode = [[childNode copy] autorelease]; + childNode.parentNode = node; + [node addChild:childNode]; + } + return node; +} + +- (void)purgeChildren +{ + [children removeAllObjects]; +} + - (void)addChild:(id)child { [children addObject:child]; diff --git a/IJSVGNode.h b/IJSVGNode.h index 04320a0..dd630a6 100644 --- a/IJSVGNode.h +++ b/IJSVGNode.h @@ -20,7 +20,7 @@ typedef NS_OPTIONS( NSInteger, IJSVGWindingRule ) { static CGFloat IJSVGInheritedFloatValue = -99.9999991; -@interface IJSVGNode : NSObject { +@interface IJSVGNode : NSObject { NSString * name; @@ -69,7 +69,7 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991; @property ( nonatomic, retain ) IJSVGGradient * fillGradient; - (id)initWithDef:(BOOL)flag; -- (void)addDef:(IJSVGDef *)aDef; +- (void)addDef:(IJSVGNode *)aDef; - (IJSVGDef *)defForID:(NSString *)anID; @end diff --git a/IJSVGNode.m b/IJSVGNode.m index 9f8def2..828f40f 100644 --- a/IJSVGNode.m +++ b/IJSVGNode.m @@ -48,6 +48,36 @@ return self; } +- (id)copyWithZone:(NSZone *)zone +{ + IJSVGNode * node = [[self class] allocWithZone:zone]; + node.name = self.name; + + node.x = self.x; + node.y = self.y; + node.width = self.width; + node.height = self.height; + + node.fillGradient = self.fillGradient; + + node.fillColor = self.fillColor; + node.strokeColor = self.strokeColor; + + node.opacity = self.opacity; + node.strokeWidth = self.strokeWidth; + node.fillOpacity = self.fillOpacity; + node.strokeOpacity = self.strokeOpacity; + + node.identifier = self.identifier; + + node.transforms = self.transforms; + node.def = self.def; + node.windingRule = self.windingRule; + node.parentNode = self.parentNode; + + return node; +} + - (id)initWithDef:(BOOL)flag { if( ( self = [super init] ) != nil ) @@ -71,7 +101,7 @@ return nil; } -- (void)addDef:(IJSVGDef *)aDef +- (void)addDef:(IJSVGNode *)aDef { [def addDef:aDef]; } @@ -143,4 +173,13 @@ return 0.f; } +// even though the spec explicity states fill color +// must be on the path, it can also be on the +- (NSColor *)fillColor +{ + if( fillColor == nil && parentNode != nil ) + return parentNode.fillColor; + return fillColor; +} + @end \ No newline at end of file diff --git a/IJSVGParser.m b/IJSVGParser.m index 08d71df..fe3acb8 100644 --- a/IJSVGParser.m +++ b/IJSVGParser.m @@ -145,7 +145,8 @@ // recursively self.name = svgElement.name; [self _parseBlock:svgElement - intoGroup:self]; + intoGroup:self + def:NO]; } @@ -226,21 +227,24 @@ - (void)_parseBlock:(NSXMLElement *)anElement intoGroup:(IJSVGGroup*)parentGroup + def:(BOOL)flag { + + // if flag is yes, then anything we find inside this + // + for( NSXMLElement * element in [anElement children] ) { NSString * subName = [[element name] lowercaseString]; - if( [subName isEqualToString:@"defs"] ) { - - // defs - [self _parseDef:element - intoNode:parentGroup]; + // any defs? + [self _parseBlock:element + intoGroup:parentGroup + def:YES]; continue; - } else if( [subName isEqualToString:@"g"] ) - { + } else if( [subName isEqualToString:@"g"] ) { // its a group IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease]; @@ -252,14 +256,14 @@ node:group]; [parentGroup addChild:group]; - // could be gradients within - // the group's aswell, so work those out - [self _parseDef:element - intoNode:group]; - // recursively parse blocks [self _parseBlock:element - intoGroup:group]; + intoGroup:group + def:NO]; + + // could be defined + if( def ) + [parentGroup addDef:group]; continue; @@ -276,6 +280,11 @@ [self _parsePathCommandData:[[element attributeForName:@"d"] stringValue] intoPath:path]; [parentGroup addChild:path]; + + // could be defined + if( def ) + [parentGroup addDef:path]; + continue; } else if( [subName isEqualToString:@"polygon"] ) { @@ -291,6 +300,11 @@ [self _parsePolygon:element intoPath:path]; [parentGroup addChild:path]; + + // could be defined + if( def ) + [parentGroup addDef:path]; + continue; } else if( [subName isEqualToString:@"polyline"] ) { @@ -306,6 +320,11 @@ [self _parsePolyline:element intoPath:path]; [parentGroup addChild:path]; + + // could be defined + if( def ) + [parentGroup addDef:path]; + continue; } else if( [subName isEqualToString:@"rect"] ) { @@ -321,6 +340,11 @@ [self _parseRect:element intoPath:path]; [parentGroup addChild:path]; + + // could be defined + if( def ) + [parentGroup addDef:path]; + continue; } else if( [subName isEqualToString:@"line"] ) { @@ -336,6 +360,11 @@ [self _parseLine:element intoPath:path]; [parentGroup addChild:path]; + + // could be defined + if( def ) + [parentGroup addDef:path]; + continue; } else if( [subName isEqualToString:@"circle"] ) { @@ -351,6 +380,11 @@ [self _parseCircle:element intoPath:path]; [parentGroup addChild:path]; + + // could be defined + if( def ) + [parentGroup addDef:path]; + continue; } else if( [subName isEqualToString:@"ellipse"] ) { @@ -366,43 +400,57 @@ [self _parseEllipse:element intoPath:path]; [parentGroup addChild:path]; + + // could be defined + if( def ) + [parentGroup addDef:path]; + continue; + } else if( [subName isEqualToString:@"use"] ) { + + // its a use command + NSString * xlink = [[element attributeForName:@"xlink:href"] stringValue]; + NSString * xlinkID = [xlink substringFromIndex:1]; + IJSVGNode * node = [parentGroup defForID:xlinkID]; + if( node != nil ) + { + // copy the node + node = [[node copy] autorelease]; + node.parentNode = parentGroup; + + // grab the common attributes + [self _parseElementForCommonAttributes:element + node:node]; + [parentGroup addChild:node]; + } + + } else if( [subName isEqualToString:@"lineargradient"] ) { + + // linear gradient + IJSVGLinearGradient * gradient = [[[IJSVGLinearGradient alloc] init] autorelease]; + gradient.gradient = [IJSVGLinearGradient parseGradient:element + gradient:gradient]; + [self _parseElementForCommonAttributes:element + node:gradient]; + [parentGroup addDef:gradient]; + continue; + + } else if( [subName isEqualToString:@"radialgradient"] ) { + + // radial gradient + IJSVGRadialGradient * gradient = [[[IJSVGRadialGradient alloc] init] autorelease]; + gradient.gradient = [IJSVGRadialGradient parseGradient:element + gradient:gradient]; + [self _parseElementForCommonAttributes:element + node:gradient]; + [parentGroup addDef:gradient]; } } } #pragma mark Parser stuff! -- (void)_parseDef:(NSXMLElement *)element - intoNode:(IJSVGNode *)node -{ - for( NSXMLElement * child in [element children] ) - { - if( [[child name] isEqualToString:@"linearGradient"] ) - { - // linear gradient - IJSVGLinearGradient * gradient = [[[IJSVGLinearGradient alloc] init] autorelease]; - gradient.gradient = [IJSVGLinearGradient parseGradient:child - gradient:gradient]; - [self _parseElementForCommonAttributes:child - node:gradient]; - [node addDef:gradient]; - - } else if( [[child name] isEqualToString:@"radialGradient"] ) - { - // radial gradient - IJSVGRadialGradient * gradient = [[[IJSVGRadialGradient alloc] init] autorelease]; - gradient.gradient = [IJSVGRadialGradient parseGradient:child - gradient:gradient]; - [self _parseElementForCommonAttributes:child - node:gradient]; - [node addDef:gradient]; - - } - } -} - - (void)_parsePathCommandData:(NSString *)command intoPath:(IJSVGPath *)path { diff --git a/IJSVGPath.m b/IJSVGPath.m index 46e29ad..786c5ec 100644 --- a/IJSVGPath.m +++ b/IJSVGPath.m @@ -30,6 +30,13 @@ return self; } +- (id)copyWithZone:(NSZone *)zone +{ + IJSVGPath * node = [super copyWithZone:zone]; + [node overwritePath:self.path]; + return node; +} + - (NSPoint)currentPoint { return [subpath currentPoint];