Skip to content

Commit

Permalink
Pattern parser core (not works)
Browse files Browse the repository at this point in the history
Refactoring
  • Loading branch information
djphoenix committed May 13, 2015
1 parent 7b8e401 commit f30383c
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 35 deletions.
9 changes: 9 additions & 0 deletions pxSVG/pxSVGGroup.m
Expand Up @@ -9,5 +9,14 @@
#import "pxSVGGroup.h"

@implementation pxSVGGroup
- (CGRect)bounds
{
CGRect f = CGRectNull;
for (pxSVGObject *o in [self subnodes]) {
f = CGRectUnion(f, o.bounds);
}
if (CGRectIsNull(f)) return f;
return CGRectApplyAffineTransform(f, CATransform3DGetAffineTransform(self.transform));
}

@end
1 change: 1 addition & 0 deletions pxSVG/pxSVGObject.h
Expand Up @@ -22,4 +22,5 @@
@property CGFloat opacity;
@property CGFloat fillOpacity;
@property CATransform3D transform;
@property (nonatomic,readonly) CGRect bounds;
@end
4 changes: 4 additions & 0 deletions pxSVG/pxSVGObject.m
Expand Up @@ -117,4 +117,8 @@ - (void)loadAttributes:(NSDictionary *)attributes
self.fillOpacity = [ma objectForKey:@"fill-opacity"]?[[ma objectForKey:@"fill-opacity"] doubleValue]:a;
}
- (void)setSubnodes:(NSArray *)subnodes { }
- (CGRect)bounds
{
return CGRectNull;
}
@end
5 changes: 5 additions & 0 deletions pxSVG/pxSVGPath.m
Expand Up @@ -198,4 +198,9 @@ - (void)loadAttributes:(NSDictionary *)attributes
self.d = [UIBezierPath bezierPathWithRect:r];
} else NSLog(@"%@",attributes);
}
- (CGRect)bounds
{
if (self.d) return CGRectApplyAffineTransform(self.d.bounds, CATransform3DGetAffineTransform(self.transform));
return CGRectNull;
}
@end
206 changes: 172 additions & 34 deletions pxSVG/pxSVGRenderPath.m
Expand Up @@ -20,12 +20,61 @@ @interface pxSVGGradient : NSObject
@implementation pxSVGGradient
@end

@interface pxSVGPattern : pxSVGGroup
@end

@implementation pxSVGPattern
@end

@interface pxSVGRenderPath ()
@property NSMutableDictionary *defs;
@property NSMutableDictionary *defCache;
@property pxXMLNode *xml;
@property pxSVGObject *root;
@property CGRect bounds;
@end

@interface pxSVGPatternLayer : CALayer
@property CALayer *patternLayer;
@end

@implementation pxSVGPatternLayer

+ (instancetype)layer
{
return [self new];
}

- (instancetype)init
{
self = [super init];
self.delegate = self;
[self setNeedsDisplayOnBoundsChange:YES];
return self;
}

- (BOOL)drawsAsynchronously
{
return NO;
}

- (void)drawInContext:(CGContextRef)ctx
{
CGRect r = CGContextGetClipBoundingBox(ctx);
CGContextTranslateCTM(ctx, -r.size.width/2-37.73, -r.size.height/2);
[self.patternLayer drawInContext:ctx];
{
CALayer *l = self.patternLayer;
UIGraphicsBeginImageContext([l frame].size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, -l.frame.origin.x, -l.frame.origin.y);
[l renderInContext:ctx];
NSLog(@"%@",UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext()));
UIGraphicsEndImageContext();
}
}

@end

