forked from pocketsvg/PocketSVG
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSVGLayer.m
More file actions
154 lines (132 loc) · 5.44 KB
/
SVGLayer.m
File metadata and controls
154 lines (132 loc) · 5.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* This file is part of the PocketSVG package.
* Copyright (c) Ponderwell, Ariel Elkin, Fjölnir Ásgeirsson, and Contributors
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SVGLayer.h"
#import "SVGPortability.h"
#import "PocketSVG.h"
#import "SVGBezierPath.h"
#import "SVGEngine.h"
@implementation SVGLayer {
NSMutableArray<SVGBezierPath*> *_untouchedPaths;
NSMutableArray *_shapeLayers;
}
- (void)commonInit
{
_shapeLayers = [NSMutableArray new];
#if TARGET_OS_IPHONE
self.shouldRasterize = YES;
self.rasterizationScale = [[UIScreen mainScreen] scale];
#endif
}
- (instancetype)init
{
if (self = [super init]) {
[self commonInit];
}
return self;
}
- (instancetype)initWithContentsOfURL:(NSURL *)url
{
if ((self = [self init])) {
[self setPaths:[SVGBezierPath pathsFromSVGAtURL:url]];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder * const)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self commonInit];
}
return self;
}
- (void)setPaths:(NSArray<SVGBezierPath*> *)paths
{
[self willChangeValueForKey:@"paths"];
_paths = paths;
[_shapeLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
[_shapeLayers removeAllObjects];
_untouchedPaths = [NSMutableArray new];
[CATransaction begin];
[CATransaction setDisableActions:YES];
for(__strong SVGBezierPath *path in paths) {
if ([path.svgAttributes[@"display"] isEqualToString:@"none"]) {
continue;
}
CAShapeLayer * const layer = [CAShapeLayer new];
if(path.svgAttributes[@"transform"]) {
SVGBezierPath * const newPath = [path copy];
[newPath applyTransform:[path.svgAttributes[@"transform"] svg_CGAffineTransformValue]];
path = newPath;
}
layer.path = path.CGPath;
layer.lineWidth = path.svgAttributes[@"stroke-width"] ? [path.svgAttributes[@"stroke-width"] floatValue] : 1.0;
layer.opacity = path.svgAttributes[@"opacity"] ? [path.svgAttributes[@"opacity"] floatValue] : 1;
[self insertSublayer:layer atIndex:(unsigned int)[_shapeLayers count]];
[_shapeLayers addObject:layer];
[_untouchedPaths addObject:path];
}
[self setNeedsLayout];
[CATransaction commit];
[self didChangeValueForKey:@"paths"];
}
- (void)setFillColor:(CGColorRef)aColor
{
_fillColor = aColor;
[_shapeLayers setValue:(__bridge id)_fillColor forKey:@"fillColor"];
}
- (void)setStrokeColor:(CGColorRef)aColor
{
_strokeColor = aColor;
[_shapeLayers setValue:(__bridge id)_strokeColor forKey:@"strokeColor"];
}
- (CGSize)preferredFrameSize
{
return SVGBoundingRectForPaths(_untouchedPaths).size;
}
- (void)layoutSublayers
{
[super layoutSublayers];
#if !TARGET_OS_IPHONE && TARGET_INTERFACE_BUILDER
self.sublayerTransform = CATransform3DTranslate(CATransform3DMakeScale(1, -1, 1),
0, -self.bounds.size.height, 0);
#endif
CGSize const size = [self preferredFrameSize];
CGRect const frame = SVGAdjustCGRectForContentsGravity(self.bounds, size, self.contentsGravity);
CGAffineTransform const scale = CGAffineTransformMakeScale(frame.size.width / size.width,
frame.size.height / size.height);
CGAffineTransform const layerTransform = CGAffineTransformConcat(scale,
CGAffineTransformMakeTranslation(frame.origin.x,
frame.origin.y));
NSAssert([_shapeLayers count] == [_untouchedPaths count],
@"Layer & Path count in SVG Image View does not match!");
for(NSUInteger i = 0; i < [_untouchedPaths count]; ++i) {
SVGBezierPath * const path = _untouchedPaths[i];
CAShapeLayer * const layer = _shapeLayers[i];
layer.fillColor = _fillColor
?: (__bridge CGColorRef)path.svgAttributes[@"fill"]
?: [[PSVGColor blackColor] CGColor];
layer.strokeColor = _strokeColor
?: (__bridge CGColorRef)path.svgAttributes[@"stroke"];
if (_scaleLineWidth && path.svgAttributes[@"stroke-width"]) {
CGFloat lineScale = (frame.size.width/size.width + frame.size.height/size.height) / 2.0;
layer.lineWidth = [path.svgAttributes[@"stroke-width"] floatValue] * lineScale;
}
if (path.svgAttributes[@"fill-rule"]) {
layer.fillRule = [path.svgAttributes[@"fill-rule"] isEqualToString:@"evenodd"] ? kCAFillRuleEvenOdd : kCAFillRuleNonZero;
}
CGRect const pathBounds = path.bounds;
layer.frame = CGRectApplyAffineTransform(pathBounds, layerTransform);
CGAffineTransform const pathTransform = CGAffineTransformConcat(
CGAffineTransformMakeTranslation(-pathBounds.origin.x,
-pathBounds.origin.y),
scale);
CGPathRef const transformedPath = CGPathCreateCopyByTransformingPath(path.CGPath, &pathTransform);
layer.path = transformedPath;
CGPathRelease(transformedPath);
}
}
@end