387 lines
11 KiB
Objective-C
387 lines
11 KiB
Objective-C
//
|
|
// IJSVGNode.m
|
|
// IconJar
|
|
//
|
|
// Created by Curtis Hard on 30/08/2014.
|
|
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
|
//
|
|
|
|
#import "IJSVGDef.h"
|
|
#import "IJSVGNode.h"
|
|
#import "IJSVGUtils.h"
|
|
|
|
@implementation IJSVGNode
|
|
|
|
@synthesize shouldRender;
|
|
@synthesize type;
|
|
@synthesize name;
|
|
@synthesize classNameList;
|
|
@synthesize className;
|
|
@synthesize unicode;
|
|
@synthesize x;
|
|
@synthesize y;
|
|
@synthesize width;
|
|
@synthesize height;
|
|
@synthesize fillColor;
|
|
@synthesize fillOpacity;
|
|
@synthesize strokeColor;
|
|
@synthesize strokeOpacity;
|
|
@synthesize strokeWidth;
|
|
@synthesize opacity;
|
|
@synthesize identifier;
|
|
@synthesize parentNode;
|
|
@synthesize intermediateParentNode;
|
|
@synthesize transforms;
|
|
@synthesize windingRule;
|
|
@synthesize def;
|
|
@synthesize fillGradient;
|
|
@synthesize fillPattern;
|
|
@synthesize strokeGradient;
|
|
@synthesize strokePattern;
|
|
@synthesize clipPath;
|
|
@synthesize lineCapStyle;
|
|
@synthesize lineJoinStyle;
|
|
@synthesize strokeDashArrayCount;
|
|
@synthesize strokeDashArray;
|
|
@synthesize strokeDashOffset;
|
|
@synthesize usesDefaultFillColor;
|
|
@synthesize svg;
|
|
@synthesize mask;
|
|
@synthesize units;
|
|
@synthesize contentUnits;
|
|
@synthesize blendMode;
|
|
|
|
- (void)dealloc
|
|
{
|
|
free(strokeDashArray);
|
|
(void)([x release]), x = nil;
|
|
(void)([y release]), y = nil;
|
|
(void)([width release]), width = nil;
|
|
(void)([height release]), height = nil;
|
|
(void)([opacity release]), opacity = nil;
|
|
(void)([fillOpacity release]), fillOpacity = nil;
|
|
(void)([strokeOpacity release]), strokeOpacity = nil;
|
|
(void)([strokeWidth release]), strokeWidth = nil;
|
|
(void)([strokeDashOffset release]), strokeDashOffset = nil;
|
|
(void)([unicode release]), unicode = nil;
|
|
(void)([fillGradient release]), fillGradient = nil;
|
|
(void)([strokeGradient release]), strokeGradient = nil;
|
|
(void)([strokePattern release]), strokePattern = nil;
|
|
(void)([transforms release]), transforms = nil;
|
|
(void)([fillColor release]), fillColor = nil;
|
|
(void)([strokeColor release]), strokeColor = nil;
|
|
(void)([identifier release]), identifier = nil;
|
|
(void)([def release]), def = nil;
|
|
(void)([name release]), name = nil;
|
|
(void)([className release]), className = nil;
|
|
(void)([classNameList release]), classNameList = nil;
|
|
(void)([fillPattern release]), fillPattern = nil;
|
|
(void)([clipPath release]), clipPath = nil;
|
|
(void)([svg release]), svg = nil;
|
|
(void)([mask release]), mask = nil;
|
|
[super dealloc];
|
|
}
|
|
|
|
+ (IJSVGNodeType)typeForString:(NSString*)string
|
|
kind:(NSXMLNodeKind)kind
|
|
{
|
|
string = [string lowercaseString];
|
|
if ([string isEqualToString:@"style"])
|
|
return IJSVGNodeTypeStyle;
|
|
if ([string isEqualToString:@"switch"])
|
|
return IJSVGNodeTypeSwitch;
|
|
if ([string isEqualToString:@"defs"])
|
|
return IJSVGNodeTypeDef;
|
|
if ([string isEqualToString:@"g"])
|
|
return IJSVGNodeTypeGroup;
|
|
if ([string isEqualToString:@"path"])
|
|
return IJSVGNodeTypePath;
|
|
if ([string isEqualToString:@"polygon"])
|
|
return IJSVGNodeTypePolygon;
|
|
if ([string isEqualToString:@"polyline"])
|
|
return IJSVGNodeTypePolyline;
|
|
if ([string isEqualToString:@"rect"])
|
|
return IJSVGNodeTypeRect;
|
|
if ([string isEqualToString:@"line"])
|
|
return IJSVGNodeTypeLine;
|
|
if ([string isEqualToString:@"circle"])
|
|
return IJSVGNodeTypeCircle;
|
|
if ([string isEqualToString:@"ellipse"])
|
|
return IJSVGNodeTypeEllipse;
|
|
if ([string isEqualToString:@"use"])
|
|
return IJSVGNodeTypeUse;
|
|
if ([string isEqualToString:@"lineargradient"])
|
|
return IJSVGNodeTypeLinearGradient;
|
|
if ([string isEqualToString:@"radialgradient"])
|
|
return IJSVGNodeTypeRadialGradient;
|
|
if ([string isEqualToString:@"glyph"])
|
|
return IJSVGNodeTypeGlyph;
|
|
if ([string isEqualToString:@"font"])
|
|
return IJSVGNodeTypeFont;
|
|
if ([string isEqualToString:@"clippath"])
|
|
return IJSVGNodeTypeClipPath;
|
|
if ([string isEqualToString:@"mask"])
|
|
return IJSVGNodeTypeMask;
|
|
if ([string isEqualToString:@"image"])
|
|
return IJSVGNodeTypeImage;
|
|
if ([string isEqualToString:@"pattern"])
|
|
return IJSVGNodeTypePattern;
|
|
if ([string isEqualToString:@"svg"])
|
|
return IJSVGNodeTypeSVG;
|
|
if ([string isEqualToString:@"text"])
|
|
return IJSVGNodeTypeText;
|
|
if ([string isEqualToString:@"tspan"] || kind == NSXMLTextKind) {
|
|
return IJSVGNodeTypeTextSpan;
|
|
}
|
|
|
|
// are we commong HTML? - if so just treat as a group
|
|
if (IJSVGIsCommonHTMLElementName(string) == YES) {
|
|
return IJSVGNodeTypeGroup;
|
|
}
|
|
|
|
return IJSVGNodeTypeNotFound;
|
|
}
|
|
|
|
- (id)init
|
|
{
|
|
if ((self = [self initWithDef:YES]) != nil) {
|
|
self.opacity = [IJSVGUnitLength unitWithFloat:1];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)applyPropertiesFromNode:(IJSVGNode*)node
|
|
{
|
|
self.name = node.name;
|
|
self.type = node.type;
|
|
self.unicode = node.unicode;
|
|
self.className = node.className;
|
|
self.classNameList = node.classNameList;
|
|
|
|
self.x = node.x;
|
|
self.y = node.y;
|
|
self.width = node.width;
|
|
self.height = node.height;
|
|
|
|
self.fillGradient = node.fillGradient;
|
|
self.fillPattern = node.fillPattern;
|
|
self.strokeGradient = node.strokeGradient;
|
|
self.strokePattern = node.strokePattern;
|
|
|
|
self.fillColor = node.fillColor;
|
|
self.strokeColor = node.strokeColor;
|
|
self.clipPath = node.clipPath;
|
|
|
|
self.units = node.units;
|
|
self.contentUnits = node.contentUnits;
|
|
|
|
self.opacity = node.opacity;
|
|
self.strokeWidth = node.strokeWidth;
|
|
self.fillOpacity = node.fillOpacity;
|
|
self.strokeOpacity = node.strokeOpacity;
|
|
|
|
self.identifier = node.identifier;
|
|
self.usesDefaultFillColor = node.usesDefaultFillColor;
|
|
|
|
self.transforms = node.transforms;
|
|
self.def = node.def;
|
|
self.windingRule = node.windingRule;
|
|
self.lineCapStyle = node.lineCapStyle;
|
|
self.lineJoinStyle = node.lineJoinStyle;
|
|
self.parentNode = node.parentNode;
|
|
|
|
self.shouldRender = node.shouldRender;
|
|
self.blendMode = node.blendMode;
|
|
|
|
// dash array needs physical memory copied
|
|
CGFloat* nStrokeDashArray = (CGFloat*)malloc(node.strokeDashArrayCount * sizeof(CGFloat));
|
|
memcpy(self.strokeDashArray, nStrokeDashArray, node.strokeDashArrayCount * sizeof(CGFloat));
|
|
self.strokeDashArray = nStrokeDashArray;
|
|
self.strokeDashArrayCount = node.strokeDashArrayCount;
|
|
self.strokeDashOffset = node.strokeDashOffset;
|
|
}
|
|
|
|
- (id)copyWithZone:(NSZone*)zone
|
|
{
|
|
IJSVGNode* node = [self.class allocWithZone:zone];
|
|
[node applyPropertiesFromNode:self];
|
|
return node;
|
|
}
|
|
|
|
- (id)initWithDef:(BOOL)flag
|
|
{
|
|
if ((self = [super init]) != nil) {
|
|
self.opacity = [IJSVGUnitLength unitWithFloat:0.f];
|
|
self.fillOpacity = [IJSVGUnitLength unitWithFloat:1.f];
|
|
self.fillOpacity.inherit = YES;
|
|
|
|
self.strokeDashOffset = [IJSVGUnitLength unitWithFloat:0.f];
|
|
self.shouldRender = YES;
|
|
|
|
self.strokeOpacity = [IJSVGUnitLength unitWithFloat:1.f];
|
|
self.strokeOpacity.inherit = YES;
|
|
|
|
self.strokeWidth = [IJSVGUnitLength unitWithFloat:1.f];
|
|
self.strokeWidth.inherit = YES;
|
|
|
|
self.windingRule = IJSVGWindingRuleInherit;
|
|
self.lineCapStyle = IJSVGLineCapStyleInherit;
|
|
self.lineJoinStyle = IJSVGLineJoinStyleInherit;
|
|
self.units = IJSVGUnitInherit;
|
|
|
|
self.blendMode = IJSVGBlendModeNormal;
|
|
|
|
if (flag) {
|
|
def = [[IJSVGDef alloc] init];
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (IJSVGDef*)defForID:(NSString*)anID
|
|
{
|
|
IJSVGDef* aDef = nil;
|
|
if ((aDef = [def defForID:anID]) != nil) {
|
|
return aDef;
|
|
}
|
|
if (parentNode != nil) {
|
|
return [parentNode defForID:anID];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (void)addDef:(IJSVGNode*)aDef
|
|
{
|
|
[def addDef:aDef];
|
|
}
|
|
|
|
// winding rule can inherit..
|
|
- (IJSVGWindingRule)windingRule
|
|
{
|
|
if (windingRule == IJSVGWindingRuleInherit && parentNode != nil) {
|
|
return parentNode.windingRule;
|
|
}
|
|
return windingRule;
|
|
}
|
|
|
|
- (IJSVGLineCapStyle)lineCapStyle
|
|
{
|
|
if (lineCapStyle == IJSVGLineCapStyleInherit) {
|
|
if (parentNode != nil) {
|
|
return parentNode.lineCapStyle;
|
|
}
|
|
}
|
|
return lineCapStyle;
|
|
}
|
|
|
|
- (IJSVGLineJoinStyle)lineJoinStyle
|
|
{
|
|
if (lineJoinStyle == IJSVGLineJoinStyleInherit) {
|
|
if (parentNode != nil) {
|
|
return parentNode.lineJoinStyle;
|
|
}
|
|
}
|
|
return lineJoinStyle;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (IJSVGUnitLength*)opacity
|
|
{
|
|
if (opacity.inherit && parentNode != nil) {
|
|
return parentNode.opacity;
|
|
}
|
|
return opacity;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (IJSVGUnitLength*)fillOpacity
|
|
{
|
|
if (fillOpacity.inherit && parentNode != nil) {
|
|
return parentNode.fillOpacity;
|
|
}
|
|
return fillOpacity;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (IJSVGUnitLength*)strokeWidth
|
|
{
|
|
if (strokeWidth.inherit && parentNode != nil) {
|
|
return parentNode.strokeWidth;
|
|
}
|
|
return strokeWidth;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (NSColor*)strokeColor
|
|
{
|
|
if (strokeColor != nil)
|
|
return strokeColor;
|
|
if (strokeColor == nil && parentNode != nil)
|
|
return parentNode.strokeColor;
|
|
return nil;
|
|
}
|
|
|
|
- (IJSVGUnitLength*)strokeOpacity
|
|
{
|
|
if (strokeOpacity.inherit && parentNode != nil) {
|
|
return parentNode.strokeOpacity;
|
|
}
|
|
return strokeOpacity;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (IJSVGGradient*)fillGradient
|
|
{
|
|
if (fillGradient == nil && parentNode != nil) {
|
|
return parentNode.fillGradient;
|
|
}
|
|
return fillGradient;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (IJSVGPattern*)fillPattern
|
|
{
|
|
if (fillPattern == nil && parentNode != nil) {
|
|
return parentNode.fillPattern;
|
|
}
|
|
return fillPattern;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (IJSVGGradient*)strokeGradient
|
|
{
|
|
if (strokeGradient == nil && parentNode != nil) {
|
|
return parentNode.strokeGradient;
|
|
}
|
|
return strokeGradient;
|
|
}
|
|
|
|
// these are all recursive, so go up the chain
|
|
// if they dont exist on this specific node
|
|
- (IJSVGPattern*)strokePattern
|
|
{
|
|
if (strokePattern == nil && parentNode != nil) {
|
|
return parentNode.strokePattern;
|
|
}
|
|
return strokePattern;
|
|
}
|
|
|
|
@end
|