@implementation pxSVGRenderPath
+ (instancetype)pathWithXML:(pxXMLNode *)xmlNode
{
Expand All @@ -34,8 +83,9 @@ + (instancetype)pathWithXML:(pxXMLNode *)xmlNode
- (instancetype)initWithXML:(pxXMLNode *)xmlNode
{
self = [super init];
self.defs = [NSMutableDictionary new];
self.root = [self parseObject:xmlNode inheritAttributes:nil];
self.xml = xmlNode;
self.defCache = [NSMutableDictionary new];
self.root = [self parseObject:self.xml inheritAttributes:nil];
if ([xmlNode.attributes objectForKey:@"viewBox"]) {
NSArray *vb = [[xmlNode.attributes objectForKey:@"viewBox"] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
self.bounds = (CGRect){
Expand Down Expand Up @@ -64,32 +114,37 @@ - (instancetype)initWithXML:(pxXMLNode *)xmlNode
}
};
} else {
self.bounds = [self objBounds:self.root];
self.bounds = self.root.bounds;
}
return self;
}
- (CGRect) objBounds:(pxSVGObject*)obj
- (pxSVGObject*)findDef:(NSString*)name inNode:(pxXMLNode*)xml
{
if ([obj respondsToSelector:@selector(d)]) {
UIBezierPath *path = [(id)obj d];
if (path) return CGRectApplyAffineTransform(path.bounds, CATransform3DGetAffineTransform(obj.transform));
}
if ([obj respondsToSelector:@selector(subnodes)]) {
CGRect f = CGRectNull;
for (pxSVGObject *o in [(id)obj subnodes]) {
f = CGRectUnion(f, [self objBounds:o]);
id def;
for (pxXMLNode *n in xml.childNodes) {
if ([[n.attributes objectForKey:@"id"] isEqualToString:name]) {
def = [self parseObject:n inheritAttributes:nil];
if (def) return def;
}
return CGRectApplyAffineTransform(f, CATransform3DGetAffineTransform(obj.transform));
def = [self findDef:name inNode:n];
if (def) return def;
}
return CGRectNull;
return nil;
}
- (pxSVGObject*)findDef:(NSString*)name
{
if (!name) return nil;
id def = [self.defCache objectForKey:name];
if (def) return def;
return [self findDef:name inNode:self.xml];
}
- (pxSVGObject*)reuseObjectWithAttributes:(NSDictionary*)attributes
{
NSString *href = [attributes objectForKey:@"xlink:href"];
if (!href) href = [attributes objectForKey:@"href"];
if (!href) return nil;
href = [href substringFromIndex:1];
pxSVGObject *oobj = [self.defs objectForKey:href], *obj;
pxSVGObject *oobj = [self findDef:href], *obj;
if (!oobj) return nil;
obj = [oobj.class new];
obj.fillColor = oobj.fillColor;
Expand All @@ -106,31 +161,31 @@ - (pxSVGObject*)reuseObjectWithAttributes:(NSDictionary*)attributes
if ([attributes objectForKey:@"x"]) tr = CATransform3DTranslate(tr, [[attributes objectForKey:@"x"] doubleValue], 0, 0);
if ([attributes objectForKey:@"y"]) tr = CATransform3DTranslate(tr, 0, [[attributes objectForKey:@"y"] doubleValue], 0);
if ([attributes objectForKey:@"width"]) {
CGFloat ow = [self objBounds:oobj].size.width, w = [[attributes objectForKey:@"width"] doubleValue];
CGFloat ow = oobj.bounds.size.width, w = [[attributes objectForKey:@"width"] doubleValue];
tr = CATransform3DScale(tr, ow/w, 1, 1);
}
if ([attributes objectForKey:@"height"]) {
CGFloat oh = [self objBounds:oobj].size.width, h = [[attributes objectForKey:@"height"] doubleValue];
CGFloat oh = oobj.bounds.size.height, h = [[attributes objectForKey:@"height"] doubleValue];
tr = CATransform3DScale(tr, 1, oh/h, 1);
}
if ([attributes objectForKey:@"transform"]) tr = CATransform3DConcat(tr, [pxSVGObject transformFromString:[attributes objectForKey:@"transform"]]);
obj.transform = tr;
obj.animations = oobj.animations;
return obj;
}
- (void)parseLinearGradient:(pxXMLNode*)node
- (pxSVGGradient*)parseLinearGradient:(pxXMLNode*)node
{
NSString *gid = [node.attributes objectForKey:@"id"];
if (!gid) return;
if (!gid) return nil;
NSString *href = [node.attributes objectForKey:@"xlink:href"];
if (!href) href = [node.attributes objectForKey:@"href"];
CGGradientRef gr;
CGPoint sp = CGPointZero, ep = (CGPoint){INFINITY,INFINITY};
NSMutableArray *cls, *locs;
if (href) {
href = [href substringFromIndex:1];
pxSVGGradient *g = [self.defs objectForKey:href];
if (![g isKindOfClass:[pxSVGGradient class]]) return;
pxSVGGradient *g = (id)[self findDef:href];
if (![g isKindOfClass:[pxSVGGradient class]]) return nil;
gr = g.gradient;
sp = g.startPoint;
ep = g.endPoint;
Expand Down Expand Up @@ -180,8 +235,78 @@ - (void)parseLinearGradient:(pxXMLNode*)node
g.locations = locs;
g.startPoint = sp;
g.endPoint = ep;
[self.defs setObject:g forKey:gid];
[self.defCache setObject:g forKey:gid];
return g;
}
return nil;
}
- (pxSVGPattern*)parsePattern:(pxXMLNode*)node
{
NSString *pid = [node.attributes objectForKey:@"id"];
if (!pid) return nil;
NSString *href = [node.attributes objectForKey:@"xlink:href"];
if (!href) href = [node.attributes objectForKey:@"href"];
pxSVGPattern *p = nil;
if (href) {
href = [href substringFromIndex:1];
pxSVGPattern *op = (id)[self findDef:href];
if (![op isKindOfClass:[pxSVGPattern class]]) return nil;
p = [pxSVGPattern new];
p.id = pid;
p.subnodes = op.subnodes;
p.transform = op.transform;
} else {
p = [pxSVGPattern new];
p.id = pid;
NSMutableArray *sub = [NSMutableArray new];
for (pxXMLNode *n in node.childNodes) {
pxSVGObject *o = [self parseObject:n inheritAttributes:nil];
if (o) [sub addObject:o];
}
p.subnodes = [NSArray arrayWithArray:sub];
p.transform = CATransform3DIdentity;
}
CGRect pr = p.bounds, tr = CGRectZero;
if ([node.attributes objectForKey:@"viewBox"]) {
NSArray *vb = [[node.attributes objectForKey:@"viewBox"] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
tr = (CGRect){
{
[vb[0] doubleValue],
[vb[1] doubleValue]
},{
[vb[2] doubleValue],
[vb[3] doubleValue]
}
};
} else if ([node.attributes objectForKey:@"width"] &&
[node.attributes objectForKey:@"height"]) {
CGPoint o = CGPointZero;
if ([node.attributes objectForKey:@"x"] &&
[node.attributes objectForKey:@"y"]) {
o = (CGPoint){
[[node.attributes objectForKey:@"x"] doubleValue],
[[node.attributes objectForKey:@"y"] doubleValue]
};
}
tr = (CGRect){
o,{
[[node.attributes objectForKey:@"width"] doubleValue],
[[node.attributes objectForKey:@"height"] doubleValue]
}
};
} else {
tr = pr;
}
if (!CGRectEqualToRect(pr, tr)) {
p.transform = CATransform3DTranslate(p.transform, -pr.origin.x-pr.size.width/2, -pr.origin.y-pr.size.height/2, 0);
p.transform = CATransform3DScale(p.transform, tr.size.width/pr.size.width,tr.size.height/pr.size.height,1);
p.transform = CATransform3DTranslate(p.transform, tr.origin.x+tr.size.width/2, tr.origin.y+tr.size.height/2, 0);
}
if ([node.attributes objectForKey:@"patternTransform"]) {
p.transform = CATransform3DConcat(p.transform, [pxSVGObject transformFromString:[node.attributes objectForKey:@"patternTransform"]]);
}
[self.defCache setObject:p forKey:pid];
return p;
}
- (pxSVGObject*)parseObject:(pxXMLNode*)node inheritAttributes:(pxSVGObject*)inherit
{
Expand All @@ -195,6 +320,7 @@ - (pxSVGObject*)parseObject:(pxXMLNode*)node inheritAttributes:(pxSVGObject*)inh
[self parseLinearGradient:node];
return nil;
}
if ([node.tagName isEqualToString:@"pattern"]) return [self parsePattern:node];;
Class objClass = pxSVGObject.class;
if ([node.tagName isEqualToString:@"g"])
objClass = pxSVGGroup.class;
Expand Down Expand Up @@ -223,7 +349,7 @@ - (pxSVGObject*)parseObject:(pxXMLNode*)node inheritAttributes:(pxSVGObject*)inh
obj.fillOpacity = inherit?inherit.fillOpacity:1;
if (!obj.strokeColor)
obj.strokeColor = inherit?inherit.strokeColor:nil;
if (obj.id) [self.defs setObject:obj forKey:obj.id];
if (obj.id) [self.defCache setObject:obj forKey:obj.id];
if (node.childNodes.count) {
NSMutableArray *subnodes = [NSMutableArray new];
for (pxXMLNode *n in node.childNodes) {
Expand All @@ -236,29 +362,41 @@ - (pxSVGObject*)parseObject:(pxXMLNode*)node inheritAttributes:(pxSVGObject*)inh
}
return obj;
}
- (CALayer *)makeLayerWithNode:(pxSVGObject*)node
- (CALayer *)makeLayerWithNode:(pxSVGObject*)node rootBounds:(CGRect)bounds;
{
CALayer *l, *fl;
CALayer *l;
if ([node respondsToSelector:@selector(d)]) {
CAShapeLayer *sl = [CAShapeLayer new];
sl.path = [(id)node d].CGPath;
UIBezierPath *p = [(id)node d];
sl.path = p.CGPath;
if (node.fillDef) {
sl.fillColor = [UIColor clearColor].CGColor;
id def = [self.defs objectForKey:node.fillDef];
id def = [self findDef:node.fillDef];
if ([def isKindOfClass:[pxSVGGradient class]]) {
CAGradientLayer *gl = [CAGradientLayer new];
gl.frame = [(id)node d].bounds;
gl.frame = p.bounds;
gl.startPoint = (CGPoint){([def startPoint].x-gl.frame.origin.x)/gl.frame.size.width,([def startPoint].y-gl.frame.origin.y)/gl.frame.size.height};
gl.endPoint = (CGPoint){([def endPoint].x-gl.frame.origin.x)/gl.frame.size.width,([def endPoint].y-gl.frame.origin.y)/gl.frame.size.height};
gl.locations = [def locations];
gl.colors = [def colors];
gl.opacity = isnan(node.fillOpacity)?1:node.fillOpacity;
CAShapeLayer *ml = [CAShapeLayer new];
ml.frame = (CGRect){{0,0},{gl.frame.size.width+gl.frame.origin.x,gl.frame.size.height+gl.frame.origin.y}};
ml.frame = (CGRect){{-p.bounds.origin.x,-p.bounds.origin.y},{p.bounds.size.width+p.bounds.origin.x,p.bounds.size.height+p.bounds.origin.y}};
ml.path = sl.path;
gl.mask = ml;
[sl addSublayer:gl];
fl = gl;
}
if ([def isKindOfClass:[pxSVGPattern class]]) {
pxSVGPatternLayer *tl = [pxSVGPatternLayer new];
CALayer *pl = [self makeLayerWithNode:def rootBounds:[def bounds]];
tl.patternLayer = pl;
tl.frame = p.bounds;
tl.opacity = isnan(node.fillOpacity)?1:node.fillOpacity;
CAShapeLayer *ml = [CAShapeLayer new];
ml.frame = (CGRect){{-p.bounds.origin.x,-p.bounds.origin.y},{p.bounds.size.width+p.bounds.origin.x,p.bounds.size.height+p.bounds.origin.y}};
ml.path = sl.path;
tl.mask = ml;
[sl addSublayer:tl];
}
} else
sl.fillColor = [(node.fillColor?:[UIColor blackColor]) colorWithAlphaComponent:isnan(node.fillOpacity)?1:node.fillOpacity].CGColor;
Expand All @@ -268,22 +406,22 @@ - (CALayer *)makeLayerWithNode:(pxSVGObject*)node
} else {
l = [CALayer new];
}
l.frame = self.bounds;
l.frame = bounds;
CATransform3D tr = node.transform;
tr = CATransform3DConcat(CATransform3DMakeTranslation( self.bounds.size.width/2, self.bounds.size.height/2, 0), tr);
tr = CATransform3DConcat(tr, CATransform3DMakeTranslation(-self.bounds.size.width/2, -self.bounds.size.height/2, 0));
l.transform = tr;
l.opacity = node.opacity;
if ([node respondsToSelector:@selector(subnodes)]) {
for (pxSVGObject *n in [(id)node subnodes]) {
CALayer *sl = [self makeLayerWithNode:n];
CALayer *sl = [self makeLayerWithNode:n rootBounds:bounds];
if (sl) [l addSublayer:sl];
}
}
return l;
}
- (CALayer *)makeLayer
{
return [self makeLayerWithNode:self.root];
return [self makeLayerWithNode:self.root rootBounds:self.bounds];
}
@end
2 changes: 1 addition & 1 deletion pxSVG/pxSVGView.m
Expand Up @@ -28,6 +28,7 @@ - (instancetype)initWithFrame:(CGRect)frame

- (void)layoutSublayersOfLayer:(CALayer *)layer
{
[super layoutSublayersOfLayer:layer];
if (layer != self.layer) return;
self.svgLayer.transform = CATransform3DIdentity;
[self.svgLayer setFrame:self.layer.bounds];
Expand All @@ -51,7 +52,6 @@ - (void)layoutSublayersOfLayer:(CALayer *)layer

- (void)svgLayerDidLoadImage:(pxSVGLayer *)svgLayer
{
[self setNeedsLayout];
[self layoutSublayersOfLayer:self.layer];
[self setNeedsDisplay];
if ([self.svgDelegate respondsToSelector:@selector(svgViewDidLoadImage:)])
Expand Down

0 comments on commit f30383c

Please sign in to comment.