Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 35fc5157b3 | |||
| 3742cfd16e | |||
| b47b487a8d | |||
| 6dc767f88e | |||
| f8efb68277 |
@@ -764,7 +764,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1520;
|
||||
LastUpgradeCheck = 1600;
|
||||
ORGANIZATIONNAME = "Curtis Hard";
|
||||
TargetAttributes = {
|
||||
594CF46E238FF38E009B251B = {
|
||||
@@ -926,7 +926,6 @@
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEFINES_MODULE = YES;
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
@@ -952,6 +951,7 @@
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "-Wl,-no_warn_duplicate_libraries";
|
||||
PRODUCT_MODULE_NAME = IJSVG;
|
||||
SDKROOT = macosx;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -1016,6 +1016,7 @@
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_LDFLAGS = "-Wl,-no_warn_duplicate_libraries";
|
||||
PRODUCT_MODULE_NAME = IJSVG;
|
||||
SDKROOT = macosx;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -1045,7 +1046,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 2.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
@@ -1075,7 +1076,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 2.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
LastUpgradeVersion = "1600"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVG;
|
||||
@class IJSVGParser;
|
||||
|
||||
@interface IJSVG : NSObject <NSPasteboardWriting> {
|
||||
|
||||
@@ -30,6 +31,7 @@
|
||||
CGRect _viewBox;
|
||||
CGFloat _backingScale;
|
||||
IJSVGUnitSize* _intrinsicSize;
|
||||
IJSVGParser* _parser;
|
||||
}
|
||||
|
||||
// set this to be called when the layer is about to draw, it will call this
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
#import <IJSVG/IJSVGTransaction.h>
|
||||
#import <IJSVG/IJSVGThreadManager.h>
|
||||
|
||||
@interface IJSVG (private)
|
||||
@property (nonatomic, strong) IJSVGParser* parser;
|
||||
@end
|
||||
|
||||
@implementation IJSVG
|
||||
|
||||
// these are explicitly implemented
|
||||
@@ -174,10 +178,10 @@
|
||||
NSError* anError = nil;
|
||||
|
||||
// create the group
|
||||
IJSVGParser* parser = [IJSVGParser parserForFileURL:aURL
|
||||
IJSVGParser *parser = [IJSVGParser parserForFileURL:aURL
|
||||
error:&anError];
|
||||
_rootNode = parser.rootNode;
|
||||
|
||||
self.parser = parser;
|
||||
|
||||
[self _setupBasicInfoFromGroup];
|
||||
[self _setupBasicsFromAnyInitializer];
|
||||
|
||||
@@ -199,6 +203,16 @@
|
||||
error:nil];
|
||||
}
|
||||
|
||||
- (void)setParser:(IJSVGParser*)parser {
|
||||
_rootNode = [parser rootNodeWithSize:CGSizeZero];
|
||||
|
||||
// if the rootNode has any form of relative units, we need to keep hold of
|
||||
// the parser so when we render, we can ask for new values.
|
||||
if(_rootNode.viewBoxContainsRelativeUnits) {
|
||||
_parser = parser;
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithSVGData:(NSData*)data
|
||||
error:(NSError**)error
|
||||
{
|
||||
@@ -224,9 +238,9 @@
|
||||
|
||||
// setup the parser
|
||||
IJSVGParser* parser = [[IJSVGParser alloc] initWithSVGString:string
|
||||
error:&anError];
|
||||
_rootNode = parser.rootNode;
|
||||
|
||||
error:&anError];
|
||||
self.parser = parser;
|
||||
|
||||
[self _setupBasicInfoFromGroup];
|
||||
[self _setupBasicsFromAnyInitializer];
|
||||
|
||||
@@ -625,7 +639,7 @@
|
||||
}
|
||||
}
|
||||
CGContextSetInterpolationQuality(ctx, quality);
|
||||
IJSVGRootLayer* rootLayer = self.rootLayer;
|
||||
IJSVGRootLayer* rootLayer = [self rootLayerWithRect:rect];
|
||||
[rootLayer renderInContext:ctx
|
||||
viewPort:rect
|
||||
backingScale:backingScale
|
||||
@@ -647,16 +661,35 @@
|
||||
return _layerTree;
|
||||
}
|
||||
|
||||
- (IJSVGRootLayer*)rootLayerWithRect:(CGRect)rect {
|
||||
// no parser, which means there is no need to recompute the value
|
||||
if(_parser == nil || !_rootNode.viewBoxContainsRelativeUnits ||
|
||||
CGSizeEqualToSize(_rootNode.clientSize, rect.size)) {
|
||||
return self.rootLayer;
|
||||
}
|
||||
|
||||
// if we do have a parser, that means the node has relative values, lets recompute
|
||||
__weak IJSVG* weakSelf = self;
|
||||
[self performBlock:^{
|
||||
IJSVG* strongSelf = weakSelf;
|
||||
strongSelf->_rootNode = [strongSelf->_parser rootNodeWithSize:rect.size];
|
||||
strongSelf->_rootLayer = [strongSelf.layerTree rootLayerForRootNode:strongSelf->_rootNode];
|
||||
}];
|
||||
return _rootLayer;
|
||||
}
|
||||
|
||||
- (IJSVGRootLayer*)rootLayer
|
||||
{
|
||||
if(_rootLayer == nil) {
|
||||
__weak IJSVG* weakSelf = self;
|
||||
[self performBlock:^{
|
||||
IJSVG* strongSelf = weakSelf;
|
||||
strongSelf->_rootLayer = [strongSelf.layerTree rootLayerForRootNode:strongSelf->_rootNode];
|
||||
}];
|
||||
}
|
||||
if(_rootLayer != nil) {
|
||||
return _rootLayer;
|
||||
}
|
||||
|
||||
__weak IJSVG* weakSelf = self;
|
||||
[self performBlock:^{
|
||||
IJSVG* strongSelf = weakSelf;
|
||||
strongSelf->_rootLayer = [strongSelf.layerTree rootLayerForRootNode:strongSelf->_rootNode];
|
||||
}];
|
||||
return _rootLayer;
|
||||
}
|
||||
|
||||
- (CGFloat)backingScaleFactor
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
@interface IJSVGRootNode : IJSVGGroup
|
||||
|
||||
@property (nonatomic, assign) CGSize clientSize;
|
||||
@property (nonatomic, assign) BOOL viewBoxContainsRelativeUnits;
|
||||
@property (nonatomic, assign) IJSVGIntrinsicDimensions intrinsicDimensions;
|
||||
@property (nonatomic, strong) IJSVGUnitSize* intrinsicSize;
|
||||
@property (nonatomic, readonly) CGRect bounds;
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
- (IJSVGRootNode *)rootNode
|
||||
{
|
||||
IJSVGRootNode* rootNode = nil;
|
||||
if((rootNode = [super rootNode]) == self) {
|
||||
if((rootNode = super.rootNode) == self) {
|
||||
IJSVGNode* parent = self.parentNode;
|
||||
if([parent isKindOfClass:IJSVGRootNode.class]) {
|
||||
return (IJSVGRootNode*)parent;
|
||||
|
||||
@@ -127,9 +127,11 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers);
|
||||
IJSVGStyleSheet* _styleSheet;
|
||||
NSMutableDictionary<NSString*, NSXMLElement*>* _detachedReferences;
|
||||
IJSVGThreadManager* _threadManager;
|
||||
CGSize _rootSize;
|
||||
IJSVGRootNode* _rootNode;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong, readonly) IJSVGRootNode* rootNode;
|
||||
@property (nonatomic, assign) CGSize defaultSize;
|
||||
|
||||
+ (BOOL)isDataSVG:(NSData*)data;
|
||||
|
||||
@@ -142,4 +144,6 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers);
|
||||
+ (IJSVGParser*)parserForFileURL:(NSURL*)aURL
|
||||
error:(NSError**)error;
|
||||
|
||||
- (IJSVGRootNode*)rootNodeWithSize:(CGSize)size;
|
||||
|
||||
@end
|
||||
|
||||
@@ -121,6 +121,8 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
error:(NSError**)error
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
// just some generic value to get it up n running.
|
||||
_defaultSize = CGSizeMake(200.f, 200.f);
|
||||
|
||||
// use NSXMLDocument as its the easiest thing to do on OSX
|
||||
NSError* anError = nil;
|
||||
@@ -138,19 +140,12 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
error:error];
|
||||
}
|
||||
|
||||
// attempt to parse the file
|
||||
[self begin];
|
||||
|
||||
// check the actual parsed SVG
|
||||
anError = nil;
|
||||
if([self _validateParse:&anError] == NO) {
|
||||
*error = anError;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// we have actually finished with the document at this point
|
||||
// so just get rid of it
|
||||
_document = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -211,7 +206,36 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)begin
|
||||
- (IJSVGRootNode*)rootNodeWithSize:(CGSize)size
|
||||
{
|
||||
__weak IJSVGParser* weakSelf = self;
|
||||
[self beginWithSetup:^{
|
||||
// if we have passed in a value that is not zero, we can just set it to that
|
||||
// else we need to compute it, as we can treat zero as auto.
|
||||
IJSVGParser* strongSelf = weakSelf;
|
||||
CGSize computeSize = size;
|
||||
if(!CGSizeEqualToSize(CGSizeZero, computeSize)) {
|
||||
strongSelf->_rootSize = size;
|
||||
return;
|
||||
}
|
||||
|
||||
// compute the value, if the value is still a nil size, we just need to
|
||||
// fallback to some generic value, which is against this object.
|
||||
IJSVGRootNode* node = [self rootNode:NO];
|
||||
if(node.viewBox == nil) {
|
||||
strongSelf->_rootSize = strongSelf->_defaultSize;
|
||||
return;
|
||||
}
|
||||
|
||||
// at this point we can just compute it again from the viewBox size.
|
||||
computeSize = [node.viewBox.size computeValue:CGSizeZero];
|
||||
strongSelf->_rootSize = CGSizeEqualToSize(CGSizeZero, computeSize) ?
|
||||
strongSelf->_defaultSize : computeSize;
|
||||
}];
|
||||
return _rootNode;
|
||||
}
|
||||
|
||||
- (void)beginWithSetup:(dispatch_block_t __nullable)setup
|
||||
{
|
||||
// setup basics to begin with
|
||||
_styleSheet = [[IJSVGStyleSheet alloc] init];
|
||||
@@ -219,12 +243,17 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
_threadManager = manager;
|
||||
_commandDataStream = manager.pathDataStream;
|
||||
_detachedReferences = [[NSMutableDictionary alloc] init];
|
||||
if(setup != nil) {
|
||||
setup();
|
||||
}
|
||||
_rootNode = [[IJSVGRootNode alloc] init];
|
||||
_rootNode.clientSize = _rootSize;
|
||||
IJSVGNodeParserPostProcessBlock postProcessBlock = nil;
|
||||
[self parseSVGElement:_document.rootElement
|
||||
ontoNode:_rootNode
|
||||
parentNode:nil
|
||||
postProcessBlock:&postProcessBlock];
|
||||
postProcessBlock:&postProcessBlock
|
||||
recursive:YES];
|
||||
if(postProcessBlock != nil) {
|
||||
postProcessBlock();
|
||||
}
|
||||
@@ -232,6 +261,23 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
_detachedReferences = nil;
|
||||
}
|
||||
|
||||
- (IJSVGRootNode*)rootNode:(BOOL)recursive
|
||||
{
|
||||
IJSVGNodeParserPostProcessBlock postProcessBlock = nil;
|
||||
IJSVGRootNode* node = [[IJSVGRootNode alloc] init];
|
||||
node.clientSize = _rootSize;
|
||||
[self parseSVGElement:_document.rootElement
|
||||
ontoNode:node
|
||||
parentNode:nil
|
||||
postProcessBlock:&postProcessBlock
|
||||
recursive:NO];
|
||||
if(postProcessBlock != nil) {
|
||||
postProcessBlock();
|
||||
}
|
||||
[node postProcess];
|
||||
return node;
|
||||
}
|
||||
|
||||
- (void)computeDefsForElement:(NSXMLElement*)element
|
||||
parentNode:(IJSVGNode*)parentNode
|
||||
{
|
||||
@@ -250,22 +296,26 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
- (void)computeViewBoxForRootNode:(IJSVGRootNode*)node
|
||||
{
|
||||
if(node.viewBox == nil) {
|
||||
CGFloat width = node.width.value;
|
||||
CGFloat height = node.height.value;
|
||||
IJSVGUnitLength* width = node.width;
|
||||
IJSVGUnitLength* height = node.height;
|
||||
|
||||
CGFloat cw = [width computeValue:_rootSize.width];
|
||||
CGFloat ch = [height computeValue:_rootSize.height];
|
||||
|
||||
if(height == 0.f && width != 0.f) {
|
||||
height = width;
|
||||
} else if(width == 0.f && height != 0.f) {
|
||||
width = height;
|
||||
if(ch == 0.f && cw != 0.f) {
|
||||
ch = cw;
|
||||
} else if(cw == 0.f && ch != 0.f) {
|
||||
cw = ch;
|
||||
}
|
||||
// nothing we can do, its a nil viewBox and has
|
||||
// no width or height
|
||||
if(width == 0.f && height == 0.f) {
|
||||
if(cw == 0.f && ch == 0.f) {
|
||||
return;
|
||||
}
|
||||
node.viewBox = [IJSVGUnitRect rectWithX:0.f y:0.f
|
||||
width:width
|
||||
height:height];
|
||||
IJSVGUnitSize* size = [IJSVGUnitSize sizeWithWidth:width
|
||||
height:height];
|
||||
node.viewBox = [IJSVGUnitRect rectWithOrigin:IJSVGUnitPoint.zeroPoint
|
||||
size:size];
|
||||
}
|
||||
|
||||
IJSVGIntrinsicDimensions dimensions = IJSVGIntrinsicDimensionNone;
|
||||
@@ -279,11 +329,25 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
dimensions |= IJSVGIntrinsicDimensionHeight;
|
||||
hl = node.height;
|
||||
}
|
||||
|
||||
// make note if we are using relative units for the width or height.
|
||||
if(wl.type == IJSVGUnitLengthTypePercentage ||
|
||||
hl.type == IJSVGUnitLengthTypePercentage) {
|
||||
node.viewBoxContainsRelativeUnits = YES;
|
||||
}
|
||||
|
||||
// store the width and height
|
||||
node.intrinsicDimensions = dimensions;
|
||||
node.intrinsicSize = [IJSVGUnitSize sizeWithWidth:wl
|
||||
height:hl];
|
||||
|
||||
// compute the new width and height based on the passed in size as the fall
|
||||
// back for all the percentage values.
|
||||
CGSize computedSize = CGSizeMake([wl computeValue:_rootSize.width],
|
||||
[hl computeValue:_rootSize.height]);
|
||||
node.intrinsicSize = [IJSVGUnitSize sizeWithCGSize:computedSize];
|
||||
|
||||
// compute the viewbox
|
||||
CGRect computedViewBox = [node.viewBox computeValue:_rootSize];
|
||||
node.viewBox.size = [IJSVGUnitSize sizeWithCGSize:computedViewBox.size];
|
||||
}
|
||||
|
||||
- (IJSVGNodeParserPostProcessBlock)computeAttributesFromElement:(NSXMLElement*)element
|
||||
@@ -1400,6 +1464,7 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
ontoNode:(IJSVGRootNode*)node
|
||||
parentNode:(IJSVGNode*)parentNode
|
||||
postProcessBlock:(IJSVGNodeParserPostProcessBlock*)postProcessBlock
|
||||
recursive:(BOOL)recursive
|
||||
{
|
||||
node.type = IJSVGNodeTypeSVG;
|
||||
node.name = element.localName;
|
||||
@@ -1429,8 +1494,10 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
[self computeViewBoxForRootNode:node];
|
||||
|
||||
// recursively compute children
|
||||
[self computeElement:element
|
||||
parentNode:node];
|
||||
if(recursive == YES) {
|
||||
[self computeElement:element
|
||||
parentNode:node];
|
||||
}
|
||||
}
|
||||
|
||||
- (IJSVGNode*)parseSVGElement:(NSXMLElement*)element
|
||||
@@ -1441,7 +1508,8 @@ void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers)
|
||||
[self parseSVGElement:element
|
||||
ontoNode:node
|
||||
parentNode:parentNode
|
||||
postProcessBlock:postProcessBlock];
|
||||
postProcessBlock:postProcessBlock
|
||||
recursive:YES];
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ IJSVGParsingStringMethod** IJSVGParsingMethodParseString(const char* string,
|
||||
// now we can add
|
||||
if(methodCount + 1 > currentBufferSize) {
|
||||
currentBufferSize += defBufferSize;
|
||||
*methods = *(IJSVGParsingStringMethod**)realloc(methods, sizeof(IJSVGParsingStringMethod*)*currentBufferSize);
|
||||
methods = (IJSVGParsingStringMethod**)realloc(methods, sizeof(IJSVGParsingStringMethod*)*currentBufferSize);
|
||||
}
|
||||
methods[methodCount++] = method;
|
||||
method = NULL;
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 1.3 MiB |
Reference in New Issue
Block a user