163 lines
4.9 KiB
Objective-C
163 lines
4.9 KiB
Objective-C
//
|
|
// IJSVGShapeLayer.m
|
|
// IJSVGExample
|
|
//
|
|
// Created by Curtis Hard on 07/01/2017.
|
|
// Copyright © 2017 Curtis Hard. All rights reserved.
|
|
//
|
|
|
|
#import "IJSVGShapeLayer.h"
|
|
#import "IJSVGGroupLayer.h"
|
|
|
|
@implementation IJSVGShapeLayer
|
|
|
|
@synthesize gradientFillLayer;
|
|
@synthesize patternFillLayer;
|
|
@synthesize gradientStrokeLayer;
|
|
@synthesize patternStrokeLayer;
|
|
@synthesize strokeLayer;
|
|
@synthesize requiresBackingScaleHelp;
|
|
@synthesize backingScaleFactor;
|
|
@synthesize blendingMode;
|
|
@synthesize convertMasksToPaths;
|
|
@synthesize originalPathOrigin;
|
|
@synthesize renderQuality;
|
|
|
|
- (void)dealloc
|
|
{
|
|
[_maskingLayer release], _maskingLayer = nil;
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void)addSublayer:(CALayer *)layer {
|
|
if([layer isKindOfClass:[IJSVGLayer class]] == NO &&
|
|
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) {
|
|
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.",
|
|
[layer class]];
|
|
NSException * exception = [NSException exceptionWithName:@"IJSVGInvalidSublayerException"
|
|
reason:r
|
|
userInfo:nil];
|
|
@throw exception;
|
|
}
|
|
[super addSublayer:layer];
|
|
}
|
|
|
|
- (void)setBackingScaleFactor:(CGFloat)newFactor
|
|
{
|
|
if(self.backingScaleFactor == newFactor) {
|
|
return;
|
|
}
|
|
backingScaleFactor = newFactor;
|
|
self.contentsScale = newFactor;
|
|
self.rasterizationScale = newFactor;
|
|
[self setNeedsDisplay];
|
|
}
|
|
|
|
- (void)_customRenderInContext:(CGContextRef)ctx
|
|
{
|
|
if(self.convertMasksToPaths == YES && _maskingLayer != nil) {
|
|
CGContextSaveGState(ctx);
|
|
[self applySublayerMaskToContext:ctx
|
|
forSublayer:(IJSVGLayer *)self
|
|
withOffset:CGPointZero];
|
|
[super renderInContext:ctx];
|
|
CGContextRestoreGState(ctx);
|
|
return;
|
|
}
|
|
[super renderInContext:ctx];
|
|
}
|
|
|
|
- (void)setConvertMasksToPaths:(BOOL)flag
|
|
{
|
|
if(convertMasksToPaths == flag) {
|
|
return;
|
|
}
|
|
convertMasksToPaths = flag;
|
|
if(flag == YES) {
|
|
if(_maskingLayer != nil) {
|
|
[_maskingLayer release], _maskingLayer = nil;
|
|
}
|
|
_maskingLayer = [(IJSVGLayer *)self.mask retain];
|
|
self.mask = nil;
|
|
} else {
|
|
self.mask = _maskingLayer;
|
|
[_maskingLayer release], _maskingLayer = nil;
|
|
}
|
|
}
|
|
|
|
- (void)applySublayerMaskToContext:(CGContextRef)context
|
|
forSublayer:(IJSVGLayer *)sublayer
|
|
withOffset:(CGPoint)offset
|
|
{
|
|
// apply any transforms needed
|
|
CGPoint layerOffset = offset;
|
|
CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(sublayer.transform);
|
|
CGContextConcatCTM( context, CGAffineTransformInvert(sublayerTransform) );
|
|
|
|
// walk up the superlayer chain
|
|
CALayer * superlayer = self.superlayer;
|
|
if (IJSVGIsSVGLayer(superlayer) == YES) {
|
|
[(IJSVGLayer *)superlayer applySublayerMaskToContext:context
|
|
forSublayer:(IJSVGLayer *)self
|
|
withOffset:layerOffset];
|
|
}
|
|
|
|
// grab the masking layer
|
|
IJSVGShapeLayer * maskingLayer = [self maskingLayer];
|
|
|
|
// if its a group we need to get the lowest level children
|
|
// and walk up the chain again
|
|
if([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
|
|
NSArray * subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer];
|
|
for(IJSVGLayer * subLayer in subs) {
|
|
[subLayer applySublayerMaskToContext:context
|
|
forSublayer:(IJSVGLayer *)self
|
|
withOffset:layerOffset];
|
|
}
|
|
} else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
|
|
// is a shape, go for it!
|
|
CGPathRef maskPath = maskingLayer.path;
|
|
CGContextTranslateCTM(context, -layerOffset.x, -layerOffset.y);
|
|
CGContextAddPath(context, maskPath);
|
|
CGContextClip(context);
|
|
CGContextTranslateCTM(context, layerOffset.x, layerOffset.y);
|
|
}
|
|
CGContextConcatCTM(context, sublayerTransform);
|
|
}
|
|
|
|
- (IJSVGShapeLayer *)maskingLayer
|
|
{
|
|
return (IJSVGShapeLayer *)_maskingLayer ?: nil;
|
|
}
|
|
|
|
- (void)renderInContext:(CGContextRef)ctx
|
|
{
|
|
if(self.blendingMode != kCGBlendModeNormal) {
|
|
CGContextSaveGState(ctx);
|
|
CGContextSetBlendMode(ctx, self.blendingMode);
|
|
[self _customRenderInContext:ctx];
|
|
CGContextRestoreGState(ctx);
|
|
return;
|
|
}
|
|
[self _customRenderInContext:ctx];
|
|
}
|
|
|
|
- (CGPoint)absoluteOrigin
|
|
{
|
|
CGPoint point = CGPointZero;
|
|
CALayer * pLayer = self;
|
|
while(pLayer != nil) {
|
|
point.x += pLayer.frame.origin.x;
|
|
point.y += pLayer.frame.origin.y;
|
|
pLayer = pLayer.superlayer;
|
|
}
|
|
return point;
|
|
}
|
|
|
|
- (id<CAAction>)actionForKey:(NSString *)event
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
@end
|