diff --git a/Framework/IJSVG/IJSVG.xcodeproj/project.pbxproj b/Framework/IJSVG/IJSVG.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2dae9c0 --- /dev/null +++ b/Framework/IJSVG/IJSVG.xcodeproj/project.pbxproj @@ -0,0 +1,893 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 594CF55F238FF462009B251B /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 594CF55E238FF462009B251B /* AppKit.framework */; }; + 594CF561238FF46C009B251B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 594CF560238FF46C009B251B /* Foundation.framework */; }; + 594CF563238FF473009B251B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 594CF562238FF473009B251B /* QuartzCore.framework */; }; + 599EB4D3238FF570004CB6BC /* libobjc.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 599EB4D2238FF535004CB6BC /* libobjc.tbd */; }; + 59EB75D623905F7300F5AE63 /* IJSVGLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756523905F6B00F5AE63 /* IJSVGLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75D723905F7300F5AE63 /* IJSVGGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756623905F6B00F5AE63 /* IJSVGGradientLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75D823905F7300F5AE63 /* IJSVGStyleSheetRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB756723905F6B00F5AE63 /* IJSVGStyleSheetRule.m */; }; + 59EB75D923905F7300F5AE63 /* IJSVGCommandLineTo.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756823905F6B00F5AE63 /* IJSVGCommandLineTo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75DA23905F7300F5AE63 /* IJSVGDef.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB756923905F6B00F5AE63 /* IJSVGDef.m */; }; + 59EB75DB23905F7300F5AE63 /* IJSVG.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756A23905F6B00F5AE63 /* IJSVG.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75DC23905F7300F5AE63 /* IJSVGText.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756B23905F6B00F5AE63 /* IJSVGText.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75DD23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB756C23905F6B00F5AE63 /* IJSVGCommandQuadraticCurve.m */; }; + 59EB75DE23905F7300F5AE63 /* IJSVGCommandVerticalLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756D23905F6C00F5AE63 /* IJSVGCommandVerticalLine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75DF23905F7300F5AE63 /* IJSVGWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75E023905F7300F5AE63 /* IJSVGStyleSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75E123905F7300F5AE63 /* IJSVGCommandSmoothCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75E223905F7300F5AE63 /* IJSVGColorList.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757123905F6C00F5AE63 /* IJSVGColorList.m */; }; + 59EB75E323905F7300F5AE63 /* IJSVGRadialGradient.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75E423905F7300F5AE63 /* IJSVGGradientUnitLength.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757323905F6C00F5AE63 /* IJSVGGradientUnitLength.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75E523905F7300F5AE63 /* IJSVGStrokeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757423905F6C00F5AE63 /* IJSVGStrokeLayer.m */; }; + 59EB75E623905F7300F5AE63 /* IJSVGStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757523905F6C00F5AE63 /* IJSVGStyle.m */; }; + 59EB75E723905F7300F5AE63 /* IJSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757623905F6C00F5AE63 /* IJSVGImage.m */; }; + 59EB75E823905F7300F5AE63 /* IJSVGUnitLength.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757723905F6C00F5AE63 /* IJSVGUnitLength.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75E923905F7300F5AE63 /* IJSVGStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */; }; + 59EB75EA23905F7300F5AE63 /* IJSVGTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757923905F6C00F5AE63 /* IJSVGTransaction.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75EB23905F7300F5AE63 /* IJSVGShapeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */; }; + 59EB75EC23905F7300F5AE63 /* IJSVGLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */; }; + 59EB75ED23905F7300F5AE63 /* IJSVGFontConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */; }; + 59EB75EE23905F7300F5AE63 /* IJSVGImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */; }; + 59EB75EF23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757E23905F6C00F5AE63 /* IJSVGCommandQuadraticCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75F023905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757F23905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75F123905F7300F5AE63 /* IJSVGUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758023905F6C00F5AE63 /* IJSVGUtils.m */; }; + 59EB75F223905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758123905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.m */; }; + 59EB75F323905F7300F5AE63 /* IJSVGGroupLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758223905F6C00F5AE63 /* IJSVGGroupLayer.m */; }; + 59EB75F423905F7300F5AE63 /* IJSVGColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758323905F6C00F5AE63 /* IJSVGColor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75F523905F7300F5AE63 /* IJSVGError.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758423905F6C00F5AE63 /* IJSVGError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75F623905F7300F5AE63 /* IJSVGColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758523905F6C00F5AE63 /* IJSVGColor.m */; }; + 59EB75F723905F7300F5AE63 /* IJSVGDef.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758623905F6C00F5AE63 /* IJSVGDef.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75F823905F7300F5AE63 /* IJSVGCommandHorizontalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758723905F6C00F5AE63 /* IJSVGCommandHorizontalLine.m */; }; + 59EB75F923905F7300F5AE63 /* IJSVGFontConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75FA23905F7300F5AE63 /* IJSVGWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758923905F6D00F5AE63 /* IJSVGWriter.m */; }; + 59EB75FB23905F7300F5AE63 /* IJSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758A23905F6D00F5AE63 /* IJSVGPath.m */; }; + 59EB75FC23905F7300F5AE63 /* IJSVGGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB75FD23905F7300F5AE63 /* IJSVGPatternLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */; }; + 59EB75FE23905F7300F5AE63 /* IJSVGRenderingStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */; }; + 59EB75FF23905F7300F5AE63 /* IJSVGBezierPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */; }; + 59EB760023905F7300F5AE63 /* IJSVGGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758F23905F6D00F5AE63 /* IJSVGGradientLayer.m */; }; + 59EB760123905F7300F5AE63 /* IJSVGLayerTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */; }; + 59EB760223905F7300F5AE63 /* IJSVGCommandVerticalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759123905F6D00F5AE63 /* IJSVGCommandVerticalLine.m */; }; + 59EB760323905F7300F5AE63 /* IJSVGNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759223905F6D00F5AE63 /* IJSVGNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760423905F7300F5AE63 /* IJSVGCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759323905F6D00F5AE63 /* IJSVGCache.m */; }; + 59EB760523905F7300F5AE63 /* IJSVGUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759423905F6D00F5AE63 /* IJSVGUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760623905F7300F5AE63 /* IJSVGCommandHorizontalLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759523905F6D00F5AE63 /* IJSVGCommandHorizontalLine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760723905F7300F5AE63 /* IJSVGNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759623905F6D00F5AE63 /* IJSVGNode.m */; }; + 59EB760823905F7300F5AE63 /* IJSVGShapeLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759723905F6D00F5AE63 /* IJSVGShapeLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760923905F7300F5AE63 /* IJSVGCommandCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759823905F6E00F5AE63 /* IJSVGCommandCurve.m */; }; + 59EB760A23905F7300F5AE63 /* IJSVGCommandMove.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759923905F6E00F5AE63 /* IJSVGCommandMove.m */; }; + 59EB760B23905F7300F5AE63 /* IJSVGStyleSheetSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759A23905F6E00F5AE63 /* IJSVGStyleSheetSelector.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760C23905F7300F5AE63 /* IJSVGStyleSheetRule.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759B23905F6E00F5AE63 /* IJSVGStyleSheetRule.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760D23905F7300F5AE63 /* IJSVGCommandCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759C23905F6E00F5AE63 /* IJSVGCommandCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760E23905F7300F5AE63 /* IJSVGPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759D23905F6E00F5AE63 /* IJSVGPath.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB760F23905F7300F5AE63 /* IJSVGCommandEllipticalArc.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759E23905F6E00F5AE63 /* IJSVGCommandEllipticalArc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761023905F7300F5AE63 /* IJSVGLinearGradient.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761123905F7300F5AE63 /* IJSVGCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A023905F6E00F5AE63 /* IJSVGCommand.m */; }; + 59EB761223905F7300F5AE63 /* IJSVGRenderingStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A123905F6E00F5AE63 /* IJSVGRenderingStyle.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761323905F7300F5AE63 /* IJSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A223905F6E00F5AE63 /* IJSVG.m */; }; + 59EB761423905F7300F5AE63 /* IJSVGImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761523905F7300F5AE63 /* IJSVGStrokeLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761623905F7300F5AE63 /* IJSVGParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A523905F6E00F5AE63 /* IJSVGParser.m */; }; + 59EB761723905F7300F5AE63 /* IJSVGRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */; }; + 59EB761823905F7300F5AE63 /* IJSVGParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A723905F6F00F5AE63 /* IJSVGParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761923905F7300F5AE63 /* IJSVGCommandSmoothCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A823905F6F00F5AE63 /* IJSVGCommandSmoothCurve.m */; }; + 59EB761A23905F7300F5AE63 /* IJSVGColorList.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761B23905F7300F5AE63 /* IJSVGPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75AA23905F6F00F5AE63 /* IJSVGPattern.m */; }; + 59EB761C23905F7300F5AE63 /* IJSVGGradient.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AB23905F6F00F5AE63 /* IJSVGGradient.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761D23905F7300F5AE63 /* IJSVGStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AC23905F6F00F5AE63 /* IJSVGStyle.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761E23905F7300F5AE63 /* IJSVGGroupLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AD23905F6F00F5AE63 /* IJSVGGroupLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB761F23905F7300F5AE63 /* IJSVGCommandLineTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75AE23905F6F00F5AE63 /* IJSVGCommandLineTo.m */; }; + 59EB762023905F7300F5AE63 /* IJSVGCommandMove.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AF23905F6F00F5AE63 /* IJSVGCommandMove.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762123905F7300F5AE63 /* IJSVGTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75B023905F6F00F5AE63 /* IJSVGTransform.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762223905F7300F5AE63 /* IJSVGMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75B123905F6F00F5AE63 /* IJSVGMath.m */; }; + 59EB762323905F7300F5AE63 /* IJSVGExporterPathInstruction.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75B223905F6F00F5AE63 /* IJSVGExporterPathInstruction.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762423905F7300F5AE63 /* IJSVGTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75B323905F6F00F5AE63 /* IJSVGTransaction.m */; }; + 59EB762523905F7300F5AE63 /* IJSVGTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75B423905F6F00F5AE63 /* IJSVGTransform.m */; }; + 59EB762623905F7300F5AE63 /* IJSVGImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75B523905F7000F5AE63 /* IJSVGImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762723905F7300F5AE63 /* IJSVGMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75B623905F7000F5AE63 /* IJSVGMath.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762823905F7300F5AE63 /* IJSVGCommandClose.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75B723905F7000F5AE63 /* IJSVGCommandClose.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762923905F7300F5AE63 /* IJSVGStringAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75B823905F7000F5AE63 /* IJSVGStringAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762A23905F7300F5AE63 /* IJSVGGradientUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75B923905F7000F5AE63 /* IJSVGGradientUnitLength.m */; }; + 59EB762B23905F7300F5AE63 /* IJSVGUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75BA23905F7000F5AE63 /* IJSVGUnitLength.m */; }; + 59EB762C23905F7300F5AE63 /* IJSVGPattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BB23905F7000F5AE63 /* IJSVGPattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762D23905F7300F5AE63 /* IJSVGLayerTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BC23905F7000F5AE63 /* IJSVGLayerTree.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB762E23905F7300F5AE63 /* IJSVGExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75BD23905F7000F5AE63 /* IJSVGExporter.m */; }; + 59EB762F23905F7300F5AE63 /* IJSVGCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BE23905F7000F5AE63 /* IJSVGCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB763023905F7300F5AE63 /* IJSVGPatternLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB763123905F7300F5AE63 /* IJSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C023905F7100F5AE63 /* IJSVGText.m */; }; + 59EB763223905F7300F5AE63 /* IJSVGView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C123905F7100F5AE63 /* IJSVGView.m */; }; + 59EB763323905F7300F5AE63 /* IJSVGLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */; }; + 59EB763423905F7300F5AE63 /* IJSVGBezierPathAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB763523905F7300F5AE63 /* IJSVGStyleSheetSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C423905F7100F5AE63 /* IJSVGStyleSheetSelector.m */; }; + 59EB763623905F7300F5AE63 /* IJSVGImageLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C523905F7100F5AE63 /* IJSVGImageLayer.m */; }; + 59EB763723905F7300F5AE63 /* IJSVGCommandClose.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C623905F7100F5AE63 /* IJSVGCommandClose.m */; }; + 59EB763823905F7300F5AE63 /* IJSVGCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75C723905F7100F5AE63 /* IJSVGCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB763923905F7300F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C823905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m */; }; + 59EB763A23905F7300F5AE63 /* IJSVGForeignObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C923905F7200F5AE63 /* IJSVGForeignObject.m */; }; + 59EB763B23905F7300F5AE63 /* IJSVGCommandSmoothQuadraticCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75CA23905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB763C23905F7300F5AE63 /* IJSVGCommandEllipticalArc.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75CB23905F7200F5AE63 /* IJSVGCommandEllipticalArc.m */; }; + 59EB763D23905F7300F5AE63 /* IJSVGGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75CC23905F7200F5AE63 /* IJSVGGroup.m */; }; + 59EB763E23905F7300F5AE63 /* IJSVGView.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75CD23905F7200F5AE63 /* IJSVGView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB763F23905F7300F5AE63 /* IJSVGForeignObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB764023905F7300F5AE63 /* IJSVGExporterPathInstruction.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75CF23905F7200F5AE63 /* IJSVGExporterPathInstruction.m */; }; + 59EB764123905F7300F5AE63 /* IJSVGImageLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75D023905F7200F5AE63 /* IJSVGImageLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB764223905F7300F5AE63 /* IJSVGStyleSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75D123905F7300F5AE63 /* IJSVGStyleSheet.m */; }; + 59EB764323905F7300F5AE63 /* IJSVGGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75D223905F7300F5AE63 /* IJSVGGradient.m */; }; + 59EB764423905F7300F5AE63 /* IJSVGRendering.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75D323905F7300F5AE63 /* IJSVGRendering.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB764523905F7300F5AE63 /* IJSVGExporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75D423905F7300F5AE63 /* IJSVGExporter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59EB764623905F7300F5AE63 /* IJSVGRendering.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75D523905F7300F5AE63 /* IJSVGRendering.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 594CF46F238FF38E009B251B /* IJSVG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IJSVG.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 594CF473238FF38E009B251B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 594CF55E238FF462009B251B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 594CF560238FF46C009B251B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 594CF562238FF473009B251B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 599EB4D2238FF535004CB6BC /* libobjc.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libobjc.tbd; path = usr/lib/libobjc.tbd; sourceTree = SDKROOT; }; + 59EB756523905F6B00F5AE63 /* IJSVGLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLayer.h; sourceTree = ""; }; + 59EB756623905F6B00F5AE63 /* IJSVGGradientLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradientLayer.h; sourceTree = ""; }; + 59EB756723905F6B00F5AE63 /* IJSVGStyleSheetRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetRule.m; sourceTree = ""; }; + 59EB756823905F6B00F5AE63 /* IJSVGCommandLineTo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandLineTo.h; sourceTree = ""; }; + 59EB756923905F6B00F5AE63 /* IJSVGDef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGDef.m; sourceTree = ""; }; + 59EB756A23905F6B00F5AE63 /* IJSVG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVG.h; path = ../../../../source/IJSVG.h; sourceTree = ""; }; + 59EB756B23905F6B00F5AE63 /* IJSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGText.h; sourceTree = ""; }; + 59EB756C23905F6B00F5AE63 /* IJSVGCommandQuadraticCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandQuadraticCurve.m; sourceTree = ""; }; + 59EB756D23905F6C00F5AE63 /* IJSVGCommandVerticalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandVerticalLine.h; sourceTree = ""; }; + 59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGWriter.h; path = ../../../../source/IJSVGWriter.h; sourceTree = ""; }; + 59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheet.h; sourceTree = ""; }; + 59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandSmoothCurve.h; sourceTree = ""; }; + 59EB757123905F6C00F5AE63 /* IJSVGColorList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorList.m; sourceTree = ""; }; + 59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRadialGradient.h; sourceTree = ""; }; + 59EB757323905F6C00F5AE63 /* IJSVGGradientUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradientUnitLength.h; sourceTree = ""; }; + 59EB757423905F6C00F5AE63 /* IJSVGStrokeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStrokeLayer.m; sourceTree = ""; }; + 59EB757523905F6C00F5AE63 /* IJSVGStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyle.m; sourceTree = ""; }; + 59EB757623905F6C00F5AE63 /* IJSVGImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImage.m; sourceTree = ""; }; + 59EB757723905F6C00F5AE63 /* IJSVGUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitLength.h; sourceTree = ""; }; + 59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStringAdditions.m; sourceTree = ""; }; + 59EB757923905F6C00F5AE63 /* IJSVGTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGTransaction.h; sourceTree = ""; }; + 59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGShapeLayer.m; sourceTree = ""; }; + 59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLayer.m; sourceTree = ""; }; + 59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGFontConverter.m; path = ../../../../source/IJSVGFontConverter.m; sourceTree = ""; }; + 59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGImageRep.m; path = ../../../../source/IJSVGImageRep.m; sourceTree = ""; }; + 59EB757E23905F6C00F5AE63 /* IJSVGCommandQuadraticCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandQuadraticCurve.h; sourceTree = ""; }; + 59EB757F23905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetSelectorRaw.h; sourceTree = ""; }; + 59EB758023905F6C00F5AE63 /* IJSVGUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGUtils.m; sourceTree = ""; }; + 59EB758123905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetSelectorRaw.m; sourceTree = ""; }; + 59EB758223905F6C00F5AE63 /* IJSVGGroupLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroupLayer.m; sourceTree = ""; }; + 59EB758323905F6C00F5AE63 /* IJSVGColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGColor.h; sourceTree = ""; }; + 59EB758423905F6C00F5AE63 /* IJSVGError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGError.h; path = ../../../../source/IJSVGError.h; sourceTree = ""; }; + 59EB758523905F6C00F5AE63 /* IJSVGColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGColor.m; sourceTree = ""; }; + 59EB758623905F6C00F5AE63 /* IJSVGDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGDef.h; sourceTree = ""; }; + 59EB758723905F6C00F5AE63 /* IJSVGCommandHorizontalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandHorizontalLine.m; sourceTree = ""; }; + 59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGFontConverter.h; path = ../../../../source/IJSVGFontConverter.h; sourceTree = ""; }; + 59EB758923905F6D00F5AE63 /* IJSVGWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGWriter.m; path = ../../../../source/IJSVGWriter.m; sourceTree = ""; }; + 59EB758A23905F6D00F5AE63 /* IJSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPath.m; sourceTree = ""; }; + 59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGroup.h; sourceTree = ""; }; + 59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPatternLayer.m; sourceTree = ""; }; + 59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRenderingStyle.m; sourceTree = ""; }; + 59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGBezierPathAdditions.m; sourceTree = ""; }; + 59EB758F23905F6D00F5AE63 /* IJSVGGradientLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGradientLayer.m; sourceTree = ""; }; + 59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLayerTree.m; sourceTree = ""; }; + 59EB759123905F6D00F5AE63 /* IJSVGCommandVerticalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandVerticalLine.m; sourceTree = ""; }; + 59EB759223905F6D00F5AE63 /* IJSVGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGNode.h; sourceTree = ""; }; + 59EB759323905F6D00F5AE63 /* IJSVGCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGCache.m; path = ../../../../source/IJSVGCache.m; sourceTree = ""; }; + 59EB759423905F6D00F5AE63 /* IJSVGUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGUtils.h; sourceTree = ""; }; + 59EB759523905F6D00F5AE63 /* IJSVGCommandHorizontalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandHorizontalLine.h; sourceTree = ""; }; + 59EB759623905F6D00F5AE63 /* IJSVGNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGNode.m; sourceTree = ""; }; + 59EB759723905F6D00F5AE63 /* IJSVGShapeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGShapeLayer.h; sourceTree = ""; }; + 59EB759823905F6E00F5AE63 /* IJSVGCommandCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandCurve.m; sourceTree = ""; }; + 59EB759923905F6E00F5AE63 /* IJSVGCommandMove.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandMove.m; sourceTree = ""; }; + 59EB759A23905F6E00F5AE63 /* IJSVGStyleSheetSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetSelector.h; sourceTree = ""; }; + 59EB759B23905F6E00F5AE63 /* IJSVGStyleSheetRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetRule.h; sourceTree = ""; }; + 59EB759C23905F6E00F5AE63 /* IJSVGCommandCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandCurve.h; sourceTree = ""; }; + 59EB759D23905F6E00F5AE63 /* IJSVGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGPath.h; sourceTree = ""; }; + 59EB759E23905F6E00F5AE63 /* IJSVGCommandEllipticalArc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandEllipticalArc.h; sourceTree = ""; }; + 59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLinearGradient.h; sourceTree = ""; }; + 59EB75A023905F6E00F5AE63 /* IJSVGCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommand.m; sourceTree = ""; }; + 59EB75A123905F6E00F5AE63 /* IJSVGRenderingStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRenderingStyle.h; sourceTree = ""; }; + 59EB75A223905F6E00F5AE63 /* IJSVG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVG.m; path = ../../../../source/IJSVG.m; sourceTree = ""; }; + 59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGImageRep.h; path = ../../../../source/IJSVGImageRep.h; sourceTree = ""; }; + 59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStrokeLayer.h; sourceTree = ""; }; + 59EB75A523905F6E00F5AE63 /* IJSVGParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGParser.m; sourceTree = ""; }; + 59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRadialGradient.m; sourceTree = ""; }; + 59EB75A723905F6F00F5AE63 /* IJSVGParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGParser.h; sourceTree = ""; }; + 59EB75A823905F6F00F5AE63 /* IJSVGCommandSmoothCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandSmoothCurve.m; sourceTree = ""; }; + 59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGColorList.h; sourceTree = ""; }; + 59EB75AA23905F6F00F5AE63 /* IJSVGPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPattern.m; sourceTree = ""; }; + 59EB75AB23905F6F00F5AE63 /* IJSVGGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradient.h; sourceTree = ""; }; + 59EB75AC23905F6F00F5AE63 /* IJSVGStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyle.h; sourceTree = ""; }; + 59EB75AD23905F6F00F5AE63 /* IJSVGGroupLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGroupLayer.h; sourceTree = ""; }; + 59EB75AE23905F6F00F5AE63 /* IJSVGCommandLineTo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandLineTo.m; sourceTree = ""; }; + 59EB75AF23905F6F00F5AE63 /* IJSVGCommandMove.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandMove.h; sourceTree = ""; }; + 59EB75B023905F6F00F5AE63 /* IJSVGTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGTransform.h; sourceTree = ""; }; + 59EB75B123905F6F00F5AE63 /* IJSVGMath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGMath.m; sourceTree = ""; }; + 59EB75B223905F6F00F5AE63 /* IJSVGExporterPathInstruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporterPathInstruction.h; sourceTree = ""; }; + 59EB75B323905F6F00F5AE63 /* IJSVGTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGTransaction.m; sourceTree = ""; }; + 59EB75B423905F6F00F5AE63 /* IJSVGTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGTransform.m; sourceTree = ""; }; + 59EB75B523905F7000F5AE63 /* IJSVGImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImage.h; sourceTree = ""; }; + 59EB75B623905F7000F5AE63 /* IJSVGMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGMath.h; sourceTree = ""; }; + 59EB75B723905F7000F5AE63 /* IJSVGCommandClose.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandClose.h; sourceTree = ""; }; + 59EB75B823905F7000F5AE63 /* IJSVGStringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStringAdditions.h; sourceTree = ""; }; + 59EB75B923905F7000F5AE63 /* IJSVGGradientUnitLength.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGradientUnitLength.m; sourceTree = ""; }; + 59EB75BA23905F7000F5AE63 /* IJSVGUnitLength.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitLength.m; sourceTree = ""; }; + 59EB75BB23905F7000F5AE63 /* IJSVGPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGPattern.h; sourceTree = ""; }; + 59EB75BC23905F7000F5AE63 /* IJSVGLayerTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLayerTree.h; sourceTree = ""; }; + 59EB75BD23905F7000F5AE63 /* IJSVGExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporter.m; sourceTree = ""; }; + 59EB75BE23905F7000F5AE63 /* IJSVGCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGCache.h; path = ../../../../source/IJSVGCache.h; sourceTree = ""; }; + 59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGPatternLayer.h; sourceTree = ""; }; + 59EB75C023905F7100F5AE63 /* IJSVGText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGText.m; sourceTree = ""; }; + 59EB75C123905F7100F5AE63 /* IJSVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGView.m; path = ../../../../source/IJSVGView.m; sourceTree = ""; }; + 59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLinearGradient.m; sourceTree = ""; }; + 59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGBezierPathAdditions.h; sourceTree = ""; }; + 59EB75C423905F7100F5AE63 /* IJSVGStyleSheetSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetSelector.m; sourceTree = ""; }; + 59EB75C523905F7100F5AE63 /* IJSVGImageLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImageLayer.m; sourceTree = ""; }; + 59EB75C623905F7100F5AE63 /* IJSVGCommandClose.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandClose.m; sourceTree = ""; }; + 59EB75C723905F7100F5AE63 /* IJSVGCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommand.h; sourceTree = ""; }; + 59EB75C823905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandSmoothQuadraticCurve.m; sourceTree = ""; }; + 59EB75C923905F7200F5AE63 /* IJSVGForeignObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGForeignObject.m; sourceTree = ""; }; + 59EB75CA23905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandSmoothQuadraticCurve.h; sourceTree = ""; }; + 59EB75CB23905F7200F5AE63 /* IJSVGCommandEllipticalArc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandEllipticalArc.m; sourceTree = ""; }; + 59EB75CC23905F7200F5AE63 /* IJSVGGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroup.m; sourceTree = ""; }; + 59EB75CD23905F7200F5AE63 /* IJSVGView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGView.h; path = ../../../../source/IJSVGView.h; sourceTree = ""; }; + 59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGForeignObject.h; sourceTree = ""; }; + 59EB75CF23905F7200F5AE63 /* IJSVGExporterPathInstruction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporterPathInstruction.m; sourceTree = ""; }; + 59EB75D023905F7200F5AE63 /* IJSVGImageLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImageLayer.h; sourceTree = ""; }; + 59EB75D123905F7300F5AE63 /* IJSVGStyleSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheet.m; sourceTree = ""; }; + 59EB75D223905F7300F5AE63 /* IJSVGGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGradient.m; sourceTree = ""; }; + 59EB75D323905F7300F5AE63 /* IJSVGRendering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRendering.h; sourceTree = ""; }; + 59EB75D423905F7300F5AE63 /* IJSVGExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporter.h; sourceTree = ""; }; + 59EB75D523905F7300F5AE63 /* IJSVGRendering.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRendering.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 594CF46C238FF38E009B251B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 599EB4D3238FF570004CB6BC /* libobjc.tbd in Frameworks */, + 594CF55F238FF462009B251B /* AppKit.framework in Frameworks */, + 594CF561238FF46C009B251B /* Foundation.framework in Frameworks */, + 594CF563238FF473009B251B /* QuartzCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 592ABBE223979F9B00F44380 /* Commands */ = { + isa = PBXGroup; + children = ( + 59EB75C723905F7100F5AE63 /* IJSVGCommand.h */, + 59EB75A023905F6E00F5AE63 /* IJSVGCommand.m */, + 59EB75B723905F7000F5AE63 /* IJSVGCommandClose.h */, + 59EB75C623905F7100F5AE63 /* IJSVGCommandClose.m */, + 59EB759C23905F6E00F5AE63 /* IJSVGCommandCurve.h */, + 59EB759823905F6E00F5AE63 /* IJSVGCommandCurve.m */, + 59EB759E23905F6E00F5AE63 /* IJSVGCommandEllipticalArc.h */, + 59EB75CB23905F7200F5AE63 /* IJSVGCommandEllipticalArc.m */, + 59EB759523905F6D00F5AE63 /* IJSVGCommandHorizontalLine.h */, + 59EB758723905F6C00F5AE63 /* IJSVGCommandHorizontalLine.m */, + 59EB756823905F6B00F5AE63 /* IJSVGCommandLineTo.h */, + 59EB75AE23905F6F00F5AE63 /* IJSVGCommandLineTo.m */, + 59EB75AF23905F6F00F5AE63 /* IJSVGCommandMove.h */, + 59EB759923905F6E00F5AE63 /* IJSVGCommandMove.m */, + 59EB757E23905F6C00F5AE63 /* IJSVGCommandQuadraticCurve.h */, + 59EB756C23905F6B00F5AE63 /* IJSVGCommandQuadraticCurve.m */, + 59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */, + 59EB75A823905F6F00F5AE63 /* IJSVGCommandSmoothCurve.m */, + 59EB75CA23905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.h */, + 59EB75C823905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m */, + 59EB756D23905F6C00F5AE63 /* IJSVGCommandVerticalLine.h */, + 59EB759123905F6D00F5AE63 /* IJSVGCommandVerticalLine.m */, + ); + path = Commands; + sourceTree = ""; + }; + 592ABBE323979FBB00F44380 /* Stylesheets */ = { + isa = PBXGroup; + children = ( + 59EB75AC23905F6F00F5AE63 /* IJSVGStyle.h */, + 59EB757523905F6C00F5AE63 /* IJSVGStyle.m */, + 59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */, + 59EB75D123905F7300F5AE63 /* IJSVGStyleSheet.m */, + 59EB759B23905F6E00F5AE63 /* IJSVGStyleSheetRule.h */, + 59EB756723905F6B00F5AE63 /* IJSVGStyleSheetRule.m */, + 59EB759A23905F6E00F5AE63 /* IJSVGStyleSheetSelector.h */, + 59EB75C423905F7100F5AE63 /* IJSVGStyleSheetSelector.m */, + 59EB757F23905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.h */, + 59EB758123905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.m */, + ); + path = Stylesheets; + sourceTree = ""; + }; + 592ABBE423979FD200F44380 /* Colors */ = { + isa = PBXGroup; + children = ( + 59EB758323905F6C00F5AE63 /* IJSVGColor.h */, + 59EB758523905F6C00F5AE63 /* IJSVGColor.m */, + 59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */, + 59EB757123905F6C00F5AE63 /* IJSVGColorList.m */, + ); + path = Colors; + sourceTree = ""; + }; + 592ABBE523979FE100F44380 /* Layers */ = { + isa = PBXGroup; + children = ( + 59EB756623905F6B00F5AE63 /* IJSVGGradientLayer.h */, + 59EB758F23905F6D00F5AE63 /* IJSVGGradientLayer.m */, + 59EB75AD23905F6F00F5AE63 /* IJSVGGroupLayer.h */, + 59EB758223905F6C00F5AE63 /* IJSVGGroupLayer.m */, + 59EB75D023905F7200F5AE63 /* IJSVGImageLayer.h */, + 59EB75C523905F7100F5AE63 /* IJSVGImageLayer.m */, + 59EB756523905F6B00F5AE63 /* IJSVGLayer.h */, + 59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */, + 59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */, + 59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */, + 59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */, + 59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */, + 59EB759723905F6D00F5AE63 /* IJSVGShapeLayer.h */, + 59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */, + 59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */, + 59EB757423905F6C00F5AE63 /* IJSVGStrokeLayer.m */, + ); + path = Layers; + sourceTree = ""; + }; + 592ABBE62397A00C00F44380 /* Parsing */ = { + isa = PBXGroup; + children = ( + 59EB75A723905F6F00F5AE63 /* IJSVGParser.h */, + 59EB75A523905F6E00F5AE63 /* IJSVGParser.m */, + ); + path = Parsing; + sourceTree = ""; + }; + 592ABBE72397A02900F44380 /* Nodes */ = { + isa = PBXGroup; + children = ( + 59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */, + 59EB75C923905F7200F5AE63 /* IJSVGForeignObject.m */, + 59EB758623905F6C00F5AE63 /* IJSVGDef.h */, + 59EB756923905F6B00F5AE63 /* IJSVGDef.m */, + 59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */, + 59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */, + 59EB75AB23905F6F00F5AE63 /* IJSVGGradient.h */, + 59EB75D223905F7300F5AE63 /* IJSVGGradient.m */, + 59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */, + 59EB75CC23905F7200F5AE63 /* IJSVGGroup.m */, + 59EB75B523905F7000F5AE63 /* IJSVGImage.h */, + 59EB757623905F6C00F5AE63 /* IJSVGImage.m */, + 59EB759223905F6D00F5AE63 /* IJSVGNode.h */, + 59EB759623905F6D00F5AE63 /* IJSVGNode.m */, + 59EB759D23905F6E00F5AE63 /* IJSVGPath.h */, + 59EB758A23905F6D00F5AE63 /* IJSVGPath.m */, + 59EB75BB23905F7000F5AE63 /* IJSVGPattern.h */, + 59EB75AA23905F6F00F5AE63 /* IJSVGPattern.m */, + 59EB756B23905F6B00F5AE63 /* IJSVGText.h */, + 59EB75C023905F7100F5AE63 /* IJSVGText.m */, + ); + path = Nodes; + sourceTree = ""; + }; + 592ABBE82397A06800F44380 /* Utils */ = { + isa = PBXGroup; + children = ( + 59EB757323905F6C00F5AE63 /* IJSVGGradientUnitLength.h */, + 59EB75B923905F7000F5AE63 /* IJSVGGradientUnitLength.m */, + 59EB75B623905F7000F5AE63 /* IJSVGMath.h */, + 59EB75B123905F6F00F5AE63 /* IJSVGMath.m */, + 59EB757923905F6C00F5AE63 /* IJSVGTransaction.h */, + 59EB75B323905F6F00F5AE63 /* IJSVGTransaction.m */, + 59EB75B023905F6F00F5AE63 /* IJSVGTransform.h */, + 59EB75B423905F6F00F5AE63 /* IJSVGTransform.m */, + 59EB757723905F6C00F5AE63 /* IJSVGUnitLength.h */, + 59EB75BA23905F7000F5AE63 /* IJSVGUnitLength.m */, + 59EB759423905F6D00F5AE63 /* IJSVGUtils.h */, + 59EB758023905F6C00F5AE63 /* IJSVGUtils.m */, + ); + path = Utils; + sourceTree = ""; + }; + 592ABBE92397A08500F44380 /* Exporter */ = { + isa = PBXGroup; + children = ( + 59EB75D423905F7300F5AE63 /* IJSVGExporter.h */, + 59EB75BD23905F7000F5AE63 /* IJSVGExporter.m */, + 59EB75B223905F6F00F5AE63 /* IJSVGExporterPathInstruction.h */, + 59EB75CF23905F7200F5AE63 /* IJSVGExporterPathInstruction.m */, + ); + path = Exporter; + sourceTree = ""; + }; + 592ABBEA2397A10000F44380 /* Rendering */ = { + isa = PBXGroup; + children = ( + 59EB75BC23905F7000F5AE63 /* IJSVGLayerTree.h */, + 59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */, + 59EB75D323905F7300F5AE63 /* IJSVGRendering.h */, + 59EB75D523905F7300F5AE63 /* IJSVGRendering.m */, + 59EB75A123905F6E00F5AE63 /* IJSVGRenderingStyle.h */, + 59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */, + ); + path = Rendering; + sourceTree = ""; + }; + 592ABBEB2397A11800F44380 /* Additions */ = { + isa = PBXGroup; + children = ( + 59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */, + 59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */, + 59EB75B823905F7000F5AE63 /* IJSVGStringAdditions.h */, + 59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */, + ); + path = Additions; + sourceTree = ""; + }; + 594CF465238FF38E009B251B = { + isa = PBXGroup; + children = ( + 594CF471238FF38E009B251B /* IJSVG */, + 594CF470238FF38E009B251B /* Products */, + 594CF55D238FF461009B251B /* Frameworks */, + ); + sourceTree = ""; + }; + 594CF470238FF38E009B251B /* Products */ = { + isa = PBXGroup; + children = ( + 594CF46F238FF38E009B251B /* IJSVG.framework */, + ); + name = Products; + sourceTree = ""; + }; + 594CF471238FF38E009B251B /* IJSVG */ = { + isa = PBXGroup; + children = ( + 59EB756423905F3100F5AE63 /* Source */, + 594CF473238FF38E009B251B /* Info.plist */, + ); + path = IJSVG; + sourceTree = ""; + }; + 594CF55D238FF461009B251B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 599EB4D2238FF535004CB6BC /* libobjc.tbd */, + 594CF562238FF473009B251B /* QuartzCore.framework */, + 594CF560238FF46C009B251B /* Foundation.framework */, + 594CF55E238FF462009B251B /* AppKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 59EB756423905F3100F5AE63 /* Source */ = { + isa = PBXGroup; + children = ( + 592ABBEB2397A11800F44380 /* Additions */, + 592ABBEA2397A10000F44380 /* Rendering */, + 592ABBE92397A08500F44380 /* Exporter */, + 592ABBE82397A06800F44380 /* Utils */, + 592ABBE72397A02900F44380 /* Nodes */, + 592ABBE62397A00C00F44380 /* Parsing */, + 592ABBE523979FE100F44380 /* Layers */, + 592ABBE423979FD200F44380 /* Colors */, + 592ABBE323979FBB00F44380 /* Stylesheets */, + 592ABBE223979F9B00F44380 /* Commands */, + 59EB756A23905F6B00F5AE63 /* IJSVG.h */, + 59EB75A223905F6E00F5AE63 /* IJSVG.m */, + 59EB75BE23905F7000F5AE63 /* IJSVGCache.h */, + 59EB759323905F6D00F5AE63 /* IJSVGCache.m */, + 59EB758423905F6C00F5AE63 /* IJSVGError.h */, + 59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */, + 59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */, + 59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */, + 59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */, + 59EB75CD23905F7200F5AE63 /* IJSVGView.h */, + 59EB75C123905F7100F5AE63 /* IJSVGView.m */, + 59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */, + 59EB758923905F6D00F5AE63 /* IJSVGWriter.m */, + ); + path = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 594CF46A238FF38E009B251B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 59EB762623905F7300F5AE63 /* IJSVGImage.h in Headers */, + 59EB760823905F7300F5AE63 /* IJSVGShapeLayer.h in Headers */, + 59EB75DF23905F7300F5AE63 /* IJSVGWriter.h in Headers */, + 59EB760F23905F7300F5AE63 /* IJSVGCommandEllipticalArc.h in Headers */, + 59EB75F523905F7300F5AE63 /* IJSVGError.h in Headers */, + 59EB763E23905F7300F5AE63 /* IJSVGView.h in Headers */, + 59EB75DB23905F7300F5AE63 /* IJSVG.h in Headers */, + 59EB764423905F7300F5AE63 /* IJSVGRendering.h in Headers */, + 59EB75DC23905F7300F5AE63 /* IJSVGText.h in Headers */, + 59EB761C23905F7300F5AE63 /* IJSVGGradient.h in Headers */, + 59EB75F923905F7300F5AE63 /* IJSVGFontConverter.h in Headers */, + 59EB75EF23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.h in Headers */, + 59EB75FC23905F7300F5AE63 /* IJSVGGroup.h in Headers */, + 59EB760323905F7300F5AE63 /* IJSVGNode.h in Headers */, + 59EB762023905F7300F5AE63 /* IJSVGCommandMove.h in Headers */, + 59EB762C23905F7300F5AE63 /* IJSVGPattern.h in Headers */, + 59EB762923905F7300F5AE63 /* IJSVGStringAdditions.h in Headers */, + 59EB761A23905F7300F5AE63 /* IJSVGColorList.h in Headers */, + 59EB762123905F7300F5AE63 /* IJSVGTransform.h in Headers */, + 59EB763F23905F7300F5AE63 /* IJSVGForeignObject.h in Headers */, + 59EB75F423905F7300F5AE63 /* IJSVGColor.h in Headers */, + 59EB760D23905F7300F5AE63 /* IJSVGCommandCurve.h in Headers */, + 59EB763823905F7300F5AE63 /* IJSVGCommand.h in Headers */, + 59EB760C23905F7300F5AE63 /* IJSVGStyleSheetRule.h in Headers */, + 59EB75E323905F7300F5AE63 /* IJSVGRadialGradient.h in Headers */, + 59EB760523905F7300F5AE63 /* IJSVGUtils.h in Headers */, + 59EB763B23905F7300F5AE63 /* IJSVGCommandSmoothQuadraticCurve.h in Headers */, + 59EB75E823905F7300F5AE63 /* IJSVGUnitLength.h in Headers */, + 59EB762723905F7300F5AE63 /* IJSVGMath.h in Headers */, + 59EB761523905F7300F5AE63 /* IJSVGStrokeLayer.h in Headers */, + 59EB762F23905F7300F5AE63 /* IJSVGCache.h in Headers */, + 59EB75DE23905F7300F5AE63 /* IJSVGCommandVerticalLine.h in Headers */, + 59EB764123905F7300F5AE63 /* IJSVGImageLayer.h in Headers */, + 59EB75E023905F7300F5AE63 /* IJSVGStyleSheet.h in Headers */, + 59EB761423905F7300F5AE63 /* IJSVGImageRep.h in Headers */, + 59EB761223905F7300F5AE63 /* IJSVGRenderingStyle.h in Headers */, + 59EB760E23905F7300F5AE63 /* IJSVGPath.h in Headers */, + 59EB75EA23905F7300F5AE63 /* IJSVGTransaction.h in Headers */, + 59EB75D723905F7300F5AE63 /* IJSVGGradientLayer.h in Headers */, + 59EB75F723905F7300F5AE63 /* IJSVGDef.h in Headers */, + 59EB760623905F7300F5AE63 /* IJSVGCommandHorizontalLine.h in Headers */, + 59EB762323905F7300F5AE63 /* IJSVGExporterPathInstruction.h in Headers */, + 59EB761023905F7300F5AE63 /* IJSVGLinearGradient.h in Headers */, + 59EB75E123905F7300F5AE63 /* IJSVGCommandSmoothCurve.h in Headers */, + 59EB75D923905F7300F5AE63 /* IJSVGCommandLineTo.h in Headers */, + 59EB75D623905F7300F5AE63 /* IJSVGLayer.h in Headers */, + 59EB763023905F7300F5AE63 /* IJSVGPatternLayer.h in Headers */, + 59EB75F023905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.h in Headers */, + 59EB763423905F7300F5AE63 /* IJSVGBezierPathAdditions.h in Headers */, + 59EB761823905F7300F5AE63 /* IJSVGParser.h in Headers */, + 59EB761E23905F7300F5AE63 /* IJSVGGroupLayer.h in Headers */, + 59EB761D23905F7300F5AE63 /* IJSVGStyle.h in Headers */, + 59EB764523905F7300F5AE63 /* IJSVGExporter.h in Headers */, + 59EB762823905F7300F5AE63 /* IJSVGCommandClose.h in Headers */, + 59EB75E423905F7300F5AE63 /* IJSVGGradientUnitLength.h in Headers */, + 59EB762D23905F7300F5AE63 /* IJSVGLayerTree.h in Headers */, + 59EB760B23905F7300F5AE63 /* IJSVGStyleSheetSelector.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 594CF46E238FF38E009B251B /* IJSVG */ = { + isa = PBXNativeTarget; + buildConfigurationList = 594CF477238FF38E009B251B /* Build configuration list for PBXNativeTarget "IJSVG" */; + buildPhases = ( + 594CF46A238FF38E009B251B /* Headers */, + 594CF46B238FF38E009B251B /* Sources */, + 594CF46C238FF38E009B251B /* Frameworks */, + 594CF46D238FF38E009B251B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = IJSVG; + productName = IJSVG; + productReference = 594CF46F238FF38E009B251B /* IJSVG.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 594CF466238FF38E009B251B /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = "Curtis Hard"; + TargetAttributes = { + 594CF46E238FF38E009B251B = { + CreatedOnToolsVersion = 11.0; + }; + }; + }; + buildConfigurationList = 594CF469238FF38E009B251B /* Build configuration list for PBXProject "IJSVG" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 594CF465238FF38E009B251B; + productRefGroup = 594CF470238FF38E009B251B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 594CF46E238FF38E009B251B /* IJSVG */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 594CF46D238FF38E009B251B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 594CF46B238FF38E009B251B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 59EB763123905F7300F5AE63 /* IJSVGText.m in Sources */, + 59EB760223905F7300F5AE63 /* IJSVGCommandVerticalLine.m in Sources */, + 59EB75FD23905F7300F5AE63 /* IJSVGPatternLayer.m in Sources */, + 59EB763923905F7300F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m in Sources */, + 59EB75D823905F7300F5AE63 /* IJSVGStyleSheetRule.m in Sources */, + 59EB75FB23905F7300F5AE63 /* IJSVGPath.m in Sources */, + 59EB760123905F7300F5AE63 /* IJSVGLayerTree.m in Sources */, + 59EB763A23905F7300F5AE63 /* IJSVGForeignObject.m in Sources */, + 59EB761123905F7300F5AE63 /* IJSVGCommand.m in Sources */, + 59EB760923905F7300F5AE63 /* IJSVGCommandCurve.m in Sources */, + 59EB763323905F7300F5AE63 /* IJSVGLinearGradient.m in Sources */, + 59EB761923905F7300F5AE63 /* IJSVGCommandSmoothCurve.m in Sources */, + 59EB761323905F7300F5AE63 /* IJSVG.m in Sources */, + 59EB763623905F7300F5AE63 /* IJSVGImageLayer.m in Sources */, + 59EB75EC23905F7300F5AE63 /* IJSVGLayer.m in Sources */, + 59EB75E523905F7300F5AE63 /* IJSVGStrokeLayer.m in Sources */, + 59EB763223905F7300F5AE63 /* IJSVGView.m in Sources */, + 59EB763523905F7300F5AE63 /* IJSVGStyleSheetSelector.m in Sources */, + 59EB760723905F7300F5AE63 /* IJSVGNode.m in Sources */, + 59EB75E923905F7300F5AE63 /* IJSVGStringAdditions.m in Sources */, + 59EB761723905F7300F5AE63 /* IJSVGRadialGradient.m in Sources */, + 59EB760423905F7300F5AE63 /* IJSVGCache.m in Sources */, + 59EB75E223905F7300F5AE63 /* IJSVGColorList.m in Sources */, + 59EB75ED23905F7300F5AE63 /* IJSVGFontConverter.m in Sources */, + 59EB763C23905F7300F5AE63 /* IJSVGCommandEllipticalArc.m in Sources */, + 59EB75E723905F7300F5AE63 /* IJSVGImage.m in Sources */, + 59EB75FF23905F7300F5AE63 /* IJSVGBezierPathAdditions.m in Sources */, + 59EB75E623905F7300F5AE63 /* IJSVGStyle.m in Sources */, + 59EB75EB23905F7300F5AE63 /* IJSVGShapeLayer.m in Sources */, + 59EB75F623905F7300F5AE63 /* IJSVGColor.m in Sources */, + 59EB75F323905F7300F5AE63 /* IJSVGGroupLayer.m in Sources */, + 59EB762523905F7300F5AE63 /* IJSVGTransform.m in Sources */, + 59EB760023905F7300F5AE63 /* IJSVGGradientLayer.m in Sources */, + 59EB762B23905F7300F5AE63 /* IJSVGUnitLength.m in Sources */, + 59EB75F823905F7300F5AE63 /* IJSVGCommandHorizontalLine.m in Sources */, + 59EB75FA23905F7300F5AE63 /* IJSVGWriter.m in Sources */, + 59EB764623905F7300F5AE63 /* IJSVGRendering.m in Sources */, + 59EB762E23905F7300F5AE63 /* IJSVGExporter.m in Sources */, + 59EB761623905F7300F5AE63 /* IJSVGParser.m in Sources */, + 59EB75DD23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.m in Sources */, + 59EB762423905F7300F5AE63 /* IJSVGTransaction.m in Sources */, + 59EB75DA23905F7300F5AE63 /* IJSVGDef.m in Sources */, + 59EB763723905F7300F5AE63 /* IJSVGCommandClose.m in Sources */, + 59EB764323905F7300F5AE63 /* IJSVGGradient.m in Sources */, + 59EB762A23905F7300F5AE63 /* IJSVGGradientUnitLength.m in Sources */, + 59EB764223905F7300F5AE63 /* IJSVGStyleSheet.m in Sources */, + 59EB764023905F7300F5AE63 /* IJSVGExporterPathInstruction.m in Sources */, + 59EB75FE23905F7300F5AE63 /* IJSVGRenderingStyle.m in Sources */, + 59EB75F223905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.m in Sources */, + 59EB75EE23905F7300F5AE63 /* IJSVGImageRep.m in Sources */, + 59EB762223905F7300F5AE63 /* IJSVGMath.m in Sources */, + 59EB763D23905F7300F5AE63 /* IJSVGGroup.m in Sources */, + 59EB761F23905F7300F5AE63 /* IJSVGCommandLineTo.m in Sources */, + 59EB75F123905F7300F5AE63 /* IJSVGUtils.m in Sources */, + 59EB760A23905F7300F5AE63 /* IJSVGCommandMove.m in Sources */, + 59EB761B23905F7300F5AE63 /* IJSVGPattern.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 594CF475238FF38E009B251B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 594CF476238FF38E009B251B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 594CF478238FF38E009B251B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_COMMA = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = NO; + DEVELOPMENT_TEAM = 9KTR4W9XX6; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = IJSVG/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 2.1; + PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 594CF479238FF38E009B251B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_COMMA = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = NO; + DEVELOPMENT_TEAM = 9KTR4W9XX6; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = IJSVG/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 2.1; + PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 594CF469238FF38E009B251B /* Build configuration list for PBXProject "IJSVG" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 594CF475238FF38E009B251B /* Debug */, + 594CF476238FF38E009B251B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 594CF477238FF38E009B251B /* Build configuration list for PBXNativeTarget "IJSVG" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 594CF478238FF38E009B251B /* Debug */, + 594CF479238FF38E009B251B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 594CF466238FF38E009B251B /* Project object */; +} diff --git a/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5015e8c --- /dev/null +++ b/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate b/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..59975ff Binary files /dev/null and b/Framework/IJSVG/IJSVG.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Framework/IJSVG/IJSVG.xcodeproj/xcshareddata/xcschemes/IJSVG.xcscheme b/Framework/IJSVG/IJSVG.xcodeproj/xcshareddata/xcschemes/IJSVG.xcscheme new file mode 100644 index 0000000..1950dfc --- /dev/null +++ b/Framework/IJSVG/IJSVG.xcodeproj/xcshareddata/xcschemes/IJSVG.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Framework/IJSVG/IJSVG.xcodeproj/xcuserdata/curtishard.xcuserdatad/xcschemes/xcschememanagement.plist b/Framework/IJSVG/IJSVG.xcodeproj/xcuserdata/curtishard.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..04c7a3b --- /dev/null +++ b/Framework/IJSVG/IJSVG.xcodeproj/xcuserdata/curtishard.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + IJSVG.xcscheme_^#shared#^_ + + orderHint + 2 + + + SuppressBuildableAutocreation + + 594CF46E238FF38E009B251B + + primary + + + + + diff --git a/Framework/IJSVG/IJSVG/Info.plist b/Framework/IJSVG/IJSVG/Info.plist new file mode 100644 index 0000000..b093a5f --- /dev/null +++ b/Framework/IJSVG/IJSVG/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2019 Curtis Hard. All rights reserved. + + diff --git a/source/IJSVGBezierPathAdditions.h b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGBezierPathAdditions.h similarity index 92% rename from source/IJSVGBezierPathAdditions.h rename to Framework/IJSVG/IJSVG/Source/Additions/IJSVGBezierPathAdditions.h index d0d2929..cb7970d 100644 --- a/source/IJSVGBezierPathAdditions.h +++ b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGBezierPathAdditions.h @@ -6,6 +6,7 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // +#import #import @interface NSBezierPath (IJSVGAdditions) diff --git a/source/IJSVGBezierPathAdditions.m b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGBezierPathAdditions.m similarity index 67% rename from source/IJSVGBezierPathAdditions.m rename to Framework/IJSVG/IJSVG/Source/Additions/IJSVGBezierPathAdditions.m index bb15699..528ceeb 100644 --- a/source/IJSVGBezierPathAdditions.m +++ b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGBezierPathAdditions.m @@ -15,9 +15,9 @@ - (void)addQuadCurveToPoint:(CGPoint)QP2 { CGPoint QP0 = [self currentPoint]; CGPoint CP3 = QP2; - CGPoint CP1 = CGPointMake( QP0.x + ((2.0 / 3.0) * (QP1.x - QP0.x)), QP0.y + ((2.0 / 3.0) * (QP1.y - QP0.y))); - CGPoint CP2 = CGPointMake( QP2.x + (2.0 / 3.0) * (QP1.x - QP2.x), QP2.y + (2.0 / 3.0) * (QP1.y - QP2.y) ); - + CGPoint CP1 = CGPointMake(QP0.x + ((2.0 / 3.0) * (QP1.x - QP0.x)), QP0.y + ((2.0 / 3.0) * (QP1.y - QP0.y))); + CGPoint CP2 = CGPointMake(QP2.x + (2.0 / 3.0) * (QP1.x - QP2.x), QP2.y + (2.0 / 3.0) * (QP1.y - QP2.y)); + [self curveToPoint:CP3 controlPoint1:CP1 controlPoint2:CP2]; diff --git a/source/IJSVGStringAdditions.h b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGStringAdditions.h similarity index 88% rename from source/IJSVGStringAdditions.h rename to Framework/IJSVG/IJSVG/Source/Additions/IJSVGStringAdditions.h index 8e2ea52..44488b3 100644 --- a/source/IJSVGStringAdditions.h +++ b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGStringAdditions.h @@ -13,6 +13,6 @@ - (NSArray *)ijsvg_componentsSeparatedByChars:(char *)aChar; - (BOOL)ijsvg_isNumeric; - (BOOL)ijsvg_containsAlpha; -- (NSArray *)ijsvg_componentsSplitByWhiteSpace; +- (NSArray*)ijsvg_componentsSplitByWhiteSpace; @end diff --git a/source/IJSVGStringAdditions.m b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGStringAdditions.m similarity index 59% rename from source/IJSVGStringAdditions.m rename to Framework/IJSVG/IJSVG/Source/Additions/IJSVGStringAdditions.m index 672c7b8..202a80a 100644 --- a/source/IJSVGStringAdditions.m +++ b/Framework/IJSVG/IJSVG/Source/Additions/IJSVGStringAdditions.m @@ -10,50 +10,49 @@ @implementation NSString (IJSVGAdditions) -- (NSArray *)ijsvg_componentsSeparatedByChars:(char *)aChar +- (NSArray*)ijsvg_componentsSeparatedByChars:(char*)aChar { - NSMutableArray * comp = [[[NSMutableArray alloc] init] autorelease]; + NSMutableArray* comp = [[[NSMutableArray alloc] init] autorelease]; NSInteger length = self.length; - unichar * chars = (unichar *)calloc(sizeof(unichar),self.length); - + unichar* chars = (unichar*)calloc(sizeof(unichar), self.length); + NSInteger ind = 0; BOOL startedString = NO; - + // block for easy comparison NSUInteger aLength = strlen(aChar); BOOL (^charsContainsChar)(char anotherChar) = ^(char anotherChar) { - for(NSInteger i = 0; i < aLength; i++) { - if(aChar[i] == anotherChar) { + for (NSInteger i = 0; i < aLength; i++) { + if (aChar[i] == anotherChar) { return YES; } } return NO; }; - - for(NSInteger i = 0; i < length; i++) { - + + for (NSInteger i = 0; i < length; i++) { + // the char unichar theChar = [self characterAtIndex:i]; - + // start the buffer BOOL isEqualToChar = charsContainsChar(theChar); - if(isEqualToChar == NO) { + if (isEqualToChar == NO) { startedString = YES; chars[ind++] = theChar; } - + // has started and char is the search char, or its at end - if((startedString == YES && isEqualToChar) || - (i == (length-1) && startedString == YES)) { + if ((startedString == YES && isEqualToChar) || (i == (length - 1) && startedString == YES)) { startedString = NO; - + // append the comp [comp addObject:[NSString stringWithCharacters:chars length:ind]]; free(chars); - + // restart and realloc the memory ind = 0; - chars = (unichar *)calloc(sizeof(unichar), self.length); + chars = (unichar*)calloc(sizeof(unichar), self.length); } } free(chars); @@ -62,10 +61,10 @@ @implementation NSString (IJSVGAdditions) - (BOOL)ijsvg_containsAlpha { - const char * buffer = self.UTF8String; + const char* buffer = self.UTF8String; unsigned long length = strlen(buffer); - for( int i = 0; i < length; i++ ) { - if( isalpha(buffer[i]) ) { + for (int i = 0; i < length; i++) { + if (isalpha(buffer[i])) { return YES; } } @@ -74,19 +73,19 @@ - (BOOL)ijsvg_containsAlpha - (BOOL)ijsvg_isNumeric { - const char * buffer = self.UTF8String; + const char* buffer = self.UTF8String; unsigned long length = strlen(buffer); - for(int i = 0; i < length; i++) { - if(!isnumber(buffer[i])) { + for (int i = 0; i < length; i++) { + if (!isnumber(buffer[i])) { return NO; } } return YES; } -- (NSArray *)ijsvg_componentsSplitByWhiteSpace +- (NSArray*)ijsvg_componentsSplitByWhiteSpace { - return [self componentsSeparatedByChars:"\t\n\r "]; + return [self ijsvg_componentsSeparatedByChars:"\t\n\r "]; } @end diff --git a/source/IJSVGColor.h b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColor.h similarity index 78% rename from source/IJSVGColor.h rename to Framework/IJSVG/IJSVG/Source/Colors/IJSVGColor.h index 5fe939f..0fd3746 100644 --- a/source/IJSVGColor.h +++ b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColor.h @@ -6,6 +6,7 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // +#import #import typedef NS_OPTIONS(NSInteger, IJSVGColorStringOptions) { @@ -16,7 +17,7 @@ typedef NS_OPTIONS(NSInteger, IJSVGColorStringOptions) { IJSVGColorStringOptionDefault = IJSVGColorStringOptionAllowShortHand }; -typedef NS_ENUM( NSInteger, IJSVGPredefinedColor ) { +typedef NS_ENUM(NSInteger, IJSVGPredefinedColor) { IJSVGColorAliceblue, IJSVGColorAntiquewhite, IJSVGColorAqua, @@ -168,29 +169,29 @@ typedef NS_ENUM( NSInteger, IJSVGPredefinedColor ) { @interface IJSVGColor : NSObject -CGFloat * IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness); +CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness); -+ (NSColor *)computeColorSpace:(NSColor *)color; -+ (NSColorSpace *)defaultColorSpace; -+ (BOOL)isColor:(NSString *)string; -+ (NSString *)colorStringFromColor:(NSColor *)color - options:(IJSVGColorStringOptions)options; -+ (NSString *)colorStringFromColor:(NSColor *)color; -+ (NSColor *)colorFromHEXInteger:(NSInteger)hex; -+ (NSColor *)computeColor:(id)colour; -+ (NSColor *)colorFromString:(NSString *)string; -+ (NSColor *)colorFromHEXString:(NSString *)string; -+ (NSColor *)colorFromHEXString:(NSString *)string - containsAlphaComponent:(BOOL *)containsAlphaComponent; ++ (NSColor*)computeColorSpace:(NSColor*)color; ++ (NSColorSpace*)defaultColorSpace; ++ (BOOL)isColor:(NSString*)string; ++ (NSString*)colorStringFromColor:(NSColor*)color + options:(IJSVGColorStringOptions)options; ++ (NSString*)colorStringFromColor:(NSColor*)color; ++ (NSColor*)colorFromHEXInteger:(NSInteger)hex; ++ (NSColor*)computeColor:(id)colour; ++ (NSColor*)colorFromString:(NSString*)string; ++ (NSColor*)colorFromHEXString:(NSString*)string; ++ (NSColor*)colorFromHEXString:(NSString*)string + containsAlphaComponent:(BOOL*)containsAlphaComponent; + (BOOL)HEXContainsAlphaComponent:(NSUInteger)hex; + (unsigned long)lengthOfHEXInteger:(NSUInteger)hex; -+ (NSColor *)colorFromRString:(NSString *)rString - gString:(NSString *)gString - bString:(NSString *)bString - aString:(NSString *)aString; -+ (NSColor *)colorFromPredefinedColorName:(NSString *)name; -+ (NSString *)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color; -+ (NSColor *)changeAlphaOnColor:(NSColor *)color - to:(CGFloat)alphaValue; ++ (NSColor*)colorFromRString:(NSString*)rString + gString:(NSString*)gString + bString:(NSString*)bString + aString:(NSString*)aString; ++ (NSColor*)colorFromPredefinedColorName:(NSString*)name; ++ (NSString*)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color; ++ (NSColor*)changeAlphaOnColor:(NSColor*)color + to:(CGFloat)alphaValue; @end diff --git a/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColor.m b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColor.m new file mode 100644 index 0000000..af28843 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColor.m @@ -0,0 +1,791 @@ +// +// IJSVGColor.m +// IconJar +// +// Created by Curtis Hard on 31/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGColor.h" +#import "IJSVGUtils.h" + +@implementation IJSVGColor + +static NSDictionary* _colorTree = nil; + +CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness) +{ + hue *= (1.f / 360.f); + hue = (hue - floorf(hue)); + saturation *= 0.01; + lightness *= 0.01; + lightness *= 2.f; + + CGFloat s = saturation * ((lightness < 1.f) ? lightness : (2.f - lightness)); + CGFloat brightness = (lightness + s) * .5f; + if (s != 0.f) { + s = (2.f * s) / (lightness + s); + } + CGFloat* floats = (CGFloat*)malloc(3 * sizeof(CGFloat)); + floats[0] = hue; + floats[1] = s; + floats[2] = brightness; + return floats; +}; + ++ (void)load +{ + [self.class _generateTree]; +} + ++ (NSColorSpace*)defaultColorSpace +{ + return NSColorSpace.deviceRGBColorSpace; +} + ++ (NSColor*)computeColorSpace:(NSColor*)color +{ + NSColorSpace* space = [self defaultColorSpace]; + if (color.colorSpace != space) { + color = [color colorUsingColorSpace:space]; + } + return color; +} + ++ (void)_generateTree +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _colorTree = [@{ + @"aliceblue" : @(0xf0f8ff), + @"antiquewhite" : @(0xfaebd7), + @"aqua" : @(0x00ffff), + @"aquamarine" : @(0x7fffd4), + @"azure" : @(0xf0ffff), + @"beige" : @(0xf5f5dc), + @"bisque" : @(0xffe4c4), + @"black" : @(0x000000), + @"blanchedalmond" : @(0xffebcd), + @"blue" : @(0x0000ff), + @"blueviolet" : @(0x8a2be2), + @"brown" : @(0xa52a2a), + @"burlywood" : @(0xdeb887), + @"cadetblue" : @(0x5f9ea0), + @"chartreuse" : @(0x7fff00), + @"chocolate" : @(0xd2691e), + @"coral" : @(0xff7f50), + @"cornflowerblue" : @(0x6495ed), + @"cornsilk" : @(0xfff8dc), + @"crimson" : @(0xdc143c), + @"currentcolor" : @(0x000000), + @"cyan" : @(0x00ffff), + @"darkblue" : @(0x00008b), + @"darkcyan" : @(0x008b8b), + @"darkgoldenrod" : @(0xb8860b), + @"darkgray" : @(0xa9a9a9), + @"darkgreen" : @(0x006400), + @"darkgrey" : @(0xa9a9a9), + @"darkkhaki" : @(0xbdb76b), + @"darkmagenta" : @(0x8b008b), + @"darkolivegreen" : @(0x556b2f), + @"darkorange" : @(0xff8c00), + @"darkorchid" : @(0x9932cc), + @"darkred" : @(0x8b0000), + @"darksalmon" : @(0xe9967a), + @"darkseagreen" : @(0x8fbc8f), + @"darkslateblue" : @(0x483d8b), + @"darkslategray" : @(0x2f4f4f), + @"darkturquoise" : @(0x00ced1), + @"darkviolet" : @(0x9400d3), + @"deeppink" : @(0xff1493), + @"deepskyblue" : @(0x00bfff), + @"dimgray" : @(0x696969), + @"dimgrey" : @(0x696969), + @"dodgerblue" : @(0x1e90ff), + @"firebrick" : @(0xb22222), + @"floralwhite" : @(0xfffaf0), + @"forestgreen" : @(0x228b22), + @"fuchsia" : @(0xff00ff), + @"gainsboro" : @(0xdcdcdc), + @"ghostwhite" : @(0xf8f8ff), + @"gold" : @(0xffd700), + @"goldenrod" : @(0xdaa520), + @"gray" : @(0x808080), + @"green" : @(0x008000), + @"greenyellow" : @(0xadff2f), + @"grey" : @(0x808080), + @"honeydew" : @(0xf0fff0), + @"hotpink" : @(0xff69b4), + @"indianred" : @(0xcd5c5c), + @"indigo" : @(0x4b0082), + @"ivory" : @(0xfffff0), + @"khaki" : @(0xf0e68c), + @"lavender" : @(0xe6e6fa), + @"lavenderblush" : @(0xfff0f5), + @"lawngreen" : @(0x7cfc00), + @"lemonchiffon" : @(0xfffacd), + @"lightblue" : @(0xadd8e6), + @"lightcoral" : @(0xf08080), + @"lightcyan" : @(0xe0ffff), + @"lightgoldenrodyellow" : @(0xfafad2), + @"lightgray" : @(0xd3d3d3), + @"lightgreen" : @(0x90ee90), + @"lightgrey" : @(0xd3d3d3), + @"lightpink" : @(0xffb6c1), + @"lightsalmon" : @(0xffa07a), + @"lightseagreen" : @(0x20b2aa), + @"lightskyblue" : @(0x87cefa), + @"lightslategray" : @(0x778899), + @"lightsteelblue" : @(0xb0c4de), + @"lightyellow" : @(0xffffe0), + @"lime" : @(0x00ff00), + @"limegreen" : @(0x32cd32), + @"linen" : @(0xfaf0e6), + @"magenta" : @(0xff00ff), + @"maroon" : @(0x800000), + @"mediumaquamarine" : @(0x66cdaa), + @"mediumblue" : @(0x0000cd), + @"mediumorchid" : @(0xba55d3), + @"mediumpurple" : @(0x9370db), + @"mediumseagreen" : @(0x3cb371), + @"mediumslateblue" : @(0x7b68ee), + @"mediumspringgreen" : @(0x00fa9a), + @"mediumturquoise" : @(0x48d1cc), + @"mediumvioletred" : @(0xc71585), + @"midnightblue" : @(0x191970), + @"mintcream" : @(0xf5fffa), + @"mistyrose" : @(0xffe4e1), + @"moccasin" : @(0xffe4b5), + @"navajowhite" : @(0xffdead), + @"navy" : @(0x000080), + @"oldlace" : @(0xfdf5e6), + @"olive" : @(0x808000), + @"olivedrab" : @(0x6b8e23), + @"orange" : @(0xffa500), + @"orangered" : @(0xff4500), + @"orchid" : @(0xda70d6), + @"palegoldenrod" : @(0xeee8aa), + @"palegreen" : @(0x98fb98), + @"paleturquoise" : @(0xafeeee), + @"palevioletred" : @(0xdb7093), + @"papayawhip" : @(0xffefd5), + @"peachpuff" : @(0xffdab9), + @"peru" : @(0xcd853f), + @"pink" : @(0xffc0cb), + @"plum" : @(0xdda0dd), + @"powderblue" : @(0xb0e0e6), + @"purple" : @(0x800080), + @"red" : @(0xff0000), + @"rosybrown" : @(0xbc8f8f), + @"royalblue" : @(0x4169e1), + @"saddlebrown" : @(0x8b4513), + @"salmon" : @(0xfa8072), + @"sandybrown" : @(0xf4a460), + @"seagreen" : @(0x2e8b57), + @"seashell" : @(0xfff5ee), + @"sienna" : @(0xa0522d), + @"silver" : @(0xc0c0c0), + @"skyblue" : @(0x87ceeb), + @"slateblue" : @(0x6a5acd), + @"slategrey" : @(0x708090), + @"snow" : @(0xfffafa), + @"springgreen" : @(0x00ff7f), + @"steelblue" : @(0x4682b4), + @"tan" : @(0xd2b48c), + @"teal" : @(0x008080), + @"thistle" : @(0xd8bfd8), + @"tomato" : @(0xff6347), + @"turquoise" : @(0x40e0d0), + @"violet" : @(0xee82ee), + @"wheat" : @(0xf5deb3), + @"white" : @(0xffffff), + @"whitesmoke" : @(0xf5f5f5), + @"yellow" : @(0xffff00), + @"yellowgreen" : @(0x9acd32) + } retain]; + }); +} + ++ (NSColor*)computeColor:(id)colour +{ + if ([colour isKindOfClass:[NSColor class]]) + return colour; + return nil; +} + ++ (NSColor*)colorFromRString:(NSString*)rString + gString:(NSString*)gString + bString:(NSString*)bString + aString:(NSString*)aString +{ + return [self colorFromRUnit:[IJSVGUnitLength unitWithString:rString] + gUnit:[IJSVGUnitLength unitWithString:gString] + bUnit:[IJSVGUnitLength unitWithString:bString] + aUnit:[IJSVGUnitLength unitWithString:aString]]; +} + ++ (NSColor*)colorFromRUnit:(IJSVGUnitLength*)rUnit + gUnit:(IJSVGUnitLength*)gUnit + bUnit:(IJSVGUnitLength*)bUnit + aUnit:(IJSVGUnitLength*)aUnit +{ + CGFloat r = rUnit.type == IJSVGUnitLengthTypePercentage ? [rUnit computeValue:255.f] : [rUnit computeValue:1.f]; + CGFloat g = gUnit.type == IJSVGUnitLengthTypePercentage ? [gUnit computeValue:255.f] : [gUnit computeValue:1.f]; + CGFloat b = bUnit.type == IJSVGUnitLengthTypePercentage ? [bUnit computeValue:255.f] : [bUnit computeValue:1.f]; + CGFloat a = [aUnit computeValue:100.f]; + return [self computeColorSpace:[NSColor colorWithDeviceRed:(r / 255.f) + green:(g / 255.f) + blue:(b / 255.f) + alpha:a]]; +} + ++ (NSColor*)colorFromString:(NSString*)string +{ + NSCharacterSet* set = NSCharacterSet.whitespaceAndNewlineCharacterSet; + string = [string stringByTrimmingCharactersInSet:set]; + + if ([string length] < 3) { + return nil; + } + + NSColor* color = nil; + string = [string lowercaseString]; + if ([self.class isHex:string] == NO) { + color = [self.class colorFromPredefinedColorName:string]; + if (color != nil) { + return color; + } + } + + // is simply a clear color, dont fill + if ([string.lowercaseString isEqualToString:@"none"] || + [string.lowercaseString isEqualToString:@"transparent"]) { + return [self computeColorSpace:NSColor.clearColor]; + } + + // is it RGB? + if ([string hasPrefix:@"rgb"] == YES) { + NSRange range = [IJSVGUtils rangeOfParentheses:string]; + NSString* rgbString = [string substringWithRange:range]; + NSArray* parts = [rgbString ijsvg_componentsSeparatedByChars:","]; + NSString* alpha = @"100%"; + if (parts.count == 4) { + alpha = parts[3]; + } + return [self colorFromRString:parts[0] + gString:parts[1] + bString:parts[2] + aString:alpha]; + } + + // is it HSL? + if ([string hasPrefix:@"hsl"]) { + NSInteger count = 0; + CGFloat* params = [IJSVGUtils commandParameters:string + count:&count]; + CGFloat alpha = 1; + if (count == 4) { + alpha = params[3]; + } + + // convert HSL to HSB + CGFloat* hsb = IJSVGColorCSSHSLToHSB(params[0], params[1], params[2]); + color = [NSColor colorWithDeviceHue:hsb[0] + saturation:hsb[1] + brightness:hsb[2] + alpha:alpha]; + + color = [self computeColorSpace:color]; + + // memory clean! + free(hsb); + free(params); + return color; + } + + color = [self.class colorFromHEXString:string]; + return color; +} + ++ (NSColor*)colorFromPredefinedColorName:(NSString*)name +{ + NSNumber* hex = nil; + name = [name.lowercaseString stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet]; + if ((hex = _colorTree[name]) == nil) { + return nil; + } + return [self.class colorFromHEXInteger:hex.integerValue]; +} + ++ (NSString*)colorStringFromColor:(NSColor*)color +{ + IJSVGColorStringOptions options = IJSVGColorStringOptionDefault; + return [self colorStringFromColor:color + options:options]; +} + ++ (NSString*)colorStringFromColor:(NSColor*)color + options:(IJSVGColorStringOptions)options +{ + // convert to RGB + color = [self computeColorSpace:color]; + + int red = color.redComponent * 0xFF; + int green = color.greenComponent * 0xFF; + int blue = color.blueComponent * 0xFF; + int alpha = (int)(color.alphaComponent * 100); + + BOOL forceHex = (options & IJSVGColorStringOptionForceHEX) != 0; + BOOL allowShortHand = (options & IJSVGColorStringOptionAllowShortHand) != 0; + BOOL allowRRGGBBAA = (options & IJSVGColorStringOptionAllowRRGGBBAA) != 0; + + // jsut return none + if (alpha == 0 && forceHex == NO) { + return @"none"; + } + + // always return hex unless criteria is met + if (forceHex == YES || allowRRGGBBAA == YES || alpha == 100 || (red == 0 && green == 0 && blue == 0 && alpha == 0) || (red == 255 && green == 255 && blue == 255 && alpha == 100)) { + + // we need to make sure the last 2 chars + // are the same or we cant enable shorthand + if (allowRRGGBBAA == YES) { + NSString* alphaHexString = [NSString stringWithFormat:@"%02X", + (int)(color.alphaComponent * 0xFF)]; + if ([alphaHexString characterAtIndex:0] != + [alphaHexString characterAtIndex:1]) { + allowShortHand = NO; + } + } + + if (allowShortHand == YES) { + NSString* r = [NSString stringWithFormat:@"%02X", red]; + NSString* g = [NSString stringWithFormat:@"%02X", green]; + NSString* b = [NSString stringWithFormat:@"%02X", blue]; + if ([r characterAtIndex:0] == [r characterAtIndex:1] && + [g characterAtIndex:0] == [g characterAtIndex:1] && + [b characterAtIndex:0] == [b characterAtIndex:1]) { + // allow shorthand alpha + if (allowRRGGBBAA == YES && alpha != 100) { + NSString* a = [NSString stringWithFormat:@"%02X", + (int)(color.alphaComponent * 0xFF)]; + return [NSString stringWithFormat:@"#%c%c%c%c", + [r characterAtIndex:0], [g characterAtIndex:0], + [b characterAtIndex:0], [a characterAtIndex:0]]; + } + return [NSString stringWithFormat:@"#%c%c%c", [r characterAtIndex:0], + [g characterAtIndex:0], [b characterAtIndex:0]]; + } + } + if (allowRRGGBBAA == YES && alpha != 100) { + return [NSString stringWithFormat:@"#%02X%02X%02X%02X", red, green, + blue, (int)(color.alphaComponent * 0xFF)]; + } + return [NSString stringWithFormat:@"#%02X%02X%02X", red, green, blue]; + } + + // note the %g, CSS alpha is 0 to 1, not 0 - 100, my bad! + return [NSString stringWithFormat:@"rgba(%d,%d,%d,%g)", red, green, blue, + ((float)alpha / 100.f)]; +} + ++ (NSString*)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color +{ + switch (color) { + case IJSVGColorAliceblue: + return @"aliceblue"; + case IJSVGColorAntiquewhite: + return @"antiquewhite"; + case IJSVGColorAqua: + return @"aqua"; + case IJSVGColorAquamarine: + return @"aquamarine"; + case IJSVGColorAzure: + return @"azure"; + case IJSVGColorBeige: + return @"beige"; + case IJSVGColorBisque: + return @"bisque"; + case IJSVGColorBlack: + return @"black"; + case IJSVGColorBlanchedalmond: + return @"blanchedalmond"; + case IJSVGColorBlue: + return @"blue"; + case IJSVGColorBlueviolet: + return @"blueviolet"; + case IJSVGColorBrown: + return @"brown"; + case IJSVGColorBurlywood: + return @"burlywood"; + case IJSVGColorCadetblue: + return @"cadetblue"; + case IJSVGColorChartreuse: + return @"chartreuse"; + case IJSVGColorChocolate: + return @"chocolate"; + case IJSVGColorCoral: + return @"coral"; + case IJSVGColorCornflowerblue: + return @"cornflowerblue"; + case IJSVGColorCornsilk: + return @"cornsilk"; + case IJSVGColorCrimson: + return @"crimson"; + case IJSVGColorCyan: + return @"cyan"; + case IJSVGColorDarkblue: + return @"darkblue"; + case IJSVGColorDarkcyan: + return @"darkcyan"; + case IJSVGColorDarkgoldenrod: + return @"darkgoldenrod"; + case IJSVGColorDarkgray: + return @"darkgray"; + case IJSVGColorDarkgreen: + return @"darkgreen"; + case IJSVGColorDarkgrey: + return @"darkgrey"; + case IJSVGColorDarkkhaki: + return @"darkkhaki"; + case IJSVGColorDarkmagenta: + return @"darkmagenta"; + case IJSVGColorDarkolivegreen: + return @"darkolivegreen"; + case IJSVGColorDarkorange: + return @"darkorange"; + case IJSVGColorDarkorchid: + return @"darkorchid"; + case IJSVGColorDarkred: + return @"darkred"; + case IJSVGColorDarksalmon: + return @"darksalmon"; + case IJSVGColorDarkseagreen: + return @"darkseagreen"; + case IJSVGColorDarkslateblue: + return @"darkslateblue"; + case IJSVGColorDarkslategray: + return @"darkslategray"; + case IJSVGColorDarkslategrey: + return @"darkslategrey"; + case IJSVGColorDarkturquoise: + return @"darkturquoise"; + case IJSVGColorDarkviolet: + return @"darkviolet"; + case IJSVGColorDeeppink: + return @"deeppink"; + case IJSVGColorDeepskyblue: + return @"deepskyblue"; + case IJSVGColorDimgray: + return @"dimgray"; + case IJSVGColorDimgrey: + return @"dimgrey"; + case IJSVGColorDodgerblue: + return @"dodgerblue"; + case IJSVGColorFirebrick: + return @"firebrick"; + case IJSVGColorFloralwhite: + return @"floralwhite"; + case IJSVGColorForestgreen: + return @"forestgreen"; + case IJSVGColorFuchsia: + return @"fuchsia"; + case IJSVGColorGainsboro: + return @"gainsboro"; + case IJSVGColorGhostwhite: + return @"ghostwhite"; + case IJSVGColorGold: + return @"gold"; + case IJSVGColorGoldenrod: + return @"goldenrod"; + case IJSVGColorGray: + return @"gray"; + case IJSVGColorGreen: + return @"green"; + case IJSVGColorGreenyellow: + return @"greenyellow"; + case IJSVGColorGrey: + return @"grey"; + case IJSVGColorHoneydew: + return @"honeydew"; + case IJSVGColorHotpink: + return @"hotpink"; + case IJSVGColorIndianred: + return @"indianred"; + case IJSVGColorIndigo: + return @"indigo"; + case IJSVGColorIvory: + return @"ivory"; + case IJSVGColorKhaki: + return @"khaki"; + case IJSVGColorLavender: + return @"lavender"; + case IJSVGColorLavenderblush: + return @"lavenderblush"; + case IJSVGColorLawngreen: + return @"lawngreen"; + case IJSVGColorLemonchiffon: + return @"lemonchiffon"; + case IJSVGColorLightblue: + return @"lightblue"; + case IJSVGColorLightcoral: + return @"lightcoral"; + case IJSVGColorLightcyan: + return @"lightcyan"; + case IJSVGColorLightgoldenrodyellow: + return @"lightgoldenrodyellow"; + case IJSVGColorLightgray: + return @"lightgray"; + case IJSVGColorLightgreen: + return @"lightgreen"; + case IJSVGColorLightgrey: + return @"lightgrey"; + case IJSVGColorLightpink: + return @"lightpink"; + case IJSVGColorLightsalmon: + return @"lightsalmon"; + case IJSVGColorLightseagreen: + return @"lightseagreen"; + case IJSVGColorLightskyblue: + return @"lightskyblue"; + case IJSVGColorLightslategray: + return @"lightslategray"; + case IJSVGColorLightslategrey: + return @"lightslategrey"; + case IJSVGColorLightsteelblue: + return @"lightsteelblue"; + case IJSVGColorLightyellow: + return @"lightyellow"; + case IJSVGColorLime: + return @"lime"; + case IJSVGColorLimegreen: + return @"limegreen"; + case IJSVGColorLinen: + return @"linen"; + case IJSVGColorMagenta: + return @"magenta"; + case IJSVGColorMaroon: + return @"maroon"; + case IJSVGColorMediumaquamarine: + return @"mediumaquamarine"; + case IJSVGColorMediumblue: + return @"mediumblue"; + case IJSVGColorMediumorchid: + return @"mediumorchid"; + case IJSVGColorMediumpurple: + return @"mediumpurple"; + case IJSVGColorMediumseagreen: + return @"mediumseagreen"; + case IJSVGColorMediumslateblue: + return @"mediumslateblue"; + case IJSVGColorMediumspringgreen: + return @"mediumspringgreen"; + case IJSVGColorMediumturquoise: + return @"mediumturquoise"; + case IJSVGColorMediumvioletred: + return @"mediumvioletred"; + case IJSVGColorMidnightblue: + return @"midnightblue"; + case IJSVGColorMintcream: + return @"mintcream"; + case IJSVGColorMistyrose: + return @"mistyrose"; + case IJSVGColorMoccasin: + return @"moccasin"; + case IJSVGColorNavajowhite: + return @"navajowhite"; + case IJSVGColorNavy: + return @"navy"; + case IJSVGColorOldlace: + return @"oldlace"; + case IJSVGColorOlive: + return @"olive"; + case IJSVGColorOlivedrab: + return @"olivedrab"; + case IJSVGColorOrange: + return @"orange"; + case IJSVGColorOrangered: + return @"orangered"; + case IJSVGColorOrchid: + return @"orchid"; + case IJSVGColorPalegoldenrod: + return @"palegoldenrod"; + case IJSVGColorPalegreen: + return @"palegreen"; + case IJSVGColorPaleturquoise: + return @"paleturquoise"; + case IJSVGColorPalevioletred: + return @"palevioletred"; + case IJSVGColorPapayawhip: + return @"papayawhip"; + case IJSVGColorPeachpuff: + return @"peachpuff"; + case IJSVGColorPeru: + return @"peru"; + case IJSVGColorPink: + return @"pink"; + case IJSVGColorPlum: + return @"plum"; + case IJSVGColorPowderblue: + return @"powderblue"; + case IJSVGColorPurple: + return @"purple"; + case IJSVGColorRed: + return @"red"; + case IJSVGColorRosybrown: + return @"rosybrown"; + case IJSVGColorRoyalblue: + return @"royalblue"; + case IJSVGColorSaddlebrown: + return @"saddlebrown"; + case IJSVGColorSalmon: + return @"salmon"; + case IJSVGColorSandybrown: + return @"sandybrown"; + case IJSVGColorSeagreen: + return @"seagreen"; + case IJSVGColorSeashell: + return @"seashell"; + case IJSVGColorSienna: + return @"sienna"; + case IJSVGColorSilver: + return @"silver"; + case IJSVGColorSkyblue: + return @"skyblue"; + case IJSVGColorSlateblue: + return @"slateblue"; + case IJSVGColorSlategray: + return @"slategray"; + case IJSVGColorSlategrey: + return @"slategrey"; + case IJSVGColorSnow: + return @"snow"; + case IJSVGColorSpringgreen: + return @"springgreen"; + case IJSVGColorSteelblue: + return @"steelblue"; + case IJSVGColorTan: + return @"tan"; + case IJSVGColorTeal: + return @"teal"; + case IJSVGColorThistle: + return @"thistle"; + case IJSVGColorTomato: + return @"tomato"; + case IJSVGColorTurquoise: + return @"turquoise"; + case IJSVGColorViolet: + return @"violet"; + case IJSVGColorWheat: + return @"wheat"; + case IJSVGColorWhite: + return @"white"; + case IJSVGColorWhitesmoke: + return @"whitesmoke"; + case IJSVGColorYellow: + return @"yellow"; + case IJSVGColorYellowgreen: + return @"yellowgreen"; + } + return nil; +} + ++ (NSColor*)changeAlphaOnColor:(NSColor*)color + to:(CGFloat)alphaValue +{ + color = [self computeColorSpace:color]; + return [self computeColorSpace:[NSColor colorWithDeviceRed:color.redComponent + green:color.greenComponent + blue:color.blueComponent + alpha:alphaValue]]; +} + ++ (BOOL)isColor:(NSString*)string +{ + return [string hasPrefix:@"#"] || [string hasPrefix:@"rgb"]; +} + ++ (BOOL)isHex:(NSString*)string +{ + const char* validList = "0123456789ABCDEFabcdef#"; + for (NSInteger i = 0; i < string.length; i++) { + char c = [string characterAtIndex:i]; + if (strchr(validList, c) == NULL) { + return NO; + } + } + return YES; +} + ++ (unsigned long)lengthOfHEXInteger:(NSUInteger)hex +{ + char* buffer; + asprintf(&buffer, "%lX", (long)hex); + unsigned long length = strlen(buffer); + free(buffer); + return length; +} + ++ (BOOL)HEXContainsAlphaComponent:(NSUInteger)hex +{ + return [self lengthOfHEXInteger:hex] == 8; +} + ++ (NSColor*)colorFromHEXInteger:(NSInteger)hex +{ + CGFloat alpha = 1.f; + if ([self HEXContainsAlphaComponent:hex] == YES) { + alpha = (hex & 0xFF) / 255.f; + hex = hex >> 8; + } + return [self computeColorSpace:[NSColor colorWithDeviceRed:((hex >> 16) & 0xFF) / 255.f + green:((hex >> 8) & 0xFF) / 255.f + blue:(hex & 0xFF) / 255.f + alpha:alpha]]; +} + ++ (unsigned long)HEXFromArbitraryHexString:(NSString*)aString +{ + const char* hexString = [aString cStringUsingEncoding:NSUTF8StringEncoding]; + return strtoul(hexString, NULL, 16); +} + ++ (NSColor*)colorFromHEXString:(NSString*)string +{ + return [self colorFromHEXString:string + containsAlphaComponent:nil]; +} + ++ (NSColor*)colorFromHEXString:(NSString*)string + containsAlphaComponent:(BOOL*)containsAlphaComponent +{ + // absolutely no string + if (string == nil || string.length == 0 || ![self.class isHex:string]) { + return nil; + } + + if ([string hasPrefix:@"#"] == YES) { + string = [string substringFromIndex:1]; + } + + // whats the length? + NSUInteger length = string.length; + if (length == 3 || length == 4) { + // shorthand... + NSMutableString* str = [[[NSMutableString alloc] init] autorelease]; + for (NSInteger i = 0; i < length; i++) { + NSString* sub = [string substringWithRange:NSMakeRange(i, 1)]; + [str appendFormat:@"%@%@", sub, sub]; + } + string = str; + } + + // now convert rest to hex + unsigned long hex = [self HEXFromArbitraryHexString:string]; + if (containsAlphaComponent != nil) { + *containsAlphaComponent = [self HEXContainsAlphaComponent:hex]; + } + return [self colorFromHEXInteger:hex]; +} + +@end diff --git a/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColorList.h b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColorList.h new file mode 100644 index 0000000..4a3abe2 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColorList.h @@ -0,0 +1,31 @@ +// +// IJSVGColorList.h +// IconJar +// +// Created by Curtis Hard on 07/07/2019. +// Copyright © 2019 Curtis Hard. All rights reserved. +// + +#import "IJSVGColor.h" +#import + +@interface IJSVGColorList : NSObject { + +@private + NSMutableDictionary* _replacementColorTree; + NSMutableSet* _colors; +} + +- (NSColor*)proposedColorForColor:(NSColor*)color; +- (void)removeAllReplacementColors; +- (void)removeReplacementColor:(NSColor*)color; +- (void)setReplacementColor:(NSColor*)newColor + forColor:(NSColor*)color; +- (void)setReplacementColors:(NSDictionary*)colors + clearExistingColors:(BOOL)clearExistingColors; + +- (void)addColorsFromList:(IJSVGColorList*)sheet; +- (NSSet*)colors; +- (void)addColor:(NSColor*)color; + +@end diff --git a/source/IJSVGColorList.m b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColorList.m similarity index 61% rename from source/IJSVGColorList.m rename to Framework/IJSVG/IJSVG/Source/Colors/IJSVGColorList.m index 5ec8f5f..5eb9128 100644 --- a/source/IJSVGColorList.m +++ b/Framework/IJSVG/IJSVG/Source/Colors/IJSVGColorList.m @@ -12,39 +12,39 @@ @implementation IJSVGColorList - (void)dealloc { - [_replacementColorTree release], _replacementColorTree = nil; - [_colors release], _colors = nil; + (void)([_replacementColorTree release]), _replacementColorTree = nil; + (void)([_colors release]), _colors = nil; [super dealloc]; } - (instancetype)init { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { _replacementColorTree = [[NSMutableDictionary alloc] init]; _colors = [[NSMutableSet alloc] init]; } return self; } -- (id)copyWithZone:(NSZone *)zone +- (id)copyWithZone:(NSZone*)zone { - IJSVGColorList * sheet = [[self.class alloc] init]; + IJSVGColorList* sheet = [[self.class alloc] init]; [sheet setReplacementColors:[_replacementColorTree.copy autorelease] clearExistingColors:YES]; return sheet; } -- (NSColor *)proposedColorForColor:(NSColor *)color +- (NSColor*)proposedColorForColor:(NSColor*)color { // nothing found, just return color - if(_replacementColorTree == nil || _replacementColorTree.count == 0) { + if (_replacementColorTree == nil || _replacementColorTree.count == 0) { return color; } - + // check the mappings - NSColor * found = nil; + NSColor* found = nil; color = [IJSVGColor computeColorSpace:color]; - if((found = _replacementColorTree[color]) != nil) { + if ((found = _replacementColorTree[color]) != nil) { return found; } return color; @@ -52,7 +52,7 @@ - (NSColor *)proposedColorForColor:(NSColor *)color - (void)_invalidateColorTree { - [_replacementColorTree release], _replacementColorTree = nil; + (void)([_replacementColorTree release]), _replacementColorTree = nil; _replacementColorTree = [[NSMutableDictionary alloc] init]; } @@ -61,53 +61,52 @@ - (void)removeAllReplacementColors [self _invalidateColorTree]; } -- (void)removeReplacementColor:(NSColor *)color +- (void)removeReplacementColor:(NSColor*)color { - if(_replacementColorTree == nil) { + if (_replacementColorTree == nil) { return; } [_replacementColorTree removeObjectForKey:[IJSVGColor computeColorSpace:color]]; } -- (void)setReplacementColor:(NSColor *)newColor - forColor:(NSColor *)color +- (void)setReplacementColor:(NSColor*)newColor + forColor:(NSColor*)color { color = [IJSVGColor computeColorSpace:color]; newColor = [IJSVGColor computeColorSpace:newColor]; _replacementColorTree[color] = newColor; } -- (void)setReplacementColors:(NSDictionary *)colors +- (void)setReplacementColors:(NSDictionary*)colors clearExistingColors:(BOOL)clearExistingColors { - if(clearExistingColors == YES) { + if (clearExistingColors == YES) { [self _invalidateColorTree]; } - for(NSColor * oldColor in colors) { + for (NSColor* oldColor in colors) { [self setReplacementColor:colors[oldColor] forColor:oldColor]; } } -- (NSSet *)colors +- (NSSet*)colors { return [NSSet setWithSet:_colors]; } -- (void)addColorsFromList:(IJSVGColorList *)sheet +- (void)addColorsFromList:(IJSVGColorList*)sheet { [_colors addObjectsFromArray:sheet.colors.allObjects]; } -- (void)addColor:(NSColor *)color +- (void)addColor:(NSColor*)color { [_colors addObject:[IJSVGColor computeColorSpace:color]]; } -- (void)removeColor:(NSColor *)color +- (void)removeColor:(NSColor*)color { [_colors removeObject:[IJSVGColor computeColorSpace:color]]; } - @end diff --git a/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommand.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommand.h new file mode 100644 index 0000000..f65cf21 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommand.h @@ -0,0 +1,72 @@ +// +// IJSVGCommand.h +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGPath.h" +#import + +static const NSInteger IJSVGCustomVariableParameterCount = NSNotFound; + +typedef NS_ENUM(NSInteger, IJSVGCommandType) { + kIJSVGCommandTypeAbsolute, + kIJSVGCommandTypeRelative +}; + +typedef NS_ENUM(NSUInteger, IJSVGPathDataSequence) { + kIJSVGPathDataSequenceTypeFloat, + kIJSVGPathDataSequenceTypeFlag +}; + +@interface IJSVGCommand : NSObject { + NSString* commandString; + NSString* command; + CGFloat* parameters; + NSInteger parameterCount; + NSArray* subCommands; + NSInteger requiredParameters; + IJSVGCommandType type; + IJSVGCommand* previousCommand; + NSInteger _currentIndex; + BOOL isSubCommand; +} + +@property (nonatomic, copy) NSString* commandString; +@property (nonatomic, copy) NSString* command; +@property (nonatomic, assign) CGFloat* parameters; +@property (nonatomic, assign) NSInteger parameterCount; +@property (nonatomic, assign) NSInteger requiredParameters; +@property (nonatomic, assign) IJSVGCommandType type; +@property (nonatomic, retain) NSArray* subCommands; +@property (nonatomic, assign) IJSVGCommand* previousCommand; +@property (nonatomic, assign) BOOL isSubCommand; + ++ (Class)commandClassForCommandChar:(char)aChar; ++ (NSInteger)requiredParameterCount; ++ (NSPoint)readCoordinatePair:(CGFloat*)pairs + index:(NSInteger)index; ++ (IJSVGPathDataSequence*)pathDataSequence; ++ (void)runWithParams:(CGFloat*)params + paramCount:(NSInteger)count + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command + type:(IJSVGCommandType)type + path:(IJSVGPath*)path; ++ (void)parseParams:(CGFloat*)params + paramCount:(NSInteger)paramCount + intoArray:(NSMutableArray*)commands + parentCommand:(IJSVGCommand*)parentCommand; + +- (id)initWithCommandString:(NSString*)commandString; +- (IJSVGCommand*)subcommandWithParameters:(CGFloat*)subParams + previousCommand:(IJSVGCommand*)command; + +- (CGFloat)readFloat; +- (NSPoint)readPoint; +- (BOOL)readBOOL; +- (void)resetRead; + +@end diff --git a/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommand.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommand.m new file mode 100644 index 0000000..31ff3e1 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommand.m @@ -0,0 +1,212 @@ +// +// IJSVGCommand.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGCommand.h" +#import "IJSVGUtils.h" + +#import "IJSVGCommandClose.h" +#import "IJSVGCommandCurve.h" +#import "IJSVGCommandEllipticalArc.h" +#import "IJSVGCommandHorizontalLine.h" +#import "IJSVGCommandLineTo.h" +#import "IJSVGCommandMove.h" +#import "IJSVGCommandQuadraticCurve.h" +#import "IJSVGCommandSmoothCurve.h" +#import "IJSVGCommandSmoothQuadraticCurve.h" +#import "IJSVGCommandVerticalLine.h" + +@implementation IJSVGCommand + +@synthesize commandString; +@synthesize command; +@synthesize parameterCount; +@synthesize parameters; +@synthesize subCommands; +@synthesize requiredParameters; +@synthesize type; +@synthesize previousCommand; +@synthesize isSubCommand; + ++ (BOOL)requiresCustomParameterParsing +{ + return NO; +} + ++ (NSInteger)requiredParameterCount +{ + return 1; +} + ++ (IJSVGPathDataSequence*)pathDataSequence +{ + return NULL; +} + ++ (void)runWithParams:(CGFloat*)params + paramCount:(NSInteger)count + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command + type:(IJSVGCommandType)type + path:(IJSVGPath*)path +{ +} + ++ (void)parseParams:(CGFloat*)params + paramCount:(NSInteger)paramCount + intoArray:(NSMutableArray*)commands + parentCommand:(IJSVGCommand*)parentCommand +{ +} + ++ (NSPoint)readCoordinatePair:(CGFloat*)pairs + index:(NSInteger)index +{ + return NSMakePoint(pairs[index * 2], pairs[index * 2 + 1]); +} + ++ (void)load +{ + // register here... +} + ++ (Class)commandClassForCommandChar:(char)aChar +{ + aChar = tolower(aChar); + switch (aChar) { + case 'a': + return IJSVGCommandEllipticalArc.class; + case 'c': + return IJSVGCommandCurve.class; + case 'h': + return IJSVGCommandHorizontalLine.class; + case 'l': + return IJSVGCommandLineTo.class; + case 'm': + return IJSVGCommandMove.class; + case 'q': + return IJSVGCommandQuadraticCurve.class; + case 's': + return IJSVGCommandSmoothCurve.class; + case 't': + return IJSVGCommandSmoothQuadraticCurve.class; + case 'v': + return IJSVGCommandVerticalLine.class; + case 'z': + return IJSVGCommandClose.class; + } + return nil; +} + +- (void)dealloc +{ + (void)([commandString release]), commandString = nil; + (void)([command release]), command = nil; + (void)([subCommands release]), subCommands = nil; + if (parameters) { + (void)(free(parameters)), parameters = nil; + } + [super dealloc]; +} + +- (id)initWithCommandString:(NSString*)str +{ + if ((self = [super init]) != nil) { + // work out the basics + _currentIndex = 0; + command = [[str substringToIndex:1] copy]; + type = [IJSVGUtils typeForCommandString:self.command]; + requiredParameters = [self.class requiredParameterCount]; + NSInteger sets = 0; + IJSVGPathDataSequence* sequence = [self.class pathDataSequence]; + parameters = IJSVGParsePathDataSequence(str, sequence, requiredParameters, &sets); + + if (sets <= 1) { + CGFloat* subParams = [self parametersFromIndexOffset:0]; + IJSVGCommand* command = [self subcommandWithParameters:subParams + previousCommand:nil]; + subCommands = @[ command ].retain; + } else { + + NSMutableArray* subCommandArray = nil; + subCommandArray = [[NSMutableArray alloc] initWithCapacity:sets].autorelease; + + // interate over the sets + IJSVGCommand* lastCommand = nil; + for (NSInteger i = 0; i < sets; i++) { + // memory for this will be handled by the created subcommand + CGFloat* subParams = [self parametersFromIndexOffset:i]; + + // generate the subcommand + IJSVGCommand* command = [self subcommandWithParameters:subParams + previousCommand:lastCommand]; + + // make sure we assign the last command or hell breaks + // lose and the firey demons will run wild, namely, commands will break + // if they are multiples of a set + lastCommand = command; + [subCommandArray addObject:command]; + } + + // store the retained value + subCommands = subCommandArray.copy; + } + } + return self; +} + +- (CGFloat*)parametersFromIndexOffset:(NSInteger)index +{ + CGFloat* subParams = 0; + NSInteger req = self.requiredParameters; + if (req != 0) { + subParams = (CGFloat*)malloc(req * sizeof(CGFloat)); + memcpy(subParams, &self.parameters[index * req], sizeof(CGFloat) * req); + } + return subParams; +} + +- (IJSVGCommand*)subcommandWithParameters:(CGFloat*)subParams + previousCommand:(IJSVGCommand*)aPreviousCommand +{ + // create a subcommand per set + IJSVGCommand* c = [[[self.class alloc] init] autorelease]; + c.parameterCount = self.requiredParameters; + c.parameters = subParams; + c.type = self.type; + c.command = self.command; + c.previousCommand = aPreviousCommand; + c.isSubCommand = aPreviousCommand != nil; + return c; +} + +- (CGFloat)readFloat +{ + CGFloat f = parameters[_currentIndex]; + _currentIndex++; + return f; +} + +- (NSPoint)readPoint +{ + CGFloat x = parameters[_currentIndex]; + CGFloat y = parameters[_currentIndex + 1]; + _currentIndex += 2; + return NSMakePoint(x, y); +} + +- (BOOL)readBOOL +{ + return [self readFloat] == 1; +} + +- (void)resetRead +{ + _currentIndex = 0; +} + +@end diff --git a/source/IJSVGCommandClose.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandClose.h similarity index 100% rename from source/IJSVGCommandClose.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandClose.h index bba4082..92a19be 100644 --- a/source/IJSVGCommandClose.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandClose.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandClose : IJSVGCommand diff --git a/source/IJSVGCommandClose.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandClose.m similarity index 67% rename from source/IJSVGCommandClose.m rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandClose.m index 6d46704..38afc44 100644 --- a/source/IJSVGCommandClose.m +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandClose.m @@ -15,12 +15,12 @@ + (NSInteger)requiredParameterCount return 0; } -+ (void)runWithParams:(CGFloat *)params ++ (void)runWithParams:(CGFloat*)params paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command type:(IJSVGCommandType)type - path:(IJSVGPath *)path + path:(IJSVGPath*)path { [path close]; } diff --git a/source/IJSVGCommandCurve.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandCurve.h similarity index 100% rename from source/IJSVGCommandCurve.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandCurve.h index bbf87d1..1db2579 100644 --- a/source/IJSVGCommandCurve.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandCurve.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandCurve : IJSVGCommand diff --git a/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandCurve.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandCurve.m new file mode 100644 index 0000000..d33422f --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandCurve.m @@ -0,0 +1,36 @@ +// +// IJSVGCommandCurve.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGCommandCurve.h" + +@implementation IJSVGCommandCurve + ++ (NSInteger)requiredParameterCount +{ + return 6; +} + ++ (void)runWithParams:(CGFloat*)params + paramCount:(NSInteger)count + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command + type:(IJSVGCommandType)type + path:(IJSVGPath*)path +{ + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] curveToPoint:NSMakePoint(params[4], params[5]) + controlPoint1:NSMakePoint(params[0], params[1]) + controlPoint2:NSMakePoint(params[2], params[3])]; + return; + } + [[path currentSubpath] relativeCurveToPoint:NSMakePoint(params[4], params[5]) + controlPoint1:NSMakePoint(params[0], params[1]) + controlPoint2:NSMakePoint(params[2], params[3])]; +} + +@end diff --git a/source/IJSVGCommandEllipticalArc.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandEllipticalArc.h similarity index 100% rename from source/IJSVGCommandEllipticalArc.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandEllipticalArc.h index c083d69..9714103 100644 --- a/source/IJSVGCommandEllipticalArc.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandEllipticalArc.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandEllipticalArc : IJSVGCommand diff --git a/source/IJSVGCommandEllipticalArc.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandEllipticalArc.m similarity index 72% rename from source/IJSVGCommandEllipticalArc.m rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandEllipticalArc.m index 3815618..243fa2d 100644 --- a/source/IJSVGCommandEllipticalArc.m +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandEllipticalArc.m @@ -11,17 +11,34 @@ @implementation IJSVGCommandEllipticalArc +static IJSVGPathDataSequence* _sequence; + + (NSInteger)requiredParameterCount { return 7; } -+ (void)runWithParams:(CGFloat *)params ++ (IJSVGPathDataSequence*)pathDataSequence +{ + if(_sequence == NULL) { + _sequence = (IJSVGPathDataSequence*)malloc(sizeof(IJSVGPathDataSequence) * 7); + _sequence[0] = kIJSVGPathDataSequenceTypeFloat; + _sequence[1] = kIJSVGPathDataSequenceTypeFloat; + _sequence[2] = kIJSVGPathDataSequenceTypeFloat; + _sequence[3] = kIJSVGPathDataSequenceTypeFlag; + _sequence[4] = kIJSVGPathDataSequenceTypeFlag; + _sequence[5] = kIJSVGPathDataSequenceTypeFloat; + _sequence[6] = kIJSVGPathDataSequenceTypeFloat; + } + return _sequence; +} + ++ (void)runWithParams:(CGFloat*)params paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command type:(IJSVGCommandType)type - path:(IJSVGPath *)path + path:(IJSVGPath*)path { CGPoint radii = CGPointZero; CGPoint arcEndPoint = CGPointZero; @@ -29,79 +46,77 @@ + (void)runWithParams:(CGFloat *)params CGFloat xAxisRotation = 0; BOOL largeArcFlag = 0; BOOL sweepFlag = 0; - + radii = [currentCommand readPoint]; xAxisRotation = [currentCommand readFloat]; largeArcFlag = [currentCommand readBOOL]; sweepFlag = [currentCommand readBOOL]; arcEndPoint = [currentCommand readPoint]; - - if (type == IJSVGCommandTypeRelative) { + + if (type == kIJSVGCommandTypeRelative) { arcEndPoint.x += path.currentPoint.x; arcEndPoint.y += path.currentPoint.y; } - + xAxisRotation *= M_PI / 180.f; CGPoint currentPoint = CGPointMake(cos(xAxisRotation) * (arcStartPoint.x - arcEndPoint.x) / 2.0 + sin(xAxisRotation) * (arcStartPoint.y - arcEndPoint.y) / 2.0, -sin(xAxisRotation) * (arcStartPoint.x - arcEndPoint.x) / 2.0 + cos(xAxisRotation) * (arcStartPoint.y - arcEndPoint.y) / 2.0); - + CGFloat radiiAdjustment = pow(currentPoint.x, 2) / pow(radii.x, 2) + pow(currentPoint.y, 2) / pow(radii.y, 2); radii.x *= (radiiAdjustment > 1) ? sqrt(radiiAdjustment) : 1; radii.y *= (radiiAdjustment > 1) ? sqrt(radiiAdjustment) : 1; - + CGFloat sweep = (largeArcFlag == sweepFlag ? -1 : 1) * sqrt(((pow(radii.x, 2) * pow(radii.y, 2)) - (pow(radii.x, 2) * pow(currentPoint.y, 2)) - (pow(radii.y, 2) * pow(currentPoint.x, 2))) / (pow(radii.x, 2) * pow(currentPoint.y, 2) + pow(radii.y, 2) * pow(currentPoint.x, 2))); sweep = (sweep != sweep) ? 0 : sweep; CGPoint preCenterPoint = CGPointMake(sweep * radii.x * currentPoint.y / radii.y, sweep * -radii.y * currentPoint.x / radii.x); - + CGPoint centerPoint = CGPointMake((arcStartPoint.x + arcEndPoint.x) / 2.0 + cos(xAxisRotation) * preCenterPoint.x - sin(xAxisRotation) * preCenterPoint.y, (arcStartPoint.y + arcEndPoint.y) / 2.0 + sin(xAxisRotation) * preCenterPoint.x + cos(xAxisRotation) * preCenterPoint.y); - - CGFloat startAngle = angle(CGPointMake(1, 0), CGPointMake((currentPoint.x-preCenterPoint.x)/radii.x, - (currentPoint.y-preCenterPoint.y)/radii.y)); - + + CGFloat startAngle = angle(CGPointMake(1, 0), CGPointMake((currentPoint.x - preCenterPoint.x) / radii.x, (currentPoint.y - preCenterPoint.y) / radii.y)); + CGPoint deltaU = CGPointMake((currentPoint.x - preCenterPoint.x) / radii.x, - (currentPoint.y - preCenterPoint.y) / radii.y); + (currentPoint.y - preCenterPoint.y) / radii.y); CGPoint deltaV = CGPointMake((-currentPoint.x - preCenterPoint.x) / radii.x, - (-currentPoint.y - preCenterPoint.y) / radii.y); + (-currentPoint.y - preCenterPoint.y) / radii.y); CGFloat angleDelta = (deltaU.x * deltaV.y < deltaU.y * deltaV.x ? -1 : 1) * acos(ratio(deltaU, deltaV)); - + angleDelta = (ratio(deltaU, deltaV) <= -1) ? M_PI : (ratio(deltaU, deltaV) >= 1) ? 0 : angleDelta; - + // check for actually numbers, if this is not valid // kill it, blame WWDC 2017 SVG background for this... - if(isnan(startAngle) || isnan(angleDelta)) { + if (isnan(startAngle) || isnan(angleDelta)) { return; } - + CGFloat radius = MAX(radii.x, radii.y); - CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) : - CGPointMake(radii.x / radii.y, 1); - - NSAffineTransform * trans = [NSAffineTransform transform]; + CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) : CGPointMake(radii.x / radii.y, 1); + + NSAffineTransform* trans = NSAffineTransform.transform; [trans translateXBy:-centerPoint.x yBy:-centerPoint.y]; [path.currentSubpath transformUsingAffineTransform:trans]; - - trans = [NSAffineTransform transform]; + + trans = NSAffineTransform.transform; [trans rotateByRadians:-xAxisRotation]; [path.currentSubpath transformUsingAffineTransform:trans]; - - trans = [NSAffineTransform transform]; - [trans scaleXBy:(1/scale.x) yBy:(1/scale.y)]; + + trans = NSAffineTransform.transform; + [trans scaleXBy:(1 / scale.x) yBy:(1 / scale.y)]; [path.currentSubpath transformUsingAffineTransform:trans]; - + [path.currentSubpath appendBezierPathWithArcWithCenter:NSZeroPoint radius:radius startAngle:radians_to_degrees(startAngle) endAngle:radians_to_degrees(startAngle + angleDelta) clockwise:!sweepFlag]; - - trans = [NSAffineTransform transform]; + + trans = NSAffineTransform.transform; [trans scaleXBy:scale.x yBy:scale.y]; [path.currentSubpath transformUsingAffineTransform:trans]; - - trans = [NSAffineTransform transform]; + + trans = NSAffineTransform.transform; [trans rotateByRadians:xAxisRotation]; [path.currentSubpath transformUsingAffineTransform:trans]; - - trans = [NSAffineTransform transform]; + + trans = NSAffineTransform.transform; [trans translateXBy:centerPoint.x yBy:centerPoint.y]; [path.currentSubpath transformUsingAffineTransform:trans]; } diff --git a/source/IJSVGCommandHorizontalLine.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandHorizontalLine.h similarity index 100% rename from source/IJSVGCommandHorizontalLine.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandHorizontalLine.h index 06e47f3..dbe0c6e 100644 --- a/source/IJSVGCommandHorizontalLine.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandHorizontalLine.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandHorizontalLine : IJSVGCommand diff --git a/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandHorizontalLine.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandHorizontalLine.m new file mode 100644 index 0000000..b4e5b6d --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandHorizontalLine.m @@ -0,0 +1,32 @@ +// +// IJSVGCommandHorizontalLine.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGCommandHorizontalLine.h" + +@implementation IJSVGCommandHorizontalLine + ++ (NSInteger)requiredParameterCount +{ + return 1; +} + ++ (void)runWithParams:(CGFloat*)params + paramCount:(NSInteger)count + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command + type:(IJSVGCommandType)type + path:(IJSVGPath*)path +{ + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] lineToPoint:NSMakePoint(params[0], [path currentSubpath].currentPoint.y)]; + return; + } + [[path currentSubpath] relativeLineToPoint:NSMakePoint(params[0], 0.f)]; +} + +@end diff --git a/source/IJSVGCommandLineTo.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandLineTo.h similarity index 100% rename from source/IJSVGCommandLineTo.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandLineTo.h index 55d5d55..48b9069 100644 --- a/source/IJSVGCommandLineTo.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandLineTo.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandLineTo : IJSVGCommand diff --git a/source/IJSVGCommandLineTo.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandLineTo.m similarity index 57% rename from source/IJSVGCommandLineTo.m rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandLineTo.m index 0000fde..f560405 100644 --- a/source/IJSVGCommandLineTo.m +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandLineTo.m @@ -15,19 +15,19 @@ + (NSInteger)requiredParameterCount return 2; } -+ (void)runWithParams:(CGFloat *)params ++ (void)runWithParams:(CGFloat*)params paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command type:(IJSVGCommandType)type - path:(IJSVGPath *)path + path:(IJSVGPath*)path { - if( type == IJSVGCommandTypeAbsolute ) { - [[path currentSubpath] lineToPoint:NSMakePoint( params[0], params[1])]; + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] lineToPoint:NSMakePoint(params[0], params[1])]; return; } NSPoint point = NSMakePoint([path currentSubpath].currentPoint.x + params[0], - [path currentSubpath].currentPoint.y + params[1]); + [path currentSubpath].currentPoint.y + params[1]); [[path currentSubpath] lineToPoint:point]; } diff --git a/source/IJSVGCommandMove.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandMove.h similarity index 100% rename from source/IJSVGCommandMove.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandMove.h index 6bfa68e..b28d8b6 100644 --- a/source/IJSVGCommandMove.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandMove.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandMove : IJSVGCommand diff --git a/source/IJSVGCommandMove.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandMove.m similarity index 61% rename from source/IJSVGCommandMove.m rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandMove.m index df6a589..b6ea3da 100644 --- a/source/IJSVGCommandMove.m +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandMove.m @@ -6,9 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import "IJSVGCommandMove.h" #import "IJSVGCommandLineTo.h" - +#import "IJSVGCommandMove.h" @implementation IJSVGCommandMove @@ -17,16 +16,16 @@ + (NSInteger)requiredParameterCount return 2; } -+ (void)runWithParams:(CGFloat *)params ++ (void)runWithParams:(CGFloat*)params paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command type:(IJSVGCommandType)type - path:(IJSVGPath *)path + path:(IJSVGPath*)path { // move to's allow more then one move to, but if there are more then one, // we need to run the line to instead...who knew! - if( command.class == self.class && currentCommand.isSubCommand == YES) { + if (command.class == self.class && currentCommand.isSubCommand == YES) { [IJSVGCommandLineTo runWithParams:params paramCount:count command:currentCommand @@ -35,17 +34,17 @@ + (void)runWithParams:(CGFloat *)params path:path]; return; } - + // actual move to command - if( type == IJSVGCommandTypeAbsolute ) { - [[path currentSubpath] moveToPoint:NSMakePoint( params[0], params[1])]; + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] moveToPoint:NSMakePoint(params[0], params[1])]; return; } @try { - [[path currentSubpath] relativeMoveToPoint:NSMakePoint( params[0], params[1])]; + [[path currentSubpath] relativeMoveToPoint:NSMakePoint(params[0], params[1])]; } - @catch (NSException *exception) { - [[path currentSubpath] moveToPoint:NSMakePoint( params[0], params[1])]; + @catch (NSException* exception) { + [[path currentSubpath] moveToPoint:NSMakePoint(params[0], params[1])]; } } diff --git a/source/IJSVGCommandQuadraticCurve.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandQuadraticCurve.h similarity index 100% rename from source/IJSVGCommandQuadraticCurve.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandQuadraticCurve.h index 7dc9c6b..10608cb 100644 --- a/source/IJSVGCommandQuadraticCurve.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandQuadraticCurve.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandQuadraticCurve : IJSVGCommand diff --git a/source/IJSVGCommandQuadraticCurve.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandQuadraticCurve.m similarity index 65% rename from source/IJSVGCommandQuadraticCurve.m rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandQuadraticCurve.m index 6fa21f2..76a9d37 100644 --- a/source/IJSVGCommandQuadraticCurve.m +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandQuadraticCurve.m @@ -16,17 +16,16 @@ + (NSInteger)requiredParameterCount return 4; } -+ (void)runWithParams:(CGFloat *)params ++ (void)runWithParams:(CGFloat*)params paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command type:(IJSVGCommandType)type - path:(IJSVGPath *)path + path:(IJSVGPath*)path { - if( type == IJSVGCommandTypeAbsolute ) - { - [[path currentSubpath] addQuadCurveToPoint:NSMakePoint( params[2], params[3]) - controlPoint:NSMakePoint( params[0], params[1])]; + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] addQuadCurveToPoint:NSMakePoint(params[2], params[3]) + controlPoint:NSMakePoint(params[0], params[1])]; return; } [[path currentSubpath] addQuadCurveToPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[2], [path currentSubpath].currentPoint.y + params[3]) diff --git a/source/IJSVGCommandSmoothCurve.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothCurve.h similarity index 100% rename from source/IJSVGCommandSmoothCurve.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothCurve.h index 19dfd30..a0fe69a 100644 --- a/source/IJSVGCommandSmoothCurve.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothCurve.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandSmoothCurve : IJSVGCommand diff --git a/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothCurve.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothCurve.m new file mode 100644 index 0000000..c4b9be3 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothCurve.m @@ -0,0 +1,64 @@ +// +// IJSVGCommandSmoothCurve.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGCommandCurve.h" +#import "IJSVGCommandSmoothCurve.h" +#import "IJSVGUtils.h" + +@implementation IJSVGCommandSmoothCurve + ++ (NSInteger)requiredParameterCount +{ + return 4; +} + ++ (void)runWithParams:(CGFloat*)params + paramCount:(NSInteger)count + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command + type:(IJSVGCommandType)type + path:(IJSVGPath*)path +{ + NSPoint firstControl = NSMakePoint([path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y); + if (command != nil) { + if (command.class == [IJSVGCommandCurve class] || command.class == self.class) { + if (command.class == [IJSVGCommandCurve class]) { + if (command.type == kIJSVGCommandTypeAbsolute) { + firstControl = NSMakePoint(-1 * command.parameters[2] + 2 * [path currentSubpath].currentPoint.x, + -1 * command.parameters[3] + 2 * [path currentSubpath].currentPoint.y); + } else { + NSPoint oldPoint = NSMakePoint([path currentSubpath].currentPoint.x - command.parameters[4], + [path currentSubpath].currentPoint.y - command.parameters[5]); + firstControl = NSMakePoint(-1 * (command.parameters[2] + oldPoint.x) + 2 * [path currentSubpath].currentPoint.x, + -1 * (command.parameters[3] + oldPoint.y) + 2 * [path currentSubpath].currentPoint.y); + } + } else { + if (command.type == kIJSVGCommandTypeAbsolute) { + firstControl = NSMakePoint(-1 * command.parameters[0] + 2 * [path currentSubpath].currentPoint.x, + -1 * command.parameters[1] + 2 * [path currentSubpath].currentPoint.y); + } else { + NSPoint oldPoint = NSMakePoint([path currentSubpath].currentPoint.x - command.parameters[2], + [path currentSubpath].currentPoint.y - command.parameters[3]); + firstControl = NSMakePoint(-1 * (command.parameters[0] + oldPoint.x) + 2 * [path currentSubpath].currentPoint.x, + -1 * (command.parameters[1] + oldPoint.y) + 2 * [path currentSubpath].currentPoint.y); + } + } + } + } + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] curveToPoint:NSMakePoint(params[2], params[3]) + controlPoint1:NSMakePoint(firstControl.x, firstControl.y) + controlPoint2:NSMakePoint(params[0], params[1])]; + return; + } + [[path currentSubpath] curveToPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[2], [path currentSubpath].currentPoint.y + params[3]) + controlPoint1:NSMakePoint(firstControl.x, firstControl.y) + controlPoint2:NSMakePoint([path currentSubpath].currentPoint.x + params[0], [path currentSubpath].currentPoint.y + params[1])]; +} + +@end diff --git a/source/IJSVGCommandSmoothQuadraticCurve.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothQuadraticCurve.h similarity index 100% rename from source/IJSVGCommandSmoothQuadraticCurve.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothQuadraticCurve.h index 8c3146b..4c3f4fc 100644 --- a/source/IJSVGCommandSmoothQuadraticCurve.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothQuadraticCurve.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandSmoothQuadraticCurve : IJSVGCommand diff --git a/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothQuadraticCurve.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothQuadraticCurve.m new file mode 100644 index 0000000..fc286be --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandSmoothQuadraticCurve.m @@ -0,0 +1,56 @@ +// +// IJSVGCommandCommandQuadraticCurve.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGCommandQuadraticCurve.h" +#import "IJSVGCommandSmoothQuadraticCurve.h" +#import "IJSVGUtils.h" + +@implementation IJSVGCommandSmoothQuadraticCurve + ++ (NSInteger)requiredParameterCount +{ + return 2; +} + ++ (void)runWithParams:(CGFloat*)params + paramCount:(NSInteger)count + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command + type:(IJSVGCommandType)type + path:(IJSVGPath*)path +{ + NSPoint commandPoint = NSMakePoint([path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y); + if (command != nil) { + if (command.class == IJSVGCommandQuadraticCurve.class) { + // quadratic curve + if (command.type == kIJSVGCommandTypeAbsolute) { + commandPoint = NSMakePoint(-1 * command.parameters[0] + 2 * [path currentSubpath].currentPoint.x, + -1 * command.parameters[1] + 2 * [path currentSubpath].currentPoint.y); + } else { + NSPoint oldPoint = CGPointMake([path currentSubpath].currentPoint.x - command.parameters[2], + [path currentSubpath].currentPoint.y - command.parameters[3]); + commandPoint = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * ([path currentSubpath].currentPoint.x), + -1 * (command.parameters[1] + oldPoint.y) + 2 * [path currentSubpath].currentPoint.y); + } + } else if (command.class == self.class) { + // smooth quadratic curve + commandPoint = CGPointMake(-1 * (path.lastControlPoint.x) + 2 * ([path currentSubpath].currentPoint.x), + -1 * (path.lastControlPoint.y) + 2 * [path currentSubpath].currentPoint.y); + } + } + path.lastControlPoint = commandPoint; + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] addQuadCurveToPoint:NSMakePoint(params[0], params[1]) + controlPoint:commandPoint]; + return; + } + [[path currentSubpath] addQuadCurveToPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[0], [path currentSubpath].currentPoint.y + params[1]) + controlPoint:commandPoint]; +} + +@end diff --git a/source/IJSVGCommandVerticalLine.h b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandVerticalLine.h similarity index 100% rename from source/IJSVGCommandVerticalLine.h rename to Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandVerticalLine.h index 1cd92fa..0a0957f 100644 --- a/source/IJSVGCommandVerticalLine.h +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandVerticalLine.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGCommand.h" +#import @interface IJSVGCommandVerticalLine : IJSVGCommand diff --git a/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandVerticalLine.m b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandVerticalLine.m new file mode 100644 index 0000000..b5e9eb3 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Commands/IJSVGCommandVerticalLine.m @@ -0,0 +1,32 @@ +// +// IJSVGCommandVerticalLine.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGCommandVerticalLine.h" + +@implementation IJSVGCommandVerticalLine + ++ (NSInteger)requiredParameterCount +{ + return 1; +} + ++ (void)runWithParams:(CGFloat*)params + paramCount:(NSInteger)count + command:(IJSVGCommand*)currentCommand + previousCommand:(IJSVGCommand*)command + type:(IJSVGCommandType)type + path:(IJSVGPath*)path +{ + if (type == kIJSVGCommandTypeAbsolute) { + [[path currentSubpath] lineToPoint:NSMakePoint([path currentSubpath].currentPoint.x, params[0])]; + return; + } + [[path currentSubpath] relativeLineToPoint:NSMakePoint(0.f, params[0])]; +} + +@end diff --git a/source/IJSVGExporter.h b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporter.h similarity index 52% rename from source/IJSVGExporter.h rename to Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporter.h index 28bf44d..68f67c5 100644 --- a/source/IJSVGExporter.h +++ b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporter.h @@ -10,11 +10,12 @@ @class IJSVG; -typedef void (^IJSVGCGPathHandler)(const CGPathElement * pathElement); +typedef void (^IJSVGCGPathHandler)(const CGPathElement* pathElement); +typedef void (^IJSVGPathElementEnumerationBlock)(const CGPathElement* pathElement, CGPoint currentPoint); -void IJSVGExporterPathCaller(void * info, const CGPathElement * pathElement); +void IJSVGExporterPathCaller(void* info, const CGPathElement* pathElement); -typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) { +typedef NS_OPTIONS(NSInteger, IJSVGExporterOptions) { IJSVGExporterOptionNone = 1 << 0, IJSVGExporterOptionRemoveUselessGroups = 1 << 1, IJSVGExporterOptionRemoveUselessDef = 1 << 2, @@ -30,43 +31,33 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) { IJSVGExporterOptionCreateClasses = 1 << 12, IJSVGExporterOptionRemoveWidthHeightAttributes = 1 << 13, IJSVGExporterOptionColorAllowRRGGBBAA = 1 << 14, - IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef| - IJSVGExporterOptionRemoveUselessGroups| - IJSVGExporterOptionCreateUseForPaths| - IJSVGExporterOptionMoveAttributesToGroup| - IJSVGExporterOptionSortAttributes| - IJSVGExporterOptionCollapseGroups| - IJSVGExporterOptionCleanupPaths| - IJSVGExporterOptionRemoveHiddenElements| - IJSVGExporterOptionScaleToSizeIfNecessary| - IJSVGExporterOptionCompressOutput| - IJSVGExporterOptionCollapseGradients| - IJSVGExporterOptionRemoveWidthHeightAttributes| - IJSVGExporterOptionColorAllowRRGGBBAA + IJSVGExporterOptionRemoveComments = 1 << 15, + IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef | IJSVGExporterOptionRemoveUselessGroups | IJSVGExporterOptionCreateUseForPaths | IJSVGExporterOptionMoveAttributesToGroup | IJSVGExporterOptionSortAttributes | IJSVGExporterOptionCollapseGroups | IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements | IJSVGExporterOptionScaleToSizeIfNecessary | IJSVGExporterOptionCompressOutput | IJSVGExporterOptionCollapseGradients | IJSVGExporterOptionRemoveWidthHeightAttributes | IJSVGExporterOptionColorAllowRRGGBBAA | IJSVGExporterOptionRemoveComments }; BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option); +void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlock enumBlock); @interface IJSVGExporter : NSObject { - + @private - IJSVG * _svg; + IJSVG* _svg; CGSize _size; IJSVGExporterOptions _options; - NSXMLDocument * _dom; - NSXMLElement * _defElement; - NSXMLElement * _scaledRootNode; + NSXMLDocument* _dom; + NSXMLElement* _defElement; + NSXMLElement* _scaledRootNode; NSInteger _idCount; NSInteger _shortIdCount; } -@property (nonatomic, copy) NSString * title; -@property (nonatomic, copy) NSString * description; +@property (nonatomic, copy) NSString* title; +@property (nonatomic, copy) NSString* description; -- (id)initWithSVG:(IJSVG *)svg +- (id)initWithSVG:(IJSVG*)svg size:(CGSize)size options:(IJSVGExporterOptions)options; -- (NSString *)SVGString; -- (NSData *)SVGData; +- (NSString*)SVGString; +- (NSData*)SVGData; @end diff --git a/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporter.m b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporter.m new file mode 100644 index 0000000..d574ab5 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporter.m @@ -0,0 +1,1509 @@ +// +// IJSVGExporter.m +// IJSVGExample +// +// Created by Curtis Hard on 06/01/2017. +// Copyright © 2017 Curtis Hard. All rights reserved. +// + +#import "IJSVG.h" +#import "IJSVGExporter.h" +#import "IJSVGExporterPathInstruction.h" +#import "IJSVGGradientLayer.h" +#import "IJSVGGroupLayer.h" +#import "IJSVGImageLayer.h" +#import "IJSVGLinearGradient.h" +#import "IJSVGMath.h" +#import "IJSVGPatternLayer.h" +#import "IJSVGRadialGradient.h" +#import "IJSVGShapeLayer.h" +#import "IJSVGStrokeLayer.h" + +@implementation IJSVGExporter + +#define XML_DOC_VERSION 1.1f +#define XML_DOC_NS @"http://www.w3.org/2000/svg" +#define XML_DOC_NSXLINK @"http://www.w3.org/1999/xlink" +#define XML_DOCTYPE_VERSION @"1.0" +#define XML_DOC_CHARSET @"UTF-8" +#define XML_DOC_GENERATOR @"Generated by IJSVG (https://github.com/iconjar/IJSVG)" + +@synthesize title; +@synthesize description; + +BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option) +{ + return (options & option) != 0; +}; + +const NSArray* IJSVGShortCharacterArray() +{ + static NSArray* _array; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _array = [@[ @"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j", @"k", @"l", + @"m", @"n", @"o", @"p", @"q", @"r", @"s", @"t", @"u", @"v", @"w", @"x", @"y", @"z", + @"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", + @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z" ] retain]; + }); + return _array; +} + +const NSArray* IJSVGInheritableAttributes() +{ + static NSArray* _attributes; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _attributes = [@[ + @"clip-rule", + @"color", + @"color-interpolation", + @"color-interpolation-filters", + @"color-profile", + @"color-rendering", + @"cursor", + @"direction", + @"fill", + @"fill-opacity", + @"fill-rule", + @"font", + @"font-family", + @"font-size", + @"font-size-adjust", + @"font-stretch", + @"font-style", + @"font-variant", + @"font-weight", + @"glyph-orientation-horizontal", + @"glyph-orientation-vertical", + @"image-rendering", + @"kerning", + @"letter-spacing", + @"marker", + @"marker-end", + @"marker-mid", + @"marker-start", + @"pointer-events", + @"shape-rendering", + @"stroke", + @"stroke-dasharray", + @"stroke-dashoffset", + @"stroke-linecap", + @"stroke-linejoin", + @"stroke-miterlimit", + @"stroke-opacity", + @"stroke-width", + @"text-anchor", + @"text-rendering", + @"visibility", + @"white-space", + @"word-spacing", + @"writing-mode" + ] retain]; + }); + return _attributes; +} + +void IJSVGApplyAttributesToElement(NSDictionary* attributes, NSXMLElement* element) +{ + [element setAttributesAsDictionary:attributes]; +}; + +NSDictionary* IJSVGElementAttributeDictionary(NSXMLElement* element) +{ + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + for (NSXMLNode* attribute in element.attributes) { + dict[attribute.name] = attribute.stringValue; + } + return dict; +}; + +NSString* IJSVGHashURL(NSString* key) +{ + return [NSString stringWithFormat:@"url(#%@)", key]; +}; + +NSString* IJSVGHash(NSString* key) +{ + return [@"#" stringByAppendingString:key]; +} + +- (void)dealloc +{ + (void)([_scaledRootNode release]), _scaledRootNode = nil; + (void)([_svg release]), _svg = nil; + (void)([_dom release]), _dom = nil; + (void)([_defElement release]), _defElement = nil; + (void)([title release]), title = nil; + (void)([description release]), description = nil; + [super dealloc]; +} + +- (id)initWithSVG:(IJSVG*)svg + size:(CGSize)size + options:(IJSVGExporterOptions)options +{ + if ((self = [super init]) != nil) { + _options = options; + _size = size; + _svg = [svg retain]; + + // clear memory as soon as possible + @autoreleasepool { + [self _prepare]; + } + } + return self; +} + +- (NSXMLElement*)defElement +{ + if (_defElement != nil) { + return _defElement; + } + return _defElement = [[NSXMLElement alloc] initWithName:@"defs"]; +} + +- (NSString*)viewBoxWithRect:(NSRect)rect +{ + char* buffer; + asprintf(&buffer, "%g %g %g %g", rect.origin.x, rect.origin.y, + rect.size.width, rect.size.height); + NSString* viewBox = [NSString stringWithCString:buffer + encoding:NSUTF8StringEncoding]; + free(buffer); + return viewBox; +} + +- (NSXMLElement*)rootNode +{ + // generates the root document + NSXMLElement* root = [[[NSXMLElement alloc] initWithName:@"svg"] autorelease]; + + // sort out viewbox + NSRect viewBox = _svg.viewBox; + NSDictionary* attributes = @{ + @"viewBox" : [self viewBoxWithRect:viewBox], + @"version" : [NSString stringWithFormat:@"%g", XML_DOC_VERSION], + @"xmlns" : XML_DOC_NS, + @"xmlns:xlink" : XML_DOC_NSXLINK + }; + + // add on width and height unless specified otherwise + if ((_options & IJSVGExporterOptionRemoveWidthHeightAttributes) == 0) { + NSMutableDictionary* attDict = [[attributes mutableCopy] autorelease]; + attDict[@"width"] = IJSVGShortFloatString(_size.width); + attDict[@"height"] = IJSVGShortFloatString(_size.height); + attributes = [[attDict copy] autorelease]; + } + + // was there a size set? + if (CGSizeEqualToSize(CGSizeZero, _size) == NO && (_size.width != viewBox.size.width && _size.height != viewBox.size.height)) { + + // copy the attributes + NSMutableDictionary* att = [[attributes mutableCopy] autorelease]; + att[@"width"] = IJSVGShortFloatString(_size.width); + att[@"height"] = IJSVGShortFloatString(_size.height); + + // scale the whole SVG to fit the specified size + if ((_options & IJSVGExporterOptionScaleToSizeIfNecessary) != 0) { + // work out the scale + CGFloat scale = MIN(_size.width / viewBox.size.width, + _size.height / viewBox.size.height); + + // actually do the scale + if (scale != 1.f) { + NSString* scaleString = [NSString stringWithFormat:@"scale(%g)", scale]; + NSDictionary* transform = @{ @"transform" : scaleString }; + + // create the main group and apply transform + _scaledRootNode = [[NSXMLElement alloc] initWithName:@"g"]; + IJSVGApplyAttributesToElement(transform, _scaledRootNode); + + // add it back onto root + [root addChild:_scaledRootNode]; + + // compute x and y, dont multiply 0 + const CGFloat x = viewBox.origin.x == 0.f ? 0.f : (viewBox.origin.x * scale); + const CGFloat y = viewBox.origin.y == 0.f ? 0.f : (viewBox.origin.y * scale); + + // reset the viewbox for the exported SVG + att[@"viewBox"] = [self viewBoxWithRect:(NSRect){ + .origin = NSMakePoint(x, y), + .size = NSMakeSize(_size.width, _size.height) }]; + } + } + + // reset attributes + attributes = [[att copy] autorelease]; + } + + // apply the attributes + IJSVGApplyAttributesToElement(attributes, root); + return root; +} + +- (NSString*)generateID +{ + const NSArray* chars = IJSVGShortCharacterArray(); + if (_idCount < chars.count) { + return chars[_idCount++]; + } + + if ((_idCount % chars.count) == 0) { + _shortIdCount++; + } + return [NSString stringWithFormat:@"%@%ld", chars[(_idCount++ % chars.count)], _shortIdCount]; +} + +- (void)_prepare +{ + // create the stand alone DOM + _dom = [[NSXMLDocument alloc] initWithRootElement:[self rootNode]]; + _dom.version = XML_DOCTYPE_VERSION; + _dom.characterEncoding = XML_DOC_CHARSET; + + // sort out header + + // sort out stuff, so here we go... + [self _recursiveParseFromLayer:_svg.layer + intoElement:(_scaledRootNode ?: _dom.rootElement)]; + + // this needs to be added incase it needs to be cleaned + NSXMLElement* defNode = [self defElement]; + if (defNode.childCount != 0) { + [_dom.rootElement insertChild:[self defElement] + atIndex:0]; + } + + // cleanup + [self _cleanup]; + + // could had been removed during cleaning process needs to be added back in! + if (defNode.childCount != 0 && defNode.parent == nil) { + [_dom.rootElement insertChild:[self defElement] + atIndex:0]; + } + + // add generator + if ((_options & IJSVGExporterOptionRemoveComments) == 0) { + NSXMLNode* generatorNode = [[[NSXMLNode alloc] initWithKind:NSXMLCommentKind] autorelease]; + generatorNode.stringValue = XML_DOC_GENERATOR; + [_dom.rootElement insertChild:generatorNode + atIndex:0]; + } +} + +- (void)_cleanup +{ + // remove hidden elements + if ((_options & IJSVGExporterOptionRemoveHiddenElements) != 0) { + [self _removeHiddenElements]; + } + + // convert any duplicate paths into use + if ((_options & IJSVGExporterOptionCreateUseForPaths) != 0) { + [self _convertUseElements]; + } + + // cleanup def + if ((_options & IJSVGExporterOptionRemoveUselessDef) != 0) { + [self _cleanDef]; + } + + // collapse groups + if ((_options & IJSVGExporterOptionCollapseGroups) != 0) { + [self _collapseGroups]; + } + + // clean any blank groups + if ((_options & IJSVGExporterOptionRemoveUselessGroups) != 0) { + [self _cleanEmptyGroups]; + } + + // sort attributes + if ((_options & IJSVGExporterOptionSortAttributes) != 0) { + [self _sortAttributesOnElement:_dom.rootElement]; + } + + // compress groups together + if ((_options & IJSVGExporterOptionCollapseGroups) != 0) { + [self _compressGroups]; + } + + // collapse gradients? + if ((_options & IJSVGExporterOptionCollapseGradients) != 0) { + [self _collapseGradients]; + } + + // create classes? + if ((_options & IJSVGExporterOptionCreateClasses) != 0) { + [self _createClasses]; + } + + // move attributes to group + if ((_options & IJSVGExporterOptionMoveAttributesToGroup) != 0) { + [self _moveAttributesToGroupWithElement:_dom.rootElement]; + } +} + +- (void)_createClasses +{ + const NSArray* inhert = IJSVGInheritableAttributes(); + NSArray* elements = [_dom nodesForXPath:@"//*" + error:nil]; + NSMutableDictionary* rules = [[[NSMutableDictionary alloc] init] autorelease]; + for (NSXMLElement* element in elements) { + NSDictionary* inhertEl = [self intersectableAttributes:IJSVGElementAttributeDictionary(element) + inheritableAttributes:inhert]; + NSString* styles = [self styleSheetRulesFromDictionary:inhertEl]; + NSString* className = nil; + if ((className = [rules objectForKey:styles]) == nil) { + className = [NSString stringWithFormat:@"%@", [self generateID]]; + rules[styles] = className; + } + + for (NSString* attributeName in inhertEl) { + [element removeAttributeForName:attributeName]; + } + IJSVGApplyAttributesToElement(@{ @"class" : className }, element); + } + + // add styles to dom + NSXMLElement* styles = [[[NSXMLElement alloc] initWithName:@"style"] autorelease]; + NSXMLNode* node = [[[NSXMLNode alloc] initWithKind:NSXMLTextKind] autorelease]; + + NSMutableArray* classes = [[[NSMutableArray alloc] initWithCapacity:rules.count] autorelease]; + for (NSString* r in rules) { + [classes addObject:[NSString stringWithFormat:@".%@%@", rules[r], r]]; + } + node.stringValue = [classes componentsJoinedByString:@""]; + [styles addChild:node]; + [_dom.rootElement insertChild:styles atIndex:0]; +} + +- (NSString*)styleSheetRulesFromDictionary:(NSDictionary*)dict +{ + NSMutableArray* array = [[[NSMutableArray alloc] initWithCapacity:dict.count] autorelease]; + for (NSString* key in dict.allKeys) { + [array addObject:[NSString stringWithFormat:@"%@: %@;", key, dict[key]]]; + } + return [NSString stringWithFormat:@"{%@}", [array componentsJoinedByString:@" "]]; +} + +- (void)_sortAttributesOnElement:(NSXMLElement*)element +{ + // only apply to XML elements, not XMLNodes + if ([element isKindOfClass:[NSXMLElement class]] == NO) { + return; + } + [self sortAttributesOnElement:element]; + for (NSXMLElement* child in element.children) { + [self _sortAttributesOnElement:child]; + } +} + +- (void)_removeHiddenElements +{ + // find any elements where they have a style, but the element itself + // must not be in the defs + NSArray* elements = [_dom nodesForXPath:@"//*[@display='none']" + error:nil]; + + for (NSXMLElement* element in elements) { + NSXMLElement* parent = (NSXMLElement*)element.parent; + [parent removeChildAtIndex:element.index]; + } +} + +- (void)_collapseGradients +{ + NSString* xPath = @"//defs/*[self::linearGradient or self::radialGradient]"; + NSArray* gradients = [_dom nodesForXPath:xPath error:nil]; + for (NSInteger i = 0; i < gradients.count; i++) { + if (i != 0) { + NSXMLElement* gradientA = gradients[i]; + NSXMLElement* gradientB = nil; + for (NSInteger s = (i - 1); s >= 0; s--) { + gradientB = gradients[s]; + if ([self compareElementChildren:gradientA toElement:gradientB] == YES) { + NSString* idString = [gradientB attributeForName:@"id"].stringValue; + if (idString == nil || idString.length == 0) { + idString = [self generateID]; + IJSVGApplyAttributesToElement(@{ @"id" : idString }, gradientB); + } + NSDictionary* atts = @{ @"xlink:href" : IJSVGHash(idString) }; + IJSVGApplyAttributesToElement(atts, gradientA); + [gradientA setChildren:nil]; + break; + } + } + } + } +} + +- (BOOL)compareElementChildren:(NSXMLElement*)element + toElement:(NSXMLElement*)toElement +{ + NSArray* childrenA = element.children; + NSArray* childrenB = toElement.children; + if (childrenA.count != childrenB.count) { + return NO; + } + for (NSInteger i = 0; i < childrenA.count; i++) { + NSXMLElement* childA = childrenA[i]; + NSXMLElement* childB = childrenB[i]; + if ([self compareElement:childA withElement:childB] == NO) { + return NO; + } + } + return YES; +} + +- (void)_moveAttributesToGroupWithElement:(NSXMLElement*)parentElement +{ + + const NSArray* excludedNodes = @[ @"script", @"style", @"defs" ]; + if ([excludedNodes containsObject:parentElement.name] == YES) { + return; + } + + const NSArray* inheritableAttributes = IJSVGInheritableAttributes(); + + NSDictionary* intersection = @{}; + NSMutableArray* grouped = [[[NSMutableArray alloc] init] autorelease]; + + NSInteger counter = 0; + NSInteger size = parentElement.childCount - 1; + for (NSXMLElement* element in parentElement.children) { + + NSDictionary* attributes = [self intersectableAttributes:IJSVGElementAttributeDictionary(element) + inheritableAttributes:inheritableAttributes]; + + if (intersection.count == 0) { + intersection = attributes; + } + + NSDictionary* dict = [self intersectionInheritableAttributes:intersection + currentAttributes:attributes + inheritableAttributes:inheritableAttributes]; + + for (NSString* attributeToRemove in dict.allKeys) { + [element removeAttributeForName:attributeToRemove]; + } + if (dict != nil) { + [grouped addObject:element]; + } + + if (dict == nil || counter == size) { + if (grouped.count > 1) { + NSXMLElement* groupElement = [[[NSXMLElement alloc] initWithName:@"g"] autorelease]; + NSXMLElement* lastElement = (NSXMLElement*)grouped.lastObject; + NSInteger index = lastElement.index; + [parentElement replaceChildAtIndex:index withNode:groupElement]; + for (NSXMLElement* elementToGroup in grouped) { + [elementToGroup detach]; + [groupElement addChild:elementToGroup]; + } + IJSVGApplyAttributesToElement(intersection, groupElement); + } else { + if (grouped.count == 1) { + NSXMLElement* onlyElement = (NSXMLElement*)grouped.lastObject; + IJSVGApplyAttributesToElement(intersection, onlyElement); + } + } + intersection = @{}; + [grouped removeAllObjects]; + } + + counter++; + } +} + +- (NSDictionary*)intersectableAttributes:(NSDictionary*)atts + inheritableAttributes:(const NSArray*)inheritable +{ + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + for (NSString* key in atts.allKeys) { + if ([inheritable containsObject:key]) { + dict[key] = atts[key]; + } + } + return dict; +} + +- (NSDictionary*)intersectionInheritableAttributes:(NSDictionary*)newAttributes + currentAttributes:(NSDictionary*)currentAttributes + inheritableAttributes:(const NSArray*)inheritableAtts +{ + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + for (NSString* key in newAttributes.allKeys) { + // make sure they are the same and + // they are inheritable + if ([currentAttributes objectForKey:key] == nil) { + return nil; + } + + if ([currentAttributes objectForKey:key] != nil && + [inheritableAtts containsObject:key] && + [newAttributes[key] isEqualToString:currentAttributes[key]]) { + dict[key] = currentAttributes[key]; + } + } + + // nothing to return, kill it + if (dict.count == 0) { + return nil; + } + return dict; +} + +- (void)_cleanDef +{ + NSXMLElement* defNode = [self defElement]; + if (defNode.children == 0) { + NSXMLElement* parent = (NSXMLElement*)defNode.parent; + [parent removeChildAtIndex:defNode.index]; + } +} + +- (void)_cleanEmptyGroups +{ + @autoreleasepool { + // cleanup any groups that are completely useless + NSArray* groups = [_dom nodesForXPath:@"//g" error:nil]; + for (NSXMLElement* element in groups) { + NSXMLElement* parent = (NSXMLElement*)element.parent; + if (element.childCount == 0) { + // empty group + [(NSXMLElement*)element.parent removeChildAtIndex:element.index]; + } else if (element.attributes.count == 0) { + // no useful data on the group + NSInteger index = element.index; + for (NSXMLElement* child in element.children) { + [(NSXMLElement*)child.parent removeChildAtIndex:child.index]; + [parent insertChild:child + atIndex:index++]; + } + [parent removeChildAtIndex:element.index]; + } + } + } +} + +- (void)_compressGroups +{ + NSArray* groups = [_dom nodesForXPath:@"//g" error:nil]; + for (NSXMLElement* group in groups) { + + // whats the next group? + if (group.parent == nil) { + continue; + } + + // compare each group with its next sibling + NSXMLElement* nextGroup = (NSXMLElement*)group.nextSibling; + while ([self compareElement:group withElement:nextGroup]) { + // move each child into the older group + for (NSXMLElement* child in nextGroup.children) { + [nextGroup removeChildAtIndex:child.index]; + [group addChild:child]; + } + + // remove the newer + NSXMLElement* n = nextGroup; + nextGroup = (NSXMLElement*)nextGroup.nextSibling; + [(NSXMLElement*)n.parent removeChildAtIndex:n.index]; + } + } +} + +- (void)_collapseGroups +{ + NSArray* groups = [_dom nodesForXPath:@"//g" error:nil]; + const NSArray* inheritable = IJSVGInheritableAttributes(); + for (NSXMLElement* group in groups) { + + // dont do anything due to it being referenced + if ([group attributeForName:@"id"] != nil) { + return; + } + + if (group.attributes.count != 0 && group.children.count == 1) { + + // grab the first child as its a loner + NSXMLElement* child = (NSXMLElement*)group.children[0]; + if ([child attributeForName:@"transform"] != nil) { + continue; + } + + for (NSXMLNode* gAttribute in group.attributes) { + + // if it just doesnt have the attriute, just add it + if ([child attributeForName:gAttribute.name] == NO) { + // remove first, or throws a wobbly + [group removeAttributeForName:gAttribute.name]; + [child addAttribute:gAttribute]; + } else if ([gAttribute.name isEqualToString:@"transform"]) { + // transform requires concatination + NSXMLNode* childTransform = [child attributeForName:@"transform"]; + childTransform.stringValue = [NSString stringWithFormat:@"%@ %@", + gAttribute.stringValue, childTransform.stringValue]; + + } else if ([inheritable containsObject:gAttribute.name] == NO) { + // if its not inheritable, only remove it if its not equal + NSXMLNode* aAtt = [child attributeForName:gAttribute.name]; + if (aAtt == nil || (aAtt != nil && [aAtt.stringValue isEqualToString:gAttribute.stringValue] == NO)) { + continue; + } + } + [group removeAttributeForName:gAttribute.name]; + } + + // remove the group as its useless! + if (group.attributes.count == 0) { + [child detach]; + [(NSXMLElement*)group.parent replaceChildAtIndex:group.index + withNode:child]; + } + } + } +} + +- (BOOL)compareElement:(NSXMLElement*)element + withElement:(NSXMLElement*)anotherElement +{ + // not a matching element + if ([element.name isEqualToString:anotherElement.name] == NO || element.attributes.count != anotherElement.attributes.count) { + return NO; + } + + // compare attributes + for (NSXMLNode* attribute in element.attributes) { + NSString* compareString = [anotherElement attributeForName:attribute.name].stringValue; + if ([attribute.stringValue isEqualToString:compareString] == NO) { + return NO; + } + } + return YES; +} + +- (void)_convertUseElements +{ + @autoreleasepool { + NSArray* paths = [_dom nodesForXPath:@"//path" + error:nil]; + + NSCountedSet* set = [[[NSCountedSet alloc] init] autorelease]; + for (NSXMLElement* element in paths) { + [set addObject:[element attributeForName:@"d"].stringValue]; + } + + NSMutableDictionary* defs = [[[NSMutableDictionary alloc] init] autorelease]; + + // now actually compute them + for (NSXMLElement* element in paths) { + NSString* data = [element attributeForName:@"d"].stringValue; + if ([set countForObject:data] == 1) { + continue; + } + + // at this point, we know the path is being used more then once + NSXMLElement* defParentElement = nil; + if ((defParentElement = [defs objectForKey:data]) == nil) { + // create the def + NSXMLElement* element = [[[NSXMLElement alloc] init] autorelease]; + element.name = @"path"; + + NSDictionary* atts = @{ @"d" : data, + @"id" : [self generateID] }; + IJSVGApplyAttributesToElement(atts, element); + + // store it against the def + defs[data] = element; + defParentElement = element; + } + + // we know at this point, we need to swap out the path to a use + NSXMLElement* use = [[[NSXMLElement alloc] init] autorelease]; + use.name = @"use"; + + // grab the id + NSString* pathId = [defParentElement attributeForName:@"id"].stringValue; + + NSXMLNode* useAttribute = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; + useAttribute.name = @"xlink:href"; + useAttribute.stringValue = IJSVGHash(pathId); + [use addAttribute:useAttribute]; + + // remove the d attribute + for (NSXMLNode* attribute in element.attributes) { + if ([attribute.name isEqualToString:@"d"]) { + continue; + } + [element removeAttributeForName:attribute.name]; + [use addAttribute:attribute]; + } + + // swap it out + [(NSXMLElement*)element.parent replaceChildAtIndex:element.index + withNode:use]; + } + + // add the defs back in + NSXMLElement* def = [self defElement]; + for (NSXMLElement* defElement in defs.allValues) { + [def addChild:defElement]; + } + } +} + +- (void)_recursiveParseFromLayer:(IJSVGLayer*)layer + intoElement:(NSXMLElement*)element +{ + // is a shape + if ([layer class] == [IJSVGShapeLayer class]) { + NSXMLElement* child = [self elementForShape:(IJSVGShapeLayer*)layer + fromParent:element]; + if (child != nil) { + [element addChild:child]; + } + } else if ([layer isKindOfClass:[IJSVGImageLayer class]]) { + NSXMLElement* child = [self elementForImage:(IJSVGImageLayer*)layer + fromParent:element]; + if (child != nil) { + [element addChild:child]; + } + } else if ([layer isKindOfClass:[IJSVGGroupLayer class]]) { + // assume its probably a group? + NSXMLElement* child = [self elementForGroup:layer + fromParent:element]; + if (child != nil) { + [element addChild:child]; + } + } +} + +- (void)applyTransformToElement:(NSXMLElement*)element + fromLayer:(IJSVGLayer*)layer +{ + CGAffineTransform transform = layer.affineTransform; + if (CGAffineTransformEqualToTransform(transform, CGAffineTransformIdentity) == YES) { + return; + } + + // append the string + NSString* transformStr = [IJSVGTransform affineTransformToSVGMatrixString:transform]; + + // apply it to the node + IJSVGApplyAttributesToElement(@{ @"transform" : transformStr }, element); +} + +- (NSXMLElement*)elementForGroup:(IJSVGLayer*)layer + fromParent:(NSXMLElement*)parent +{ + // create the element + NSXMLElement* e = [[[NSXMLElement alloc] init] autorelease]; + e.name = @"g"; + + // stick defaults + [self applyDefaultsToElement:e + fromLayer:layer]; + + // add group children + for (IJSVGLayer* childLayer in layer.sublayers) { + [self _recursiveParseFromLayer:childLayer + intoElement:e]; + } + + return e; +} + +- (NSString*)base64EncodedStringFromCGImage:(CGImageRef)image +{ + if (image == nil) { + return nil; + } + + // convert the CGImage into an NSImage + NSBitmapImageRep* rep = [[[NSBitmapImageRep alloc] initWithCGImage:image] autorelease]; + + // work out the data + NSData* data = [rep representationUsingType:NSBitmapImageFileTypePNG + properties:@{}]; + + NSString* base64String = [data base64EncodedStringWithOptions:0]; + return [@"data:image/png;base64," stringByAppendingString:base64String]; +} + +- (void)applyPatternFromLayer:(IJSVGPatternLayer*)layer + parentLayer:(IJSVGLayer*)parentLayer + stroke:(BOOL)stroke + toElement:(NSXMLElement*)element +{ + // now we need the pattern + IJSVGGroupLayer* patternLayer = (IJSVGGroupLayer*)layer.pattern; + + NSXMLElement* patternElement = [self elementForGroup:patternLayer + fromParent:nil]; + patternElement.name = @"pattern"; + + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + dict[@"id"] = [self generateID]; + dict[@"width"] = IJSVGShortFloatString(layer.patternNode.width.value); + dict[@"height"] = IJSVGShortFloatString(layer.patternNode.height.value); + + // sort out x and y position + IJSVGUnitLength* x = layer.patternNode.x; + IJSVGUnitLength* y = layer.patternNode.y; + + if (x.value != 0) { + dict[@"x"] = [layer.patternNode.x stringValue]; + } + + if (y.value != 0) { + dict[@"y"] = [layer.patternNode.y stringValue]; + } + + IJSVGApplyAttributesToElement(dict, patternElement); + + [[self defElement] addChild:patternElement]; + + // now the use statement + NSXMLElement* useElement = [[[NSXMLElement alloc] init] autorelease]; + useElement.name = @"use"; + + // now add the fill + NSDictionary* aDict = nil; + if (stroke == NO) { + aDict = @{ @"fill" : IJSVGHashURL([patternElement attributeForName:@"id"].stringValue) }; + IJSVGApplyAttributesToElement(aDict, element); + + // fill opacity + if (patternLayer.opacity != 1.f) { + IJSVGApplyAttributesToElement(@{ @"fill-opacity" : IJSVGShortFloatString(patternLayer.opacity) }, element); + } + } else { + aDict = @{ @"stroke" : IJSVGHashURL([patternElement attributeForName:@"id"].stringValue) }; + IJSVGApplyAttributesToElement(aDict, element); + } +} + +- (void)applyGradientFromLayer:(IJSVGGradientLayer*)layer + parentLayer:(IJSVGLayer*)parentLayer + stroke:(BOOL)stroke + toElement:(NSXMLElement*)element +{ + IJSVGGradient* gradient = layer.gradient; + NSString* gradKey = [self generateID]; + NSXMLElement* gradientElement = [[[NSXMLElement alloc] init] autorelease]; + + // work out linear gradient + if ([gradient isKindOfClass:[IJSVGLinearGradient class]]) { + + IJSVGLinearGradient* lGradient = (IJSVGLinearGradient*)gradient; + gradientElement.name = @"linearGradient"; + NSDictionary* dict = @{ @"id" : gradKey, + @"x1" : lGradient.x1.stringValue, + @"y1" : lGradient.y1.stringValue, + @"x2" : lGradient.x2.stringValue, + @"y2" : lGradient.y2.stringValue }; + + // give it the attibutes + IJSVGApplyAttributesToElement(dict, gradientElement); + } else { + + // assume radial + IJSVGRadialGradient* rGradient = (IJSVGRadialGradient*)gradient; + gradientElement.name = @"radialGradient"; + NSDictionary* dict = @{ @"id" : gradKey, + @"cx" : rGradient.cx.stringValue, + @"cy" : rGradient.cy.stringValue, + @"fx" : rGradient.fx.stringValue, + @"fy" : rGradient.fy.stringValue, + @"r" : rGradient.radius.stringValue }; + + // give it the attributes + IJSVGApplyAttributesToElement(dict, gradientElement); + } + + // apply the units + if (layer.gradient.units == IJSVGUnitUserSpaceOnUse) { + IJSVGApplyAttributesToElement(@{ @"gradientUnits" : @"userSpaceOnUse" }, + gradientElement); + } + + // add the stops + NSGradient* grad = layer.gradient.gradient; + IJSVGColorList* sheet = layer.gradient.colorList; + NSInteger noStops = grad.numberOfColorStops; + for (NSInteger i = 0; i < noStops; i++) { + + // grab each color from the gradient + NSColor* aColor = nil; + CGFloat location; + [grad getColor:&aColor + location:&location + atIndex:i]; + + if (sheet != nil) { + aColor = [sheet proposedColorForColor:aColor]; + } + + // create the stop element + NSXMLElement* stop = [[[NSXMLElement alloc] init] autorelease]; + stop.name = @"stop"; + + NSMutableDictionary* atts = [[[NSMutableDictionary alloc] init] autorelease]; + atts[@"offset"] = [NSString stringWithFormat:@"%g%%", (location * 100)]; + + // add the color + IJSVGColorStringOptions options = IJSVGColorStringOptionForceHEX | IJSVGColorStringOptionAllowShortHand; + NSString* stopColor = [IJSVGColor colorStringFromColor:aColor + options:options]; + if ([stopColor isEqualToString:@"#000000"] == NO) { + atts[@"stop-color"] = stopColor; + } + + // we need to work out the color at this point, annoyingly... + CGFloat opacity = aColor.alphaComponent; + + // is opacity is equal to 1, no need to add it as spec + // defaults opacity to 1 anyway :) + if (opacity != 1.f) { + atts[@"stop-opacity"] = IJSVGShortFloatStringWithPrecision(opacity, 2); + } + + // att the attributes + + IJSVGApplyAttributesToElement(atts, stop); + + // append the stop the gradient + [gradientElement addChild:stop]; + } + + // append it to the defs + [[self defElement] addChild:gradientElement]; + + // work out the transform + NSArray* transforms = layer.gradient.transforms; + if (transforms.count != 0.f) { + CGAffineTransform transform = IJSVGConcatTransforms(transforms); + NSString* transformString = [IJSVGTransform affineTransformToSVGMatrixString:transform]; + IJSVGApplyAttributesToElement(@{ @"gradientTransform" : transformString }, gradientElement); + } + + // add it to the element passed in + if (stroke == NO) { + IJSVGApplyAttributesToElement(@{ @"fill" : IJSVGHashURL(gradKey) }, element); + + // fill opacity + if (layer.opacity != 1.f) { + IJSVGApplyAttributesToElement(@{ @"fill-opacity" : IJSVGShortFloatStringWithPrecision(layer.opacity, 2) }, element); + } + } else { + IJSVGApplyAttributesToElement(@{ @"stroke" : IJSVGHashURL(gradKey) }, element); + } +} + +- (CGAffineTransform)affineTransformFromTransforms:(NSArray*)transforms +{ + CGAffineTransform t = CGAffineTransformIdentity; + for (IJSVGTransform* transform in transforms) { + t = CGAffineTransformConcat(t, [transform CGAffineTransform]); + } + return t; +} + +- (NSXMLElement*)elementForImage:(IJSVGImageLayer*)layer + fromParent:(NSXMLElement*)parent +{ + NSString* base64String = [self base64EncodedStringFromCGImage:(CGImageRef)layer.contents]; + if (base64String == nil || layer.contents == nil) { + return nil; + } + + // image element for the SVG + NSXMLElement* imageElement = [[[NSXMLElement alloc] init] autorelease]; + imageElement.name = @"image"; + + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + dict[@"id"] = [self generateID]; + dict[@"width"] = IJSVGShortFloatString(layer.frame.size.width); + dict[@"height"] = IJSVGShortFloatString(layer.frame.size.height); + dict[@"xlink:href"] = base64String; + + // work out any position + if (layer.frame.origin.x != 0.f) { + dict[@"x"] = IJSVGShortFloatString(layer.frame.origin.x); + } + if (layer.frame.origin.y != 0.f) { + dict[@"y"] = IJSVGShortFloatString(layer.frame.origin.y); + } + + // add the attributes + IJSVGApplyAttributesToElement(dict, imageElement); + return imageElement; +} + +- (IJSVGColorStringOptions)colorOptions +{ + IJSVGColorStringOptions options = IJSVGColorStringOptionDefault; + if ((_options & IJSVGExporterOptionColorAllowRRGGBBAA) != 0) { + options |= IJSVGColorStringOptionAllowRRGGBBAA; + } + return options; +} + +- (NSString*)elementNameForPrimitiveType:(IJSVGPrimitivePathType)primitiveType +{ + switch (primitiveType) { + case IJSVGPrimitivePathTypeRect: + return @"rect"; + case IJSVGPrimitivePathTypePolyLine: + return @"polyline"; + case IJSVGPrimitivePathTypeEllipse: + return @"ellipse"; + case IJSVGPrimitivePathTypeCircle: + return @"circle"; + case IJSVGPrimitivePathTypeLine: + return @"line"; + case IJSVGPrimitivePathTypePolygon: + return @"polygon"; + case IJSVGPrimitivePathTypePath: + default: + return @"path"; + } +} + +- (NSXMLElement*)elementForShape:(IJSVGShapeLayer*)layer + fromParent:(NSXMLElement*)parent +{ + NSXMLElement* e = [[[NSXMLElement alloc] init] autorelease]; + e.name = [self elementNameForPrimitiveType:layer.primitiveType]; + CGPathRef path = layer.path; + + // copy the path as we want to translate + CGAffineTransform trans = CGAffineTransformMakeTranslation(layer.originalPathOrigin.x, + layer.originalPathOrigin.y); + CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &trans); + + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + + // path + switch (layer.primitiveType) { + case IJSVGPrimitivePathTypeRect: { + __block BOOL radiusSet = NO; + IJSVGEnumerateCGPathElements(transformPath, ^(const CGPathElement* pathElement, CGPoint currentPoint) { + if (radiusSet == NO && pathElement->type == kCGPathElementAddCurveToPoint) { + radiusSet = YES; + CGFloat radX = fabs(pathElement->points[0].x - currentPoint.x); + CGFloat radY = fabs(pathElement->points[0].y - currentPoint.y); + dict[@"rx"] = IJSVGShortFloatString(radX); + if (radX != radY) { + dict[@"ry"] = IJSVGShortFloatString(radY); + } + } + }); + CGRect boundingBox = CGPathGetBoundingBox(transformPath); + if (boundingBox.origin.x != 0.f) { + dict[@"x"] = IJSVGShortFloatString(boundingBox.origin.x); + } + if (boundingBox.origin.y != 0.f) { + dict[@"y"] = IJSVGShortFloatString(boundingBox.origin.y); + } + dict[@"width"] = IJSVGShortFloatString(boundingBox.size.width); + dict[@"height"] = IJSVGShortFloatString(boundingBox.size.height); + break; + } + case IJSVGPrimitivePathTypeLine: { + IJSVGEnumerateCGPathElements(transformPath, ^(const CGPathElement* pathElement, CGPoint currentPoint) { + switch (pathElement->type) { + case kCGPathElementMoveToPoint: { + dict[@"x1"] = IJSVGShortFloatString(pathElement->points[0].x); + dict[@"y1"] = IJSVGShortFloatString(pathElement->points[0].y); + break; + } + case kCGPathElementAddLineToPoint: { + dict[@"x2"] = IJSVGShortFloatString(pathElement->points[0].x); + dict[@"y2"] = IJSVGShortFloatString(pathElement->points[0].y); + break; + } + default: + break; + } + }); + break; + } + case IJSVGPrimitivePathTypePolygon: + case IJSVGPrimitivePathTypePolyLine: { + NSMutableArray* points = [[[NSMutableArray alloc] init] autorelease]; + IJSVGEnumerateCGPathElements(transformPath, ^(const CGPathElement* pathElement, CGPoint currentPoint) { + switch (pathElement->type) { + case kCGPathElementMoveToPoint: { + [points addObject:IJSVGPointToCommandString(pathElement->points[0])]; + break; + } + case kCGPathElementAddLineToPoint: { + [points addObject:IJSVGPointToCommandString(pathElement->points[0])]; + break; + } + default: + break; + } + }); + // polygon does not need the move to command + if (layer.primitiveType == IJSVGPrimitivePathTypePolygon) { + [points removeLastObject]; + } + dict[@"points"] = [points componentsJoinedByString:@" "]; + break; + } + case IJSVGPrimitivePathTypeEllipse: { + CGRect boundingBox = CGPathGetPathBoundingBox(transformPath); + dict[@"cx"] = IJSVGShortFloatString(boundingBox.origin.x + boundingBox.size.width / 2.f); + dict[@"cy"] = IJSVGShortFloatString(boundingBox.origin.y + boundingBox.size.height / 2.f); + dict[@"rx"] = IJSVGShortFloatString(boundingBox.size.width / 2.f); + dict[@"ry"] = IJSVGShortFloatString(boundingBox.size.height / 2.f); + break; + } + case IJSVGPrimitivePathTypeCircle: { + // IJSVGCGPathHandler callback = ^(const CGPathElement * pathElement) { + CGRect boundingBox = CGPathGetPathBoundingBox(transformPath); + dict[@"cx"] = IJSVGShortFloatString(boundingBox.origin.x + boundingBox.size.width / 2.f); + dict[@"cy"] = IJSVGShortFloatString(boundingBox.origin.y + boundingBox.size.height / 2.f); + dict[@"r"] = IJSVGShortFloatString(boundingBox.size.width / 2.f); + break; + } + case IJSVGPrimitivePathTypePath: + default: + dict[@"d"] = [self pathFromCGPath:transformPath]; + } + + CGPathRelease(transformPath); + + // work out even odd rule + if ([layer.fillRule isEqualToString:kCAFillRuleNonZero] == NO) { + dict[@"fill-rule"] = @"evenodd"; + } + + // fill color + if (layer.fillColor != nil) { + NSColor* fillColor = [NSColor colorWithCGColor:layer.fillColor]; + NSString* colorString = [IJSVGColor colorStringFromColor:fillColor + options:[self colorOptions]]; + + // could be none + if (colorString != nil) { + dict[@"fill"] = colorString; + } + } + + // is there a gradient fill? + if (layer.gradientFillLayer != nil) { + [self applyGradientFromLayer:layer.gradientFillLayer + parentLayer:(IJSVGLayer*)layer + stroke:NO + toElement:e]; + } + + // is there a pattern? + if (layer.patternFillLayer != nil) { + [self applyPatternFromLayer:layer.patternFillLayer + parentLayer:(IJSVGLayer*)layer + stroke:NO + toElement:e]; + } + + // is there a stroke layer? + if (layer.strokeLayer != nil) { + // check the type + IJSVGStrokeLayer* strokeLayer = layer.strokeLayer; + if ([strokeLayer isKindOfClass:[IJSVGShapeLayer class]]) { + // stroke + if (strokeLayer.lineWidth != 0.f) { + dict[@"stroke-width"] = IJSVGShortFloatString(strokeLayer.lineWidth); + } + + // stroke gradient + if (layer.gradientStrokeLayer != nil) { + [self applyGradientFromLayer:layer.gradientStrokeLayer + parentLayer:(IJSVGPatternLayer*)layer + stroke:YES + toElement:e]; + + } else if (layer.patternStrokeLayer != nil) { + // stroke pattern + [self applyPatternFromLayer:layer.patternStrokeLayer + parentLayer:(IJSVGPatternLayer*)layer + stroke:YES + toElement:e]; + + } else if (strokeLayer.strokeColor != nil) { + NSColor* strokeColor = [NSColor colorWithCGColor:strokeLayer.strokeColor]; + NSString* strokeColorString = [IJSVGColor colorStringFromColor:strokeColor + options:[self colorOptions]]; + + // could be none + if (strokeColorString != nil) { + dict[@"stroke"] = strokeColorString; + if ([strokeColorString isEqualToString:@"none"] == YES) { + // remove the stroke width as its completely useless + [dict removeObjectForKey:@"stroke-width"]; + } + } + } + + // work out line cap + if ([strokeLayer.lineCap isEqualToString:kCALineCapButt] == NO) { + NSString* capStyle = nil; + if ([strokeLayer.lineCap isEqualToString:kCALineCapRound]) { + capStyle = @"round"; + } else if ([strokeLayer.lineCap isEqualToString:kCALineCapSquare]) { + capStyle = @"square"; + } + if (capStyle != nil) { + dict[@"stroke-linecap"] = capStyle; + } + } + + // work out line join + if ([strokeLayer.lineJoin isEqualToString:kCALineJoinMiter] == NO) { + NSString* joinStyle = nil; + if ([strokeLayer.lineJoin isEqualToString:kCALineJoinBevel]) { + joinStyle = @"bevel"; + } else if ([strokeLayer.lineJoin isEqualToString:kCALineJoinRound]) { + joinStyle = @"round"; + } + if (joinStyle != nil) { + dict[@"stroke-linejoin"] = joinStyle; + } + } + + // work out dash offset... + if (strokeLayer.lineDashPhase != 0.f) { + dict[@"stroke-dashoffset"] = IJSVGShortFloatString(strokeLayer.lineDashPhase); + } + + // work out dash array + if (strokeLayer.lineDashPattern.count != 0) { + dict[@"stroke-dasharray"] = [strokeLayer.lineDashPattern componentsJoinedByString:@" "]; + } + } + } + + // apply the attributes + IJSVGApplyAttributesToElement(dict, e); + + // apple defaults + [self applyDefaultsToElement:e + fromLayer:(IJSVGLayer*)layer]; + return e; +} + +- (void)applyDefaultsToElement:(NSXMLElement*)element + fromLayer:(IJSVGLayer*)layer +{ + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + + // opacity + if (layer.opacity != 1.f) { + dict[@"opacity"] = IJSVGShortFloatStringWithPrecision(layer.opacity, 2); + } + + // blendmode - we only every apply a stylesheet blend mode + NSMutableDictionary* style = [[[NSMutableDictionary alloc] init] autorelease]; + if (layer.blendingMode != kCGBlendModeNormal) { + NSString* str = [IJSVGUtils mixBlendingModeForBlendMode:(IJSVGBlendMode)layer.blendingMode]; + if (str != nil) { + style[@"mix-blend-mode"] = str; + } + } + + // hidden? + if (layer.isHidden) { + style[@"display"] = @"none"; + } + + if (style.count != 0) { + NSMutableString* styleString = [[[NSMutableString alloc] init] autorelease]; + for (NSString* styleKey in style.allKeys) { + NSString* format = [NSString stringWithFormat:@"%@:%@;", styleKey, style[styleKey]]; + [styleString appendString:format]; + } + dict[@"style"] = styleString; + } + + // add atttributes + IJSVGApplyAttributesToElement(dict, element); + + // apply transforms + [self applyTransformToElement:element + fromLayer:layer]; + + // add any masks... + if (layer.mask != nil) { + [self applyMaskToElement:element + fromLayer:layer]; + } +} + +- (void)applyMaskToElement:(NSXMLElement*)element + fromLayer:(IJSVGLayer*)layer +{ + // create the element + NSXMLElement* mask = [[[NSXMLElement alloc] init] autorelease]; + mask.name = @"mask"; + + // create the key + NSString* maskKey = [self generateID]; + NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease]; + dict[@"id"] = maskKey; + dict[@"maskContentUnits"] = @"userSpaceOnUse"; + dict[@"maskUnits"] = @"objectBoundingBox"; + + if (layer.mask.frame.origin.x != 0.f) { + dict[@"x"] = IJSVGShortFloatString(layer.mask.frame.origin.x); + } + if (layer.mask.frame.origin.y != 0.f) { + dict[@"y"] = IJSVGShortFloatString(layer.mask.frame.origin.y); + } + + IJSVGApplyAttributesToElement(dict, mask); + + // add the cool stuff + [self _recursiveParseFromLayer:(IJSVGLayer*)layer.mask + intoElement:mask]; + + // add mask id to element + IJSVGApplyAttributesToElement(@{ @"mask" : IJSVGHashURL(maskKey) }, element); + + // add it defs + [[self defElement] addChild:mask]; +} + +- (NSString*)SVGString +{ + NSXMLNodeOptions options = NSXMLNodePrettyPrint; + if ((_options & IJSVGExporterOptionCompressOutput) != 0) { + options = NSXMLNodeOptionsNone; + } + return [_dom XMLStringWithOptions:options]; +} + +- (NSData*)SVGData +{ + return [[self SVGString] dataUsingEncoding:NSUTF8StringEncoding]; +} + +#pragma mark CGPath stuff + +- (NSString*)pathFromCGPath:(CGPathRef)path +{ + // string to store the path in + NSArray* instructions = [IJSVGExporterPathInstruction instructionsFromPath:path]; + + // work out what to do... + if ((_options & IJSVGExporterOptionCleanupPaths) != 0) { + [IJSVGExporterPathInstruction convertInstructionsToRelativeCoordinates:instructions]; + } + return [IJSVGExporterPathInstruction pathStringFromInstructions:instructions]; +} + +void IJSVGExporterPathCaller(void* info, const CGPathElement* pathElement) +{ + IJSVGCGPathHandler handler = (IJSVGCGPathHandler)info; + handler(pathElement); +}; + +void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlock enumBlock) +{ + __block CGPoint currentPoint = CGPointZero; + CGPathApplyWithBlock(path, ^(const CGPathElement* _Nonnull element) { + switch (element->type) { + case kCGPathElementMoveToPoint: { + enumBlock(element, currentPoint); + currentPoint = element->points[0]; + break; + } + case kCGPathElementAddLineToPoint: { + enumBlock(element, currentPoint); + currentPoint = element->points[0]; + break; + } + case kCGPathElementAddCurveToPoint: { + enumBlock(element, currentPoint); + currentPoint = element->points[2]; + break; + } + case kCGPathElementAddQuadCurveToPoint: { + enumBlock(element, currentPoint); + currentPoint = element->points[1]; + break; + } + case kCGPathElementCloseSubpath: { + enumBlock(element, currentPoint); + break; + } + } + }); +}; + +- (void)sortAttributesOnElement:(NSXMLElement*)element +{ + const NSArray* order = @[ @"id", @"width", @"height", @"x", @"x1", @"x2", + @"y", @"y1", @"y2", @"cx", @"cy", @"r", @"fill", + @"stroke", @"marker", @"d", @"points", @"transform", + @"gradientTransform", @"xlink:href" ]; + + // grab the attributes + NSArray* attributes = element.attributes; + NSInteger count = attributes.count; + + // sort the attributes using a custom sort + NSArray* sorted = [attributes sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { + // tell compiler we are nodes + NSXMLNode* attribute1 = (NSXMLNode*)obj1; + NSXMLNode* attribute2 = (NSXMLNode*)obj2; + + // base index + float aIndex = count; + float bIndex = count; + + // loop around each order string + for (NSInteger i = 0; i < order.count; i++) { + if ([attribute1.name isEqualToString:order[i]]) { + aIndex = i; + } else if ([attribute1.name rangeOfString:[order[i] stringByAppendingString:@"-"]].location == 0) { + aIndex = i + .5; + } + if ([attribute2.name isEqualToString:order[i]]) { + bIndex = i; + } else if ([attribute2.name rangeOfString:[order[i] stringByAppendingString:@"-"]].location == 0) { + bIndex = i + .5; + } + } + + // return the comparison set + if (aIndex != bIndex) { + if (aIndex > bIndex) { + return NSOrderedDescending; + } else { + return NSOrderedAscending; + } + } + return [attribute1.name compare:attribute2.name]; + }]; + + // remove all attributes + for (NSXMLNode* node in attributes) { + [element removeAttributeForName:node.name]; + } + + // add them back on in order + for (NSXMLNode* attribute in sorted) { + [element addAttribute:attribute]; + } +} + +@end diff --git a/source/IJSVGExporterPathInstruction.h b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporterPathInstruction.h similarity index 67% rename from source/IJSVGExporterPathInstruction.h rename to Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporterPathInstruction.h index e196571..c492378 100644 --- a/source/IJSVGExporterPathInstruction.h +++ b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporterPathInstruction.h @@ -9,24 +9,24 @@ #import @interface IJSVGExporterPathInstruction : NSObject { - + @private NSInteger _dataCount; char _instruction; - CGFloat * _data; + CGFloat* _data; } -+ (NSArray *)instructionsFromPath:(CGPathRef)path; ++ (NSArray*)instructionsFromPath:(CGPathRef)path; - (id)initWithInstruction:(char)instruction dataCount:(NSInteger)floatCount; - (void)setInstruction:(char)newInstruction; - (char)instruction; -- (CGFloat *)data; +- (CGFloat*)data; - (NSInteger)dataLength; -+ (void)convertInstructionsToRelativeCoordinates:(NSArray *)instructions; -+ (NSString *)pathStringFromInstructions:(NSArray *)instructions; ++ (void)convertInstructionsToRelativeCoordinates:(NSArray*)instructions; ++ (NSString*)pathStringFromInstructions:(NSArray*)instructions; @end diff --git a/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporterPathInstruction.m b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporterPathInstruction.m new file mode 100644 index 0000000..5298876 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Exporter/IJSVGExporterPathInstruction.m @@ -0,0 +1,369 @@ +// +// IJSVGExporterPathInstruction.m +// IconJar +// +// Created by Curtis Hard on 08/01/2017. +// Copyright © 2017 Curtis Hard. All rights reserved. +// + +#import "IJSVGExporter.h" +#import "IJSVGExporterPathInstruction.h" + +@implementation IJSVGExporterPathInstruction + +- (void)dealloc +{ + if (_data != NULL) { + free(_data); + } + [super dealloc]; +} + +- (id)initWithInstruction:(char)instruction + dataCount:(NSInteger)floatCount +{ + if ((self = [super init]) != nil) { + _instruction = instruction; + + // only allocate if not zero + if (floatCount != 0) { + _data = (CGFloat*)calloc(sizeof(CGFloat), floatCount); + } + } + return self; +} + +- (NSInteger)dataLength +{ + return _dataCount; +} + +- (void)setInstruction:(char)newInstruction +{ + _instruction = newInstruction; +} + +- (char)instruction +{ + return _instruction; +} + +- (CGFloat*)data +{ + return _data; +} + ++ (NSString*)pathStringFromInstructions:(NSArray*)instructions +{ + NSMutableArray* pathData = [[[NSMutableArray alloc] init] autorelease]; + for (IJSVGExporterPathInstruction* instruction in instructions) { + CGFloat* data = instruction.data; + NSString* str = nil; + switch (instruction.instruction) { + + // move + case 'M': + case 'm': { + char* buffer; + asprintf(&buffer, "%c%g,%g", instruction.instruction, data[0], data[1]); + str = [NSString stringWithCString:buffer + encoding:NSUTF8StringEncoding]; + free(buffer); + [pathData addObject:str]; + break; + } + + // vertical and horizonal line + case 'V': + case 'v': + case 'H': + case 'h': { + char* buffer; + asprintf(&buffer, "%c%g", instruction.instruction, data[0]); + str = [NSString stringWithCString:buffer + encoding:NSUTF8StringEncoding]; + free(buffer); + [pathData addObject:str]; + break; + } + + // line + case 'L': + case 'l': { + char* buffer; + asprintf(&buffer, "%c%g,%g", instruction.instruction, data[0], data[1]); + str = [NSString stringWithCString:buffer + encoding:NSUTF8StringEncoding]; + free(buffer); + [pathData addObject:str]; + break; + } + + // curve + case 'C': + case 'c': { + char* buffer; + asprintf(&buffer, "%c%g,%g %g,%g %g,%g", instruction.instruction, + data[0], data[1], data[2], data[3], data[4], data[5]); + str = [NSString stringWithCString:buffer + encoding:NSUTF8StringEncoding]; + free(buffer); + [pathData addObject:str]; + break; + } + + // quadratic curve + case 'Q': + case 'q': { + char* buffer; + asprintf(&buffer, "%c%g,%g %g,%g", instruction.instruction, + data[0], data[1], data[2], data[3]); + str = [NSString stringWithCString:buffer + encoding:NSUTF8StringEncoding]; + free(buffer); + [pathData addObject:str]; + break; + } + + // close path + case 'Z': + case 'z': { + str = [NSString stringWithFormat:@"%c", instruction.instruction]; + [pathData addObject:str]; + } + } + } + return [pathData componentsJoinedByString:@""]; +} + ++ (void)convertInstructionsToRelativeCoordinates:(NSArray*)instructions +{ + CGFloat point[2] = { 0, 0 }; + CGFloat subpathPoint[2] = { 0, 0 }; + + NSInteger index = 0; + for (IJSVGExporterPathInstruction* anInstruction in instructions) { + char instruction = anInstruction.instruction; + CGFloat* data = anInstruction.data; + NSInteger length = anInstruction.dataLength; + + if (data != NULL) { + + // already relative + if (instruction == 'm' || instruction == 'c' || instruction == 's' || instruction == 'l' || instruction == 'q' || instruction == 't' || instruction == 'a') { + + point[0] += data[length - 2]; + point[1] += data[length - 1]; + + if (instruction == 'm') { + subpathPoint[0] = point[0]; + subpathPoint[1] = point[1]; + } + + } else if (instruction == 'h') { + point[0] += data[0]; + } else if (instruction == 'v') { + point[1] += data[0]; + } + + // convert absolute to relative + if (instruction == 'M') { + if (index > 0) { + instruction = 'm'; + } + + data[0] -= point[0]; + data[1] -= point[1]; + + subpathPoint[0] = point[0] += data[0]; + subpathPoint[1] = point[1] += data[1]; + + } else if (instruction == 'L' || instruction == 'T') { + + instruction = tolower(instruction); + + data[0] -= point[0]; + data[1] -= point[1]; + + point[0] += data[0]; + point[1] += data[1]; + + } else if (instruction == 'C') { + + instruction = 'c'; + + data[0] -= point[0]; + data[1] -= point[1]; + data[2] -= point[0]; + data[3] -= point[1]; + data[4] -= point[0]; + data[5] -= point[1]; + + point[0] += data[4]; + point[1] += data[5]; + + } else if (instruction == 'S' || instruction == 'Q') { + + instruction = tolower(instruction); + + data[0] -= point[0]; + data[1] -= point[1]; + data[2] -= point[0]; + data[3] -= point[1]; + + point[0] += data[2]; + point[1] += data[3]; + + } else if (instruction == 'A') { + + instruction = 'a'; + + data[5] -= point[0]; + data[6] -= point[1]; + + point[0] += data[5]; + point[1] += data[6]; + + } else if (instruction == 'H') { + + instruction = 'h'; + + data[0] -= point[0]; + + point[0] += data[0]; + + } else if (instruction == 'V') { + + instruction = 'v'; + + data[0] -= point[1]; + + point[1] += data[0]; + } + + // reset the instruction + [anInstruction setInstruction:instruction]; + + } else if (instruction == 'Z' || instruction == 'z') { + point[0] = subpathPoint[0]; + point[1] = subpathPoint[1]; + } + + // increment index + index++; + } +} + ++ (NSArray*)instructionsFromPath:(CGPathRef)path +{ + + // keep track of the current point + __block CGPoint currentPoint = CGPointZero; + NSMutableArray* instructions = [[[NSMutableArray alloc] init] autorelease]; + + // create the path callback + IJSVGCGPathHandler callback = ^(const CGPathElement* pathElement) { + IJSVGExporterPathInstruction* instruction = nil; + // work out what to do + switch (pathElement->type) { + + case kCGPathElementMoveToPoint: { + // move to command + instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'M' + dataCount:2] autorelease]; + CGPoint point = pathElement->points[0]; + instruction.data[0] = point.x; + instruction.data[1] = point.y; + currentPoint = point; + + [instructions addObject:instruction]; + break; + } + + case kCGPathElementAddLineToPoint: { + // line to command + CGPoint point = pathElement->points[0]; + if (point.x == currentPoint.x) { + instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'V' + dataCount:1] autorelease]; + instruction.data[0] = point.y; + } else if (point.y == currentPoint.y) { + instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'H' + dataCount:1] autorelease]; + instruction.data[0] = point.x; + } else { + instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'L' + dataCount:2] autorelease]; + instruction.data[0] = point.x; + instruction.data[1] = point.y; + } + currentPoint = point; + + [instructions addObject:instruction]; + break; + } + + case kCGPathElementAddQuadCurveToPoint: { + // quad curve to command + CGPoint controlPoint = pathElement->points[0]; + CGPoint point = pathElement->points[1]; + instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Q' + dataCount:4] autorelease]; + instruction.data[0] = controlPoint.x; + instruction.data[1] = controlPoint.y; + instruction.data[2] = point.x; + instruction.data[3] = point.y; + currentPoint = point; + + [instructions addObject:instruction]; + break; + } + + case kCGPathElementAddCurveToPoint: { + // curve to command + CGPoint controlPoint1 = pathElement->points[0]; + CGPoint controlPoint2 = pathElement->points[1]; + CGPoint point = pathElement->points[2]; + currentPoint = point; + instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'C' + dataCount:6] autorelease]; + instruction.data[0] = controlPoint1.x; + instruction.data[1] = controlPoint1.y; + instruction.data[2] = controlPoint2.x; + instruction.data[3] = controlPoint2.y; + instruction.data[4] = point.x; + instruction.data[5] = point.y; + + [instructions addObject:instruction]; + break; + } + + case kCGPathElementCloseSubpath: { + // close command + instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z' + dataCount:0] autorelease]; + [instructions addObject:instruction]; + break; + } + } + }; + + // apply the + CGPathApply(path, (__bridge void*)callback, IJSVGExporterPathCaller); + + // remove last instruction if it was Z -> M + IJSVGExporterPathInstruction* lastInstruction = instructions.lastObject; + if (lastInstruction.instruction == 'M' || lastInstruction.instruction == 'm') { + if (instructions.count >= 2) { + NSInteger index = [instructions indexOfObject:lastInstruction] - 1; + IJSVGExporterPathInstruction* prevInstruction = instructions[index]; + if (prevInstruction.instruction == 'z' || prevInstruction.instruction == 'Z') { + [instructions removeLastObject]; + } + } + } + + return instructions; +} + +@end diff --git a/source/IJSVGGradientLayer.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGGradientLayer.h similarity index 88% rename from source/IJSVGGradientLayer.h rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGGradientLayer.h index 32d5acc..4a3a23d 100644 --- a/source/IJSVGGradientLayer.h +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGGradientLayer.h @@ -6,17 +6,16 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import #import "IJSVGGradient.h" -#import "IJSVGPath.h" #import "IJSVGLayer.h" +#import "IJSVGPath.h" +#import @interface IJSVGGradientLayer : IJSVGLayer { - } @property (nonatomic, assign) CGRect viewBox; -@property (nonatomic, retain) IJSVGGradient * gradient; +@property (nonatomic, retain) IJSVGGradient* gradient; @property (nonatomic, assign) CGAffineTransform absoluteTransform; @property (nonatomic, assign) CGRect objectRect; diff --git a/source/IJSVGGradientLayer.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGGradientLayer.m similarity index 68% rename from source/IJSVGGradientLayer.m rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGGradientLayer.m index 3a030ab..5bf8358 100644 --- a/source/IJSVGGradientLayer.m +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGGradientLayer.m @@ -17,35 +17,35 @@ @implementation IJSVGGradientLayer - (void)dealloc { - [gradient release], gradient = nil; + (void)([gradient release]), gradient = nil; [super dealloc]; } - (id)init { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { self.requiresBackingScaleHelp = YES; self.shouldRasterize = YES; } return self; } -- (void)setGradient:(IJSVGGradient *)newGradient +- (void)setGradient:(IJSVGGradient*)newGradient { - if(gradient != nil) { - [gradient release], gradient = nil; + if (gradient != nil) { + (void)([gradient release]), gradient = nil; } gradient = [newGradient retain]; - + // lets check its alpha properties on the colors BOOL hasAlphaChannel = NO; NSInteger stops = gradient.gradient.numberOfColorStops; - for(NSInteger i = 0; i < stops; i++) { - NSColor * color = nil; + for (NSInteger i = 0; i < stops; i++) { + NSColor* color = nil; [gradient.gradient getColor:&color location:NULL atIndex:i]; - if(color.alphaComponent != 1.f) { + if (color.alphaComponent != 1.f) { hasAlphaChannel = YES; break; } @@ -55,7 +55,7 @@ - (void)setGradient:(IJSVGGradient *)newGradient - (void)setOpacity:(float)opacity { - if(opacity != 1.f) { + if (opacity != 1.f) { self.opaque = NO; } [super setOpacity:opacity]; @@ -64,17 +64,17 @@ - (void)setOpacity:(float)opacity - (void)setBackingScaleFactor:(CGFloat)backingScaleFactor { switch (self.renderQuality) { - case IJSVGRenderQualityOptimized: { - backingScaleFactor = (backingScaleFactor * .35f); - break; - } - case IJSVGRenderQualityLow: { - backingScaleFactor = (backingScaleFactor * .05f); - break; - } - default: { - break; - } + case kIJSVGRenderQualityOptimized: { + backingScaleFactor = (backingScaleFactor * .35f); + break; + } + case kIJSVGRenderQualityLow: { + backingScaleFactor = (backingScaleFactor * .05f); + break; + } + default: { + break; + } } [super setBackingScaleFactor:backingScaleFactor]; } @@ -82,16 +82,16 @@ - (void)setBackingScaleFactor:(CGFloat)backingScaleFactor - (void)drawInContext:(CGContextRef)ctx { [super drawInContext:ctx]; - + // nothing to do :( - if(self.gradient == nil) { + if (self.gradient == nil) { return; } - + // draw the gradient CGAffineTransform trans = CGAffineTransformMakeTranslation(-CGRectGetMinX(objectRect), - -CGRectGetMinY(objectRect)); - CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform,trans); + -CGRectGetMinY(objectRect)); + CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform, trans); CGContextSaveGState(ctx); [self.gradient drawInContextRef:ctx objectRect:objectRect diff --git a/source/IJSVGGroupLayer.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGGroupLayer.h similarity index 100% rename from source/IJSVGGroupLayer.h rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGGroupLayer.h index bfd2350..6a3fcf3 100644 --- a/source/IJSVGGroupLayer.h +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGGroupLayer.h @@ -6,9 +6,9 @@ // Copyright © 2017 Curtis Hard. All rights reserved. // -#import #import "IJSVGLayer.h" #import "IJSVGShapeLayer.h" +#import @interface IJSVGGroupLayer : IJSVGLayer diff --git a/source/IJSVGGroupLayer.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGGroupLayer.m similarity index 100% rename from source/IJSVGGroupLayer.m rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGGroupLayer.m diff --git a/source/IJSVGImageLayer.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGImageLayer.h similarity index 82% rename from source/IJSVGImageLayer.h rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGImageLayer.h index b60294f..62d7b81 100644 --- a/source/IJSVGImageLayer.h +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGImageLayer.h @@ -6,14 +6,14 @@ // Copyright © 2017 Curtis Hard. All rights reserved. // -#import #import "IJSVGLayer.h" +#import +#import @interface IJSVGImageLayer : IJSVGLayer { - } -- (id)initWithImage:(NSImage *)image; +- (id)initWithImage:(NSImage*)image; - (id)initWithCGImage:(CGImageRef)imageRef; @end diff --git a/source/IJSVGImageLayer.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGImageLayer.m similarity index 88% rename from source/IJSVGImageLayer.m rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGImageLayer.m index c2ae00d..fd616f6 100644 --- a/source/IJSVGImageLayer.m +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGImageLayer.m @@ -10,7 +10,7 @@ @implementation IJSVGImageLayer -- (id)initWithImage:(NSImage *)image +- (id)initWithImage:(NSImage*)image { NSRect rect = (NSRect){ .origin = NSZeroPoint, @@ -24,19 +24,19 @@ - (id)initWithImage:(NSImage *)image - (id)initWithCGImage:(CGImageRef)imageRef { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { // set the contents self.contents = (id)imageRef; - + // make sure we say we need help self.requiresBackingScaleHelp = YES; self.shouldRasterize = YES; - + // set the frame, simple stuff self.frame = (CGRect){ .origin = CGPointZero, .size = CGSizeMake(CGImageGetWidth(imageRef), - CGImageGetHeight(imageRef)) + CGImageGetHeight(imageRef)) }; } return self; diff --git a/source/IJSVGLayer.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGLayer.h similarity index 58% rename from source/IJSVGLayer.h rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGLayer.h index ce0ec79..60627e2 100644 --- a/source/IJSVGLayer.h +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGLayer.h @@ -6,9 +6,9 @@ // Copyright © 2017 Curtis Hard. All rights reserved. // -#import -#import "IJSVGTransaction.h" #import "IJSVGRendering.h" +#import "IJSVGTransaction.h" +#import @class IJSVGShapeLayer; @class IJSVGGradientLayer; @@ -17,16 +17,16 @@ @class IJSVGGroupLayer; @interface IJSVGLayer : CALayer { - + @private - IJSVGLayer * _maskingLayer; + IJSVGLayer* _maskingLayer; } -@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer; -@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer; -@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer; -@property (nonatomic, assign) IJSVGGradientLayer * gradientStrokeLayer; -@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer; +@property (nonatomic, assign) IJSVGGradientLayer* gradientFillLayer; +@property (nonatomic, assign) IJSVGPatternLayer* patternFillLayer; +@property (nonatomic, assign) IJSVGStrokeLayer* strokeLayer; +@property (nonatomic, assign) IJSVGGradientLayer* gradientStrokeLayer; +@property (nonatomic, assign) IJSVGPatternLayer* patternStrokeLayer; @property (nonatomic, assign) BOOL requiresBackingScaleHelp; @property (nonatomic, assign) CGFloat backingScaleFactor; @property (nonatomic, assign) IJSVGRenderQuality renderQuality; @@ -34,12 +34,12 @@ @property (nonatomic, assign) CGPoint absoluteOrigin; @property (nonatomic, assign) BOOL convertMasksToPaths; -+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer; -+ (void)recursivelyWalkLayer:(CALayer *)layer - withBlock:(void (^)(CALayer * layer, BOOL isMask))block; ++ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer; ++ (void)recursivelyWalkLayer:(CALayer*)layer + withBlock:(void (^)(CALayer* layer, BOOL isMask))block; - (void)applySublayerMaskToContext:(CGContextRef)context - forSublayer:(IJSVGLayer *)sublayer + forSublayer:(IJSVGLayer*)sublayer withOffset:(CGPoint)offset; @end diff --git a/Framework/IJSVG/IJSVG/Source/Layers/IJSVGLayer.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGLayer.m new file mode 100644 index 0000000..eadbdc6 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGLayer.m @@ -0,0 +1,169 @@ +// +// IJSVGLayer.m +// IJSVGExample +// +// Created by Curtis Hard on 07/01/2017. +// Copyright © 2017 Curtis Hard. All rights reserved. +// + +#import "IJSVG.h" +#import "IJSVGGroupLayer.h" +#import "IJSVGLayer.h" +#import "IJSVGShapeLayer.h" + +@implementation IJSVGLayer + +@synthesize gradientFillLayer; +@synthesize patternFillLayer; +@synthesize gradientStrokeLayer; +@synthesize patternStrokeLayer; +@synthesize strokeLayer; +@synthesize requiresBackingScaleHelp; +@synthesize backingScaleFactor; +@synthesize blendingMode; +@synthesize convertMasksToPaths; + +- (void)dealloc +{ + (void)([_maskingLayer release]), _maskingLayer = nil; + [super dealloc]; +} + ++ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer +{ + NSMutableArray* arr = [[[NSMutableArray alloc] init] autorelease]; + for (CALayer* subLayer in layer.sublayers) { + if (subLayer.sublayers.count != 0) { + NSArray* moreLayers = [self deepestSublayersOfLayer:(IJSVGLayer*)subLayer]; + [arr addObjectsFromArray:moreLayers]; + } else { + [arr addObject:subLayer]; + } + } + return arr; +} + ++ (void)recursivelyWalkLayer:(CALayer*)layer + withBlock:(void (^)(CALayer* layer, BOOL isMask))block +{ + // call for layer and mask if there is one + block(layer, NO); + + // do the mask too! + if (layer.mask != nil) { + block(layer.mask, YES); + } + + // sublayers!! + for (CALayer* aLayer in layer.sublayers) { + [self recursivelyWalkLayer:aLayer + withBlock:block]; + } +} + +- (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) { + (void)([_maskingLayer release]), _maskingLayer = nil; + } + _maskingLayer = [(IJSVGLayer*)self.mask retain]; + self.mask = nil; + } else { + self.mask = _maskingLayer; + (void)([_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]; +} + +- (id)actionForKey:(NSString*)event +{ + return nil; +} + +@end diff --git a/source/IJSVGPatternLayer.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGPatternLayer.h similarity index 71% rename from source/IJSVGPatternLayer.h rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGPatternLayer.h index 3565fca..e2c8f83 100644 --- a/source/IJSVGPatternLayer.h +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGPatternLayer.h @@ -6,13 +6,13 @@ // Copyright © 2017 Curtis Hard. All rights reserved. // -#import #import "IJSVGLayer.h" #import "IJSVGPattern.h" +#import @interface IJSVGPatternLayer : IJSVGLayer -@property (nonatomic, retain) IJSVGLayer * pattern; -@property (nonatomic, retain) IJSVGPattern * patternNode; +@property (nonatomic, retain) IJSVGLayer* pattern; +@property (nonatomic, retain) IJSVGPattern* patternNode; @end diff --git a/source/IJSVGPatternLayer.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGPatternLayer.m similarity index 55% rename from source/IJSVGPatternLayer.m rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGPatternLayer.m index 15b3cb4..24311eb 100644 --- a/source/IJSVGPatternLayer.m +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGPatternLayer.m @@ -15,50 +15,51 @@ @implementation IJSVGPatternLayer - (void)dealloc { - [pattern release], pattern = nil; - [patternNode release], patternNode = nil; + (void)([pattern release]), pattern = nil; + (void)([patternNode release]), patternNode = nil; [super dealloc]; } - (id)init { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { self.requiresBackingScaleHelp = YES; self.shouldRasterize = YES; } return self; } -void IJSVGPatternDrawingCallBack(void * info, CGContextRef ctx) { +void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx) +{ // reassign the layer - IJSVGPatternLayer * layer = (IJSVGPatternLayer *)info; + IJSVGPatternLayer* layer = (IJSVGPatternLayer*)info; [layer.pattern renderInContext:ctx]; }; - (void)drawInContext:(CGContextRef)ctx { // holder for callback - static const CGPatternCallbacks callbacks = {0, &IJSVGPatternDrawingCallBack, NULL}; - + static const CGPatternCallbacks callbacks = { 0, &IJSVGPatternDrawingCallBack, NULL }; + // create base pattern space CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); CGContextSetFillColorSpace(ctx, patternSpace); CGColorSpaceRelease(patternSpace); - + // create the pattern CGRect rect = self.bounds; - CGPatternRef ref = CGPatternCreate( (void *)self, self.bounds, - CGAffineTransformIdentity, - roundf(rect.size.width*self.patternNode.width.value), - roundf(rect.size.height*self.patternNode.height.value), - kCGPatternTilingConstantSpacing, - true, &callbacks); - + CGPatternRef ref = CGPatternCreate((void*)self, self.bounds, + CGAffineTransformIdentity, + roundf(rect.size.width * self.patternNode.width.value), + roundf(rect.size.height * self.patternNode.height.value), + kCGPatternTilingConstantSpacing, + true, &callbacks); + // set the pattern then release it CGFloat alpha = 1.f; CGContextSetFillPattern(ctx, ref, &alpha); CGPatternRelease(ref); - + // fill it CGContextFillRect(ctx, rect); } diff --git a/Framework/IJSVG/IJSVG/Source/Layers/IJSVGRadialGradient.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGRadialGradient.h new file mode 100644 index 0000000..577a0a3 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGRadialGradient.h @@ -0,0 +1,23 @@ +// +// IJSVGRadialGradient.h +// IJSVGExample +// +// Created by Curtis Hard on 03/09/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGGradient.h" +#import + +@interface IJSVGRadialGradient : IJSVGGradient + +@property (nonatomic, retain) IJSVGUnitLength* cx; +@property (nonatomic, retain) IJSVGUnitLength* cy; +@property (nonatomic, retain) IJSVGUnitLength* fx; +@property (nonatomic, retain) IJSVGUnitLength* fy; +@property (nonatomic, retain) IJSVGUnitLength* radius; + ++ (NSGradient*)parseGradient:(NSXMLElement*)element + gradient:(IJSVGRadialGradient*)gradient; + +@end diff --git a/source/IJSVGRadialGradient.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGRadialGradient.m similarity index 63% rename from source/IJSVGRadialGradient.m rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGRadialGradient.m index e5e8cb8..b414dd3 100644 --- a/source/IJSVGRadialGradient.m +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGRadialGradient.m @@ -18,17 +18,17 @@ @implementation IJSVGRadialGradient - (void)dealloc { - [cx release], cx = nil; - [cy release], cy = nil; - [fx release], fx = nil; - [fy release], fy = nil; - [radius release], radius = nil; + (void)([cx release]), cx = nil; + (void)([cy release]), cy = nil; + (void)([fx release]), fx = nil; + (void)([fy release]), fy = nil; + (void)([radius release]), radius = nil; [super dealloc]; } -- (id)copyWithZone:(NSZone *)zone +- (id)copyWithZone:(NSZone*)zone { - IJSVGRadialGradient * grad = [super copyWithZone:zone]; + IJSVGRadialGradient* grad = [super copyWithZone:zone]; grad.fx = self.fx; grad.fy = self.fy; grad.cx = self.cx; @@ -37,19 +37,18 @@ - (id)copyWithZone:(NSZone *)zone return grad; } - -+ (NSGradient *)parseGradient:(NSXMLElement *)element - gradient:(IJSVGRadialGradient *)gradient ++ (NSGradient*)parseGradient:(NSXMLElement*)element + gradient:(IJSVGRadialGradient*)gradient { // cx defaults to 50% if not specified - NSDictionary * kv = @{@"cx":@"cx", - @"cy":@"cy", - @"r":@"radius"}; - - for(NSString * key in kv.allKeys) { - NSString * str = [element attributeForName:key].stringValue; - IJSVGUnitLength * unit = nil; - if(str != nil) { + NSDictionary* kv = @{ @"cx" : @"cx", + @"cy" : @"cy", + @"r" : @"radius" }; + + for (NSString* key in kv.allKeys) { + NSString* str = [element attributeForName:key].stringValue; + IJSVGUnitLength* unit = nil; + if (str != nil) { unit = [IJSVGUnitLength unitWithString:str fromUnitType:gradient.units]; } else { @@ -59,33 +58,33 @@ + (NSGradient *)parseGradient:(NSXMLElement *)element [gradient setValue:unit forKey:kv[key]]; } - + // fx and fy are the same unless specified otherwise gradient.fx = gradient.cx; gradient.fy = gradient.cy; - + // needs fixing - NSString * fx = [element attributeForName:@"fx"].stringValue; - if(fx != nil) { + NSString* fx = [element attributeForName:@"fx"].stringValue; + if (fx != nil) { gradient.fx = [IJSVGUnitLength unitWithString:fx fromUnitType:gradient.units]; } - - NSString * fy = [element attributeForName:@"fy"].stringValue; - if(fx != nil) { + + NSString* fy = [element attributeForName:@"fy"].stringValue; + if (fx != nil) { gradient.fy = [IJSVGUnitLength unitWithString:fy fromUnitType:gradient.units]; } - - if( gradient.gradient != nil ) { + + if (gradient.gradient != nil) { return nil; } - - NSArray * colors = nil; - CGFloat * colorStops = [self.class computeColorStopsFromString:element colors:&colors]; - NSGradient * ret = [[[NSGradient alloc] initWithColors:colors - atLocations:colorStops - colorSpace:IJSVGColor.defaultColorSpace] autorelease]; + + NSArray* colors = nil; + CGFloat* colorStops = [self.class computeColorStopsFromString:element colors:&colors]; + NSGradient* ret = [[[NSGradient alloc] initWithColors:colors + atLocations:colorStops + colorSpace:IJSVGColor.defaultColorSpace] autorelease]; free(colorStops); return ret; } @@ -100,42 +99,41 @@ - (void)drawInContextRef:(CGContextRef)ctx CGPoint startPoint = CGPointZero; CGPoint gradientStartPoint = CGPointZero; CGPoint gradientEndPoint = CGPointZero; - + // transforms CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms); - + CGRect boundingBox = inUserSpace ? viewBox : objectRect; - + // make sure we apply the absolute position to // transform us back into the correct space - if(inUserSpace == YES) { + if (inUserSpace == YES) { CGContextConcatCTM(ctx, absoluteTransform); } - - + // compute size based on percentages CGFloat x = [self.cx computeValue:CGRectGetWidth(boundingBox)]; CGFloat y = [self.cy computeValue:CGRectGetHeight(boundingBox)]; startPoint = CGPointMake(x, y); CGFloat val = MIN(CGRectGetWidth(boundingBox), - CGRectGetHeight(boundingBox)); + CGRectGetHeight(boundingBox)); radius = [self.radius computeValue:val]; - + CGFloat ex = [self.fx computeValue:CGRectGetWidth(boundingBox)]; CGFloat ey = [self.fy computeValue:CGRectGetHeight(boundingBox)]; - + gradientEndPoint = CGPointMake(ex, ey); gradientStartPoint = startPoint; - + // transform if width or height is not equal - this can only // be done if we are using objectBoundingBox - if(inUserSpace == NO && CGRectGetWidth(boundingBox) != CGRectGetHeight(boundingBox)) { + if (inUserSpace == NO && CGRectGetWidth(boundingBox) != CGRectGetHeight(boundingBox)) { CGAffineTransform tr = CGAffineTransformMakeTranslation(gradientStartPoint.x, - gradientStartPoint.y); - if(CGRectGetWidth(boundingBox) > CGRectGetHeight(boundingBox)) { - tr = CGAffineTransformScale(tr, CGRectGetWidth(boundingBox)/CGRectGetHeight(boundingBox), 1); + gradientStartPoint.y); + if (CGRectGetWidth(boundingBox) > CGRectGetHeight(boundingBox)) { + tr = CGAffineTransformScale(tr, CGRectGetWidth(boundingBox) / CGRectGetHeight(boundingBox), 1); } else { - tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(boundingBox)/CGRectGetWidth(boundingBox)); + tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(boundingBox) / CGRectGetWidth(boundingBox)); } tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y); selfTransform = CGAffineTransformConcat(tr, selfTransform); @@ -145,14 +143,12 @@ - (void)drawInContextRef:(CGContextRef)ctx CGContextConcatCTM(ctx, selfTransform); // draw the gradient - CGGradientDrawingOptions options = - kCGGradientDrawsBeforeStartLocation| - kCGGradientDrawsAfterEndLocation; + CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; CGContextDrawRadialGradient(ctx, self.CGGradient, - gradientEndPoint, 0, - gradientStartPoint, - radius, options); - + gradientEndPoint, 0, + gradientStartPoint, + radius, options); + #ifdef IJSVG_DEBUG_GRADIENTS [self _debugStart:gradientStartPoint end:gradientEndPoint diff --git a/source/IJSVGShapeLayer.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGShapeLayer.h similarity index 62% rename from source/IJSVGShapeLayer.h rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGShapeLayer.h index 7e24054..723a90d 100644 --- a/source/IJSVGShapeLayer.h +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGShapeLayer.h @@ -6,21 +6,21 @@ // Copyright © 2017 Curtis Hard. All rights reserved. // -#import #import "IJSVGLayer.h" #import "IJSVGUtils.h" +#import @interface IJSVGShapeLayer : CAShapeLayer { - + @private - IJSVGLayer * _maskingLayer; + IJSVGLayer* _maskingLayer; } -@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer; -@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer; -@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer; -@property (nonatomic, assign) IJSVGGradientLayer * gradientStrokeLayer; -@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer; +@property (nonatomic, assign) IJSVGGradientLayer* gradientFillLayer; +@property (nonatomic, assign) IJSVGPatternLayer* patternFillLayer; +@property (nonatomic, assign) IJSVGStrokeLayer* strokeLayer; +@property (nonatomic, assign) IJSVGGradientLayer* gradientStrokeLayer; +@property (nonatomic, assign) IJSVGPatternLayer* patternStrokeLayer; @property (nonatomic, assign) BOOL requiresBackingScaleHelp; @property (nonatomic, assign) CGFloat backingScaleFactor; @property (nonatomic, assign) IJSVGRenderQuality renderQuality; @@ -28,9 +28,10 @@ @property (nonatomic, assign) CGPoint absoluteOrigin; @property (nonatomic, assign) CGPoint originalPathOrigin; @property (nonatomic, assign) BOOL convertMasksToPaths; +@property (nonatomic, assign) IJSVGPrimitivePathType primitiveType; - (void)applySublayerMaskToContext:(CGContextRef)context - forSublayer:(IJSVGLayer *)sublayer + forSublayer:(IJSVGLayer*)sublayer withOffset:(CGPoint)offset; @end diff --git a/source/IJSVGShapeLayer.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGShapeLayer.m similarity index 58% rename from source/IJSVGShapeLayer.m rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGShapeLayer.m index fa94790..b3670c9 100644 --- a/source/IJSVGShapeLayer.m +++ b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGShapeLayer.m @@ -6,8 +6,8 @@ // Copyright © 2017 Curtis Hard. All rights reserved. // -#import "IJSVGShapeLayer.h" #import "IJSVGGroupLayer.h" +#import "IJSVGShapeLayer.h" @implementation IJSVGShapeLayer @@ -22,29 +22,17 @@ @implementation IJSVGShapeLayer @synthesize convertMasksToPaths; @synthesize originalPathOrigin; @synthesize renderQuality; +@synthesize primitiveType; - (void)dealloc { - [_maskingLayer release], _maskingLayer = nil; + (void)([_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) { + if (self.backingScaleFactor == newFactor) { return; } backingScaleFactor = newFactor; @@ -55,10 +43,10 @@ - (void)setBackingScaleFactor:(CGFloat)newFactor - (void)_customRenderInContext:(CGContextRef)ctx { - if(self.convertMasksToPaths == YES && _maskingLayer != nil) { + if (self.convertMasksToPaths == YES && _maskingLayer != nil) { CGContextSaveGState(ctx); [self applySublayerMaskToContext:ctx - forSublayer:(IJSVGLayer *)self + forSublayer:(IJSVGLayer*)self withOffset:CGPointZero]; [super renderInContext:ctx]; CGContextRestoreGState(ctx); @@ -69,49 +57,49 @@ - (void)_customRenderInContext:(CGContextRef)ctx - (void)setConvertMasksToPaths:(BOOL)flag { - if(convertMasksToPaths == flag) { + if (convertMasksToPaths == flag) { return; } convertMasksToPaths = flag; - if(flag == YES) { - if(_maskingLayer != nil) { - [_maskingLayer release], _maskingLayer = nil; + if (flag == YES) { + if (_maskingLayer != nil) { + (void)([_maskingLayer release]), _maskingLayer = nil; } - _maskingLayer = [(IJSVGLayer *)self.mask retain]; + _maskingLayer = [(IJSVGLayer*)self.mask retain]; self.mask = nil; } else { self.mask = _maskingLayer; - [_maskingLayer release], _maskingLayer = nil; + (void)([_maskingLayer release]), _maskingLayer = nil; } } - (void)applySublayerMaskToContext:(CGContextRef)context - forSublayer:(IJSVGLayer *)sublayer + forSublayer:(IJSVGLayer*)sublayer withOffset:(CGPoint)offset { // apply any transforms needed CGPoint layerOffset = offset; CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(sublayer.transform); - CGContextConcatCTM( context, CGAffineTransformInvert(sublayerTransform) ); - + CGContextConcatCTM(context, CGAffineTransformInvert(sublayerTransform)); + // walk up the superlayer chain - CALayer * superlayer = self.superlayer; + CALayer* superlayer = self.superlayer; if (IJSVGIsSVGLayer(superlayer) == YES) { - [(IJSVGLayer *)superlayer applySublayerMaskToContext:context - forSublayer:(IJSVGLayer *)self - withOffset:layerOffset]; + [(IJSVGLayer*)superlayer applySublayerMaskToContext:context + forSublayer:(IJSVGLayer*)self + withOffset:layerOffset]; } - + // grab the masking layer - IJSVGShapeLayer * maskingLayer = [self maskingLayer]; - + 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) { + if ([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) { + NSArray* subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer]; + for (IJSVGLayer* subLayer in subs) { [subLayer applySublayerMaskToContext:context - forSublayer:(IJSVGLayer *)self + forSublayer:(IJSVGLayer*)self withOffset:layerOffset]; } } else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) { @@ -125,14 +113,14 @@ - (void)applySublayerMaskToContext:(CGContextRef)context CGContextConcatCTM(context, sublayerTransform); } -- (IJSVGShapeLayer *)maskingLayer +- (IJSVGShapeLayer*)maskingLayer { - return (IJSVGShapeLayer *)_maskingLayer ?: nil; + return (IJSVGShapeLayer*)_maskingLayer ?: nil; } - (void)renderInContext:(CGContextRef)ctx { - if(self.blendingMode != kCGBlendModeNormal) { + if (self.blendingMode != kCGBlendModeNormal) { CGContextSaveGState(ctx); CGContextSetBlendMode(ctx, self.blendingMode); [self _customRenderInContext:ctx]; @@ -145,8 +133,8 @@ - (void)renderInContext:(CGContextRef)ctx - (CGPoint)absoluteOrigin { CGPoint point = CGPointZero; - CALayer * pLayer = self; - while(pLayer != nil) { + CALayer* pLayer = self; + while (pLayer != nil) { point.x += pLayer.frame.origin.x; point.y += pLayer.frame.origin.y; pLayer = pLayer.superlayer; @@ -154,7 +142,7 @@ - (CGPoint)absoluteOrigin return point; } -- (id)actionForKey:(NSString *)event +- (id)actionForKey:(NSString*)event { return nil; } diff --git a/source/IJSVGStrokeLayer.h b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGStrokeLayer.h similarity index 100% rename from source/IJSVGStrokeLayer.h rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGStrokeLayer.h diff --git a/source/IJSVGStrokeLayer.m b/Framework/IJSVG/IJSVG/Source/Layers/IJSVGStrokeLayer.m similarity index 100% rename from source/IJSVGStrokeLayer.m rename to Framework/IJSVG/IJSVG/Source/Layers/IJSVGStrokeLayer.m diff --git a/source/IJSVGDef.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGDef.h similarity index 77% rename from source/IJSVGDef.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGDef.h index b41c4be..04a71a0 100644 --- a/source/IJSVGDef.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGDef.h @@ -6,16 +6,15 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGNode.h" +#import @interface IJSVGDef : IJSVGNode { @private - NSMutableDictionary * _dict; - + NSMutableDictionary* _dict; } -- (void)addDef:(IJSVGNode *)aDef; +- (void)addDef:(IJSVGNode*)aDef; @end diff --git a/source/IJSVGDef.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGDef.m similarity index 70% rename from source/IJSVGDef.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGDef.m index bab5fca..12b8bd8 100644 --- a/source/IJSVGDef.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGDef.m @@ -12,28 +12,28 @@ @implementation IJSVGDef - (void)dealloc { - [_dict release], _dict = nil; + (void)([_dict release]), _dict = nil; [super dealloc]; } - (id)init { - if( ( self = [super initWithDef:NO] ) != nil ) { + if ((self = [super initWithDef:NO]) != nil) { _dict = [[NSMutableDictionary alloc] init]; } return self; } -- (void)addDef:(IJSVGNode *)aDef +- (void)addDef:(IJSVGNode*)aDef { - if( aDef.identifier == nil ) { + if (aDef.identifier == nil) { return; } [_dict setObject:aDef forKey:aDef.identifier]; } -- (IJSVGDef *)defForID:(NSString *)anID +- (IJSVGDef*)defForID:(NSString*)anID { return [_dict objectForKey:anID]; } diff --git a/source/IJSVGForeignObject.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGForeignObject.h similarity index 98% rename from source/IJSVGForeignObject.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGForeignObject.h index 524cf66..59817d9 100644 --- a/source/IJSVGForeignObject.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGForeignObject.h @@ -10,7 +10,7 @@ #import "IJSVGNode.h" @interface IJSVGForeignObject : IJSVGNode { - + NSString * requiredExtension; } diff --git a/source/IJSVGForeignObject.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGForeignObject.m similarity index 81% rename from source/IJSVGForeignObject.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGForeignObject.m index 1b979a6..e04ed46 100644 --- a/source/IJSVGForeignObject.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGForeignObject.m @@ -14,7 +14,7 @@ @implementation IJSVGForeignObject - (void)dealloc { - [requiredExtension release], requiredExtension = nil; + (void)([requiredExtension release]), requiredExtension = nil; [super dealloc]; } diff --git a/source/IJSVGGradient.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGradient.h similarity index 53% rename from source/IJSVGGradient.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGradient.h index 2fc906f..9f32737 100644 --- a/source/IJSVGGradient.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGradient.h @@ -6,23 +6,23 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import +#import "IJSVGColorList.h" #import "IJSVGDef.h" #import "IJSVGTransform.h" -#import "IJSVGColorList.h" +#import @interface IJSVGGradient : IJSVGNode -@property ( nonatomic, retain ) NSGradient * gradient; -@property ( nonatomic, assign ) CGGradientRef CGGradient; -@property ( nonatomic, retain ) IJSVGUnitLength * x1; -@property ( nonatomic, retain ) IJSVGUnitLength * x2; -@property ( nonatomic, retain ) IJSVGUnitLength * y1; -@property ( nonatomic, retain ) IJSVGUnitLength * y2; -@property ( nonatomic, retain) IJSVGColorList * colorList; +@property (nonatomic, retain) NSGradient* gradient; +@property (nonatomic, assign) CGGradientRef CGGradient; +@property (nonatomic, retain) IJSVGUnitLength* x1; +@property (nonatomic, retain) IJSVGUnitLength* x2; +@property (nonatomic, retain) IJSVGUnitLength* y1; +@property (nonatomic, retain) IJSVGUnitLength* y2; +@property (nonatomic, retain) IJSVGColorList* colorList; -+ (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element - colors:(NSArray **)someColors; ++ (CGFloat*)computeColorStopsFromString:(NSXMLElement*)element + colors:(NSArray**)someColors; - (CGGradientRef)CGGradient; - (void)drawInContextRef:(CGContextRef)ctx objectRect:(NSRect)objectRect @@ -33,6 +33,6 @@ end:(CGPoint)endPoint context:(CGContextRef)ctx; -- (IJSVGColorList *)computedColorList; +- (IJSVGColorList*)computedColorList; @end diff --git a/source/IJSVGGradient.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGradient.m similarity index 60% rename from source/IJSVGGradient.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGradient.m index 7b0f9fe..5d01702 100644 --- a/source/IJSVGGradient.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGradient.m @@ -16,78 +16,78 @@ @implementation IJSVGGradient - (void)dealloc { - [x1 release], x1 = nil; - [x2 release], x2 = nil; - [y1 release], y1 = nil; - [y2 release], y2 = nil; - [gradient release], gradient = nil; - [_colorList release], _colorList = nil; - if(CGGradient != nil) { + (void)([x1 release]), x1 = nil; + (void)([x2 release]), x2 = nil; + (void)([y1 release]), y1 = nil; + (void)([y2 release]), y2 = nil; + (void)([gradient release]), gradient = nil; + (void)([_colorList release]), _colorList = nil; + if (CGGradient != nil) { CGGradientRelease(CGGradient); } [super dealloc]; } -- (id)copyWithZone:(NSZone *)zone +- (id)copyWithZone:(NSZone*)zone { - IJSVGGradient * clone = [super copyWithZone:zone]; + IJSVGGradient* clone = [super copyWithZone:zone]; clone.gradient = [[self.gradient copy] autorelease]; return clone; } -- (void)setColorList:(IJSVGColorList *)list +- (void)setColorList:(IJSVGColorList*)list { - [_colorList release], _colorList = nil; + (void)([_colorList release]), _colorList = nil; _colorList = list.retain; - if(CGGradient != nil) { + if (CGGradient != nil) { CGGradientRelease(CGGradient); } } -+ (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element - colors:(NSArray **)someColors ++ (CGFloat*)computeColorStopsFromString:(NSXMLElement*)element + colors:(NSArray**)someColors { // find each stop element - NSArray * stops = [element children]; - NSMutableArray * colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease]; - CGFloat * stopsParams = (CGFloat *)malloc(stops.count*sizeof(CGFloat)); + NSArray* stops = [element children]; + NSMutableArray* colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease]; + CGFloat* stopsParams = (CGFloat*)malloc(stops.count * sizeof(CGFloat)); NSInteger i = 0; - for( NSXMLElement * stop in stops ) { + for (NSXMLElement* stop in stops) { // find the offset CGFloat offset = [stop attributeForName:@"offset"].stringValue.floatValue; - if( offset > 1.f ) { + if (offset > 1.f) { offset /= 100.f; } - + stopsParams[i++] = offset; - + // find the stop opacity CGFloat stopOpacity = 1.f; - NSXMLNode * stopOpacityAttribute = [stop attributeForName:@"stop-opacity"]; - if( stopOpacityAttribute != nil ) { + NSXMLNode* stopOpacityAttribute = [stop attributeForName:@"stop-opacity"]; + if (stopOpacityAttribute != nil) { stopOpacity = stopOpacityAttribute.stringValue.floatValue; } - + // find the stop color - NSString * scs = [stop attributeForName:@"stop-color"].stringValue; - NSColor * stopColor = [IJSVGColor colorFromString:scs]; - if(stopColor != nil && stopOpacity != 1.f) { + NSString* scs = [stop attributeForName:@"stop-color"].stringValue; + NSColor* stopColor = [IJSVGColor colorFromString:scs]; + if (stopColor != nil && stopOpacity != 1.f) { stopColor = [IJSVGColor changeAlphaOnColor:stopColor to:stopOpacity]; } - + // compute any style that there was... - NSXMLNode * styleAttribute = [stop attributeForName:@"style"]; - if( styleAttribute != nil ) { - - IJSVGStyle * style = [IJSVGStyle parseStyleString:styleAttribute.stringValue]; - NSColor * color = [IJSVGColor colorFromString:[style property:@"stop-color"]]; - + NSXMLNode* styleAttribute = [stop attributeForName:@"style"]; + if (styleAttribute != nil) { + + IJSVGStyle* style = [IJSVGStyle parseStyleString:styleAttribute.stringValue]; + NSColor* color = [IJSVGColor colorFromString:[style property:@"stop-color"]]; + // we have a color! - if( color != nil ) { + if (color != nil) { // is there a stop opacity? - NSString * numberString = nil; - if( (numberString = [style property:@"stop-opacity"] ) != nil ) { + NSString* numberString = nil; + if ((numberString = [style property:@"stop-opacity"]) != nil) { color = [IJSVGColor changeAlphaOnColor:color to:numberString.floatValue]; } else { @@ -97,29 +97,29 @@ + (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element stopColor = color; } } - + // default is black - if(stopColor == nil) { + if (stopColor == nil) { stopColor = [IJSVGColor colorFromString:@"black"]; - if(stopOpacity != 1.f) { + if (stopOpacity != 1.f) { stopColor = [IJSVGColor changeAlphaOnColor:stopColor to:stopOpacity]; } } - + // add the stop color - [(NSMutableArray *)colors addObject:stopColor]; + [(NSMutableArray*)colors addObject:stopColor]; } *someColors = colors; return stopsParams; } -- (IJSVGColorList *)computedColorList +- (IJSVGColorList*)computedColorList { - IJSVGColorList * sheet = [[[IJSVGColorList alloc] init] autorelease]; + IJSVGColorList* sheet = [[[IJSVGColorList alloc] init] autorelease]; NSInteger num = self.gradient.numberOfColorStops; - for(NSInteger i = 0; i < num; i++) { - NSColor * color; + for (NSInteger i = 0; i < num; i++) { + NSColor* color; [self.gradient getColor:&color location:nil atIndex:i]; @@ -131,27 +131,27 @@ - (IJSVGColorList *)computedColorList - (CGGradientRef)CGGradient { // store it in the cache - if(CGGradient != nil) { + if (CGGradient != nil) { return CGGradient; } - + // actually create the gradient NSInteger num = self.gradient.numberOfColorStops; - CGFloat * locations = malloc(sizeof(CGFloat)*num); + CGFloat* locations = malloc(sizeof(CGFloat) * num); CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num, - &kCFTypeArrayCallBacks); - for( NSInteger i = 0; i < num; i++ ) { - NSColor * color; + &kCFTypeArrayCallBacks); + for (NSInteger i = 0; i < num; i++) { + NSColor* color; [self.gradient getColor:&color location:&locations[i] atIndex:i]; - if(_colorList != nil) { + if (_colorList != nil) { color = [_colorList proposedColorForColor:color]; } CFArrayAppendValue(colors, color.CGColor); } CGGradientRef result = CGGradientCreateWithColors(self.gradient.colorSpace.CGColorSpace, - colors, locations); + colors, locations); CFRelease(colors); free(locations); return CGGradient = result; diff --git a/source/IJSVGGroup.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGroup.h similarity index 83% rename from source/IJSVGGroup.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGroup.h index 7d67a97..853bd49 100644 --- a/source/IJSVGGroup.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGroup.h @@ -6,18 +6,17 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGNode.h" #import "IJSVGPath.h" +#import @interface IJSVGGroup : IJSVGNode { - - NSMutableArray * children; - + + NSMutableArray* children; } - (void)addChild:(id)child; -- (NSArray *)children; +- (NSArray*)children; - (void)purgeChildren; @end diff --git a/source/IJSVGGroup.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGroup.m similarity index 65% rename from source/IJSVGGroup.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGroup.m index 0cc9592..81cf818 100644 --- a/source/IJSVGGroup.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGGroup.m @@ -12,14 +12,13 @@ @implementation IJSVGGroup - (void)dealloc { - [children release], children = nil; + (void)([children release]), children = nil; [super dealloc]; } - (id)init { - if( ( self = [super init] ) != nil ) - { + if ((self = [super init]) != nil) { children = [[NSMutableArray alloc] init]; } return self; @@ -30,13 +29,12 @@ - (void)prepareFromCopy children = [[NSMutableArray alloc] init]; } -- (id)copyWithZone:(NSZone *)zone +- (id)copyWithZone:(NSZone*)zone { - IJSVGGroup * node = [super copyWithZone:zone]; + IJSVGGroup* node = [super copyWithZone:zone]; [node prepareFromCopy]; - - for( IJSVGNode * childNode in self.children ) - { + + for (IJSVGNode* childNode in self.children) { childNode = [[childNode copy] autorelease]; childNode.parentNode = node; [node addChild:childNode]; @@ -51,18 +49,18 @@ - (void)purgeChildren - (void)addChild:(id)child { - if( child != nil ) + if (child != nil) [children addObject:child]; } -- (NSArray *)children +- (NSArray*)children { return children; } -- (NSString *)description +- (NSString*)description { - return [NSString stringWithFormat:@"%@ - %@",[super description],self.children]; + return [NSString stringWithFormat:@"%@ - %@", [super description], self.children]; } @end diff --git a/source/IJSVGImage.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGImage.h similarity index 68% rename from source/IJSVGImage.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGImage.h index ea8e529..b99c099 100644 --- a/source/IJSVGImage.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGImage.h @@ -6,22 +6,21 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import #import "IJSVGNode.h" +#import @class IJSVGPath; @interface IJSVGImage : IJSVGNode { - - NSImage * image; + + NSImage* image; CGImageRef CGImage; - IJSVGPath * imagePath; - + IJSVGPath* imagePath; } - (CGImageRef)CGImage; - (void)drawInContextRef:(CGContextRef)context - path:(IJSVGPath *)path; -- (void)loadFromBase64EncodedString:(NSString *)encodedString; + path:(IJSVGPath*)path; +- (void)loadFromBase64EncodedString:(NSString*)encodedString; @end diff --git a/source/IJSVGImage.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGImage.m similarity index 66% rename from source/IJSVGImage.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGImage.m index 6b7cb3a..8fdb407 100644 --- a/source/IJSVGImage.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGImage.m @@ -14,36 +14,36 @@ @implementation IJSVGImage - (void)dealloc { - CGImageRelease(CGImage), CGImage = nil; - [imagePath release], imagePath = nil; - [image release], image = nil; + (void)(CGImageRelease(CGImage)), CGImage = nil; + (void)([imagePath release]), imagePath = nil; + (void)([image release]), image = nil; [super dealloc]; } -- (void)loadFromBase64EncodedString:(NSString *)encodedString +- (void)loadFromBase64EncodedString:(NSString*)encodedString { - if([encodedString hasPrefix:@"data:"]) { + if ([encodedString hasPrefix:@"data:"]) { encodedString = [encodedString stringByReplacingOccurrencesOfString:@"\\s+" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, encodedString.length)]; } - NSURL * URL = [NSURL URLWithString:encodedString]; - NSData * data = [NSData dataWithContentsOfURL:URL]; - + NSURL* URL = [NSURL URLWithString:encodedString]; + NSData* data = [NSData dataWithContentsOfURL:URL]; + // no data, just ignore...invalid probably - if(data == nil) { + if (data == nil) { return; } - + // set the image against the container - NSImage * anImage = [[[NSImage alloc] initWithData:data] autorelease]; + NSImage* anImage = [[[NSImage alloc] initWithData:data] autorelease]; [self setImage:anImage]; } -- (IJSVGPath *)path +- (IJSVGPath*)path { - if(imagePath == nil) { + if (imagePath == nil) { // lazy load the path as it might not be needed imagePath = [[IJSVGPath alloc] init]; [imagePath.path appendBezierPathWithRect:NSMakeRect(0.f, 0.f, self.width.value, self.height.value)]; @@ -52,23 +52,23 @@ - (IJSVGPath *)path return imagePath; } -- (void)setImage:(NSImage *)anImage +- (void)setImage:(NSImage*)anImage { - if(image != nil) { - [image release], image = nil; + if (image != nil) { + (void)([image release]), image = nil; } image = [anImage retain]; - - if(CGImage != nil) { + + if (CGImage != nil) { CGImageRelease(CGImage); CGImage = nil; } - - NSRect rect = NSMakeRect( 0.f, 0.f, self.width.value, self.height.value); + + NSRect rect = NSMakeRect(0.f, 0.f, self.width.value, self.height.value); CGImage = [image CGImageForProposedRect:&rect context:nil hints:nil]; - + // be sure to retain (some reason this is required in Xcode 8 beta 5?) CGImageRetain(CGImage); } @@ -79,29 +79,29 @@ - (CGImageRef)CGImage } - (void)drawInContextRef:(CGContextRef)context - path:(IJSVGPath *)path + path:(IJSVGPath*)path { // run the transforms // draw the image - if(self.width.value == 0.f || self.height.value == 0.f) { + if (self.width.value == 0.f || self.height.value == 0.f) { return; } - + // make sure path is set - if(path == nil) { + if (path == nil) { path = [self path]; } - + CGRect rect = path.path.bounds; - CGRect bounds = CGRectMake( 0.f, 0.f, rect.size.width, rect.size.height); - + CGRect bounds = CGRectMake(0.f, 0.f, rect.size.width, rect.size.height); + // save the state of the context CGContextSaveGState(context); { // flip the coordinates - CGContextTranslateCTM(context, rect.origin.x, (rect.origin.y)+rect.size.height); + CGContextTranslateCTM(context, rect.origin.x, (rect.origin.y) + rect.size.height); CGContextScaleCTM(context, 1.f, -1.f); - CGContextDrawImage( context, bounds, CGImage); + CGContextDrawImage(context, bounds, CGImage); } CGContextRestoreGState(context); } diff --git a/source/IJSVGLinearGradient.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGLinearGradient.h similarity index 68% rename from source/IJSVGLinearGradient.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGLinearGradient.h index 5601bd0..eeee22b 100644 --- a/source/IJSVGLinearGradient.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGLinearGradient.h @@ -6,12 +6,12 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGGradient.h" +#import @interface IJSVGLinearGradient : IJSVGGradient -+ (NSGradient *)parseGradient:(NSXMLElement *)element - gradient:(IJSVGLinearGradient *)aGradient; ++ (NSGradient*)parseGradient:(NSXMLElement*)element + gradient:(IJSVGLinearGradient*)aGradient; @end diff --git a/source/IJSVGLinearGradient.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGLinearGradient.m similarity index 61% rename from source/IJSVGLinearGradient.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGLinearGradient.m index ee6432b..75057a4 100644 --- a/source/IJSVGLinearGradient.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGLinearGradient.m @@ -11,29 +11,29 @@ @implementation IJSVGLinearGradient -+ (NSGradient *)parseGradient:(NSXMLElement *)element - gradient:(IJSVGLinearGradient *)aGradient ++ (NSGradient*)parseGradient:(NSXMLElement*)element + gradient:(IJSVGLinearGradient*)aGradient { // just ask unit for the value - NSString * x1 = ([element attributeForName:@"x1"].stringValue ?: @"0"); - NSString * x2 = ([element attributeForName:@"x2"].stringValue ?: @"100%"); - NSString * y1 = ([element attributeForName:@"y1"].stringValue ?: @"0"); - NSString * y2 = ([element attributeForName:@"y2"].stringValue ?: @"0"); + NSString* x1 = ([element attributeForName:@"x1"].stringValue ?: @"0"); + NSString* x2 = ([element attributeForName:@"x2"].stringValue ?: @"100%"); + NSString* y1 = ([element attributeForName:@"y1"].stringValue ?: @"0"); + NSString* y2 = ([element attributeForName:@"y2"].stringValue ?: @"0"); aGradient.x1 = [IJSVGGradientUnitLength unitWithString:x1 fromUnitType:aGradient.units]; aGradient.x2 = [IJSVGGradientUnitLength unitWithString:x2 fromUnitType:aGradient.units]; aGradient.y1 = [IJSVGGradientUnitLength unitWithString:y1 fromUnitType:aGradient.units]; aGradient.y2 = [IJSVGGradientUnitLength unitWithString:y2 fromUnitType:aGradient.units]; // compute the color stops and colours - NSArray * colors = nil; - CGFloat * stopsParams = [self.class computeColorStopsFromString:element - colors:&colors]; - + NSArray* colors = nil; + CGFloat* stopsParams = [self.class computeColorStopsFromString:element + colors:&colors]; + // create the gradient with the colours - NSGradient * grad = [[NSGradient alloc] initWithColors:colors - atLocations:stopsParams - colorSpace:IJSVGColor.defaultColorSpace]; - + NSGradient* grad = [[NSGradient alloc] initWithColors:colors + atLocations:stopsParams + colorSpace:IJSVGColor.defaultColorSpace]; + free(stopsParams); return [grad autorelease]; } @@ -44,38 +44,36 @@ - (void)drawInContextRef:(CGContextRef)ctx viewPort:(CGRect)viewBox { BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse; - + CGPoint gradientStartPoint = CGPointZero; CGPoint gradientEndPoint = CGPointZero; CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms); - + CGRect boundingBox = inUserSpace ? viewBox : objectRect; - + // make sure we apply the absolute position to // transform us back into the correct space - if(inUserSpace == YES) { + if (inUserSpace == YES) { CGContextConcatCTM(ctx, absoluteTransform); } - + CGFloat width = CGRectGetWidth(boundingBox); CGFloat height = CGRectGetHeight(boundingBox); gradientStartPoint = CGPointMake([self.x1 computeValue:width], - [self.y1 computeValue:height]); - + [self.y1 computeValue:height]); + gradientEndPoint = CGPointMake([self.x2 computeValue:width], - [self.y2 computeValue:height]); + [self.y2 computeValue:height]); // transform the context CGContextConcatCTM(ctx, selfTransform); - + // draw the gradient - CGGradientDrawingOptions options = - kCGGradientDrawsBeforeStartLocation| - kCGGradientDrawsAfterEndLocation; - + CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; + CGContextDrawLinearGradient(ctx, self.CGGradient, gradientStartPoint, - gradientEndPoint, options); - + gradientEndPoint, options); + #ifdef IJSVG_DEBUG [self _debugStart:gradientStartPoint end:gradientEndPoint diff --git a/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGNode.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGNode.h new file mode 100644 index 0000000..1cec7b2 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGNode.h @@ -0,0 +1,147 @@ +// +// IJSVGNode.h +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGStyle.h" +#import "IJSVGUnitLength.h" +#import +#import + +@class IJSVG; +@class IJSVGGroup; +@class IJSVGDef; +@class IJSVGGradient; +@class IJSVGGroup; +@class IJSVGPattern; +@class IJSVGTransform; + +typedef NS_ENUM(NSInteger, IJSVGNodeType) { + IJSVGNodeTypeGroup, + IJSVGNodeTypePath, + IJSVGNodeTypeDef, + IJSVGNodeTypePolygon, + IJSVGNodeTypePolyline, + IJSVGNodeTypeRect, + IJSVGNodeTypeLine, + IJSVGNodeTypeCircle, + IJSVGNodeTypeEllipse, + IJSVGNodeTypeUse, + IJSVGNodeTypeLinearGradient, + IJSVGNodeTypeRadialGradient, + IJSVGNodeTypeClipPath, + IJSVGNodeTypeFont, + IJSVGNodeTypeGlyph, + IJSVGNodeTypeMask, + IJSVGNodeTypeImage, + IJSVGNodeTypePattern, + IJSVGNodeTypeSVG, + IJSVGNodeTypeText, + IJSVGNodeTypeTextSpan, + IJSVGNodeTypeStyle, + IJSVGNodeTypeSwitch, + IJSVGNodeTypeNotFound, +}; + +typedef NS_ENUM(NSInteger, IJSVGWindingRule) { + IJSVGWindingRuleNonZero, + IJSVGWindingRuleEvenOdd, + IJSVGWindingRuleInherit +}; + +typedef NS_ENUM(NSInteger, IJSVGLineCapStyle) { + IJSVGLineCapStyleNone, + IJSVGLineCapStyleButt, + IJSVGLineCapStyleRound, + IJSVGLineCapStyleSquare, + IJSVGLineCapStyleInherit +}; + +typedef NS_ENUM(NSInteger, IJSVGLineJoinStyle) { + IJSVGLineJoinStyleNone, + IJSVGLineJoinStyleMiter, + IJSVGLineJoinStyleRound, + IJSVGLineJoinStyleBevel, + IJSVGLineJoinStyleInherit +}; + +typedef NS_OPTIONS(NSInteger, IJSVGFontTraits) { + IJSVGFontTraitNone = 1 << 0, + IJSVGFontTraitBold = 1 << 1, + IJSVGFontTraitItalic = 1 << 2 +}; + +typedef NS_ENUM(NSInteger, IJSVGBlendMode) { + IJSVGBlendModeNormal = kCGBlendModeNormal, + IJSVGBlendModeMultiply = kCGBlendModeMultiply, + IJSVGBlendModeScreen = kCGBlendModeScreen, + IJSVGBlendModeOverlay = kCGBlendModeOverlay, + IJSVGBlendModeDarken = kCGBlendModeDarken, + IJSVGBlendModeLighten = kCGBlendModeLighten, + IJSVGBlendModeColorDodge = kCGBlendModeColorDodge, + IJSVGBlendModeColorBurn = kCGBlendModeColorBurn, + IJSVGBlendModeHardLight = kCGBlendModeHardLight, + IJSVGBlendModeSoftLight = kCGBlendModeSoftLight, + IJSVGBlendModeDifference = kCGBlendModeDifference, + IJSVGBlendModeExclusion = kCGBlendModeExclusion, + IJSVGBlendModeHue = kCGBlendModeHue, + IJSVGBlendModeSaturation = kCGBlendModeSaturation, + IJSVGBlendModeColor = kCGBlendModeColor, + IJSVGBlendModeLuminosity = kCGBlendModeLuminosity +}; + +static CGFloat IJSVGInheritedFloatValue = -99.9999991; + +@interface IJSVGNode : NSObject + +@property (nonatomic, assign) IJSVGNodeType type; +@property (nonatomic, copy) NSString* name; +@property (nonatomic, copy) NSString* className; +@property (nonatomic, retain) NSArray* classNameList; +@property (nonatomic, copy) NSString* unicode; +@property (nonatomic, assign) BOOL shouldRender; +@property (nonatomic, assign) BOOL usesDefaultFillColor; +@property (nonatomic, retain) IJSVGUnitLength* x; +@property (nonatomic, retain) IJSVGUnitLength* y; +@property (nonatomic, retain) IJSVGUnitLength* width; +@property (nonatomic, retain) IJSVGUnitLength* height; +@property (nonatomic, retain) IJSVGUnitLength* opacity; +@property (nonatomic, retain) IJSVGUnitLength* fillOpacity; +@property (nonatomic, retain) IJSVGUnitLength* strokeOpacity; +@property (nonatomic, retain) IJSVGUnitLength* strokeWidth; +@property (nonatomic, retain) NSColor* fillColor; +@property (nonatomic, retain) NSColor* strokeColor; +@property (nonatomic, copy) NSString* identifier; +@property (nonatomic, assign) IJSVGNode* parentNode; +@property (nonatomic, assign) IJSVGNode* intermediateParentNode; +@property (nonatomic, retain) IJSVGGroup* clipPath; +@property (nonatomic, retain) IJSVGGroup* mask; +@property (nonatomic, assign) IJSVGWindingRule windingRule; +@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle; +@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle; +@property (nonatomic, retain) NSArray* transforms; +@property (nonatomic, retain) IJSVGDef* def; +@property (nonatomic, retain) IJSVGGradient* fillGradient; +@property (nonatomic, retain) IJSVGPattern* fillPattern; +@property (nonatomic, retain) IJSVGGradient* strokeGradient; +@property (nonatomic, retain) IJSVGPattern* strokePattern; +@property (nonatomic, assign) CGFloat* strokeDashArray; +@property (nonatomic, assign) NSInteger strokeDashArrayCount; +@property (nonatomic, retain) IJSVGUnitLength* strokeDashOffset; +@property (nonatomic, retain) IJSVG* svg; +@property (nonatomic, assign) IJSVGUnitType contentUnits; +@property (nonatomic, assign) IJSVGUnitType units; +@property (nonatomic, assign) IJSVGBlendMode blendMode; + ++ (IJSVGNodeType)typeForString:(NSString*)string + kind:(NSXMLNodeKind)kind; + +- (void)applyPropertiesFromNode:(IJSVGNode*)node; +- (id)initWithDef:(BOOL)flag; +- (void)addDef:(IJSVGNode*)aDef; +- (IJSVGDef*)defForID:(NSString*)anID; + +@end diff --git a/source/IJSVGNode.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGNode.m similarity index 62% rename from source/IJSVGNode.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGNode.m index 92c9a19..9da800e 100644 --- a/source/IJSVGNode.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGNode.m @@ -6,8 +6,8 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import "IJSVGNode.h" #import "IJSVGDef.h" +#import "IJSVGNode.h" #import "IJSVGUtils.h" @implementation IJSVGNode @@ -54,205 +54,203 @@ @implementation IJSVGNode - (void)dealloc { free(strokeDashArray); - [x release], x = nil; - [y release], y = nil; - [width release], width = nil; - [height release], height = nil; - [opacity release], opacity = nil; - [fillOpacity release], fillOpacity = nil; - [strokeOpacity release], strokeOpacity = nil; - [strokeWidth release], strokeWidth = nil; - [strokeDashOffset release], strokeDashOffset = nil; - [unicode release], unicode = nil; - [fillGradient release], fillGradient = nil; - [strokeGradient release], strokeGradient = nil; - [strokePattern release], strokePattern = nil; - [transforms release], transforms = nil; - [fillColor release], fillColor = nil; - [strokeColor release], strokeColor = nil; - [identifier release], identifier = nil; - [def release], def = nil; - [name release], name = nil; - [className release], className = nil; - [classNameList release], classNameList = nil; - [fillPattern release], fillPattern = nil; - [clipPath release], clipPath = nil; - [svg release], svg = nil; - [mask release], mask = nil; + (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 ++ (IJSVGNodeType)typeForString:(NSString*)string kind:(NSXMLNodeKind)kind { string = [string lowercaseString]; - if([string isEqualToString:@"style"]) + if ([string isEqualToString:@"style"]) return IJSVGNodeTypeStyle; - if([string isEqualToString:@"switch"]) + if ([string isEqualToString:@"switch"]) return IJSVGNodeTypeSwitch; - if( [string isEqualToString:@"defs"] ) + if ([string isEqualToString:@"defs"]) return IJSVGNodeTypeDef; - if( [string isEqualToString:@"g"] ) + if ([string isEqualToString:@"g"]) return IJSVGNodeTypeGroup; - if( [string isEqualToString:@"path"] ) + if ([string isEqualToString:@"path"]) return IJSVGNodeTypePath; - if( [string isEqualToString:@"polygon"] ) + if ([string isEqualToString:@"polygon"]) return IJSVGNodeTypePolygon; - if( [string isEqualToString:@"polyline"] ) + if ([string isEqualToString:@"polyline"]) return IJSVGNodeTypePolyline; - if( [string isEqualToString:@"rect"] ) + if ([string isEqualToString:@"rect"]) return IJSVGNodeTypeRect; - if( [string isEqualToString:@"line"] ) + if ([string isEqualToString:@"line"]) return IJSVGNodeTypeLine; - if( [string isEqualToString:@"circle"] ) + if ([string isEqualToString:@"circle"]) return IJSVGNodeTypeCircle; - if( [string isEqualToString:@"ellipse"] ) + if ([string isEqualToString:@"ellipse"]) return IJSVGNodeTypeEllipse; - if( [string isEqualToString:@"use"] ) + if ([string isEqualToString:@"use"]) return IJSVGNodeTypeUse; - if( [string isEqualToString:@"lineargradient"] ) + if ([string isEqualToString:@"lineargradient"]) return IJSVGNodeTypeLinearGradient; - if( [string isEqualToString:@"radialgradient"] ) + if ([string isEqualToString:@"radialgradient"]) return IJSVGNodeTypeRadialGradient; - if( [string isEqualToString:@"glyph"] ) + if ([string isEqualToString:@"glyph"]) return IJSVGNodeTypeGlyph; - if( [string isEqualToString:@"font"] ) + if ([string isEqualToString:@"font"]) return IJSVGNodeTypeFont; - if( [string isEqualToString:@"clippath"] ) + if ([string isEqualToString:@"clippath"]) return IJSVGNodeTypeClipPath; - if( [string isEqualToString:@"mask"] ) + if ([string isEqualToString:@"mask"]) return IJSVGNodeTypeMask; - if( [string isEqualToString:@"image"] ) + if ([string isEqualToString:@"image"]) return IJSVGNodeTypeImage; - if([string isEqualToString:@"pattern"]) + if ([string isEqualToString:@"pattern"]) return IJSVGNodeTypePattern; - if([string isEqualToString:@"svg"]) + if ([string isEqualToString:@"svg"]) return IJSVGNodeTypeSVG; - if([string isEqualToString:@"text"]) + if ([string isEqualToString:@"text"]) return IJSVGNodeTypeText; - if([string isEqualToString:@"tspan"] || kind == NSXMLTextKind) { + if ([string isEqualToString:@"tspan"] || kind == NSXMLTextKind) { return IJSVGNodeTypeTextSpan; } - + // are we commong HTML? - if so just treat as a group - if(IJSVGIsCommonHTMLElementName(string) == YES) { + if (IJSVGIsCommonHTMLElementName(string) == YES) { return IJSVGNodeTypeGroup; } - + return IJSVGNodeTypeNotFound; } - (id)init { - if( ( self = [self initWithDef:YES] ) != nil ) - { + if ((self = [self initWithDef:YES]) != nil) { self.opacity = [IJSVGUnitLength unitWithFloat:1]; } return self; } -- (void)applyPropertiesFromNode:(IJSVGNode *)node +- (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)); + 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 +- (id)copyWithZone:(NSZone*)zone { - IJSVGNode * node = [self.class allocWithZone:zone]; + IJSVGNode* node = [self.class allocWithZone:zone]; [node applyPropertiesFromNode:self]; return node; } - (id)initWithDef:(BOOL)flag { - if( ( self = [super init] ) != nil ) - { + 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 ) { + + if (flag) { def = [[IJSVGDef alloc] init]; } } return self; } -- (IJSVGDef *)defForID:(NSString *)anID +- (IJSVGDef*)defForID:(NSString*)anID { - IJSVGDef * aDef = nil; - if( (aDef = [def defForID:anID]) != nil ) { + IJSVGDef* aDef = nil; + if ((aDef = [def defForID:anID]) != nil) { return aDef; } - if( parentNode != nil ) { + if (parentNode != nil) { return [parentNode defForID:anID]; } return nil; } -- (void)addDef:(IJSVGNode *)aDef +- (void)addDef:(IJSVGNode*)aDef { [def addDef:aDef]; } @@ -260,7 +258,7 @@ - (void)addDef:(IJSVGNode *)aDef // winding rule can inherit.. - (IJSVGWindingRule)windingRule { - if(windingRule == IJSVGWindingRuleInherit && parentNode != nil) { + if (windingRule == IJSVGWindingRuleInherit && parentNode != nil) { return parentNode.windingRule; } return windingRule; @@ -268,8 +266,8 @@ - (IJSVGWindingRule)windingRule - (IJSVGLineCapStyle)lineCapStyle { - if( lineCapStyle == IJSVGLineCapStyleInherit ) { - if( parentNode != nil ) { + if (lineCapStyle == IJSVGLineCapStyleInherit) { + if (parentNode != nil) { return parentNode.lineCapStyle; } } @@ -278,8 +276,8 @@ - (IJSVGLineCapStyle)lineCapStyle - (IJSVGLineJoinStyle)lineJoinStyle { - if( lineJoinStyle == IJSVGLineJoinStyleInherit ) { - if( parentNode != nil ) { + if (lineJoinStyle == IJSVGLineJoinStyleInherit) { + if (parentNode != nil) { return parentNode.lineJoinStyle; } } @@ -288,9 +286,9 @@ - (IJSVGLineJoinStyle)lineJoinStyle // these are all recursive, so go up the chain // if they dont exist on this specific node -- (IJSVGUnitLength *)opacity +- (IJSVGUnitLength*)opacity { - if(opacity.inherit && parentNode != nil) { + if (opacity.inherit && parentNode != nil) { return parentNode.opacity; } return opacity; @@ -298,9 +296,9 @@ - (IJSVGUnitLength *)opacity // these are all recursive, so go up the chain // if they dont exist on this specific node -- (IJSVGUnitLength *)fillOpacity +- (IJSVGUnitLength*)fillOpacity { - if(fillOpacity.inherit && parentNode != nil) { + if (fillOpacity.inherit && parentNode != nil) { return parentNode.fillOpacity; } return fillOpacity; @@ -308,9 +306,9 @@ - (IJSVGUnitLength *)fillOpacity // these are all recursive, so go up the chain // if they dont exist on this specific node -- (IJSVGUnitLength *)strokeWidth +- (IJSVGUnitLength*)strokeWidth { - if(strokeWidth.inherit && parentNode != nil) { + if (strokeWidth.inherit && parentNode != nil) { return parentNode.strokeWidth; } return strokeWidth; @@ -318,18 +316,18 @@ - (IJSVGUnitLength *)strokeWidth // these are all recursive, so go up the chain // if they dont exist on this specific node -- (NSColor *)strokeColor +- (NSColor*)strokeColor { - if( strokeColor != nil ) + if (strokeColor != nil) return strokeColor; - if( strokeColor == nil && parentNode != nil ) + if (strokeColor == nil && parentNode != nil) return parentNode.strokeColor; return nil; } -- (IJSVGUnitLength *)strokeOpacity +- (IJSVGUnitLength*)strokeOpacity { - if(strokeOpacity.inherit && parentNode != nil) { + if (strokeOpacity.inherit && parentNode != nil) { return parentNode.strokeOpacity; } return strokeOpacity; @@ -337,9 +335,9 @@ - (IJSVGUnitLength *)strokeOpacity // even though the spec explicity states fill color // must be on the path, it can also be on the -- (NSColor *)fillColor +- (NSColor*)fillColor { - if( fillColor == nil && parentNode != nil ) { + if (fillColor == nil && parentNode != nil) { return parentNode.fillColor; } return fillColor; @@ -347,9 +345,9 @@ - (NSColor *)fillColor // these are all recursive, so go up the chain // if they dont exist on this specific node -- (IJSVGGradient *)fillGradient +- (IJSVGGradient*)fillGradient { - if(fillGradient == nil && parentNode != nil) { + if (fillGradient == nil && parentNode != nil) { return parentNode.fillGradient; } return fillGradient; @@ -357,9 +355,9 @@ - (IJSVGGradient *)fillGradient // these are all recursive, so go up the chain // if they dont exist on this specific node -- (IJSVGPattern *)fillPattern +- (IJSVGPattern*)fillPattern { - if(fillPattern == nil && parentNode != nil) { + if (fillPattern == nil && parentNode != nil) { return parentNode.fillPattern; } return fillPattern; @@ -367,9 +365,9 @@ - (IJSVGPattern *)fillPattern // these are all recursive, so go up the chain // if they dont exist on this specific node -- (IJSVGGradient *)strokeGradient +- (IJSVGGradient*)strokeGradient { - if(strokeGradient == nil && parentNode != nil) { + if (strokeGradient == nil && parentNode != nil) { return parentNode.strokeGradient; } return strokeGradient; @@ -377,9 +375,9 @@ - (IJSVGGradient *)strokeGradient // these are all recursive, so go up the chain // if they dont exist on this specific node -- (IJSVGPattern *)strokePattern +- (IJSVGPattern*)strokePattern { - if(strokePattern == nil && parentNode != nil) { + if (strokePattern == nil && parentNode != nil) { return parentNode.strokePattern; } return strokePattern; diff --git a/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPath.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPath.h new file mode 100644 index 0000000..96de73b --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPath.h @@ -0,0 +1,44 @@ +// +// IJSVGPath.h +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGBezierPathAdditions.h" +#import "IJSVGNode.h" +#import + +@class IJSVGGroup; + +typedef NS_ENUM(NSInteger, IJSVGPrimitivePathType) { + IJSVGPrimitivePathTypePath, + IJSVGPrimitivePathTypeRect, + IJSVGPrimitivePathTypePolygon, + IJSVGPrimitivePathTypePolyLine, + IJSVGPrimitivePathTypeCircle, + IJSVGPrimitivePathTypeEllipse, + IJSVGPrimitivePathTypeLine +}; + +@interface IJSVGPath : IJSVGNode { + + NSBezierPath* path; + NSBezierPath* subpath; + CGPoint lastControlPoint; +} + +@property (nonatomic, assign) IJSVGPrimitivePathType primitiveType; +@property (nonatomic, readonly) NSBezierPath* path; +@property (nonatomic, readonly) NSBezierPath* subpath; +@property (nonatomic, assign) CGPoint lastControlPoint; +@property (nonatomic, readonly) CGPathRef CGPath; + +- (NSBezierPath*)currentSubpath; +- (void)close; +- (NSPoint)currentPoint; +- (void)overwritePath:(NSBezierPath*)aPath; +- (CGPathRef)newPathRefByAutoClosingPath:(BOOL)autoClose; + +@end diff --git a/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPath.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPath.m new file mode 100644 index 0000000..1318d6f --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPath.m @@ -0,0 +1,140 @@ +// +// IJSVGPath.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGGroup.h" +#import "IJSVGPath.h" + +@implementation IJSVGPath + +@synthesize path; +@synthesize subpath; +@synthesize lastControlPoint; +@synthesize CGPath = _CGPath; +@synthesize primitiveType = _primitiveType; + +- (void)dealloc +{ + if(_CGPath != nil) { + CGPathRelease(_CGPath); + _CGPath = nil; + } + if (subpath != nil) { + (void)([subpath release]), subpath = nil; + } + [super dealloc]; +} + +- (id)init +{ + if ((self = [super init]) != nil) { + _primitiveType = IJSVGPrimitivePathTypePath; + subpath = NSBezierPath.bezierPath.retain; + path = subpath; // for legacy use + } + return self; +} + +- (id)copyWithZone:(NSZone*)zone +{ + IJSVGPath* node = [super copyWithZone:zone]; + [node overwritePath:self.path]; + return node; +} + +- (NSPoint)currentPoint +{ + return [subpath currentPoint]; +} + +- (NSBezierPath*)currentSubpath +{ + return subpath; +} + +- (void)close +{ + [subpath closePath]; +} + +- (CGPathRef)CGPath +{ + if(_CGPath == nil) { + _CGPath = [self newPathRefByAutoClosingPath:NO]; + } + return _CGPath; +} + +- (void)overwritePath:(NSBezierPath*)aPath +{ + (void)([subpath release]), subpath = nil; + subpath = [aPath retain]; + path = subpath; +} + +- (CGPathRef)newPathRefByAutoClosingPath:(BOOL)autoClose +{ + NSInteger i = 0; + NSInteger numElements = self.path.elementCount; + NSBezierPath* bezPath = self.path; + + // nothing to return + if (numElements == 0) { + return NULL; + } + + CGMutablePathRef aPath = CGPathCreateMutable(); + + NSPoint points[3]; + BOOL didClosePath = YES; + + for (i = 0; i < numElements; i++) { + switch ([bezPath elementAtIndex:i associatedPoints:points]) { + + // move + case NSMoveToBezierPathElement: { + CGPathMoveToPoint(aPath, NULL, points[0].x, points[0].y); + break; + } + + // line + case NSLineToBezierPathElement: { + CGPathAddLineToPoint(aPath, NULL, points[0].x, points[0].y); + didClosePath = NO; + break; + } + + // curve + case NSCurveToBezierPathElement: { + CGPathAddCurveToPoint(aPath, NULL, points[0].x, points[0].y, + points[1].x, points[1].y, + points[2].x, points[2].y); + didClosePath = NO; + break; + } + + // close + case NSClosePathBezierPathElement: { + CGPathCloseSubpath(aPath); + didClosePath = YES; + break; + } + } + } + + if (!didClosePath && autoClose) { + CGPathCloseSubpath(aPath); + } + + // create immutable and release + CGPathRef pathToReturn = CGPathCreateCopy(aPath); + CGPathRelease(aPath); + + return pathToReturn; +} + +@end diff --git a/source/IJSVGPattern.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPattern.h similarity index 98% rename from source/IJSVGPattern.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPattern.h index dca6aeb..6291a24 100644 --- a/source/IJSVGPattern.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPattern.h @@ -6,12 +6,11 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import #import "IJSVGGroup.h" #import "IJSVGImage.h" +#import @interface IJSVGPattern : IJSVGGroup { - } @end diff --git a/source/IJSVGPattern.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPattern.m similarity index 100% rename from source/IJSVGPattern.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGPattern.m diff --git a/source/IJSVGText.h b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGText.h similarity index 73% rename from source/IJSVGText.h rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGText.h index 39ea14a..bd58ca2 100644 --- a/source/IJSVGText.h +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGText.h @@ -9,11 +9,10 @@ #import "IJSVGGroup.h" @interface IJSVGText : IJSVGGroup { - - NSString * text; - + + NSString* text; } -@property (nonatomic, copy) NSString * text; +@property (nonatomic, copy) NSString* text; @end diff --git a/source/IJSVGText.m b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGText.m similarity index 70% rename from source/IJSVGText.m rename to Framework/IJSVG/IJSVG/Source/Nodes/IJSVGText.m index be56aed..2beb68e 100644 --- a/source/IJSVGText.m +++ b/Framework/IJSVG/IJSVG/Source/Nodes/IJSVGText.m @@ -14,13 +14,13 @@ @implementation IJSVGText - (void)dealloc { - [text release], text = nil; + (void)([text release]), text = nil; [super dealloc]; } -- (IJSVGText *)copyWithZone:(NSZone *)zone +- (IJSVGText*)copyWithZone:(NSZone*)zone { - IJSVGText * node = [super copyWithZone:zone]; + IJSVGText* node = [super copyWithZone:zone]; node.text = self.text; return node; } diff --git a/Framework/IJSVG/IJSVG/Source/Parsing/IJSVGParser.h b/Framework/IJSVG/IJSVG/Source/Parsing/IJSVGParser.h new file mode 100644 index 0000000..612b293 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Parsing/IJSVGParser.h @@ -0,0 +1,131 @@ +// +// IJSVGParser.h +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGColor.h" +#import "IJSVGCommand.h" +#import "IJSVGDef.h" +#import "IJSVGError.h" +#import "IJSVGForeignObject.h" +#import "IJSVGGroup.h" +#import "IJSVGImage.h" +#import "IJSVGLinearGradient.h" +#import "IJSVGPath.h" +#import "IJSVGPattern.h" +#import "IJSVGRadialGradient.h" +#import "IJSVGStyleSheet.h" +#import "IJSVGText.h" +#import "IJSVGTransform.h" +#import "IJSVGUtils.h" +#import +#import + +static NSString const* IJSVGAttributeViewBox = @"viewBox"; +static NSString const* IJSVGAttributeID = @"id"; +static NSString const* IJSVGAttributeClass = @"class"; +static NSString const* IJSVGAttributeX = @"x"; +static NSString const* IJSVGAttributeY = @"y"; +static NSString const* IJSVGAttributeWidth = @"width"; +static NSString const* IJSVGAttributeHeight = @"height"; +static NSString const* IJSVGAttributeOpacity = @"opacity"; +static NSString const* IJSVGAttributeStrokeOpacity = @"stroke-opacity"; +static NSString const* IJSVGAttributeStrokeWidth = @"stroke-width"; +static NSString const* IJSVGAttributeStrokeDashOffset = @"stroke-dashoffset"; +static NSString const* IJSVGAttributeFillOpacity = @"fill-opacity"; +static NSString const* IJSVGAttributeClipPath = @"clip-path"; +static NSString const* IJSVGAttributeMask = @"mask"; +static NSString const* IJSVGAttributeGradientUnits = @"gradientUnits"; +static NSString const* IJSVGAttributeMaskUnits = @"maskUnits"; +static NSString const* IJSVGAttributeMaskContentUnits = @"maskContentUnits"; +static NSString const* IJSVGAttributeTransform = @"transform"; +static NSString const* IJSVGAttributeGradientTransform = @"gradientTransform"; +static NSString const* IJSVGAttributeUnicode = @"unicode"; +static NSString const* IJSVGAttributeStrokeLineCap = @"stroke-linecap"; +static NSString const* IJSVGAttributeLineJoin = @"stroke-linejoin"; +static NSString const* IJSVGAttributeStroke = @"stroke"; +static NSString const* IJSVGAttributeStrokeDashArray = @"stroke-dasharray"; +static NSString const* IJSVGAttributeFill = @"fill"; +static NSString const* IJSVGAttributeFillRule = @"fill-rule"; +static NSString const* IJSVGAttributeBlendMode = @"mix-blend-mode"; +static NSString const* IJSVGAttributeDisplay = @"display"; +static NSString const* IJSVGAttributeStyle = @"style"; +static NSString const* IJSVGAttributeD = @"d"; +static NSString const* IJSVGAttributeXLink = @"xlink:href"; +static NSString const* IJSVGAttributeX1 = @"x1"; +static NSString const* IJSVGAttributeX2 = @"x2"; +static NSString const* IJSVGAttributeY1 = @"y1"; +static NSString const* IJSVGAttributeY2 = @"y2"; +static NSString const* IJSVGAttributeRX = @"rx"; +static NSString const* IJSVGAttributeRY = @"ry"; +static NSString const* IJSVGAttributeCX = @"cx"; +static NSString const* IJSVGAttributeCY = @"cy"; +static NSString const* IJSVGAttributeR = @"r"; +static NSString const* IJSVGAttributePoints = @"points"; + +@class IJSVGParser; + +@protocol IJSVGParserDelegate + +@optional +- (BOOL)svgParser:(IJSVGParser*)svg + shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject; +- (void)svgParser:(IJSVGParser*)svg + handleForeignObject:(IJSVGForeignObject*)foreignObject + document:(NSXMLDocument*)document; +- (void)svgParser:(IJSVGParser*)svg + foundSubSVG:(IJSVG*)subSVG + withSVGString:(NSString*)string; + +@end + +@interface IJSVGParser : IJSVGGroup { + + NSRect viewBox; + NSSize proposedViewSize; + +@private + id _delegate; + NSXMLDocument* _document; + NSMutableArray* _glyphs; + IJSVGStyleSheet* _styleSheet; + NSMutableArray* _parsedNodes; + NSMutableDictionary* _defNodes; + NSMutableDictionary* _baseDefNodes; + NSMutableArray* _svgs; + NSMutableArray* _definedGroups; + + struct { + unsigned int shouldHandleForeignObject : 1; + unsigned int handleForeignObject : 1; + unsigned int handleSubSVG : 1; + } _respondsTo; +} + +@property (nonatomic, readonly) NSRect viewBox; +@property (nonatomic, readonly) NSSize proposedViewSize; + ++ (BOOL)isDataSVG:(NSData*)data; + +- (id)initWithSVGString:(NSString*)string + error:(NSError**)error + delegate:(id)delegate; + +- (id)initWithFileURL:(NSURL*)aURL + error:(NSError**)error + delegate:(id)delegate; ++ (IJSVGParser*)groupForFileURL:(NSURL*)aURL; ++ (IJSVGParser*)groupForFileURL:(NSURL*)aURL + delegate:(id)delegate; ++ (IJSVGParser*)groupForFileURL:(NSURL*)aURL + error:(NSError**)error + delegate:(id)delegate; +- (NSSize)size; +- (BOOL)isFont; +- (NSArray*)glyphs; +- (NSArray*)subSVGs:(BOOL)recursive; + +@end diff --git a/Framework/IJSVG/IJSVG/Source/Parsing/IJSVGParser.m b/Framework/IJSVG/IJSVG/Source/Parsing/IJSVGParser.m new file mode 100644 index 0000000..dc3be4a --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Parsing/IJSVGParser.m @@ -0,0 +1,1320 @@ +// +// IJSVGParser.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVG.h" +#import "IJSVGParser.h" + +@implementation IJSVGParser + +@synthesize viewBox; +@synthesize proposedViewSize; + ++ (IJSVGParser*)groupForFileURL:(NSURL*)aURL +{ + return [self.class groupForFileURL:aURL + error:nil + delegate:nil]; +} + ++ (IJSVGParser*)groupForFileURL:(NSURL*)aURL + delegate:(id)delegate +{ + return [self.class groupForFileURL:aURL + error:nil + delegate:delegate]; +} + ++ (IJSVGParser*)groupForFileURL:(NSURL*)aURL + error:(NSError**)error + delegate:(id)delegate +{ + return [[[self.class alloc] initWithFileURL:aURL + error:error + delegate:delegate] autorelease]; +} + +- (void)dealloc +{ + (void)([_glyphs release]), _glyphs = nil; + (void)([_styleSheet release]), _styleSheet = nil; + (void)([_parsedNodes release]), _parsedNodes = nil; + (void)([_defNodes release]), _defNodes = nil; + (void)([_baseDefNodes release]), _baseDefNodes = nil; + (void)([_definedGroups release]), _definedGroups = nil; + (void)([_svgs release]), _svgs = nil; + [super dealloc]; +} + +- (id)initWithSVGString:(NSString*)string + error:(NSError**)error + delegate:(id)delegate +{ + if ((self = [super init]) != nil) { + _delegate = delegate; + + _respondsTo.handleForeignObject = [_delegate respondsToSelector:@selector(svgParser:handleForeignObject:document:)]; + _respondsTo.shouldHandleForeignObject = [_delegate respondsToSelector:@selector(svgParser:shouldHandleForeignObject:)]; + _respondsTo.handleSubSVG = [_delegate respondsToSelector:@selector(svgParser:foundSubSVG:withSVGString:)]; + + _glyphs = [[NSMutableArray alloc] init]; + _parsedNodes = [[NSMutableArray alloc] init]; + _defNodes = [[NSMutableDictionary alloc] init]; + _baseDefNodes = [[NSMutableDictionary alloc] init]; + _svgs = [[NSMutableArray alloc] init]; + + // load the document / file, assume its UTF8 + + // use NSXMLDocument as its the easiest thing to do on OSX + NSError* anError = nil; + @try { + _document = [[NSXMLDocument alloc] initWithXMLString:string + options:0 + error:&anError]; + } + @catch (NSException* exception) { + } + + // error parsing the XML document + if (anError != nil) { + return [self _handleErrorWithCode:IJSVGErrorParsingFile + error:error]; + } + + // attempt to parse the file + anError = nil; + @try { + [self _parse]; + } + @catch (NSException* exception) { + return [self _handleErrorWithCode:IJSVGErrorParsingSVG + error:error]; + } + + // check the actual parsed SVG + anError = nil; + if (![self _validateParse:&anError]) { + *error = anError; + (void)([_document release]), _document = nil; + (void)([self release]), self = nil; + return nil; + } + + // we have actually finished with the document at this point + // so just get rid of it + (void)([_document release]), _document = nil; + } + return self; +} + ++ (BOOL)isDataSVG:(NSData*)data +{ + @try { + NSError* error; + NSXMLDocument* doc = [[[NSXMLDocument alloc] initWithData:data + options:0 + error:&error] autorelease]; + return doc != nil && error == nil; + } @catch (NSException* exception) { + } + return NO; +} + +- (id)initWithFileURL:(NSURL*)aURL + error:(NSError**)error + delegate:(id)delegate +{ + NSError* anError = nil; + NSStringEncoding encoding; + NSString* str = [NSString stringWithContentsOfFile:aURL.path + usedEncoding:&encoding + error:&anError]; + + // error reading file + if (str == nil) { + return [self _handleErrorWithCode:IJSVGErrorReadingFile + error:error]; + } + + return [self initWithSVGString:str + error:error + delegate:delegate]; +} + +- (void*)_handleErrorWithCode:(NSUInteger)code + error:(NSError**)error +{ + if (error) { + *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain + code:code + userInfo:nil] autorelease]; + } + (void)([_document release]), _document = nil; + (void)([self release]), self = nil; + return nil; +} + +- (BOOL)_validateParse:(NSError**)error +{ + // check is font + if (self.isFont) + return YES; + + // check the viewbox + if (NSEqualRects(self.viewBox, NSZeroRect) || self.size.width == 0 || self.size.height == 0) { + if (error != NULL) { + *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain + code:IJSVGErrorInvalidViewBox + userInfo:nil] autorelease]; + } + return NO; + } + return YES; +} + +- (NSSize)size +{ + return viewBox.size; +} + +- (void)_parse +{ + NSXMLElement* svgElement = [_document rootElement]; + + // parse common attributes on the SVG element + [self _parseElementForCommonAttributes:svgElement + node:self + ignoreAttributes:nil]; + + // find the sizebox! + NSXMLNode* attribute = nil; + if ((attribute = [svgElement attributeForName:(NSString*)IJSVGAttributeViewBox]) != nil) { + // we have a viewbox... + CGFloat* box = [IJSVGUtils parseViewBox:[attribute stringValue]]; + viewBox = NSMakeRect(box[0], box[1], box[2], box[3]); + free(box); + } else { + // there is no view box so find the width and height + CGFloat w = [svgElement attributeForName:(NSString*)IJSVGAttributeWidth].stringValue.floatValue; + CGFloat h = [svgElement attributeForName:(NSString*)IJSVGAttributeHeight].stringValue.floatValue; + if (h == 0.f && w != 0.f) { + h = w; + } else if (w == 0.f && h != 0.f) { + w = h; + } + viewBox = NSMakeRect(0.f, 0.f, w, h); + } + + // parse the width and height.... + CGFloat w = [svgElement attributeForName:(NSString*)IJSVGAttributeWidth].stringValue.floatValue; + CGFloat h = [svgElement attributeForName:(NSString*)IJSVGAttributeHeight].stringValue.floatValue; + if (w == 0.f && h == 0.f) { + w = viewBox.size.width; + h = viewBox.size.height; + } else if (w == 0 && h != 0.f) { + w = viewBox.size.width; + } else if (h == 0 && w != 0.f) { + h = viewBox.size.height; + } + proposedViewSize = NSMakeSize(w, h); + + // the root element is SVG, so iterate over its children + // recursively + self.name = svgElement.name; + [self _parseBlock:svgElement + intoGroup:self + def:NO]; + + // now everything has been done we need to compute the style tree + for (NSDictionary* dict in _parsedNodes) { + [self _postParseElementForCommonAttributes:dict[@"element"] + node:dict[@"node"] + ignoreAttributes:nil]; + } + + // dont need the style sheet or the parsed nodes as this point + (void)([_styleSheet release]), _styleSheet = nil; + (void)([_parsedNodes release]), _parsedNodes = nil; + (void)([_defNodes release]), _defNodes = nil; +} + +- (void)_postParseElementForCommonAttributes:(NSXMLElement*)element + node:(IJSVGNode*)node + ignoreAttributes:(NSArray*)ignoredAttributes +{ + + // first of all, compute a style sheet + IJSVGStyle* sheetStyle = nil; + __block IJSVGStyle* style = nil; + + // attribute helpers + typedef void (^cp)(NSString*); + + // precaching the attributes is alot faster then asking for attribute for + // name each time we want to grab a value ... weird + NSArray* origAttributes = element.attributes; + NSMutableDictionary* attributes = nil; + attributes = [[[NSMutableDictionary alloc] initWithCapacity:origAttributes.count] autorelease]; + for (NSXMLNode* node in origAttributes) { + attributes[node.name] = node.stringValue; + } + + void (^attr)(const NSString*, cp) = ^(NSString* key, cp block) { + if ([ignoredAttributes containsObject:key]) { + return; + } + NSString* v = [style property:key] ?: attributes[key]; + if (v != nil && v.length != 0) { + block(v); + } + }; + + typedef id (^cap)(NSString*); + void (^atts)(NSDictionary*, cap) = ^(NSDictionary* kv, cap block) { + for (NSString* key in kv.allKeys) { + attr(key, ^(NSString* value) { + [node setValue:block(value) + forKey:kv[key]]; + }); + } + }; + + // id, this must be here for the style sheet to actually + // render and parse, basically it relies on ID/CSS selectors so these + // must be in place before its computed + attr(IJSVGAttributeID, ^(NSString* value) { + node.identifier = value; + _defNodes[node.identifier] = element; + }); + + // + attr(IJSVGAttributeClass, ^(NSString* value) { + node.className = value; + node.classNameList = [value componentsSeparatedByString:@" "]; + }); + + // work out the style sheet + if (_styleSheet != nil) { + sheetStyle = [_styleSheet styleForNode:node]; + } + + // is there a + attr(IJSVGAttributeStyle, ^(NSString* value) { + style = [IJSVGStyle parseStyleString:value]; + }); + + // merge to two together + if (sheetStyle != nil) { + style = [sheetStyle mergedStyle:style]; + } + + // floats + atts(@{ (NSString*)IJSVGAttributeX : @"x", + (NSString*)IJSVGAttributeY : @"y", + (NSString*)IJSVGAttributeWidth : @"width", + (NSString*)IJSVGAttributeHeight : @"height", + (NSString*)IJSVGAttributeOpacity : @"opacity", + (NSString*)IJSVGAttributeStrokeOpacity : @"strokeOpacity", + (NSString*)IJSVGAttributeStrokeWidth : @"strokeWidth", + (NSString*)IJSVGAttributeStrokeDashOffset : @"strokeDashOffset", + (NSString*)IJSVGAttributeFillOpacity : @"fillOpacity" }, + ^id(NSString* value) { + return [IJSVGUnitLength unitWithString:value]; + }); + + // nodes + atts(@{ (NSString*)IJSVGAttributeClipPath : @"clipPath", + (NSString*)IJSVGAttributeMask : @"mask" }, + ^id(NSString* value) { + NSString* url = [IJSVGUtils defURL:value]; + if (url != nil) { + return [self definedObjectForID:url]; + } + return nil; + }); + + // units + atts(@{ (NSString*)IJSVGAttributeGradientUnits : @"units", + (NSString*)IJSVGAttributeMaskUnits : @"units", + (NSString*)IJSVGAttributeMaskContentUnits : @"contentUnits" }, + ^id(NSString* value) { + return @([IJSVGUtils unitTypeForString:value]); + }); + + // transforms + atts(@{ (NSString*)IJSVGAttributeTransform : @"transforms", + (NSString*)IJSVGAttributeGradientTransform : @"transforms" }, + ^(NSString* value) { + NSMutableArray* tempTransforms = [[[NSMutableArray alloc] init] autorelease]; + [tempTransforms addObjectsFromArray:[IJSVGTransform transformsForString:value]]; + if (node.transforms != nil) { + [tempTransforms addObjectsFromArray:node.transforms]; + } + return tempTransforms; + }); + +#pragma mark attributes that require custom rules + + // unicode + attr(IJSVGAttributeUnicode, ^(NSString* value) { + node.unicode = [NSString stringWithFormat:@"%04x", [value characterAtIndex:0]]; + }); + + // linecap + attr(IJSVGAttributeStrokeLineCap, ^(NSString* value) { + node.lineCapStyle = [IJSVGUtils lineCapStyleForString:value]; + }); + + // line join + attr(IJSVGAttributeLineJoin, ^(NSString* value) { + node.lineJoinStyle = [IJSVGUtils lineJoinStyleForString:value]; + }); + + // stroke color + attr(IJSVGAttributeStroke, ^(NSString* value) { + NSString* fillDefID = [IJSVGUtils defURL:value]; + if (fillDefID != nil) { + // find the object + id obj = [self definedObjectForID:fillDefID]; + + // what type is it? + if ([obj isKindOfClass:[IJSVGGradient class]]) { + node.strokeGradient = (IJSVGGradient*)obj; + } else if ([obj isKindOfClass:[IJSVGPattern class]]) { + node.strokePattern = (IJSVGPattern*)obj; + } + } else { + // its a color + node.strokeColor = [IJSVGColor colorFromString:value]; + } + + }); + + // stroke dash array + attr(IJSVGAttributeStrokeDashArray, ^(NSString* value) { + // nothing specified + if ([value isEqualToString:@"none"]) { + node.strokeDashArrayCount = 0; + return; + } + NSInteger paramCount = 0; + CGFloat* params = [IJSVGUtils commandParameters:value + count:¶mCount]; + node.strokeDashArray = params; + node.strokeDashArrayCount = paramCount; + }); + + // fill - seems kinda complicated for what it actually is + attr(IJSVGAttributeFill, ^(NSString* value) { + NSString* fillDefID = [IJSVGUtils defURL:value]; + if (fillDefID != nil) { + // find the object + id obj = [self definedObjectForID:fillDefID]; + + // what type is it? + if ([obj isKindOfClass:[IJSVGGradient class]]) { + node.fillGradient = (IJSVGGradient*)obj; + } else if ([obj isKindOfClass:[IJSVGPattern class]]) { + node.fillPattern = (IJSVGPattern*)obj; + } + } else { + node.fillColor = [IJSVGColor colorFromString:value]; + } + }); + + // fill opacity + attr(IJSVGAttributeFillOpacity, ^(NSString* value) { + if (node.fillOpacity.value != 1.f) { + node.fillColor = [IJSVGColor changeAlphaOnColor:node.fillColor + to:node.fillOpacity.value]; + } + }); + + // blendmode + attr(IJSVGAttributeBlendMode, ^(NSString* value) { + node.blendMode = [IJSVGUtils blendModeForString:value]; + }); + + // fill rule + attr(IJSVGAttributeFillRule, ^(NSString* value) { + node.windingRule = [IJSVGUtils windingRuleForString:value]; + }); + + // display + attr(IJSVGAttributeDisplay, ^(NSString* value) { + if ([value.lowercaseString isEqualToString:@"none"]) { + node.shouldRender = NO; + } + }); +} + +- (id)definedObjectForID:(NSString*)anID + xmlElement:(NSXMLElement**)element +{ + // check base def nodes first, then check rest of document + NSXMLElement* parseElement = _baseDefNodes[anID] ?: _defNodes[anID]; + if (parseElement != nil) { + // parse the block + if (element != nil && element != NULL) { + *element = parseElement; + } + IJSVGGroup* group = [[[IJSVGGroup alloc] init] autorelease]; + [self _parseBaseBlock:parseElement + intoGroup:group + def:NO]; + if (_definedGroups == nil) { + _definedGroups = [[NSMutableArray alloc] init]; + } + [_definedGroups addObject:group]; + return [group defForID:anID]; + } + return nil; +} + +- (id)definedObjectForID:(NSString*)anID +{ + return [self definedObjectForID:anID + xmlElement:nil]; +} + +- (BOOL)isFont +{ + return [_glyphs count] != 0; +} + +- (NSArray*)glyphs +{ + return _glyphs; +} + +- (void)addSubSVG:(IJSVG*)anSVG +{ + [_svgs addObject:anSVG]; +} + +- (NSArray*)subSVGs:(BOOL)recursive +{ + if (recursive == NO) { + return _svgs; + } + NSMutableArray* svgs = [[[NSMutableArray alloc] init] autorelease]; + for (IJSVG* anSVG in svgs) { + [svgs addObject:anSVG]; + [svgs addObjectsFromArray:[anSVG subSVGs:recursive]]; + } + return svgs; +} + +- (void)addGlyph:(IJSVGNode*)glyph +{ + [_glyphs addObject:glyph]; +} + +- (void)_parseElementForCommonAttributes:(NSXMLElement*)element + node:(IJSVGNode*)node + ignoreAttributes:(NSArray*)ignoredAttributes +{ + [self _postParseElementForCommonAttributes:element + node:node + ignoreAttributes:ignoredAttributes]; +} + +- (void)_setupDefaultsForNode:(IJSVGNode*)node +{ + switch (node.type) { + // mask + case IJSVGNodeTypeMask: { + node.units = IJSVGUnitObjectBoundingBox; + break; + } + + // gradient + case IJSVGNodeTypeRadialGradient: + case IJSVGNodeTypeLinearGradient: { + node.units = IJSVGUnitObjectBoundingBox; + break; + } + + default: { + } + } +} + +- (void)parseDefsForElement:(NSXMLElement*)anElement +{ + // nothing found + if (anElement.childCount == 0) { + return; + } + + for (NSXMLElement* element in anElement.children) { + // not a def + if ([IJSVGNode typeForString:element.localName + kind:element.kind] + != IJSVGNodeTypeDef) { + continue; + } + + // store each object + for (NSXMLElement* childDef in element.children) { + // is there any stylesheets within this? + IJSVGNodeType childType = [IJSVGNode typeForString:childDef.localName + kind:element.kind]; + + switch (childType) { + case IJSVGNodeTypeStyle: + case IJSVGNodeTypeGlyph: + case IJSVGNodeTypeFont: { + [self _parseBaseBlock:childDef + intoGroup:self + def:NO]; + break; + } + case IJSVGNodeTypeNotFound: { + // ignore, this is insanely important - specially if its a comment + break; + } + default: { + // just a default def, continue on, as we are a def element, + // store these seperately to the default ID string ones + NSString* defID = [childDef attributeForName:@"id"].stringValue; + if (defID != nil) { + _baseDefNodes[defID] = childDef; + } + } + } + } + } +} + +- (void)_parseBaseBlock:(NSXMLElement*)element + intoGroup:(IJSVGGroup*)parentGroup + def:(BOOL)flag +{ + NSString* subName = element.localName; + NSXMLNodeKind nodeKind = element.kind; + IJSVGNodeType aType = [IJSVGNode typeForString:subName + kind:nodeKind]; + switch (aType) { + + // do nothing + default: + case IJSVGNodeTypeNotFound: { + break; + } + + // style + case IJSVGNodeTypeStyle: { + // create the sheet + if (_styleSheet == nil) { + _styleSheet = [[IJSVGStyleSheet alloc] init]; + } + + // append the string + [_styleSheet parseStyleBlock:element.stringValue]; + break; + } + + // sub SVG + case IJSVGNodeTypeSVG: { + + IJSVGGroup* path = [[[IJSVGGroup alloc] init] autorelease]; + path.type = aType; + path.name = subName; + + // grab common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + + // if its a sub svg, we can remove the attributes for x and y + // this is required or it could go out of bounds before the exporter + // hits the layers from the groups :) + [element removeAttributeForName:@"x"]; + [element removeAttributeForName:@"y"]; + + // work out the SVG + NSError* error = nil; + NSString* SVGString = element.XMLString; + IJSVG* anSVG = [[[IJSVG alloc] initWithSVGString:SVGString + error:&error + delegate:nil] autorelease]; + + // handle sub SVG + if (error == nil && _respondsTo.handleSubSVG == 1) { + [_delegate svgParser:self + foundSubSVG:anSVG + withSVGString:SVGString]; + } + + // any error? + if (anSVG != nil && error == nil) { + path.svg = anSVG; + [parentGroup addChild:path]; + [parentGroup addDef:path]; + + // make sure we add this + [self addSubSVG:anSVG]; + } + break; + } + + // glyph + case IJSVGNodeTypeGlyph: { + + // no path data + if ([element attributeForName:(NSString*)IJSVGAttributeD] == nil || + [[element attributeForName:(NSString*)IJSVGAttributeD] stringValue].length == 0) { + break; + } + + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + // find common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + + // pass the commands for it + [self _parsePathCommandData:[[element attributeForName:(NSString*)IJSVGAttributeD] stringValue] + intoPath:path]; + + // check the size... + if (NSIsEmptyRect([path path].controlPointBounds)) { + break; + } + + // add the glyph + [self addGlyph:path]; + break; + } + + // group + case IJSVGNodeTypeSwitch: + case IJSVGNodeTypeFont: + case IJSVGNodeTypeMask: + case IJSVGNodeTypeGroup: { + + // parse the defs + [self parseDefsForElement:element]; + + // create a new group + IJSVGGroup* group = [[[IJSVGGroup alloc] init] autorelease]; + group.type = aType; + group.name = subName; + group.parentNode = parentGroup; + + // only groups get added to parent, rest is added as a def - + // also addition of switches + if (!flag && ((aType == IJSVGNodeTypeGroup) || (aType == IJSVGNodeTypeSwitch))) { + [parentGroup addChild:group]; + } + + // find common attributes + [self _setupDefaultsForNode:group]; + [self _parseElementForCommonAttributes:element + node:group + ignoreAttributes:nil]; + + // recursively parse blocks + [self _parseBlock:element + intoGroup:group + def:NO]; + + [parentGroup addDef:group]; + break; + } + + // path + case IJSVGNodeTypePath: { + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + if (!flag) { + [parentGroup addChild:path]; + } + + // find common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + [self _parsePathCommandData:[[element attributeForName:(NSString*)IJSVGAttributeD] stringValue] + intoPath:path]; + + [parentGroup addDef:path]; + break; + } + + // polygon + case IJSVGNodeTypePolygon: { + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + if (!flag) { + [parentGroup addChild:path]; + } + + // find common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + [self _parsePolygon:element + intoPath:path]; + [parentGroup addDef:path]; + break; + } + + // polyline + case IJSVGNodeTypePolyline: { + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + if (!flag) { + [parentGroup addChild:path]; + } + + // find common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + [self _parsePolyline:element + intoPath:path]; + [parentGroup addDef:path]; + break; + } + + // rect + case IJSVGNodeTypeRect: { + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + if (!flag) { + [parentGroup addChild:path]; + } + + // find common attributes + [self _parseRect:element + intoPath:path]; + + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:@[ @"x", @"y" ]]; + [parentGroup addDef:path]; + break; + } + + // line + case IJSVGNodeTypeLine: { + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + [parentGroup addChild:path]; + + // find common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + [self _parseLine:element + intoPath:path]; + [parentGroup addDef:path]; + break; + } + + // circle + case IJSVGNodeTypeCircle: { + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + if (!flag) { + [parentGroup addChild:path]; + } + + // find common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + [self _parseCircle:element + intoPath:path]; + [parentGroup addDef:path]; + break; + } + + // ellipse + case IJSVGNodeTypeEllipse: { + IJSVGPath* path = [[[IJSVGPath alloc] init] autorelease]; + path.type = aType; + path.name = subName; + path.parentNode = parentGroup; + + if (!flag) { + [parentGroup addChild:path]; + } + + // find common attributes + [self _setupDefaultsForNode:path]; + [self _parseElementForCommonAttributes:element + node:path + ignoreAttributes:nil]; + [self _parseEllipse:element + intoPath:path]; + [parentGroup addDef:path]; + break; + } + + // use + case IJSVGNodeTypeUse: { + + NSString* xlink = [[element attributeForName:(NSString*)IJSVGAttributeXLink] stringValue]; + NSString* xlinkID = [xlink substringFromIndex:1]; + IJSVGNode* node = [self definedObjectForID:xlinkID]; + + // there was no specified link ID, well, not that we could find, + // so just break + if (node == nil) { + break; + } + + // due to this being a carbon clone, we need to clear the ID + if ([element attributeForName:(NSString*)IJSVGAttributeID] == nil) { + node.identifier = nil; + } + + // at this point, we need to create another group! + IJSVGGroup* subGroup = [[[IJSVGGroup alloc] init] autorelease]; + subGroup.parentNode = parentGroup; + [subGroup addChild:node]; + node.parentNode = subGroup; + node.intermediateParentNode = subGroup; + + // is there a width and height? + CGFloat x = [element attributeForName:(NSString*)IJSVGAttributeX].stringValue.floatValue; + CGFloat y = [element attributeForName:(NSString*)IJSVGAttributeY].stringValue.floatValue; + + // we need to add a transform to the subgroup + subGroup.transforms = @[ [IJSVGTransform transformByTranslatingX:x y:y] ]; + + if (!flag) { + [parentGroup addChild:subGroup]; + } + + // parse attributes from element onto group - but spec + // says ignore x, y, width, height and xlink:href... + [self _parseElementForCommonAttributes:element + node:node + ignoreAttributes:@[ @"x", @"y", @"width", + @"height", @"xlink:href" ]]; + + [parentGroup addDef:node]; + break; + } + + // linear gradient + case IJSVGNodeTypeLinearGradient: { + + NSString* xlink = [[element attributeForName:(NSString*)IJSVGAttributeXLink] stringValue]; + NSString* xlinkID = [xlink substringFromIndex:1]; + NSXMLElement* referenceElement; + IJSVGNode* node = [self definedObjectForID:xlinkID + xmlElement:&referenceElement]; + if (node != nil) { + // we are a clone + NSXMLElement* elementCopy = [self mergedElement:element + withReferenceElement:referenceElement]; + + IJSVGLinearGradient* grad = [[[IJSVGLinearGradient alloc] init] autorelease]; + grad.type = aType; + [self _setupDefaultsForNode:grad]; + [self _parseElementForCommonAttributes:elementCopy + node:grad + ignoreAttributes:nil]; + grad.gradient = [IJSVGLinearGradient parseGradient:elementCopy + gradient:grad]; + [parentGroup addDef:grad]; + break; + } + + IJSVGLinearGradient* gradient = [[[IJSVGLinearGradient alloc] init] autorelease]; + gradient.type = aType; + [self _setupDefaultsForNode:gradient]; + [self _parseElementForCommonAttributes:element + node:gradient + ignoreAttributes:nil]; + gradient.gradient = [IJSVGLinearGradient parseGradient:element + gradient:gradient]; + [parentGroup addDef:gradient]; + break; + } + + // radial gradient + case IJSVGNodeTypeRadialGradient: { + + NSString* xlink = [[element attributeForName:(NSString*)IJSVGAttributeXLink] stringValue]; + NSString* xlinkID = [xlink substringFromIndex:1]; + NSXMLElement* referenceElement; + IJSVGNode* node = [self definedObjectForID:xlinkID + xmlElement:&referenceElement]; + if (node != nil) { + // we are a clone + IJSVGRadialGradient* grad = [[[IJSVGRadialGradient alloc] init] autorelease]; + grad.type = aType; + + NSXMLElement* elementCopy = [self mergedElement:element + withReferenceElement:referenceElement]; + [self _setupDefaultsForNode:grad]; + [self _parseElementForCommonAttributes:elementCopy + node:grad + ignoreAttributes:nil]; + grad.gradient = [IJSVGRadialGradient parseGradient:elementCopy + gradient:grad]; + [parentGroup addDef:grad]; + break; + } + + IJSVGRadialGradient* gradient = [[[IJSVGRadialGradient alloc] init] autorelease]; + gradient.type = aType; + [self _setupDefaultsForNode:gradient]; + [self _parseElementForCommonAttributes:element + node:gradient + ignoreAttributes:nil]; + gradient.gradient = [IJSVGRadialGradient parseGradient:element + gradient:gradient]; + [parentGroup addDef:gradient]; + break; + } + + // clippath + case IJSVGNodeTypeClipPath: { + + IJSVGGroup* group = [[[IJSVGGroup alloc] init] autorelease]; + group.type = aType; + group.name = subName; + group.parentNode = parentGroup; + + [self _setupDefaultsForNode:group]; + + // find common attributes + [self _parseElementForCommonAttributes:element + node:group + ignoreAttributes:nil]; + + // recursively parse blocks + [self _parseBlock:element + intoGroup:group + def:NO]; + [parentGroup addDef:group]; + break; + } + + // pattern + case IJSVGNodeTypePattern: { + IJSVGPattern* pattern = [[[IJSVGPattern alloc] init] autorelease]; + + [self _setupDefaultsForNode:pattern]; + + // find common attributes + [self _parseElementForCommonAttributes:element + node:pattern + ignoreAttributes:nil]; + + // pattern has children + [self _parseBlock:element + intoGroup:pattern + def:NO]; + + [parentGroup addDef:pattern]; + break; + } + + // image + case IJSVGNodeTypeImage: { + IJSVGImage* image = [[[IJSVGImage alloc] init] autorelease]; + + [self _setupDefaultsForNode:image]; + + // find common attributes + [self _parseElementForCommonAttributes:element + node:image + ignoreAttributes:nil]; + + // from base64 + NSString* string = [element attributeForName:(NSString*)IJSVGAttributeXLink].stringValue; + [image loadFromBase64EncodedString:string]; + + // add to parent + [parentGroup addChild:image]; + [parentGroup addDef:image]; + break; + } + } +} + +- (NSXMLElement*)mergedElement:(NSXMLElement*)element + withReferenceElement:(NSXMLElement*)reference +{ + NSXMLElement* copy = [[reference copy] autorelease]; + for (NSXMLNode* attribute in element.attributes) { + [copy removeAttributeForName:attribute.name]; + attribute = [[attribute copy] autorelease]; + [copy addAttribute:attribute]; + } + return copy; +} + +- (void)_parseBlock:(NSXMLElement*)anElement + intoGroup:(IJSVGGroup*)parentGroup + def:(BOOL)flag +{ + // parse the defs + [self parseDefsForElement:anElement]; + + // parse the children + for (NSXMLElement* element in [anElement children]) { + [self _parseBaseBlock:element + intoGroup:parentGroup + def:flag]; + } +} + +#pragma mark Parser stuff! + +- (void)_parsePathCommandData:(NSString*)command + intoPath:(IJSVGPath*)path +{ + // invalid command + + if (command == nil || command.length == 0) { + return; + } + + NSUInteger len = [command length]; + + // allocate memory for the string buffer for reading + const char* buffer = [command cStringUsingEncoding:NSUTF8StringEncoding]; + + int defaultBufferSize = 200; + int currentBufferSize = 0; + int currentSize = defaultBufferSize; + + unichar* commandBuffer = NULL; + if (len != 0) { + commandBuffer = (unichar*)calloc(defaultBufferSize, sizeof(unichar)); + } + + IJSVGCommand* _currentCommand = nil; + for (int i = 0; i < len; i++) { + unichar currentChar = buffer[i]; + unichar nextChar = buffer[i + 1]; + + BOOL atEnd = i == len - 1; + BOOL isStartCommand = IJSVGIsLegalCommandCharacter(nextChar); + if ((currentBufferSize + 1) == currentSize) { + currentSize += defaultBufferSize; + commandBuffer = (unichar*)realloc(commandBuffer, sizeof(unichar) * currentSize); + } + commandBuffer[currentBufferSize++] = currentChar; + if (isStartCommand == YES || atEnd == YES) { + NSString* commandString = [NSString stringWithCharacters:commandBuffer + length:currentBufferSize]; + + // previous command is actual subcommand + IJSVGCommand* previousCommand = [_currentCommand subCommands].lastObject; + IJSVGCommand* cCommand = [self _parseCommandString:commandString + previousCommand:previousCommand + intoPath:path]; + + // retain the current one + if (cCommand != nil) { + _currentCommand = cCommand; + } + + if (atEnd == NO) { + currentBufferSize = 0; + memset(commandBuffer, '\0', sizeof(unichar) * currentSize); + } + } + } + + // free the buffer + free(commandBuffer); +} + +- (IJSVGCommand*)_parseCommandString:(NSString*)string + previousCommand:(IJSVGCommand*)previousCommand + intoPath:(IJSVGPath*)path +{ + // work out the last command - the reason this is so long is because the command + // could be a series of the same commands, so work it out by the number of parameters + // there is per command string + IJSVGCommand* preCommand = nil; + if (previousCommand) { + preCommand = previousCommand; + } + + // main commands + // Class commandClass = [IJSVGCommand classFor] + Class commandClass = [IJSVGCommand commandClassForCommandChar:[string characterAtIndex:0]]; + IJSVGCommand* command = (IJSVGCommand*)[[[commandClass alloc] initWithCommandString:string] autorelease]; + for (IJSVGCommand* subCommand in [command subCommands]) { + [command.class runWithParams:subCommand.parameters + paramCount:subCommand.parameterCount + command:subCommand + previousCommand:preCommand + type:subCommand.type + path:path]; + preCommand = subCommand; + } + return command; +} + +- (void)_parseLine:(NSXMLElement*)element + intoPath:(IJSVGPath*)path +{ + // convert a line into a command, + // basically MX1 Y1LX2 Y2 + path.primitiveType = IJSVGPrimitivePathTypeLine; + CGFloat x1 = [element attributeForName:(NSString*)IJSVGAttributeX1].stringValue.floatValue; + CGFloat y1 = [element attributeForName:(NSString*)IJSVGAttributeY1].stringValue.floatValue; + CGFloat x2 = [element attributeForName:(NSString*)IJSVGAttributeX2].stringValue.floatValue; + CGFloat y2 = [element attributeForName:(NSString*)IJSVGAttributeY2].stringValue.floatValue; + + // use sprintf as its quicker then stringWithFormat... + char buffer[50]; + sprintf(buffer, "M%.2f %.2fL%.2f %.2f", x1, y1, x2, y2); + NSString* command = [NSString stringWithCString:buffer + encoding:NSUTF8StringEncoding]; + [self _parsePathCommandData:command + intoPath:path]; +} + +- (void)_parseCircle:(NSXMLElement*)element + intoPath:(IJSVGPath*)path +{ + path.primitiveType = IJSVGPrimitivePathTypeCircle; + CGFloat cX = [element attributeForName:(NSString*)IJSVGAttributeCX].stringValue.floatValue; + CGFloat cY = [element attributeForName:(NSString*)IJSVGAttributeCY].stringValue.floatValue; + CGFloat r = [element attributeForName:(NSString*)IJSVGAttributeR].stringValue.floatValue; + NSRect rect = NSMakeRect(cX - r, cY - r, r * 2, r * 2); + [path overwritePath:[NSBezierPath bezierPathWithOvalInRect:rect]]; +} + +- (void)_parseEllipse:(NSXMLElement*)element + intoPath:(IJSVGPath*)path +{ + path.primitiveType = IJSVGPrimitivePathTypeEllipse; + CGFloat cX = [element attributeForName:(NSString*)IJSVGAttributeCX].stringValue.floatValue; + CGFloat cY = [element attributeForName:(NSString*)IJSVGAttributeCY].stringValue.floatValue; + CGFloat rX = [element attributeForName:(NSString*)IJSVGAttributeRX].stringValue.floatValue; + CGFloat rY = [element attributeForName:(NSString*)IJSVGAttributeRY].stringValue.floatValue; + NSRect rect = NSMakeRect(cX - rX, cY - rY, rX * 2, rY * 2); + [path overwritePath:[NSBezierPath bezierPathWithOvalInRect:rect]]; +} + +- (void)_parsePolyline:(NSXMLElement*)element + intoPath:(IJSVGPath*)path +{ + path.primitiveType = IJSVGPrimitivePathTypePolyLine; + [self _parsePoly:element + intoPath:path + closePath:NO]; +} + +- (void)_parsePolygon:(NSXMLElement*)element + intoPath:(IJSVGPath*)path +{ + path.primitiveType = IJSVGPrimitivePathTypePolygon; + [self _parsePoly:element + intoPath:path + closePath:YES]; +} + +- (void)_parsePoly:(NSXMLElement*)element + intoPath:(IJSVGPath*)path + closePath:(BOOL)closePath +{ + NSString* points = [element attributeForName:(NSString*)IJSVGAttributePoints].stringValue; + NSInteger count = 0; + CGFloat* params = [IJSVGUtils commandParameters:points + count:&count]; + + // error occured, free the params + if ((count % 2) != 0) { + free(params); + return; + } + + // construct a command + NSInteger capacity = count / 2; + if (closePath == YES) { + capacity += 1; + } + NSMutableString* str = [[[NSMutableString alloc] initWithCapacity:capacity] autorelease]; + [str appendFormat:@"M%f,%f L", params[0], params[1]]; + for (NSInteger i = 2; i < count; i += 2) { + [str appendFormat:@"%f,%f ", params[i], params[i + 1]]; + } + if (closePath) { + [str appendString:@"z"]; + } + [self _parsePathCommandData:str + intoPath:path]; + free(params); +} + +- (void)_parseRect:(NSXMLElement*)element + intoPath:(IJSVGPath*)path +{ + path.primitiveType = IJSVGPrimitivePathTypeRect; + // width and height + CGFloat width = [IJSVGUtils floatValue:[element attributeForName:(NSString*)IJSVGAttributeWidth].stringValue + fallBackForPercent:self.viewBox.size.width]; + + CGFloat height = [IJSVGUtils floatValue:[element attributeForName:(NSString*)IJSVGAttributeHeight].stringValue + fallBackForPercent:self.viewBox.size.height]; + + // rect uses x and y as start of path, not move path object -_- + CGFloat x = [IJSVGUtils floatValue:[element attributeForName:(NSString*)IJSVGAttributeX].stringValue + fallBackForPercent:self.viewBox.size.width]; + CGFloat y = [IJSVGUtils floatValue:[element attributeForName:(NSString*)IJSVGAttributeY].stringValue + fallBackForPercent:self.viewBox.size.height]; + + // radius + CGFloat rX = [element attributeForName:(NSString*)IJSVGAttributeRX].stringValue.floatValue; + CGFloat rY = [element attributeForName:(NSString*)IJSVGAttributeRY].stringValue.floatValue; + if ([element attributeForName:(NSString*)IJSVGAttributeRY] == nil) { + rY = rX; + } + + NSBezierPath* newPath = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(x, y, width, height) + xRadius:rX + yRadius:rY]; + [path overwritePath:newPath]; +} + +@end diff --git a/source/IJSVGLayerTree.h b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGLayerTree.h similarity index 75% rename from source/IJSVGLayerTree.h rename to Framework/IJSVG/IJSVG/Source/Rendering/IJSVGLayerTree.h index fd2a2b3..16edec8 100644 --- a/source/IJSVGLayerTree.h +++ b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGLayerTree.h @@ -6,20 +6,18 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import #import "IJSVGNode.h" #import "IJSVGRenderingStyle.h" +#import @class IJSVGLayer; @interface IJSVGLayerTree : NSObject { - } @property (nonatomic, assign) CGRect viewBox; -@property (nonatomic, retain) IJSVGRenderingStyle * style; - +@property (nonatomic, retain) IJSVGRenderingStyle* style; -- (IJSVGLayer *)layerForNode:(IJSVGNode *)node; +- (IJSVGLayer*)layerForNode:(IJSVGNode*)node; @end diff --git a/source/IJSVGLayerTree.m b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGLayerTree.m similarity index 55% rename from source/IJSVGLayerTree.m rename to Framework/IJSVG/IJSVG/Source/Rendering/IJSVGLayerTree.m index 1e7bc72..e79cc33 100644 --- a/source/IJSVGLayerTree.m +++ b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGLayerTree.m @@ -6,23 +6,23 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import "IJSVGLayerTree.h" -#import "IJSVGGroup.h" -#import "IJSVGTransform.h" -#import "IJSVGUtils.h" -#import "IJSVGPath.h" -#import "IJSVGImage.h" +#import "IJSVG.h" #import "IJSVGGradient.h" #import "IJSVGGradientLayer.h" -#import "IJSVGPatternLayer.h" -#import "IJSVGPattern.h" -#import "IJSVG.h" -#import "IJSVGText.h" +#import "IJSVGGroup.h" +#import "IJSVGGroupLayer.h" +#import "IJSVGImage.h" +#import "IJSVGImageLayer.h" #import "IJSVGLayer.h" +#import "IJSVGLayerTree.h" +#import "IJSVGPath.h" +#import "IJSVGPattern.h" +#import "IJSVGPatternLayer.h" #import "IJSVGShapeLayer.h" -#import "IJSVGImageLayer.h" -#import "IJSVGGroupLayer.h" #import "IJSVGStrokeLayer.h" +#import "IJSVGText.h" +#import "IJSVGTransform.h" +#import "IJSVGUtils.h" @implementation IJSVGLayerTree @@ -31,61 +31,61 @@ @implementation IJSVGLayerTree - (void)dealloc { - [_style release], _style = nil; + (void)([_style release]), _style = nil; [super dealloc]; } - (id)init { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { } return self; } -- (IJSVGLayer *)layerForNode:(IJSVGNode *)node +- (IJSVGLayer*)layerForNode:(IJSVGNode*)node { - IJSVGLayer * layer = nil; - + IJSVGLayer* layer = nil; + // is there a sub SVG? - if([node isKindOfClass:[IJSVGPath class]]) { + if ([node isKindOfClass:[IJSVGPath class]]) { // path - layer = [self layerForPath:(IJSVGPath *)node]; - } else if([node isKindOfClass:[IJSVGGroup class]]) { + layer = [self layerForPath:(IJSVGPath*)node]; + } else if ([node isKindOfClass:[IJSVGGroup class]]) { // group - layer = [self layerForGroup:(IJSVGGroup *)node]; - } else if([node isKindOfClass:[IJSVGImage class]]) { + layer = [self layerForGroup:(IJSVGGroup*)node]; + } else if ([node isKindOfClass:[IJSVGImage class]]) { // image - layer = [self layerForImage:(IJSVGImage *)node]; + layer = [self layerForImage:(IJSVGImage*)node]; } - + [self applyDefaultsToLayer:layer fromNode:node]; - + // create the new layer layer = [self applyTransforms:node.transforms toLayer:layer fromNode:node]; - + return layer; } -- (IJSVGLayer *)applyTransforms:(NSArray *)transforms - toLayer:(IJSVGLayer *)layer - fromNode:(IJSVGNode *)node +- (IJSVGLayer*)applyTransforms:(NSArray*)transforms + toLayer:(IJSVGLayer*)layer + fromNode:(IJSVGNode*)node { // any x and y? CGFloat x = [node.x computeValue:layer.frame.size.width]; CGFloat y = [node.y computeValue:layer.frame.size.height]; - + // do some magic transform - if(transforms.count == 0 && x == 0.f && y == 0.f) { + if (transforms.count == 0 && x == 0.f && y == 0.f) { return layer; } - - if(x != 0.f || y != 0.f) { + + if (x != 0.f || y != 0.f) { // we must add translate to the stack - NSMutableArray * trans = nil; - if(transforms != nil) { + NSMutableArray* trans = nil; + if (transforms != nil) { trans = [[transforms mutableCopy] autorelease]; } else { trans = [[[NSMutableArray alloc] initWithCapacity:1] autorelease]; @@ -93,58 +93,58 @@ - (IJSVGLayer *)applyTransforms:(NSArray *)transforms [trans addObject:[IJSVGTransform transformByTranslatingX:x y:y]]; transforms = trans; } - + // add any transforms - IJSVGLayer * topLayer = nil; - IJSVGLayer * parentLayer = nil; - - for(IJSVGTransform * transform in transforms) { + IJSVGLayer* topLayer = nil; + IJSVGLayer* parentLayer = nil; + + for (IJSVGTransform* transform in transforms) { // make sure we apply the transform to the parent // so they stack - IJSVGGroupLayer * childLayer = [[[IJSVGGroupLayer alloc] init] autorelease]; + IJSVGGroupLayer* childLayer = [[[IJSVGGroupLayer alloc] init] autorelease]; childLayer.affineTransform = transform.CGAffineTransform; - + // add it to the parent layer - if(parentLayer != nil) { + if (parentLayer != nil) { [parentLayer addSublayer:childLayer]; } else { // make sure we keep track of the top most layer topLayer = childLayer; } - + // reset parent layer to the new child parentLayer = childLayer; } - + // swap the layer around [parentLayer addSublayer:layer]; layer = topLayer; return layer; } -- (void)applyDefaultsToLayer:(IJSVGLayer *)layer - fromNode:(IJSVGNode *)node +- (void)applyDefaultsToLayer:(IJSVGLayer*)layer + fromNode:(IJSVGNode*)node { CGFloat opacity = node.opacity.value; layer.opacity = opacity; - + // setup the blending mode - if(node.blendMode != IJSVGBlendModeNormal) { + if (node.blendMode != IJSVGBlendModeNormal) { layer.blendingMode = (CGBlendMode)node.blendMode; } - + // display? - if(node.shouldRender == NO) { + if (node.shouldRender == NO) { layer.hidden = YES; } } -- (IJSVGLayer *)layerForImage:(IJSVGImage *)image +- (IJSVGLayer*)layerForImage:(IJSVGImage*)image { - IJSVGImageLayer * layer = [[[IJSVGImageLayer alloc] initWithCGImage:image.CGImage] autorelease]; + IJSVGImageLayer* layer = [[[IJSVGImageLayer alloc] initWithCGImage:image.CGImage] autorelease]; layer.affineTransform = CGAffineTransformConcat(layer.affineTransform, - CGAffineTransformMakeScale( 1.f, -1.f)); - + CGAffineTransformMakeScale(1.f, -1.f)); + // make sure we set the width and height correctly, // as this may not be exactly the same as the size of the // given image @@ -155,26 +155,25 @@ - (IJSVGLayer *)layerForImage:(IJSVGImage *)image return layer; } -- (IJSVGLayer *)layerForGroup:(IJSVGGroup *)group +- (IJSVGLayer*)layerForGroup:(IJSVGGroup*)group { - + // grab the sub layer tree from the SVG - if(group.svg != nil) { + if (group.svg != nil) { return [self layerForGroup:group.svg.rootNode]; } - - IJSVGGroupLayer * groupLayer = [[[IJSVGGroupLayer alloc] init] autorelease]; - for(IJSVGNode * node in group.children) { + + IJSVGGroupLayer* groupLayer = [[[IJSVGGroupLayer alloc] init] autorelease]; + for (IJSVGNode* node in group.children) { [groupLayer addSublayer:[self layerForNode:node]]; } groupLayer.frame = (CGRect){ .origin = CGPointZero, .size = (CGSize){ .width = group.width.value, - .height = group.height.value - } + .height = group.height.value } }; - + // mask it - forgot groups can have masks too, doh! simple // enough to apply though, recursion ftw! [self maskLayer:groupLayer @@ -184,252 +183,249 @@ - (IJSVGLayer *)layerForGroup:(IJSVGGroup *)group - (CGRect)correctedBounds:(CGRect)bounds { - if(bounds.origin.x >= INFINITY) { + if (bounds.origin.x >= INFINITY) { bounds.origin.x = 0.f; } - if(bounds.origin.y >= INFINITY) { + if (bounds.origin.y >= INFINITY) { bounds.origin.y = 0.f; } - if(bounds.size.width >= INFINITY) { + if (bounds.size.width >= INFINITY) { bounds.size.width = 0.f; } - if(bounds.size.height >= INFINITY) { + if (bounds.size.height >= INFINITY) { bounds.size.height = 0.f; } return bounds; } -- (IJSVGShapeLayer *)basicLayerForPath:(IJSVGPath *)path - originalBoundingBox:(CGRect *)originalBoundingBox +- (IJSVGShapeLayer*)basicLayerForPath:(IJSVGPath*)path + originalBoundingBox:(CGRect*)originalBoundingBox { // setup path and layer - IJSVGShapeLayer * layer = [[[IJSVGShapeLayer alloc] init] autorelease]; - CGPathRef introPath = [path newPathRefByAutoClosingPath:NO]; - + IJSVGShapeLayer* layer = [[[IJSVGShapeLayer alloc] init] autorelease]; + layer.primitiveType = path.primitiveType; + CGPathRef introPath = path.CGPath; + *originalBoundingBox = CGRectIntegral(CGPathGetBoundingBox(introPath)); layer.originalPathOrigin = (*originalBoundingBox).origin; - + CGRect bounds = [self correctedBounds:*originalBoundingBox]; - + // zero back the path CGAffineTransform trans = CGAffineTransformMakeTranslation(-bounds.origin.x, - -bounds.origin.y); - + -bounds.origin.y); + CGPathRef transformedPath = CGPathCreateCopyByTransformingPath(introPath, &trans); layer.path = transformedPath; - + // clean up path memory CGPathRelease(transformedPath); - CGPathRelease(introPath); // set the bounds layer.frame = CGRectIntegral(bounds); - + // basic fill color and rule layer.fillColor = nil; layer.fillRule = [self fillRule:path.windingRule]; return layer; } -- (IJSVGShapeLayer *)layerMaskFromLayer:(CAShapeLayer *)layer - fromNode:(IJSVGNode *)node +- (IJSVGShapeLayer*)layerMaskFromLayer:(CAShapeLayer*)layer + fromNode:(IJSVGNode*)node { - IJSVGShapeLayer * mask = [[[IJSVGShapeLayer alloc] init] autorelease]; + IJSVGShapeLayer* mask = [[[IJSVGShapeLayer alloc] init] autorelease]; mask.fillColor = [NSColor blackColor].CGColor; mask.path = layer.path; return mask; } -- (CGAffineTransform)absoluteTransform:(IJSVGNode *)node +- (CGAffineTransform)absoluteTransform:(IJSVGNode*)node { CGAffineTransform parentAbsoluteTransform = CGAffineTransformIdentity; - IJSVGNode * intermediateNode = node.intermediateParentNode; - IJSVGNode * parentSVGNode = node; - while((parentSVGNode = parentSVGNode.parentNode) != nil) { - if(node == intermediateNode) { + IJSVGNode* intermediateNode = node.intermediateParentNode; + IJSVGNode* parentSVGNode = node; + while ((parentSVGNode = parentSVGNode.parentNode) != nil) { + if (node == intermediateNode) { continue; } parentAbsoluteTransform = [self absoluteTransform:parentSVGNode]; } return CGAffineTransformConcat(IJSVGConcatTransforms(node.transforms), - parentAbsoluteTransform); + parentAbsoluteTransform); } -- (IJSVGLayer *)layerForPath:(IJSVGPath *)path +- (IJSVGLayer*)layerForPath:(IJSVGPath*)path { // grab the basic shape layer CGRect originalShapeBounds; - IJSVGShapeLayer * layer = [self basicLayerForPath:path - originalBoundingBox:&originalShapeBounds]; - - BOOL hasStroke = (path.strokeColor != nil || - path.strokePattern != nil || - path.strokeGradient != nil); - + IJSVGShapeLayer* layer = [self basicLayerForPath:path + originalBoundingBox:&originalShapeBounds]; + + BOOL hasStroke = (path.strokeColor != nil || path.strokePattern != nil || path.strokeGradient != nil); + // any gradient? - if(_style.fillColor == nil && path.fillGradient != nil) { - + if (_style.fillColor == nil && path.fillGradient != nil) { + // create the gradient - IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer - gradient:path.fillGradient - fromNode:path - objectRect:originalShapeBounds - shouldMask:YES]; - + IJSVGGradientLayer* gradLayer = [self gradientLayerForLayer:layer + gradient:path.fillGradient + fromNode:path + objectRect:originalShapeBounds + shouldMask:YES]; + // add the gradient and set it against the layer [layer addSublayer:gradLayer]; layer.gradientFillLayer = gradLayer; - - } else if(_style.fillColor == nil && path.fillPattern != nil) { - + + } else if (_style.fillColor == nil && path.fillPattern != nil) { + // create the pattern, this is actually not as easy as it may seem - IJSVGPatternLayer * patternLayer = [self patternLayerForLayer:layer - pattern:path.fillPattern - fromNode:path]; + IJSVGPatternLayer* patternLayer = [self patternLayerForLayer:layer + pattern:path.fillPattern + fromNode:path]; // add it [layer addSublayer:patternLayer]; - + // apply offsets [self applyOffsetsToLayer:patternLayer fromNode:path.fillPattern]; - + layer.patternFillLayer = patternLayer; - + } else { // only use the global if its set and the current colors // alpha channel is not 0.f, otherwise its a blank clear color, // aka, not filled in - NSColor * fColor = path.fillColor; + NSColor* fColor = path.fillColor; BOOL hasColor = (fColor.alphaComponent == 0.f || fColor == nil) == NO; BOOL hasFill = path.fillPattern != nil || path.fillGradient != nil; - if(_style.fillColor && (hasFill || hasColor || fColor == nil)) { + if (_style.fillColor && (hasFill || hasColor || fColor == nil)) { fColor = _style.fillColor; - } else if(fColor != nil && path.fillOpacity.value != 1.f) { + } else if (fColor != nil && path.fillOpacity.value != 1.f) { fColor = [IJSVGColor changeAlphaOnColor:fColor to:path.fillOpacity.value]; } - + // anything changed by user? fColor = [_style.colorList proposedColorForColor:fColor]; - + // just set the color - if(fColor != nil) { + if (fColor != nil) { layer.fillColor = fColor.CGColor; } else { // use default color - NSColor * defColor = [IJSVGColor computeColorSpace:NSColor.blackColor]; - if(path.fillOpacity.value != 1.f) { + NSColor* defColor = [IJSVGColor computeColorSpace:NSColor.blackColor]; + if (path.fillOpacity.value != 1.f) { defColor = [IJSVGColor changeAlphaOnColor:defColor to:path.fillOpacity.value]; } - + // work out if anything was changed by user - NSColor * proposedColor = [_style.colorList proposedColorForColor:defColor]; + NSColor* proposedColor = [_style.colorList proposedColorForColor:defColor]; layer.fillColor = proposedColor.CGColor; } } - + // stroke it - if(hasStroke == YES) { - + if (hasStroke == YES) { + // load the stroke layer - IJSVGStrokeLayer * strokeLayer = [self strokeLayer:layer - fromNode:path]; - + IJSVGStrokeLayer* strokeLayer = [self strokeLayer:layer + fromNode:path]; + // reset the node BOOL moveStrokeLayer = NO; - if(_style.strokeColor == nil && path.strokeGradient != nil) { - + if (_style.strokeColor == nil && path.strokeGradient != nil) { + // force reset of the mask colour as we need to use the stroke layer // as the mask for the stroke gradient strokeLayer.strokeColor = [IJSVGColor computeColorSpace:NSColor.blackColor].CGColor; - + // create the gradient - IJSVGGradientLayer * gradLayer = [self gradientStrokeLayerForLayer:layer - gradient:path.strokeGradient - fromNode:path - objectRect:originalShapeBounds]; - + IJSVGGradientLayer* gradLayer = [self gradientStrokeLayerForLayer:layer + gradient:path.strokeGradient + fromNode:path + objectRect:originalShapeBounds]; + moveStrokeLayer = YES; gradLayer.mask = strokeLayer; gradLayer.opacity = strokeLayer.opacity; - + // add it [layer addSublayer:gradLayer]; layer.strokeLayer = strokeLayer; layer.gradientStrokeLayer = gradLayer; - - } else if(_style.strokeColor == nil && path.strokePattern != nil) { - + + } else if (_style.strokeColor == nil && path.strokePattern != nil) { + // force reset of the mask strokeLayer.strokeColor = [IJSVGColor computeColorSpace:NSColor.blackColor].CGColor; - + // create the pattern - IJSVGPatternLayer * patternLayer = [self patternStrokeLayerForLayer:layer - pattern:path.strokePattern - fromNode:path]; - + IJSVGPatternLayer* patternLayer = [self patternStrokeLayerForLayer:layer + pattern:path.strokePattern + fromNode:path]; + // set the mask for it moveStrokeLayer = YES; patternLayer.mask = strokeLayer; patternLayer.opacity = strokeLayer.opacity; - + // add it [layer addSublayer:patternLayer]; layer.strokeLayer = strokeLayer; - layer.patternStrokeLayer = (IJSVGPatternLayer *)patternLayer; - + layer.patternStrokeLayer = (IJSVGPatternLayer*)patternLayer; + } else { // just add the coloured layer [layer addSublayer:strokeLayer]; layer.strokeLayer = strokeLayer; } - + // if we required to move the stroke layer // then move it in based on half of what the stroke // width is, as strokes are draw on the center - if(moveStrokeLayer) { + if (moveStrokeLayer) { CGFloat layerStrokeWidth = strokeLayer.lineWidth; CGRect rect = strokeLayer.frame; - rect.origin.x += (layerStrokeWidth*.5f); - rect.origin.y += (layerStrokeWidth*.5f); + rect.origin.x += (layerStrokeWidth * .5f); + rect.origin.y += (layerStrokeWidth * .5f); strokeLayer.frame = rect; } - } - + // apply masking - [self maskLayer:(IJSVGLayer *)layer + [self maskLayer:(IJSVGLayer*)layer fromNode:path]; - - return (IJSVGLayer *)layer; + + return (IJSVGLayer*)layer; } - (CGRect)correctBounds:(CGRect)bounds - forStrokedPath:(IJSVGNode *)path + forStrokedPath:(IJSVGNode*)path { // minus half the stroke width from x and y // plus the stroke width to width and height CGFloat val = path.strokeWidth.value; - bounds.origin.x -= (val*.5f); - bounds.origin.y -= (val*.5f); + bounds.origin.x -= (val * .5f); + bounds.origin.y -= (val * .5f); bounds.size.width += val; bounds.size.height += val; return bounds; } -- (IJSVGGradientLayer *)gradientStrokeLayerForLayer:(IJSVGShapeLayer *)layer - gradient:(IJSVGGradient *)gradient - fromNode:(IJSVGNode *)path - objectRect:(CGRect)objectRect +- (IJSVGGradientLayer*)gradientStrokeLayerForLayer:(IJSVGShapeLayer*)layer + gradient:(IJSVGGradient*)gradient + fromNode:(IJSVGNode*)path + objectRect:(CGRect)objectRect { // the gradient drawing layer - IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer - gradient:gradient - fromNode:path - objectRect:objectRect - shouldMask:NO]; - + IJSVGGradientLayer* gradLayer = [self gradientLayerForLayer:layer + gradient:gradient + fromNode:path + objectRect:objectRect + shouldMask:NO]; + // set the bounds CGRect bounds = CGPathGetBoundingBox(layer.path); bounds = [self correctBounds:bounds forStrokedPath:path]; @@ -437,323 +433,327 @@ - (IJSVGGradientLayer *)gradientStrokeLayerForLayer:(IJSVGShapeLayer *)layer return gradLayer; } - -- (IJSVGGradientLayer *)gradientLayerForLayer:(IJSVGShapeLayer *)layer - gradient:(IJSVGGradient *)gradient - fromNode:(IJSVGNode *)path - objectRect:(CGRect)objectRect - shouldMask:(BOOL)shouldMask +- (IJSVGGradientLayer*)gradientLayerForLayer:(IJSVGShapeLayer*)layer + gradient:(IJSVGGradient*)gradient + fromNode:(IJSVGNode*)path + objectRect:(CGRect)objectRect + shouldMask:(BOOL)shouldMask { // the gradient drawing layer gradient.colorList = _style.colorList; - IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease]; + IJSVGGradientLayer* gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease]; gradLayer.viewBox = self.viewBox; gradLayer.frame = layer.bounds; gradLayer.gradient = gradient; gradLayer.absoluteTransform = [self absoluteTransform:path]; gradLayer.objectRect = CGRectApplyAffineTransform(objectRect, - gradLayer.absoluteTransform); - - if(shouldMask == YES) { + gradLayer.absoluteTransform); + + if (shouldMask == YES) { // add the mask - IJSVGShapeLayer * mask = [self layerMaskFromLayer:layer - fromNode:path]; + IJSVGShapeLayer* mask = [self layerMaskFromLayer:layer + fromNode:path]; gradLayer.mask = mask; } - + // is there a fill opacity? - if(path.fillOpacity.value != 0.f) { + if (path.fillOpacity.value != 0.f) { gradLayer.opacity = path.fillOpacity.value; } gradLayer.masksToBounds = YES; return gradLayer; } -- (IJSVGPatternLayer *)patternStrokeLayerForLayer:(IJSVGShapeLayer *)layer - pattern:(IJSVGPattern *)pattern - fromNode:(IJSVGNode *)path +- (IJSVGPatternLayer*)patternStrokeLayerForLayer:(IJSVGShapeLayer*)layer + pattern:(IJSVGPattern*)pattern + fromNode:(IJSVGNode*)path { // create the pattern, this is actually not as easy as it may seem - IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease]; + IJSVGPatternLayer* patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease]; patternLayer.patternNode = pattern; patternLayer.pattern = [self layerForNode:pattern]; - + // is there a fill opacity? - if(path.fillOpacity.value != 0.f) { + if (path.fillOpacity.value != 0.f) { patternLayer.opacity = path.fillOpacity.value; } - + // set the bounds CGRect bounds = CGPathGetBoundingBox(layer.path); bounds = [self correctBounds:bounds forStrokedPath:path]; patternLayer.frame = bounds; patternLayer.masksToBounds = YES; - + // display [patternLayer setNeedsDisplay]; return patternLayer; } -- (IJSVGPatternLayer *)patternLayerForLayer:(IJSVGShapeLayer *)layer - pattern:(IJSVGPattern *)pattern - fromNode:(IJSVGNode *)path +- (IJSVGPatternLayer*)patternLayerForLayer:(IJSVGShapeLayer*)layer + pattern:(IJSVGPattern*)pattern + fromNode:(IJSVGNode*)path { // create the pattern, this is actually not as easy as it may seem - IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease]; + IJSVGPatternLayer* patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease]; patternLayer.patternNode = pattern; patternLayer.pattern = [self layerForNode:pattern]; patternLayer.frame = CGPathGetBoundingBox(layer.path); - + // is there a fill opacity? - if(path.fillOpacity.value != 0.f) { + if (path.fillOpacity.value != 0.f) { patternLayer.opacity = path.fillOpacity.value; } - + // add the mask patternLayer.mask = [self layerMaskFromLayer:layer fromNode:path]; - + // display [patternLayer setNeedsDisplay]; patternLayer.masksToBounds = YES; - + return patternLayer; } -- (void)applyOffsetsToLayer:(IJSVGLayer *)layer - fromNode:(IJSVGNode *)node +- (void)applyOffsetsToLayer:(IJSVGLayer*)layer + fromNode:(IJSVGNode*)node { // make sure it has a superlayer - if(layer.superlayer == nil) { + if (layer.superlayer == nil) { return; } - + // grab the x and y - IJSVGUnitLength * x = nil; - IJSVGUnitLength * y = nil; - + IJSVGUnitLength* x = nil; + IJSVGUnitLength* y = nil; + // sort out the rect CGRect rect = layer.superlayer.frame; CGRect frame = layer.frame; - + // x - if((x = node.x) != nil) { + if ((x = node.x) != nil) { frame.origin.x = [x computeValue:rect.size.width]; } - + // y - if((y = node.y) != nil) { + if ((y = node.y) != nil) { frame.origin.y = [y computeValue:rect.size.height]; } - + // update the frame - if(CGRectEqualToRect(frame, layer.frame) == NO) { + if (CGRectEqualToRect(frame, layer.frame) == NO) { layer.frame = frame; } - } -- (IJSVGStrokeLayer *)strokeLayer:(IJSVGShapeLayer *)layer - fromNode:(IJSVGPath *)path +- (IJSVGStrokeLayer*)strokeLayer:(IJSVGShapeLayer*)layer + fromNode:(IJSVGPath*)path { // same as fill, dont use global if the alpha is 0.f, but do use it // if there is a pattern or gradient - NSColor * sColor = path.strokeColor; - if(_style.strokeColor != nil && - ((sColor != nil && sColor.alphaComponent != 0.f) || - path.strokePattern != nil || path.strokeGradient != nil )) { + NSColor* sColor = path.strokeColor; + if (_style.strokeColor != nil && ((sColor != nil && sColor.alphaComponent != 0.f) || path.strokePattern != nil || path.strokeGradient != nil)) { sColor = _style.strokeColor; } - + sColor = [_style.colorList proposedColorForColor:sColor]; - + // stroke layer - IJSVGStrokeLayer * strokeLayer = [[[IJSVGStrokeLayer alloc] init] autorelease]; + IJSVGStrokeLayer* strokeLayer = [[[IJSVGStrokeLayer alloc] init] autorelease]; strokeLayer.path = layer.path; strokeLayer.fillColor = nil; strokeLayer.strokeColor = sColor.CGColor; - + CGFloat lineWidth = 1.f; - if(_style.lineWidth != IJSVGInheritedFloatValue) { + if (_style.lineWidth != IJSVGInheritedFloatValue) { lineWidth = _style.lineWidth; } else { lineWidth = path.strokeWidth.value; } - + // work out line styles IJSVGLineCapStyle lCapStyle; IJSVGLineJoinStyle lJoinStyle; - + // forced cap style - if(_style.lineCapStyle != IJSVGLineCapStyleNone) { + if (_style.lineCapStyle != IJSVGLineCapStyleNone) { lCapStyle = _style.lineCapStyle; } else { lCapStyle = path.lineCapStyle; } - + // forced join style - if(_style.lineJoinStyle != IJSVGLineJoinStyleNone) { + if (_style.lineJoinStyle != IJSVGLineJoinStyleNone) { lJoinStyle = _style.lineJoinStyle; } else { lJoinStyle = path.lineJoinStyle; } - + // line styles strokeLayer.lineWidth = lineWidth; strokeLayer.lineCap = [self lineCap:lCapStyle]; strokeLayer.lineJoin = [self lineJoin:lJoinStyle]; - + CGFloat strokeOpacity = 1.f; - if(path.strokeOpacity.value != 0.f) { + if (path.strokeOpacity.value != 0.f) { strokeOpacity = path.strokeOpacity.value; } strokeLayer.opacity = strokeOpacity; - + // dashing strokeLayer.lineDashPhase = path.strokeDashOffset.value; strokeLayer.lineDashPattern = [self lineDashPattern:path]; - + return strokeLayer; } -- (void)maskLayer:(IJSVGLayer *)layer - fromNode:(IJSVGNode *)node +- (void)maskLayer:(IJSVGLayer*)layer + fromNode:(IJSVGNode*)node { // any clippath? - if(node.clipPath != nil || node.mask != nil) { - IJSVGGroupLayer * maskLayer = [[[IJSVGGroupLayer alloc] init] autorelease]; - + if (node.clipPath != nil || node.mask != nil) { + IJSVGGroupLayer* maskLayer = [[[IJSVGGroupLayer alloc] init] autorelease]; + // add clip mask - if(node.clipPath != nil) { - IJSVGLayer * clip = [self layerForNode:node.clipPath]; - + if (node.clipPath != nil) { + IJSVGLayer* clip = [self layerForNode:node.clipPath]; + // adjust the frame - [self adjustLayer:clip - toParentLayerFrame:layer]; - + if (node.clipPath.units == IJSVGUnitObjectBoundingBox) { + [self adjustLayer:clip + toParentLayerFrame:layer]; + } else { + clip.affineTransform = [self absoluteTransform:node]; + } + // add the layer [maskLayer addSublayer:clip]; } - + // add the actual mask - if(node.mask != nil) { - IJSVGLayer * mask = [self layerForNode:node.mask]; - + if (node.mask != nil) { + IJSVGLayer* mask = [self layerForNode:node.mask]; + // only move if bounding box - if(node.mask.units == IJSVGUnitObjectBoundingBox) { + if (node.mask.units == IJSVGUnitObjectBoundingBox) { [self adjustLayer:mask - toParentLayerFrame:layer]; + toParentLayerFrame:layer]; + } else { + mask.affineTransform = [self absoluteTransform:node]; } - + // add the layer [maskLayer addSublayer:mask]; } - + // recursive colourize for each item [self _recursiveColorLayersFromLayer:maskLayer withColor:[IJSVGColor computeColorSpace:NSColor.whiteColor].CGColor]; - + // add the mask layer.mask = maskLayer; } } -- (void)_recursiveColorLayersFromLayer:(IJSVGLayer *)layer +- (void)_recursiveColorLayersFromLayer:(IJSVGLayer*)layer withColor:(CGColorRef)color { - if([layer isKindOfClass:[IJSVGShapeLayer class]]) { + if ([layer isKindOfClass:[IJSVGShapeLayer class]]) { // has a proper fill method - for(IJSVGLayer * c in layer.sublayers) { - if([c isKindOfClass:[IJSVGGradientLayer class]] || - [c isKindOfClass:[IJSVGPatternLayer class]]) { + for (IJSVGLayer* c in layer.sublayers) { + if ([c isKindOfClass:[IJSVGGradientLayer class]] || + [c isKindOfClass:[IJSVGPatternLayer class]]) { return; } } - + // set the fill - IJSVGShapeLayer * l = (IJSVGShapeLayer *)layer; + IJSVGShapeLayer* l = (IJSVGShapeLayer*)layer; l.fillColor = color; - } else if([layer isKindOfClass:[IJSVGGroupLayer class]]) { + } else if ([layer isKindOfClass:[IJSVGGroupLayer class]]) { // go through its children, assume its a group - for(IJSVGLayer * child in layer.sublayers) { + for (IJSVGLayer* child in layer.sublayers) { [self _recursiveColorLayersFromLayer:child withColor:color]; } } } -- (void)adjustLayer:(IJSVGLayer *)childLayer - toParentLayerFrame:(IJSVGLayer *)parent +- (void)adjustLayer:(IJSVGLayer*)childLayer + toParentLayerFrame:(IJSVGLayer*)parent { childLayer.frame = (CGRect){ .size = childLayer.frame.size, .origin = CGPointMake((childLayer.frame.origin.x - parent.frame.origin.x), - (childLayer.frame.origin.y - parent.frame.origin.y)) + (childLayer.frame.origin.y - parent.frame.origin.y)) }; } -- (NSArray *)lineDashPattern:(IJSVGNode *)node +- (NSArray*)lineDashPattern:(IJSVGNode*)node { - NSMutableArray * arr = [[[NSMutableArray alloc] init] autorelease]; - for(NSInteger i = 0; i < node.strokeDashArrayCount; i++) { + NSMutableArray* arr = [[[NSMutableArray alloc] init] autorelease]; + for (NSInteger i = 0; i < node.strokeDashArrayCount; i++) { [arr addObject:@((CGFloat)node.strokeDashArray[i])]; } return [[arr copy] autorelease]; } -- (NSString *)lineJoin:(IJSVGLineJoinStyle)joinStyle +- (NSString*)lineJoin:(IJSVGLineJoinStyle)joinStyle { switch (joinStyle) { - default: - case IJSVGLineJoinStyleMiter: { - return kCALineJoinMiter; - } - case IJSVGLineJoinStyleBevel: { - return kCALineJoinBevel; - } - case IJSVGLineJoinStyleRound: { - return kCALineJoinRound; - } + default: + case IJSVGLineJoinStyleMiter: { + return kCALineJoinMiter; + } + case IJSVGLineJoinStyleBevel: { + return kCALineJoinBevel; + } + case IJSVGLineJoinStyleRound: { + return kCALineJoinRound; + } } } -- (NSString *)lineCap:(IJSVGLineCapStyle)capStyle +- (NSString*)lineCap:(IJSVGLineCapStyle)capStyle { switch (capStyle) { - default: - case IJSVGLineCapStyleButt: { - return kCALineCapButt; - } - case IJSVGLineCapStyleRound: { - return kCALineCapRound; - } - case IJSVGLineCapStyleSquare: { - return kCALineCapSquare; - } + default: + case IJSVGLineCapStyleButt: { + return kCALineCapButt; + } + case IJSVGLineCapStyleRound: { + return kCALineCapRound; + } + case IJSVGLineCapStyleSquare: { + return kCALineCapSquare; + } } } -- (NSString *)fillRule:(IJSVGWindingRule)rule +- (NSString*)fillRule:(IJSVGWindingRule)rule { switch (rule) { - case IJSVGWindingRuleEvenOdd: { - return kCAFillRuleEvenOdd; - } - default: { - return kCAFillRuleNonZero; - } + case IJSVGWindingRuleEvenOdd: { + return kCAFillRuleEvenOdd; + } + default: { + return kCAFillRuleNonZero; + } } } -+ (void)log:(IJSVGLayer *)layer - depth:(NSInteger)depth { - NSLog(@"%@%@: %@, Transforms: %@",[@"" stringByPaddingToLength:depth - withString:@"\t" - startingAtIndex:0],layer, - NSStringFromRect(layer.frame), - [IJSVGTransform affineTransformToSVGTransformAttributeString:layer.affineTransform]); - for(IJSVGLayer * sublayer in layer.sublayers) { - [self log:(IJSVGLayer *)sublayer ++ (void)log:(IJSVGLayer*)layer + depth:(NSInteger)depth +{ + NSLog(@"%@%@: %@, Transforms: %@", [@"" stringByPaddingToLength:depth + withString:@"\t" + startingAtIndex:0], + layer, + NSStringFromRect(layer.frame), + [IJSVGTransform affineTransformToSVGTransformAttributeString:layer.affineTransform]); + for (IJSVGLayer* sublayer in layer.sublayers) { + [self log:(IJSVGLayer*)sublayer depth:depth++]; } } diff --git a/source/IJSVGRendering.h b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRendering.h similarity index 55% rename from source/IJSVGRendering.h rename to Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRendering.h index 8e33db5..e16101f 100644 --- a/source/IJSVGRendering.h +++ b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRendering.h @@ -8,12 +8,12 @@ #import -typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)(); +typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)(void); typedef NS_ENUM(NSInteger, IJSVGRenderQuality) { - IJSVGRenderQualityFullResolution, // slowest to render - IJSVGRenderQualityOptimized, // best of both worlds - IJSVGRenderQualityLow // fast rendering + kIJSVGRenderQualityFullResolution, // slowest to render + kIJSVGRenderQualityOptimized, // best of both worlds + kIJSVGRenderQualityLow // fast rendering }; @interface IJSVGRendering : NSObject diff --git a/source/IJSVGRendering.m b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRendering.m similarity index 100% rename from source/IJSVGRendering.m rename to Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRendering.m diff --git a/source/IJSVGRenderingStyle.h b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRenderingStyle.h similarity index 63% rename from source/IJSVGRenderingStyle.h rename to Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRenderingStyle.h index 79882a5..c228fc4 100644 --- a/source/IJSVGRenderingStyle.h +++ b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRenderingStyle.h @@ -6,19 +6,21 @@ // Copyright © 2019 Curtis Hard. All rights reserved. // -#import -#import "IJSVGNode.h" #import "IJSVGColorList.h" +#import "IJSVGNode.h" +#import +#import +#import @interface IJSVGRenderingStyle : NSObject @property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle; @property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle; @property (nonatomic, assign) CGFloat lineWidth; -@property (nonatomic, retain) IJSVGColorList * colorList; -@property (nonatomic, retain) NSColor * fillColor; -@property (nonatomic, retain) NSColor * strokeColor; +@property (nonatomic, retain) IJSVGColorList* colorList; +@property (nonatomic, retain) NSColor* fillColor; +@property (nonatomic, retain) NSColor* strokeColor; -+ (NSArray *)observableProperties; ++ (NSArray*)observableProperties; @end diff --git a/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRenderingStyle.m b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRenderingStyle.m new file mode 100644 index 0000000..430ac62 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Rendering/IJSVGRenderingStyle.m @@ -0,0 +1,50 @@ +// +// IJSVGStyleList.m +// IconJar +// +// Created by Curtis Hard on 09/07/2019. +// Copyright © 2019 Curtis Hard. All rights reserved. +// + +#import "IJSVGRenderingStyle.h" + +@implementation IJSVGRenderingStyle + +@synthesize colorList = _colorList; +@synthesize lineCapStyle = _lineCapStyle; +@synthesize lineJoinStyle = _lineJoinStyle; +@synthesize lineWidth = _lineWidth; +@synthesize fillColor = _fillColor; +@synthesize strokeColor = _strokeColor; + +- (void)dealloc +{ + (void)([_fillColor release]), _fillColor = nil; + (void)([_strokeColor release]), _strokeColor = nil; + (void)([_colorList release]), _colorList = nil; + [super dealloc]; +} + +- (id)init +{ + if ((self = [super init]) != nil) { + _lineCapStyle = IJSVGLineCapStyleNone; + _lineJoinStyle = IJSVGLineJoinStyleNone; + _lineWidth = IJSVGInheritedFloatValue; + _colorList = [[IJSVGColorList alloc] init]; + } + return self; +} + ++ (NSArray*)observableProperties +{ + static NSArray* array = nil; + if (array == nil) { + array = @[ @"lineCapStyle", @"lineJoinStyle", @"lineWidth", + @"colorList", @"fillColor", @"strokeColor" ] + .retain; + } + return array; +} + +@end diff --git a/source/IJSVGStyle.h b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyle.h similarity index 57% rename from source/IJSVGStyle.h rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyle.h index a480638..cb53592 100644 --- a/source/IJSVGStyle.h +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyle.h @@ -6,22 +6,21 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import #import "IJSVGColor.h" +#import @interface IJSVGStyle : NSObject { - + @private - NSMutableDictionary * _dict; - + NSMutableDictionary* _dict; } -+ (IJSVGStyle *)parseStyleString:(NSString *)string; ++ (IJSVGStyle*)parseStyleString:(NSString*)string; - (void)setPropertyValue:(id)value - forProperty:(NSString *)key; -- (id)property:(NSString *)key; + forProperty:(NSString*)key; +- (id)property:(NSString*)key; -- (IJSVGStyle *)mergedStyle:(IJSVGStyle *)style; +- (IJSVGStyle*)mergedStyle:(IJSVGStyle*)style; @end diff --git a/source/IJSVGStyle.m b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyle.m similarity index 61% rename from source/IJSVGStyle.m rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyle.m index 92a86d4..215516c 100644 --- a/source/IJSVGStyle.m +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyle.m @@ -13,68 +13,68 @@ @implementation IJSVGStyle - (void)dealloc { - [_dict release], _dict = nil; + (void)([_dict release]), _dict = nil; [super dealloc]; } - (id)init { - if( ( self = [super init] ) != nil ) { + if ((self = [super init]) != nil) { _dict = [[NSMutableDictionary alloc] init]; } return self; } - (void)setPropertyValue:(id)value - forProperty:(NSString *)key + forProperty:(NSString*)key { [_dict setObject:value forKey:key]; } -- (NSDictionary *)properties +- (NSDictionary*)properties { return _dict; } -- (id)property:(NSString *)key +- (id)property:(NSString*)key { return [_dict objectForKey:key]; } -+ (IJSVGStyle *)parseStyleString:(NSString *)string ++ (IJSVGStyle*)parseStyleString:(NSString*)string { - IJSVGStyle * style = [[[self.class alloc] init] autorelease]; + IJSVGStyle* style = [[[self.class alloc] init] autorelease]; NSInteger length = string.length; NSInteger index = 0; - NSString * key = nil; - NSString * value = nil; - + NSString* key = nil; + NSString* value = nil; + // iterate over the string - its actually really simple what we need // to do - for(NSInteger i = 0; i < length; i++) { + for (NSInteger i = 0; i < length; i++) { unichar c = [string characterAtIndex:i]; - + // find the key - if(c == ':') { - key = [string substringWithRange:NSMakeRange(index, (i-index))]; - index = i+1; + if (c == ':') { + key = [string substringWithRange:NSMakeRange(index, (i - index))]; + index = i + 1; } - + // find the value - else if(c == ';' || i == (length-1)) { + else if (c == ';' || i == (length - 1)) { NSInteger chomp; - if(i == (length-1) && c != ';') { - chomp = (i-(index-1)); + if (i == (length - 1) && c != ';') { + chomp = (i - (index - 1)); } else { - chomp = (i-index); + chomp = (i - index); } value = [string substringWithRange:NSMakeRange(index, chomp)]; - index = i+1; + index = i + 1; } - + // set the propery if it actually exists - if(key != nil && value != nil) { + if (key != nil && value != nil) { [style setPropertyValue:[self.class trimString:value] forProperty:[self.class trimString:key]]; key = nil; @@ -84,41 +84,41 @@ + (IJSVGStyle *)parseStyleString:(NSString *)string return style; } -+ (NSString *)trimString:(NSString *)string ++ (NSString*)trimString:(NSString*)string { return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; } -+ (NSArray *)allowedColourKeys ++ (NSArray*)allowedColourKeys { - return @[@"fill",@"stroke-colour",@"stop-color",@"stroke"]; + return @[ @"fill", @"stroke-colour", @"stop-color", @"stroke" ]; } -- (void)setProperties:(NSDictionary *)properties +- (void)setProperties:(NSDictionary*)properties replaceAll:(BOOL)flag { - if(flag) { + if (flag) { [_dict removeAllObjects]; } [_dict addEntriesFromDictionary:properties]; } -- (NSString *)description +- (NSString*)description { return [_dict description]; } -- (IJSVGStyle *)mergedStyle:(IJSVGStyle *)style +- (IJSVGStyle*)mergedStyle:(IJSVGStyle*)style { // create the new style - IJSVGStyle * newStyle = [[[IJSVGStyle alloc] init] autorelease]; - + IJSVGStyle* newStyle = [[[IJSVGStyle alloc] init] autorelease]; + // grab the current style - NSMutableDictionary * dict = [[[self properties] mutableCopy] autorelease]; - + NSMutableDictionary* dict = [[[self properties] mutableCopy] autorelease]; + // overwride the style with the new styles [dict addEntriesFromDictionary:[style properties]]; - + // add the styles to the style [newStyle setProperties:dict replaceAll:YES]; diff --git a/source/IJSVGStyleSheet.h b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheet.h similarity index 66% rename from source/IJSVGStyleSheet.h rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheet.h index bfbc2b3..83dcd9a 100644 --- a/source/IJSVGStyleSheet.h +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheet.h @@ -6,20 +6,20 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import -#import "IJSVGStyleSheetSelector.h" #import "IJSVGStyleSheetRule.h" +#import "IJSVGStyleSheetSelector.h" +#import @class IJSVGNode; @interface IJSVGStyleSheet : NSObject { - + @private - NSMutableDictionary * _selectors; - NSMutableArray * _rules; + NSMutableDictionary* _selectors; + NSMutableArray* _rules; } -- (void)parseStyleBlock:(NSString *)string; -- (IJSVGStyle *)styleForNode:(IJSVGNode *)node; +- (void)parseStyleBlock:(NSString*)string; +- (IJSVGStyle*)styleForNode:(IJSVGNode*)node; @end diff --git a/source/IJSVGStyleSheet.m b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheet.m similarity index 54% rename from source/IJSVGStyleSheet.m rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheet.m index 185a81f..d57b8e7 100644 --- a/source/IJSVGStyleSheet.m +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheet.m @@ -6,19 +6,18 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import "IJSVGStyleSheet.h" -#import "IJSVGStyle.h" #import "IJSVGNode.h" +#import "IJSVGStyle.h" +#import "IJSVGStyleSheet.h" @interface IJSVGStyleSheetSelectorListItem : NSObject { - - IJSVGStyleSheetSelector * selector; - IJSVGStyleSheetRule * rule; - + + IJSVGStyleSheetSelector* selector; + IJSVGStyleSheetRule* rule; } -@property (nonatomic, retain) IJSVGStyleSheetRule * rule; -@property (nonatomic, retain) IJSVGStyleSheetSelector * selector; +@property (nonatomic, retain) IJSVGStyleSheetRule* rule; +@property (nonatomic, retain) IJSVGStyleSheetSelector* selector; @end @@ -28,8 +27,8 @@ @implementation IJSVGStyleSheetSelectorListItem - (void)dealloc { - [rule release], rule = nil; - [selector release], selector = nil; + (void)([rule release]), rule = nil; + (void)([selector release]), selector = nil; [super dealloc]; } @@ -39,76 +38,73 @@ @implementation IJSVGStyleSheet - (void)dealloc { - [_selectors release], _selectors = nil; - [_rules release], _rules = nil; + (void)([_selectors release]), _selectors = nil; + (void)([_rules release]), _rules = nil; [super dealloc]; } - (id)init { - if((self = [super init]) != nil) - { + if ((self = [super init]) != nil) { _selectors = [[NSMutableDictionary alloc] init]; _rules = [[NSMutableArray alloc] init]; } return self; } -- (NSArray *)selectorsWithSelectorString:(NSString *)string +- (NSArray*)selectorsWithSelectorString:(NSString*)string { - NSMutableArray * array = [[[NSMutableArray alloc] init] autorelease]; - + NSMutableArray* array = [[[NSMutableArray alloc] init] autorelease]; + // split the string by the comma, as it could be multiple - NSArray * comp = [string componentsSeparatedByString:@","]; - NSCharacterSet * whiteSpaceCharSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - + NSArray* comp = [string componentsSeparatedByString:@","]; + NSCharacterSet* whiteSpaceCharSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + // create a selector or reuse one already being used - for( NSString * selectorName in comp ) - { + for (NSString* selectorName in comp) { selectorName = [selectorName stringByTrimmingCharactersInSet:whiteSpaceCharSet]; - IJSVGStyleSheetSelector * selector = nil; - + IJSVGStyleSheetSelector* selector = nil; + // create a new selector if not found - if((selector = [_selectors objectForKey:selectorName]) == nil) { + if ((selector = [_selectors objectForKey:selectorName]) == nil) { selector = [[[IJSVGStyleSheetSelector alloc] initWithSelectorString:selectorName] autorelease]; - if(selector != nil) { + if (selector != nil) { [_selectors setObject:selector forKey:selectorName]; } } - + // add it to our list - if(selector != nil) { + if (selector != nil) { [array addObject:selector]; } } return array; } -- (void)parseStyleBlock:(NSString *)string +- (void)parseStyleBlock:(NSString*)string { NSUInteger depth = 0, marker = 0; NSUInteger length = [string length]; - NSCharacterSet * whitespaceCharSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - - NSString * selector = nil; - - for( NSUInteger i = 0; i < length; i++ ) - { + NSCharacterSet* whitespaceCharSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + + NSString* selector = nil; + + for (NSUInteger i = 0; i < length; i++) { unichar c = [string characterAtIndex:i]; - if( c == '/' ) { + if (c == '/') { i++; - if( i -#import "IJSVGStyleSheetSelector.h" #import "IJSVGStyle.h" +#import "IJSVGStyleSheetSelector.h" +#import @class IJSVGNode; @interface IJSVGStyleSheetRule : NSObject { - - NSArray * selectors; - IJSVGStyle * style; - + + NSArray* selectors; + IJSVGStyle* style; } -@property (nonatomic, retain) NSArray * selectors; -@property (nonatomic, retain) IJSVGStyle * style; +@property (nonatomic, retain) NSArray* selectors; +@property (nonatomic, retain) IJSVGStyle* style; -- (BOOL)matchesNode:(IJSVGNode *)node - selector:(IJSVGStyleSheetSelector **)matchedSelector; +- (BOOL)matchesNode:(IJSVGNode*)node + selector:(IJSVGStyleSheetSelector**)matchedSelector; @end diff --git a/source/IJSVGStyleSheetRule.m b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetRule.m similarity index 62% rename from source/IJSVGStyleSheetRule.m rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetRule.m index 528bb70..659b425 100644 --- a/source/IJSVGStyleSheetRule.m +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetRule.m @@ -14,18 +14,18 @@ @implementation IJSVGStyleSheetRule - (void)dealloc { - [selectors release], selectors = nil; - [style release], style = nil; + (void)([selectors release]), selectors = nil; + (void)([style release]), style = nil; [super dealloc]; } -- (BOOL)matchesNode:(IJSVGNode *)node - selector:(IJSVGStyleSheetSelector **)matchedSelector +- (BOOL)matchesNode:(IJSVGNode*)node + selector:(IJSVGStyleSheetSelector**)matchedSelector { // interate over each select and work out if // it allows us to be applied - for(IJSVGStyleSheetSelector * selector in selectors) { - if([selector matchesNode:node]) { + for (IJSVGStyleSheetSelector* selector in selectors) { + if ([selector matchesNode:node]) { *matchedSelector = selector; return YES; } diff --git a/source/IJSVGStyleSheetSelector.h b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelector.h similarity index 71% rename from source/IJSVGStyleSheetSelector.h rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelector.h index 96bd602..5245f4a 100644 --- a/source/IJSVGStyleSheetSelector.h +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelector.h @@ -6,23 +6,22 @@ // Copyright © 2016 Curtis Hard. All rights reserved. // -#import #import "IJSVGStyleSheetSelectorRaw.h" +#import @class IJSVGNode; @interface IJSVGStyleSheetSelector : NSObject { - - NSString * selector; + + NSString* selector; NSUInteger specificity; @private - NSMutableArray * _rawSelectors; - + NSMutableArray* _rawSelectors; } @property (nonatomic, assign) NSUInteger specificity; -- (id)initWithSelectorString:(NSString *)string; -- (BOOL)matchesNode:(IJSVGNode *)node; +- (id)initWithSelectorString:(NSString*)string; +- (BOOL)matchesNode:(IJSVGNode*)node; @end diff --git a/source/IJSVGStyleSheetSelector.m b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelector.m similarity index 98% rename from source/IJSVGStyleSheetSelector.m rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelector.m index 6c73772..a0d7272 100644 --- a/source/IJSVGStyleSheetSelector.m +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelector.m @@ -246,8 +246,8 @@ - (BOOL)_matches:(IJSVGNode *)aNode - (void)dealloc { - [_rawSelectors release], _rawSelectors = nil; - [selector release], selector = nil; + (void)([_rawSelectors release]), _rawSelectors = nil; + (void)([selector release]), selector = nil; [super dealloc]; } @@ -260,7 +260,7 @@ - (id)initWithSelectorString:(NSString *)string // failed to compile if([self _compile] == NO) { - [self release], self = nil; + (void)([self release]), self = nil; return nil; } [self _calculate]; diff --git a/source/IJSVGStyleSheetSelectorRaw.h b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelectorRaw.h similarity index 65% rename from source/IJSVGStyleSheetSelectorRaw.h rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelectorRaw.h index 70b7031..48c46c3 100644 --- a/source/IJSVGStyleSheetSelectorRaw.h +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelectorRaw.h @@ -19,21 +19,20 @@ typedef NS_ENUM(NSUInteger, IJSVGStyleSheetSelectorCombinator) { @interface IJSVGStyleSheetSelectorRaw : NSObject { - NSString * tag; - NSString * identifier; - - NSMutableArray * classes; - + NSString* tag; + NSString* identifier; + + NSMutableArray* classes; + IJSVGStyleSheetSelectorCombinator combinator; - NSString * combinatorString; - + NSString* combinatorString; } -@property (nonatomic, copy) NSString * tag; -@property (nonatomic, copy) NSString * identifier; -@property (nonatomic, copy) NSString * combinatorString; -@property (nonatomic, retain) NSArray * classes; +@property (nonatomic, copy) NSString* tag; +@property (nonatomic, copy) NSString* identifier; +@property (nonatomic, copy) NSString* combinatorString; +@property (nonatomic, retain) NSArray* classes; @property (nonatomic, assign) IJSVGStyleSheetSelectorCombinator combinator; -- (void)addClassName:(NSString *)className; +- (void)addClassName:(NSString*)className; @end diff --git a/source/IJSVGStyleSheetSelectorRaw.m b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelectorRaw.m similarity index 70% rename from source/IJSVGStyleSheetSelectorRaw.m rename to Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelectorRaw.m index 9509dda..3833ce2 100644 --- a/source/IJSVGStyleSheetSelectorRaw.m +++ b/Framework/IJSVG/IJSVG/Source/Stylesheets/IJSVGStyleSheetSelectorRaw.m @@ -14,17 +14,16 @@ @implementation IJSVGStyleSheetSelectorRaw - (void)dealloc { - [classes release], classes = nil; - [identifier release], identifier = nil; - [tag release], tag = nil; - [combinatorString release], combinatorString = nil; + (void)([classes release]), classes = nil; + (void)([identifier release]), identifier = nil; + (void)([tag release]), tag = nil; + (void)([combinatorString release]), combinatorString = nil; [super dealloc]; } - (id)init { - if( ( self = [super init] ) != nil ) - { + if ((self = [super init]) != nil) { classes = [[NSMutableArray alloc] init]; combinator = IJSVGStyleSheetSelectorCombinatorDescendant; combinatorString = @" "; @@ -32,12 +31,12 @@ - (id)init return self; } -- (void)addClassName:(NSString *)className +- (void)addClassName:(NSString*)className { [classes addObject:className]; } -- (NSString *)description +- (NSString*)description { return [NSString stringWithFormat:@"Combinator: %@, Tag: %@, Classes: %@, Identifier: %@", combinatorString, tag, classes, identifier]; } diff --git a/source/IJSVGGradientUnitLength.h b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGGradientUnitLength.h similarity index 100% rename from source/IJSVGGradientUnitLength.h rename to Framework/IJSVG/IJSVG/Source/Utils/IJSVGGradientUnitLength.h diff --git a/source/IJSVGGradientUnitLength.m b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGGradientUnitLength.m similarity index 66% rename from source/IJSVGGradientUnitLength.m rename to Framework/IJSVG/IJSVG/Source/Utils/IJSVGGradientUnitLength.m index cff7a73..c873ac3 100644 --- a/source/IJSVGGradientUnitLength.m +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGGradientUnitLength.m @@ -10,10 +10,10 @@ @implementation IJSVGGradientUnitLength -- (NSString *)stringValue +- (NSString*)stringValue { - if(self.type == IJSVGUnitLengthTypePercentage) { - return [NSString stringWithFormat:@"%g",self.value]; + if (self.type == IJSVGUnitLengthTypePercentage) { + return [NSString stringWithFormat:@"%g", self.value]; } return [super stringValue]; } diff --git a/source/IJSVGMath.h b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGMath.h similarity index 100% rename from source/IJSVGMath.h rename to Framework/IJSVG/IJSVG/Source/Utils/IJSVGMath.h diff --git a/source/IJSVGMath.m b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGMath.m similarity index 64% rename from source/IJSVGMath.m rename to Framework/IJSVG/IJSVG/Source/Utils/IJSVGMath.m index 7f4a24c..f169c76 100644 --- a/source/IJSVGMath.m +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGMath.m @@ -10,31 +10,38 @@ @implementation IJSVGMath -CGFloat IJSVGMathRad(CGFloat val) { +CGFloat IJSVGMathRad(CGFloat val) +{ return val * M_PI / 180; }; -CGFloat IJSVGMathDeg(CGFloat val) { +CGFloat IJSVGMathDeg(CGFloat val) +{ return val * 180.f / M_PI; }; -CGFloat IJSVGMathAcos(CGFloat val) { +CGFloat IJSVGMathAcos(CGFloat val) +{ return IJSVGMathDeg(acosf(val)); }; -CGFloat IJSVGMathSin(CGFloat val) { +CGFloat IJSVGMathSin(CGFloat val) +{ return sinf(IJSVGMathRad(val)); }; -CGFloat IJSVGMathAsin(CGFloat val) { +CGFloat IJSVGMathAsin(CGFloat val) +{ return IJSVGMathDeg(asinf(val)); }; -CGFloat IJSVGMathTan(CGFloat val) { +CGFloat IJSVGMathTan(CGFloat val) +{ return tanf(IJSVGMathRad(val)); }; -CGFloat IJSVGMathAtan(CGFloat val) { +CGFloat IJSVGMathAtan(CGFloat val) +{ return IJSVGMathDeg(atanf(val)); }; diff --git a/source/IJSVGTransaction.h b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransaction.h similarity index 54% rename from source/IJSVGTransaction.h rename to Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransaction.h index 8229860..ba4b9dc 100644 --- a/source/IJSVGTransaction.h +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransaction.h @@ -7,7 +7,8 @@ // #import +#import -void IJSVGBeginTransactionLock(); -void IJSVGEndTransactionLock(); -void IJSVGObtainTransactionLock(dispatch_block_t block, BOOL renderOnMainThread); +BOOL IJSVGIsMainThread(void); +void IJSVGBeginTransactionLock(void); +void IJSVGEndTransactionLock(void); diff --git a/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransaction.m b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransaction.m new file mode 100644 index 0000000..6ef29da --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransaction.m @@ -0,0 +1,28 @@ +// +// IJSVGTransaction.m +// IconJar +// +// Created by Curtis Hard on 11/01/2017. +// Copyright © 2017 Curtis Hard. All rights reserved. +// + +#import "IJSVGTransaction.h" + +BOOL IJSVGIsMainThread(void) { return NSThread.isMainThread; }; + +void IJSVGBeginTransactionLock(void) +{ + if (IJSVGIsMainThread()) { + return; + } + [CATransaction begin]; + [CATransaction setDisableActions:YES]; +}; + +void IJSVGEndTransactionLock(void) +{ + if (IJSVGIsMainThread()) { + return; + } + [CATransaction commit]; +}; diff --git a/source/IJSVGTransform.h b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransform.h similarity index 97% rename from source/IJSVGTransform.h rename to Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransform.h index 757c0dd..0416b49 100644 --- a/source/IJSVGTransform.h +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransform.h @@ -14,7 +14,7 @@ typedef CGFloat (^IJSVGTransformParameterModifier)(NSInteger index, CGFloat value); typedef void (^IJSVGTransformApplyBlock)(IJSVGTransform * transform); -typedef NS_OPTIONS( NSInteger, IJSVGTransformCommand ) { +typedef NS_OPTIONS(NSInteger, IJSVGTransformCommand) { IJSVGTransformCommandMatrix, IJSVGTransformCommandTranslate, IJSVGTransformCommandTranslateX, diff --git a/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransform.m b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransform.m new file mode 100644 index 0000000..aef32e8 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGTransform.m @@ -0,0 +1,603 @@ +// +// IJSVGTransform.m +// IconJar +// +// Created by Curtis Hard on 01/09/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGMath.h" +#import "IJSVGTransform.h" + +@implementation IJSVGTransform + +@synthesize command; +@synthesize parameters; +@synthesize parameterCount; +@synthesize sort; + +- (void)dealloc +{ + free(parameters); + [super dealloc]; +} + +- (id)copyWithZone:(NSZone*)zone +{ + IJSVGTransform* trans = [[self.class alloc] init]; + trans.command = self.command; + trans.parameters = (CGFloat*)malloc(sizeof(CGFloat) * self.parameterCount); + trans.sort = sort; + trans.parameterCount = self.parameterCount; + memcpy(trans.parameters, self.parameters, sizeof(CGFloat) * self.parameterCount); + return trans; +} + +NSString* IJSVGDebugAffineTransform(CGAffineTransform transform) +{ + NSMutableArray* strings = [[[NSMutableArray alloc] init] autorelease]; + [strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform]]; + return [strings componentsJoinedByString:@" "]; +} + +NSString* IJSVGDebugTransforms(NSArray* transforms) +{ + NSMutableArray* strings = [[[NSMutableArray alloc] init] autorelease]; + IJSVGApplyTransform(transforms, ^(IJSVGTransform* transform) { + [strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform.CGAffineTransform]]; + }); + return [strings componentsJoinedByString:@" "]; +} + +CGAffineTransform IJSVGConcatTransforms(NSArray* transforms) +{ + __block CGAffineTransform trans = CGAffineTransformIdentity; + IJSVGApplyTransform(transforms, ^(IJSVGTransform* transform) { + trans = CGAffineTransformConcat(trans, transform.CGAffineTransform); + }); + return trans; +} + +void IJSVGApplyTransform(NSArray* transforms, IJSVGTransformApplyBlock block) +{ + for (IJSVGTransform* transform in transforms) { + block(transform); + } +}; + ++ (IJSVGTransform*)transformByTranslatingX:(CGFloat)x + y:(CGFloat)y +{ + IJSVGTransform* transform = [[[self alloc] init] autorelease]; + transform.command = IJSVGTransformCommandTranslate; + transform.parameterCount = 2; + CGFloat* params = (CGFloat*)malloc(sizeof(CGFloat) * 2); + params[0] = x; + params[1] = y; + transform.parameters = params; + return transform; +} + +- (void)recalculateWithBounds:(CGRect)bounds +{ + CGFloat max = bounds.size.width > bounds.size.height ? bounds.size.width : bounds.size.height; + switch (self.command) { + case IJSVGTransformCommandRotate: { + if (self.parameterCount == 1) + return; + self.parameters[1] = self.parameters[1] * max; + self.parameters[2] = self.parameters[2] * max; + } + default: + return; + } +} + ++ (IJSVGTransformCommand)commandForCommandString:(NSString*)str +{ + str = str.lowercaseString; + if ([str isEqualToString:@"matrix"]) + return IJSVGTransformCommandMatrix; + if ([str isEqualToString:@"translate"]) + return IJSVGTransformCommandTranslate; + if ([str isEqualToString:@"translatex"]) + return IJSVGTransformCommandTranslateX; + if ([str isEqualToString:@"translatey"]) + return IJSVGTransformCommandTranslateY; + if ([str isEqualToString:@"scale"]) + return IJSVGTransformCommandScale; + if ([str isEqualToString:@"skewx"]) + return IJSVGTransformCommandSkewX; + if ([str isEqualToString:@"skewy"]) + return IJSVGTransformCommandSkewY; + if ([str isEqualToString:@"rotate"]) + return IJSVGTransformCommandRotate; + return IJSVGTransformCommandNotImplemented; +} + ++ (NSInteger)sortForTransformCommand:(IJSVGTransformCommand)command +{ + switch (command) { + case IJSVGTransformCommandScale: + return 0; + case IJSVGTransformCommandRotate: + return 1; + case IJSVGTransformCommandMatrix: + return 2; + case IJSVGTransformCommandTranslateX: + case IJSVGTransformCommandTranslateY: + case IJSVGTransformCommandTranslate: + return -1; + default: + return 10; + } + return 10; +} + ++ (NSArray*)transformsForString:(NSString*)string +{ + static NSRegularExpression* _reg = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z]+)\\(([^\\)]+)\\)" + options:0 + error:nil]; + }); + NSMutableArray* transforms = [[[NSMutableArray alloc] init] autorelease]; + @autoreleasepool { + [_reg enumerateMatchesInString:string + options:0 + range:NSMakeRange(0, string.length) + usingBlock:^(NSTextCheckingResult* result, NSMatchingFlags flags, BOOL* stop) { + NSString* command = [string substringWithRange:[result rangeAtIndex:1]]; + IJSVGTransformCommand commandType = [self.class commandForCommandString:command]; + if (commandType == IJSVGTransformCommandNotImplemented) { + return; + } + + // create the transform + NSString* params = [string substringWithRange:[result rangeAtIndex:2]]; + IJSVGTransform* transform = [[[self.class alloc] init] autorelease]; + NSInteger count = 0; + transform.command = commandType; + transform.parameters = [IJSVGUtils commandParameters:params + count:&count]; + transform.parameterCount = count; + transform.sort = [self.class sortForTransformCommand:commandType]; + [transforms addObject:transform]; + }]; + } + return transforms; +} + ++ (NSBezierPath*)transformedPath:(IJSVGPath*)path +{ + if (path.transforms.count == 0) + return path.path; + NSBezierPath* cop = [[path.path copy] autorelease]; + for (IJSVGTransform* transform in path.transforms) { + NSAffineTransform* at = NSAffineTransform.transform; + switch (transform.command) { + // matrix + case IJSVGTransformCommandMatrix: { + at.transformStruct = (NSAffineTransformStruct){ + .m11 = transform.parameters[0], + .m12 = transform.parameters[1], + .m21 = transform.parameters[2], + .m22 = transform.parameters[3], + .tX = transform.parameters[4], + .tY = transform.parameters[5], + }; + break; + } + + // skewX + case IJSVGTransformCommandSkewX: { + CGFloat degrees = transform.parameters[0]; + CGFloat radians = degrees * M_PI / 180.f; + at.transformStruct = (NSAffineTransformStruct){ + .m11 = 1.f, + .m12 = 0.f, + .m21 = tan(radians), + .m22 = 1.f, + .tX = 0.f, + .tY = 0.f + }; + break; + } + + // skewX + case IJSVGTransformCommandSkewY: { + CGFloat degrees = transform.parameters[0]; + CGFloat radians = degrees * M_PI / 180.f; + at.transformStruct = (NSAffineTransformStruct){ + .m11 = 1.f, + .m12 = tan(radians), + .m21 = 0.f, + .m22 = 1.f, + .tX = 0.f, + .tY = 0.f + }; + break; + } + + // translate + case IJSVGTransformCommandTranslate: { + if (transform.parameterCount == 1) + [at translateXBy:transform.parameters[0] + yBy:0]; + else + [at translateXBy:transform.parameters[0] + yBy:transform.parameters[1]]; + break; + } + + // translateX + case IJSVGTransformCommandTranslateX: { + [at translateXBy:transform.parameters[0] yBy:0.f]; + break; + } + + // translateY + case IJSVGTransformCommandTranslateY: { + [at translateXBy:0.f yBy:transform.parameters[0]]; + break; + } + + // scale + case IJSVGTransformCommandScale: { + if (transform.parameterCount == 1) + [at scaleBy:transform.parameters[0]]; + else + [at scaleXBy:transform.parameters[0] + yBy:transform.parameters[1]]; + break; + } + + // rotate + case IJSVGTransformCommandRotate: { + if (transform.parameterCount == 1) + [at rotateByDegrees:transform.parameters[0]]; + else { + CGFloat centerX = transform.parameters[1]; + CGFloat centerY = transform.parameters[2]; + CGFloat angle = transform.parameters[0] * (M_PI / 180.f); + [at translateXBy:centerX + yBy:centerY]; + [at rotateByRadians:angle]; + [at translateXBy:-1.f * centerX + yBy:-1.f * centerY]; + } + break; + } + + // do nothing + case IJSVGTransformCommandNotImplemented: { + } + } + [cop transformUsingAffineTransform:at]; + } + return cop; +} + +- (CGAffineTransform)CGAffineTransform +{ + return [self CGAffineTransformWithModifier:nil]; +} + +- (CGAffineTransform)stackIdentity:(CGAffineTransform)identity +{ + switch (self.command) { + + // translate + case IJSVGTransformCommandTranslate: { + if (self.parameterCount == 1) { + return CGAffineTransformTranslate(identity, self.parameters[0], 0.f); + } + return CGAffineTransformTranslate(identity, self.parameters[0], self.parameters[1]); + } + + // translateX + case IJSVGTransformCommandTranslateX: { + return CGAffineTransformTranslate(identity, self.parameters[0], 0.f); + } + + // translateY + case IJSVGTransformCommandTranslateY: { + return CGAffineTransformTranslate(identity, 0.f, self.parameters[0]); + } + + // rotate + case IJSVGTransformCommandRotate: { + if (self.parameterCount == 1) { + return CGAffineTransformRotate(identity, (self.parameters[0] / 180) * M_PI); + } + CGFloat p0 = self.parameters[0]; + CGFloat p1 = self.parameters[1]; + CGFloat p2 = self.parameters[2]; + CGFloat angle = p0 * (M_PI / 180.f); + + identity = CGAffineTransformTranslate(identity, p1, p2); + identity = CGAffineTransformRotate(identity, angle); + return CGAffineTransformTranslate(identity, -1.f * p1, -1.f * p2); + } + + // scale + case IJSVGTransformCommandScale: { + CGFloat p0 = self.parameters[0]; + CGFloat p1 = self.parameters[1]; + if (self.parameterCount == 1) { + return CGAffineTransformScale(identity, p0, p0); + } + return CGAffineTransformScale(identity, p0, p1); + } + + // matrix + case IJSVGTransformCommandMatrix: { + CGFloat p0 = self.parameters[0]; + CGFloat p1 = self.parameters[1]; + CGFloat p2 = self.parameters[2]; + CGFloat p3 = self.parameters[3]; + CGFloat p4 = self.parameters[4]; + CGFloat p5 = self.parameters[5]; + return CGAffineTransformMake(p0, p1, p2, p3, p4, p5); + } + + // skewX + case IJSVGTransformCommandSkewX: { + CGFloat degrees = self.parameters[0]; + CGFloat radians = degrees * M_PI / 180.f; + return CGAffineTransformMake(1.f, 0.f, tan(radians), 1.f, 0.f, 0.f); + } + + // skewY + case IJSVGTransformCommandSkewY: { + CGFloat degrees = self.parameters[0]; + CGFloat radians = degrees * M_PI / 180.f; + return CGAffineTransformMake(1.f, tan(radians), 0.f, 1.f, 0.f, 0.f); + } + + case IJSVGTransformCommandNotImplemented: { + return CGAffineTransformIdentity; + } + } + return CGAffineTransformIdentity; +} + +- (CGAffineTransform)CGAffineTransformWithModifier:(IJSVGTransformParameterModifier)modifier +{ + switch (self.command) { + // matrix + case IJSVGTransformCommandMatrix: { + CGFloat p0 = self.parameters[0]; + CGFloat p1 = self.parameters[1]; + CGFloat p2 = self.parameters[2]; + CGFloat p3 = self.parameters[3]; + CGFloat p4 = self.parameters[4]; + CGFloat p5 = self.parameters[5]; + if (modifier != nil) { + p0 = modifier(0, p0); + p1 = modifier(1, p1); + p2 = modifier(2, p2); + p3 = modifier(3, p3); + p4 = modifier(4, p4); + p5 = modifier(5, p5); + } + return CGAffineTransformMake(p0, p1, p2, p3, p4, p5); + } + + // translate + case IJSVGTransformCommandTranslate: { + CGFloat p0 = self.parameters[0]; + CGFloat p1 = self.parameters[1]; + if (modifier != nil) { + p0 = modifier(0, p0); + p1 = modifier(1, p1); + } + if (self.parameterCount == 1) + return CGAffineTransformMakeTranslation(p0, 0); + return CGAffineTransformMakeTranslation(p0, p1); + } + + // translateX + case IJSVGTransformCommandTranslateX: { + CGFloat p0 = self.parameters[0]; + if (modifier != nil) { + p0 = modifier(0, p0); + } + return CGAffineTransformMakeTranslation(p0, 0.f); + } + + // translateY + case IJSVGTransformCommandTranslateY: { + CGFloat p0 = self.parameters[0]; + if (modifier != nil) { + p0 = modifier(0, p0); + } + return CGAffineTransformMakeTranslation(0.f, p0); + } + + // scale + case IJSVGTransformCommandScale: { + CGFloat p0 = self.parameters[0]; + CGFloat p1 = self.parameters[1]; + if (modifier != nil) { + p0 = modifier(0, p0); + p1 = modifier(1, p1); + } + if (self.parameterCount == 1) + return CGAffineTransformMakeScale(p0, p0); + return CGAffineTransformMakeScale(p0, p1); + } + + // skewX + case IJSVGTransformCommandSkewX: { + CGFloat degrees = self.parameters[0]; + if (modifier != nil) { + degrees = modifier(0, degrees); + } + CGFloat radians = degrees * M_PI / 180.f; + return CGAffineTransformMake(1.f, 0.f, tan(radians), 1.f, 0.f, 0.f); + } + + // skewY + case IJSVGTransformCommandSkewY: { + CGFloat degrees = self.parameters[0]; + if (modifier != nil) { + degrees = modifier(0, degrees); + } + CGFloat radians = degrees * M_PI / 180.f; + return CGAffineTransformMake(1.f, tan(radians), 0.f, 1.f, 0.f, 0.f); + } + + // rotate + case IJSVGTransformCommandRotate: { + if (self.parameterCount == 1) + return CGAffineTransformMakeRotation((self.parameters[0] / 180) * M_PI); + else { + CGFloat p0 = self.parameters[0]; + CGFloat p1 = self.parameters[1]; + CGFloat p2 = self.parameters[2]; + if (modifier != nil) { + p0 = modifier(0, p0); + p1 = modifier(1, p1); + p2 = modifier(2, p2); + } + CGFloat angle = p0 * (M_PI / 180.f); + CGAffineTransform def = CGAffineTransformIdentity; + def = CGAffineTransformTranslate(def, p1, p2); + def = CGAffineTransformRotate(def, angle); + def = CGAffineTransformTranslate(def, -1.f * p1, -1.f * p2); + return def; + } + break; + } + + // do nothing + case IJSVGTransformCommandNotImplemented: { + return CGAffineTransformIdentity; + } + } + return CGAffineTransformIdentity; +} + ++ (NSArray*)transformsFromAffineTransform:(CGAffineTransform)affineTransform +{ + NSArray* strings = [self affineTransformToSVGTransformAttributeString:affineTransform]; + return [self transformsForString:[strings componentsJoinedByString:@" "]]; +} + ++ (NSString*)affineTransformToSVGMatrixString:(CGAffineTransform)transform +{ + return [NSString stringWithFormat:@"matrix(%g,%g,%g,%g,%g,%g)", + transform.a, transform.b, transform.c, transform.d, + transform.tx, transform.ty]; +} + +// this is an Object-C version of the matrixToTransform method from SVGO ++ (NSArray*)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform +{ + const CGFloat data[6] = { + affineTransform.a, + affineTransform.b, + affineTransform.c, + affineTransform.d, + affineTransform.tx, + affineTransform.ty + }; + + CGFloat sx = sqrtf(data[0] * data[0] + data[1] * data[1]); + CGFloat sy = (data[0] * data[3] - data[1] * data[2]) / sx; + + CGFloat colSum = data[0] * data[2] + data[1] * data[3]; + CGFloat rowSum = data[0] * data[1] + data[2] * data[3]; + BOOL scaleBefore = rowSum != 0.f || (sx == sy); + + NSMutableArray* trans = [[[NSMutableArray alloc] init] autorelease]; + + // translate + if (data[4] != 0.f || data[5] != 0.f) { + NSString* str = [NSString stringWithFormat:@"translate(%g, %g)", data[4], data[5]]; + [trans addObject:str]; + } + + // skewX + if (data[1] == 0.f && data[2] != 0.f) { + NSString* str = [NSString stringWithFormat:@"skewX(%g)", IJSVGMathAtan(data[2] / sy)]; + [trans addObject:str]; + + // skewY + } else if (data[1] != 0.f && data[2] == 0.f) { + NSString* str = [NSString stringWithFormat:@"skewY(%g)", IJSVGMathAtan(data[1] / data[0])]; + [trans addObject:str]; + sx = data[0]; + sy = data[3]; + } else if (colSum == 0.f || (sx == 1.f && sy == 1.f) || scaleBefore == NO) { + if (scaleBefore == NO) { + sx = (data[0] < 0.f ? -1.f : 1.f) * sqrtf(data[0] * data[0] + data[2] * data[2]); + sy = (data[3] < 0.f ? -1.f : 1.f) * sqrtf(data[1] * data[1] + data[3] * data[3]); + NSString* str = nil; + if (sx == sy) { + str = [NSString stringWithFormat:@"scale(%g)", sx]; + } else { + str = [NSString stringWithFormat:@"scale(%g, %g)", sx, sy]; + } + [trans addObject:str]; + } + + // rotate + CGFloat rotate = IJSVGMathAcos(data[0] / sx) * (data[1] * sy < 0.f ? -1.f : 1.f); + NSString* rotateString = nil; + if (rotate != 0.f) { + rotateString = [NSString stringWithFormat:@"rotate(%g)", rotate]; + } + + // skewX + if (rowSum != 0.f && colSum != 0.f) { + NSString* str = [NSString stringWithFormat:@"skewX(%g)", IJSVGMathAtan(colSum / (sx * sx))]; + [trans addObject:str]; + } + + // rotate around center + if (rotate != 0.f && (data[4] != 0.f || data[5] != 0.f)) { + [trans removeObjectAtIndex:0]; + + CGFloat cos = data[0] / sx; + CGFloat sin = data[1] / (scaleBefore ? sx : sy); + CGFloat x = data[4] * (scaleBefore ? 1.f : sy); + CGFloat y = data[5] * (scaleBefore ? 1.f : sx); + CGFloat denom = (powf(1.f - cos, 2.f) + powf(sin, 2.f)) * (scaleBefore ? 1.f : sx * sy); + + CGFloat r1 = rotate; + CGFloat r2 = ((1.f - cos) * x - sin * y) / denom; + CGFloat r3 = ((1.f - cos) * y + sin * x) / denom; + + rotateString = [NSString stringWithFormat:@"rotate(%g, %g, %g)", r1, r2, r3]; + } + + if (rotateString != nil) { + [trans addObject:rotateString]; + } + } + + // scale + if ((scaleBefore && (sx != 1.f || sy != 1.f)) || trans.count == 0.f) { + NSString* str = nil; + if (sx == sy) { + str = [NSString stringWithFormat:@"scale(%g)", sx]; + } else { + str = [NSString stringWithFormat:@"scale(%g, %g)", sx, sy]; + } + [trans addObject:str]; + } + + return trans; +} + +- (NSString*)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], + [self.class affineTransformToSVGTransformAttributeString:self.CGAffineTransform]]; +} + +@end diff --git a/source/IJSVGUnitLength.h b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUnitLength.h similarity index 55% rename from source/IJSVGUnitLength.h rename to Framework/IJSVG/IJSVG/Source/Utils/IJSVGUnitLength.h index 83958f2..74ef6c3 100644 --- a/source/IJSVGUnitLength.h +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUnitLength.h @@ -13,7 +13,7 @@ typedef NS_ENUM(NSInteger, IJSVGUnitLengthType) { IJSVGUnitLengthTypePercentage }; -typedef NS_ENUM( NSInteger, IJSVGUnitType) { +typedef NS_ENUM(NSInteger, IJSVGUnitType) { IJSVGUnitUserSpaceOnUse, IJSVGUnitObjectBoundingBox, IJSVGUnitInherit @@ -25,18 +25,18 @@ typedef NS_ENUM( NSInteger, IJSVGUnitType) { @property (nonatomic, assign) CGFloat value; @property (nonatomic, assign) BOOL inherit; -+ (IJSVGUnitLength *)unitWithFloat:(CGFloat)number; -+ (IJSVGUnitLength *)unitWithFloat:(CGFloat)number - type:(IJSVGUnitLengthType)type; -+ (IJSVGUnitLength *)unitWithPercentageFloat:(CGFloat)number; -+ (IJSVGUnitLength *)unitWithString:(NSString *)string; -+ (IJSVGUnitLength *)unitWithPercentageString:(NSString *)string; ++ (IJSVGUnitLength*)unitWithFloat:(CGFloat)number; ++ (IJSVGUnitLength*)unitWithFloat:(CGFloat)number + type:(IJSVGUnitLengthType)type; ++ (IJSVGUnitLength*)unitWithPercentageFloat:(CGFloat)number; ++ (IJSVGUnitLength*)unitWithString:(NSString*)string; ++ (IJSVGUnitLength*)unitWithPercentageString:(NSString*)string; -+ (IJSVGUnitLength *)unitWithString:(NSString *)string - fromUnitType:(IJSVGUnitType)units; ++ (IJSVGUnitLength*)unitWithString:(NSString*)string + fromUnitType:(IJSVGUnitType)units; - (CGFloat)valueAsPercentage; - (CGFloat)computeValue:(CGFloat)anotherValue; -- (NSString *)stringValue; +- (NSString*)stringValue; @end diff --git a/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUnitLength.m b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUnitLength.m new file mode 100644 index 0000000..65da7c8 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUnitLength.m @@ -0,0 +1,104 @@ +// +// IJSVGUnitLength.m +// IJSVGExample +// +// Created by Curtis Hard on 13/01/2017. +// Copyright © 2017 Curtis Hard. All rights reserved. +// + +#import "IJSVGNode.h" +#import "IJSVGUnitLength.h" + +@implementation IJSVGUnitLength + +@synthesize value; +@synthesize type; +@synthesize inherit; + ++ (IJSVGUnitLength*)unitWithFloat:(CGFloat)number +{ + IJSVGUnitLength* unit = [[[self alloc] init] autorelease]; + unit.value = number; + unit.type = IJSVGUnitLengthTypeNumber; + return unit; +} + ++ (IJSVGUnitLength*)unitWithString:(NSString*)string + fromUnitType:(IJSVGUnitType)units +{ + if (units == IJSVGUnitObjectBoundingBox) { + return [self unitWithPercentageString:string]; + } + return [self unitWithString:string]; +} + ++ (IJSVGUnitLength*)unitWithFloat:(CGFloat)number + type:(IJSVGUnitLengthType)type +{ + IJSVGUnitLength* unit = [[[self alloc] init] autorelease]; + unit.value = number; + unit.type = type; + return unit; +} + ++ (IJSVGUnitLength*)unitWithPercentageFloat:(CGFloat)number +{ + return [self unitWithFloat:number + type:IJSVGUnitLengthTypePercentage]; +} + ++ (IJSVGUnitLength*)unitWithPercentageString:(NSString*)string +{ + IJSVGUnitLength* unit = [self unitWithString:string]; + unit.type = IJSVGUnitLengthTypePercentage; + return unit; +} + ++ (IJSVGUnitLength*)unitWithString:(NSString*)string +{ + // just return noting for inherit, node will deal + // with the rest...hopefully + NSCharacterSet* cSet = NSCharacterSet.whitespaceCharacterSet; + string = [string stringByTrimmingCharactersInSet:cSet]; + + if ([string isEqualToString:@"inherit"]) { + return nil; + } + + IJSVGUnitLength* unit = [[[self alloc] init] autorelease]; + unit.value = string.floatValue; + unit.type = IJSVGUnitLengthTypeNumber; + if ([string hasSuffix:@"%"] == YES) { + unit.value /= 100.f; + unit.type = IJSVGUnitLengthTypePercentage; + } + return unit; +} + +- (CGFloat)computeValue:(CGFloat)anotherValue +{ + if (self.type == IJSVGUnitLengthTypePercentage) { + return ((anotherValue / 100.f) * (self.value * 100.f)); + } + return self.value; +} + +- (CGFloat)valueAsPercentage +{ + return self.value / 100; +} + +- (NSString*)stringValue +{ + if (self.type == IJSVGUnitLengthTypePercentage) { + return [NSString stringWithFormat:@"%g%%", (self.value * 100.f)]; + } + return [NSString stringWithFormat:@"%g", self.value]; +} + +- (NSString*)description +{ + return [NSString stringWithFormat:@"%f%@", self.value, (self.type == IJSVGUnitLengthTypePercentage ? @"%" : @"")]; +} + +@end diff --git a/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUtils.h b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUtils.h new file mode 100644 index 0000000..0517d60 --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUtils.h @@ -0,0 +1,64 @@ +// +// IJSVGUtils.h +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGCommand.h" +#import "IJSVGGradientUnitLength.h" +#import "IJSVGStringAdditions.h" +#import +#include + +@interface IJSVGUtils : NSObject + +CGFloat magnitude(CGPoint point); +CGFloat ratio(CGPoint a, CGPoint b); +CGFloat angle(CGPoint a, CGPoint b); +CGFloat radians_to_degrees(CGFloat radians); +CGFloat degrees_to_radians(CGFloat degrees); + +BOOL IJSVGIsCommonHTMLElementName(NSString* str); +NSArray* IJSVGCommonHTMLElementNames(void); + +NSString* IJSVGPointToCommandString(CGPoint point); +NSString* IJSVGShortFloatString(CGFloat f); +NSString* IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision); + +IJSVGPathDataSequence* IJSVGPathDataSequenceCreateWithType(IJSVGPathDataSequence type, NSInteger length); +CGFloat* IJSVGParsePathDataSequence(NSString* string, IJSVGPathDataSequence* sequence, + NSInteger commandLength, NSInteger* commandsFound); + +BOOL IJSVGIsLegalCommandCharacter(unichar aChar); +BOOL IJSVGIsSVGLayer(CALayer* layer); ++ (IJSVGCommandType)typeForCommandString:(NSString*)string; ++ (CGFloat*)commandParameters:(NSString*)command + count:(NSInteger*)count; ++ (CGFloat*)parseViewBox:(NSString*)string; ++ (IJSVGWindingRule)windingRuleForString:(NSString*)string; ++ (IJSVGLineJoinStyle)lineJoinStyleForString:(NSString*)string; ++ (IJSVGLineCapStyle)lineCapStyleForString:(NSString*)string; ++ (IJSVGUnitType)unitTypeForString:(NSString*)string; ++ (IJSVGBlendMode)blendModeForString:(NSString*)string; ++ (NSString*)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode; ++ (NSRange)rangeOfParentheses:(NSString*)string; + ++ (void)logParameters:(CGFloat*)param + count:(NSInteger)count; ++ (CGFloat)floatValue:(NSString*)string; ++ (CGFloat)angleBetweenPointA:(NSPoint)point + pointb:(NSPoint)point; ++ (NSString*)defURL:(NSString*)string; ++ (CGFloat)floatValue:(NSString*)string + fallBackForPercent:(CGFloat)viewBox; ++ (CGFloat*)scanFloatsFromString:(NSString*)string + size:(NSInteger*)length; ++ (IJSVGFontTraits)fontStyleStringForString:(NSString*)string; ++ (IJSVGFontTraits)fontWeightTraitForString:(NSString*)string + weight:(CGFloat*)weight; + ++ (CGPathRef)newFlippedCGPath:(CGPathRef)path; ++ (CGPathRef)newCGPathFromBezierPath:(NSBezierPath*)bezPath; +@end diff --git a/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUtils.m b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUtils.m new file mode 100644 index 0000000..307b0ee --- /dev/null +++ b/Framework/IJSVG/IJSVG/Source/Utils/IJSVGUtils.m @@ -0,0 +1,675 @@ +// +// IJSVGUtils.m +// IconJar +// +// Created by Curtis Hard on 30/08/2014. +// Copyright (c) 2014 Curtis Hard. All rights reserved. +// + +#import "IJSVGLayer.h" +#import "IJSVGShapeLayer.h" +#import "IJSVGUtils.h" + +@implementation IJSVGUtils + +BOOL IJSVGIsCommonHTMLElementName(NSString* str) +{ + str = str.lowercaseString; + return [IJSVGCommonHTMLElementNames() containsObject:str]; +}; + +NSArray* IJSVGCommonHTMLElementNames(void) +{ + static NSArray* names = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + names = [@[ @"a", + @"abbr", + @"acronym", + @"abbr", + @"address", + @"applet", + @"embed", + @"object", + @"area", + @"article", + @"aside", + @"audio", + @"b", + @"base", + @"basefont", + @"bdi", + @"bdo", + @"big", + @"blockquote", + @"body", + @"br", + @"button", + @"canvas", + @"caption", + @"center", + @"cite", + @"code", + @"col", + @"colgroup", + @"colgroup", + @"datalist", + @"dd", + @"del", + @"details", + @"dfn", + @"dialog", + @"dir", + @"ul", + @"div", + @"dl", + @"dt", + @"em", + @"embed", + @"fieldset", + @"figcaption", + @"figure", + @"figure", + @"font", + @"footer", + @"form", + @"frame", + @"frameset", + @"h1", + @"h6", + @"head", + @"header", + @"hr", + @"html", + @"i", + @"iframe", + @"img", + @"input", + @"ins", + @"kbd", + @"label", + @"input", + @"legend", + @"fieldset", + @"li", + @"link", + @"main", + @"map", + @"mark", + @"menu", + @"menuitem", + @"meta", + @"meter", + @"nav", + @"noframes", + @"noscript", + @"object", + @"ol", + @"optgroup", + @"option", + @"output", + @"p", + @"param", + @"picture", + @"pre", + @"progress", + @"q", + @"rp", + @"rt", + @"ruby", + @"s", + @"samp", + @"script", + @"section", + @"select", + @"small", + @"source", + @"video", + @"audio", + @"span", + @"strike", + @"del", + @"s", + @"strong", + @"style", + @"sub", + @"summary", + @"details", + @"sup", + @"table", + @"tbody", + @"td", + @"template", + @"textarea", + @"tfoot", + @"th", + @"thead", + @"time", + @"title", + @"tr", + @"track", + @"video", + @"audio", + @"tt", + @"u", + @"ul", + @"var", + @"video", + @"wbr" ] retain]; + }); + return names; +}; + +NSString* IJSVGShortFloatString(CGFloat f) +{ + return [NSString stringWithFormat:@"%g", f]; +}; + +NSString* IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision) +{ + NSString* format = [NSString stringWithFormat:@"%@.%ld%@", @"%", precision, @"f"]; + NSString* ret = [NSString stringWithFormat:format, f]; + // can it be reduced even more? + if (ret.floatValue == (float)ret.integerValue) { + ret = [NSString stringWithFormat:@"%ld", ret.integerValue]; + } + return ret; +}; + +IJSVGPathDataSequence* IJSVGPathDataSequenceCreateWithType(IJSVGPathDataSequence type, NSInteger length) +{ + size_t size = sizeof(IJSVGPathDataSequence) * length; + IJSVGPathDataSequence* sequence = (IJSVGPathDataSequence*)malloc(size); + memset(sequence, type, size); + return sequence; +}; + +CGFloat* _Nullable IJSVGParsePathDataSequence(NSString* string, IJSVGPathDataSequence* _Nullable sequence, + NSInteger commandLength, NSInteger* commandsFound) +{ + // if no command length, its completely pointless function, + // so just return null and set commandsFound to 0, if we dont + // we get a arithmetic error later on due to zero + if (commandLength == 0) { + *commandsFound = 0; + return NULL; + } + + // default sizes and memory + // sizes for the string buffer + const NSInteger defFloatSize = 20; + const NSInteger defSize = 10; + + // default memory size for the float + NSInteger size = defSize; + NSInteger floatSize = defFloatSize; + + NSInteger i = 0; + NSInteger counter = 0; + + const char* cString = string.UTF8String; + const char* validChars = "eE+-."; + + // this is much faster then doing strlen as it doesnt need + // to compute the length + NSInteger sLength = string.length; + + // buffer for the returned floats + CGFloat* floats = (CGFloat*)malloc(sizeof(CGFloat) * defFloatSize); + + char* buffer = NULL; + bool isDecimal = false; + int bufferCount = 0; + + while (i < sLength) { + char currentChar = cString[i]; + + // work out next char + char nextChar = (char)0; + if (i < (sLength - 1)) { + nextChar = cString[i + 1]; + } + + // check for validator + bool isValid = (currentChar >= '0' && currentChar <= '9') || strchr(validChars, currentChar) != NULL; + + // in order to work out the split, its either because the next char is + // a hyphen or a plus, or next char is a decimal and the current number is a decimal + bool isE = currentChar == 'e' || currentChar == 'E'; + bool wantsEnd = nextChar == '-' || nextChar == '+' || (nextChar == '.' && isDecimal); + + // work our what the sequence is... + IJSVGPathDataSequence seq = kIJSVGPathDataSequenceTypeFloat; + if (sequence != NULL) { + seq = sequence[counter % commandLength]; + } + + // is a flag, consists of one value + // if its invalid, make sure we free the memory + // and return null - or hell breaks lose + if (isValid == YES && seq == kIJSVGPathDataSequenceTypeFlag) { + if (bufferCount != 0 || (currentChar != '0' && currentChar != '1')) { + if (buffer) { + (void)free(buffer), buffer = nil; + } + (void)free(floats), floats = nil; + return NULL; + } + wantsEnd = YES; + } + + // could be a float like 5.334e-5 so dont break on the hypen + if (wantsEnd && isE && (nextChar == '-' || nextChar == '+')) { + wantsEnd = false; + } + + // make sure its a valid string + if (isValid) { + // alloc the buffer if needed + if (buffer == NULL) { + buffer = (char*)calloc(sizeof(char), size); + } else if ((bufferCount + 1) == size) { + // realloc the buffer, incase the string is overflowing the + // allocated memory + size += defSize; + buffer = (char*)realloc(buffer, sizeof(char) * size); + } + // set the actual char against it + if (currentChar == '.') { + isDecimal = true; + } + buffer[bufferCount++] = currentChar; + } else { + // if its an invalid char, just stop it + wantsEnd = true; + } + + // is at end of string, or wants to be stopped + // buffer has to actually exist or its completly + // useless and will cause a crash + if ((buffer != NULL && bufferCount != 0) && (wantsEnd || i == sLength - 1)) { + // make sure there is enough room in the float pool + if ((counter + 1) == floatSize) { + floatSize += defFloatSize; + floats = (CGFloat*)realloc(floats, sizeof(CGFloat) * floatSize); + } + + // add the float + floats[counter++] = strtod_l(buffer, NULL, NULL); + + // memory clean and counter resets + memset(buffer, '\0', sizeof(*buffer) * size); + isDecimal = false; + bufferCount = 0; + } + i++; + } + if (buffer != NULL) { + free(buffer); + } + *commandsFound = (NSInteger)round(counter / commandLength); + return floats; +} + +NSString* IJSVGPointToCommandString(CGPoint point) +{ + return [NSString stringWithFormat:@"%@,%@", IJSVGShortFloatString(point.x), IJSVGShortFloatString(point.y)]; +}; + +BOOL IJSVGIsLegalCommandCharacter(unichar aChar) +{ + const char* validChars = "MmZzLlHhVvCcSsQqTtAa"; + return strchr(validChars, aChar) != NULL; +} + +BOOL IJSVGIsSVGLayer(CALayer* layer) +{ + return [layer isKindOfClass:IJSVGLayer.class] || + [layer isKindOfClass:IJSVGShapeLayer.class]; +} + +CGFloat angle(CGPoint a, CGPoint b) +{ + return [IJSVGUtils angleBetweenPointA:a + pointb:b]; +} + +CGFloat ratio(CGPoint a, CGPoint b) +{ + return (a.x * b.x + a.y * b.y) / (magnitude(a) * magnitude(b)); +} + +CGFloat magnitude(CGPoint point) +{ + return sqrtf(powf(point.x, 2) + powf(point.y, 2)); +} + +CGFloat radians_to_degrees(CGFloat radians) +{ + return ((radians) * (180.0 / M_PI)); +} + +CGFloat degrees_to_radians(CGFloat degrees) +{ + return ((degrees) / 180.0 * M_PI); +} + ++ (IJSVGCommandType)typeForCommandString:(NSString*)string +{ + return isupper([string characterAtIndex:0]) ? kIJSVGCommandTypeAbsolute : kIJSVGCommandTypeRelative; +} + ++ (NSRange)rangeOfParentheses:(NSString*)string +{ + NSRange range = NSMakeRange(NSNotFound, 0); + const char* characters = string.UTF8String; + unsigned long length = strlen(characters); + for (NSInteger i = 0; i < length; i++) { + char c = characters[i]; + if (c == '(') { + range.location = i + 1; + } else if (c == ')') { + range.length = i - range.location; + } + } + return range; +} + ++ (NSString*)defURL:(NSString*)string +{ + // insta check for URL + NSCharacterSet* set = NSCharacterSet.whitespaceCharacterSet; + string = [string stringByTrimmingCharactersInSet:set]; + NSString* check = [string substringToIndex:3].lowercaseString; + if ([check isEqualToString:@"url"] == NO) { + return nil; + } + + static NSRegularExpression* _reg = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _reg = [[NSRegularExpression alloc] initWithPattern:@"url\\(['\"]?([^)]+?)['\"]?\\)" + options:0 + error:nil]; + }); + __block NSString* foundID = nil; + [_reg enumerateMatchesInString:string + options:0 + range:NSMakeRange(0, string.length) + usingBlock:^(NSTextCheckingResult* result, + NSMatchingFlags flags, BOOL* stop) { + if ((foundID = [string substringWithRange:[result rangeAtIndex:1]]) != nil) { + *stop = YES; + } + }]; + if ([foundID hasPrefix:@"#"] == YES) { + foundID = [foundID substringFromIndex:1]; + } + return foundID; +} + ++ (IJSVGFontTraits)fontWeightTraitForString:(NSString*)string + weight:(CGFloat*)weight +{ + *weight = string.floatValue; + if ([string isEqualToString:@"bold"]) + return IJSVGFontTraitBold; + return IJSVGFontTraitNone; +} + ++ (IJSVGFontTraits)fontStyleStringForString:(NSString*)string +{ + if ([string isEqualToString:@"italic"]) + return IJSVGFontTraitItalic; + return IJSVGFontTraitNone; +} + ++ (IJSVGWindingRule)windingRuleForString:(NSString*)string +{ + if ([string isEqualToString:@"evenodd"]) + return IJSVGWindingRuleEvenOdd; + if ([string isEqualToString:@"inherit"]) + return IJSVGWindingRuleInherit; + return IJSVGWindingRuleNonZero; +} + ++ (IJSVGLineJoinStyle)lineJoinStyleForString:(NSString*)string +{ + if ([string isEqualToString:@"mitre"]) + return IJSVGLineJoinStyleMiter; + if ([string isEqualToString:@"round"]) + return IJSVGLineJoinStyleRound; + if ([string isEqualToString:@"bevel"]) + return IJSVGLineJoinStyleBevel; + if ([string isEqualToString:@"inherit"]) + return IJSVGLineJoinStyleInherit; + return IJSVGLineJoinStyleMiter; +} + ++ (IJSVGLineCapStyle)lineCapStyleForString:(NSString*)string +{ + if ([string isEqualToString:@"butt"]) + return IJSVGLineCapStyleButt; + if ([string isEqualToString:@"square"]) + return IJSVGLineCapStyleSquare; + if ([string isEqualToString:@"round"]) + return IJSVGLineCapStyleRound; + if ([string isEqualToString:@"inherit"]) + return IJSVGLineCapStyleInherit; + return IJSVGLineCapStyleButt; +} + ++ (IJSVGUnitType)unitTypeForString:(NSString*)string +{ + if ([string isEqualToString:@"userSpaceOnUse"]) { + return IJSVGUnitUserSpaceOnUse; + } + return IJSVGUnitObjectBoundingBox; +} + ++ (IJSVGBlendMode)blendModeForString:(NSString*)string +{ + string = string.lowercaseString; + if ([string isEqualToString:@"normal"]) + return IJSVGBlendModeNormal; + if ([string isEqualToString:@"multiply"]) + return IJSVGBlendModeMultiply; + if ([string isEqualToString:@"screen"]) + return IJSVGBlendModeScreen; + if ([string isEqualToString:@"overlay"]) + return IJSVGBlendModeOverlay; + if ([string isEqualToString:@"darken"]) + return IJSVGBlendModeDarken; + if ([string isEqualToString:@"lighten"]) + return IJSVGBlendModeLighten; + if ([string isEqualToString:@"color-dodge"]) + return IJSVGBlendModeColorDodge; + if ([string isEqualToString:@"color-burn"]) + return IJSVGBlendModeColorBurn; + if ([string isEqualToString:@"hard-light"]) + return IJSVGBlendModeHardLight; + if ([string isEqualToString:@"soft-light"]) + return IJSVGBlendModeSoftLight; + if ([string isEqualToString:@"difference"]) + return IJSVGBlendModeDifference; + if ([string isEqualToString:@"exclusion"]) + return IJSVGBlendModeExclusion; + if ([string isEqualToString:@"hue"]) + return IJSVGBlendModeHue; + if ([string isEqualToString:@"saturation"]) + return IJSVGBlendModeSaturation; + if ([string isEqualToString:@"color"]) + return IJSVGBlendModeColor; + if ([string isEqualToString:@"luminosity"]) + return IJSVGBlendModeLuminosity; + return IJSVGBlendModeNormal; +} + ++ (NSString*)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode +{ + switch (blendMode) { + case IJSVGBlendModeMultiply: { + return @"multiple"; + } + case IJSVGBlendModeScreen: { + return @"screen"; + } + case IJSVGBlendModeOverlay: { + return @"overlay"; + } + case IJSVGBlendModeDarken: { + return @"darken"; + } + case IJSVGBlendModeLighten: { + return @"lighten"; + } + case IJSVGBlendModeColorDodge: { + return @"color-dodge"; + } + case IJSVGBlendModeColorBurn: { + return @"color-burn"; + } + case IJSVGBlendModeHardLight: { + return @"hard-light"; + } + case IJSVGBlendModeSoftLight: { + return @"soft-light"; + } + case IJSVGBlendModeDifference: { + return @"difference"; + } + case IJSVGBlendModeExclusion: { + return @"exclusion"; + } + case IJSVGBlendModeHue: { + return @"hue"; + } + case IJSVGBlendModeSaturation: { + return @"saturation"; + } + case IJSVGBlendModeColor: { + return @"color"; + } + case IJSVGBlendModeLuminosity: { + return @"luminosity"; + } + case IJSVGBlendModeNormal: + default: { + return nil; + } + } +} + ++ (CGFloat*)commandParameters:(NSString*)command + count:(NSInteger*)count +{ + return [self.class scanFloatsFromString:command + size:count]; +} + ++ (CGFloat*)scanFloatsFromString:(NSString*)string + size:(NSInteger*)length +{ + return IJSVGParsePathDataSequence(string, NULL, 1, length); +} + ++ (CGFloat*)parseViewBox:(NSString*)string +{ + NSInteger size = 0; + return [self.class scanFloatsFromString:string + size:&size]; +} + ++ (CGFloat)floatValue:(NSString*)string + fallBackForPercent:(CGFloat)fallBack +{ + CGFloat val = [string floatValue]; + if ([string rangeOfString:@"%"].location != NSNotFound) + val = (fallBack * val) / 100; + return val; +} + ++ (void)logParameters:(CGFloat*)param + count:(NSInteger)count +{ + NSMutableString* str = [[[NSMutableString alloc] init] autorelease]; + for (NSInteger i = 0; i < count; i++) { + [str appendFormat:@"%f ", param[i]]; + } + NSLog(@"%@", str); +} + ++ (CGFloat)floatValue:(NSString*)string +{ + if ([string isEqualToString:@"inherit"]) + return IJSVGInheritedFloatValue; + return [string floatValue]; +} + ++ (CGFloat)angleBetweenPointA:(NSPoint)point1 + pointb:(NSPoint)point2 +{ + return (point1.x * point2.y < point1.y * point2.x ? -1 : 1) * acosf(ratio(point1, point2)); +} + ++ (CGPathRef)newFlippedCGPath:(CGPathRef)path +{ + CGRect boundingBox = CGPathGetPathBoundingBox(path); + CGAffineTransform scale = CGAffineTransformMakeScale(1.f, -1.f); + CGAffineTransform translate = CGAffineTransformTranslate(scale, 0.f, boundingBox.size.height); + CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &translate); + return transformPath; +} + ++ (CGPathRef)newCGPathFromBezierPath:(NSBezierPath*)bezPath +{ + CGPathRef immutablePath = NULL; + // Then draw the path elements. + NSInteger numElements = bezPath.elementCount; + if (numElements > 0) { + CGMutablePathRef path = CGPathCreateMutable(); + NSPoint points[3]; + BOOL didClosePath = YES; + + for (NSInteger i = 0; i < numElements; i++) { + switch ([bezPath elementAtIndex:i associatedPoints:points]) { + case NSMoveToBezierPathElement: { + CGPathMoveToPoint(path, NULL, points[0].x, points[0].y); + break; + } + + case NSLineToBezierPathElement: { + CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y); + didClosePath = NO; + break; + } + + case NSCurveToBezierPathElement: { + CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y, + points[1].x, points[1].y, + points[2].x, points[2].y); + didClosePath = NO; + break; + } + + case NSClosePathBezierPathElement: { + CGPathCloseSubpath(path); + didClosePath = YES; + break; + } + } + } + + // Be sure the path is closed or Quartz may not do valid hit detection. + if (didClosePath == NO) { + CGPathCloseSubpath(path); + } + + // memory clean + immutablePath = CGPathCreateCopy(path); + CGPathRelease(path); + } + return immutablePath; +} + +@end diff --git a/source/IJSVG.h b/source/IJSVG.h index bd0543f..de2fd3f 100644 --- a/source/IJSVG.h +++ b/source/IJSVG.h @@ -6,61 +6,55 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // -#import -#import "IJSVGParser.h" #import "IJSVGBezierPathAdditions.h" -#import "IJSVGLayerTree.h" +#import "IJSVGColorList.h" +#import "IJSVGExporter.h" +#import "IJSVGGradientLayer.h" #import "IJSVGGroupLayer.h" #import "IJSVGImageLayer.h" -#import "IJSVGExporter.h" +#import "IJSVGLayerTree.h" +#import "IJSVGParser.h" #import "IJSVGRendering.h" -#import "IJSVGColorList.h" -#import "IJSVGGradientLayer.h" #import "IJSVGRenderingStyle.h" +#import "IJSVGTransaction.h" +#import @class IJSVG; -@class IJSVGQuartzRenderer; -void IJSVGBeginTransactionLock(); -void IJSVGEndTransactionLock(); -void IJSVGObtainTransactionLock(dispatch_block_t block, BOOL renderOnMainThread); - -@protocol IJSVGDelegate +@protocol IJSVGDelegate @optional -- (BOOL)svg:(IJSVG *)svg -shouldHandleForeignObject:(IJSVGForeignObject *)foreignObject; -- (void)svg:(IJSVG *)svg -handleForeignObject:(IJSVGForeignObject *)foreignObject - document:(NSXMLDocument *)document; -- (void)svg:(IJSVG *)svg -foundSubSVG:(IJSVG *)subSVG -withSVGString:(NSString *)subSVGString; +- (BOOL)svg:(IJSVG*)svg + shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject; +- (void)svg:(IJSVG*)svg + handleForeignObject:(IJSVGForeignObject*)foreignObject + document:(NSXMLDocument*)document; +- (void)svg:(IJSVG*)svg + foundSubSVG:(IJSVG*)subSVG + withSVGString:(NSString*)subSVGString; @end @interface IJSVG : NSObject { - + @private - IJSVGParser * _group; + IJSVGParser* _group; CGFloat _scale; CGFloat _clipScale; id _delegate; - IJSVGLayer * _layerTree; + IJSVGLayer* _layerTree; CGRect _viewBox; CGSize _proposedViewSize; CGFloat _lastProposedBackingScale; IJSVGRenderQuality _lastProposedRenderQuality; CGFloat _backingScale; - NSMutableDictionary * _replacementColors; - IJSVGQuartzRenderer * _quartzRenderer; - + NSMutableDictionary* _replacementColors; + struct { - unsigned int shouldHandleForeignObject: 1; - unsigned int handleForeignObject: 1; - unsigned int shouldHandleSubSVG: 1; + unsigned int shouldHandleForeignObject : 1; + unsigned int handleForeignObject : 1; + unsigned int shouldHandleSubSVG : 1; } _respondsTo; - } // set this to be called when the layer is about to draw, it will call this @@ -73,91 +67,91 @@ withSVGString:(NSString *)subSVGString; // fillColor, strokeColor, pattern and gradient fill @property (nonatomic, assign) IJSVGRenderQuality renderQuality; @property (nonatomic, assign) BOOL clipToViewport; -@property (nonatomic, retain) IJSVGRenderingStyle * style; +@property (nonatomic, retain) IJSVGRenderingStyle* style; -- (void)prepForDrawingInView:(NSView *)view; +- (void)prepForDrawingInView:(NSView*)view; - (BOOL)isFont; -- (IJSVGGroup *)rootNode; +- (IJSVGGroup*)rootNode; - (NSRect)viewBox; -- (NSArray *)glyphs; -- (NSString *)identifier; -- (IJSVGLayer *)layer; -- (IJSVGLayer *)layerWithTree:(IJSVGLayerTree *)tree; -- (NSArray *)subSVGs:(BOOL)recursive; -- (NSString *)SVGStringWithOptions:(IJSVGExporterOptions)options; +- (NSArray*)glyphs; +- (NSString*)identifier; +- (IJSVGLayer*)layer; +- (IJSVGLayer*)layerWithTree:(IJSVGLayerTree*)tree; +- (NSArray*)subSVGs:(BOOL)recursive; +- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options; - (CGFloat)computeBackingScale:(CGFloat)scale; - (void)discardDOM; -+ (id)svgNamed:(NSString *)string; -+ (id)svgNamed:(NSString *)string ++ (id)svgNamed:(NSString*)string; ++ (id)svgNamed:(NSString*)string delegate:(id)delegate; -+ (id)svgNamed:(NSString *)string ++ (id)svgNamed:(NSString*)string useCache:(BOOL)useCache delegate:(id)delegate; -- (id)initWithImage:(NSImage *)image; +- (id)initWithImage:(NSImage*)image; -- (id)initWithSVGLayer:(IJSVGGroupLayer *)group +- (id)initWithSVGLayer:(IJSVGGroupLayer*)group viewBox:(NSRect)viewBox; -- (id)initWithSVGString:(NSString *)string - error:(NSError **)error +- (id)initWithSVGString:(NSString*)string + error:(NSError**)error delegate:(id)delegate; -- (id)initWithSVGString:(NSString *)string; -- (id)initWithSVGString:(NSString *)string - error:(NSError **)error; +- (id)initWithSVGString:(NSString*)string; +- (id)initWithSVGString:(NSString*)string + error:(NSError**)error; -- (id)initWithFile:(NSString *)file +- (id)initWithFile:(NSString*)file useCache:(BOOL)useCache; -- (id)initWithFile:(NSString *)file; -- (id)initWithFile:(NSString *)file - error:(NSError **)error; -- (id)initWithFile:(NSString *)file +- (id)initWithFile:(NSString*)file; +- (id)initWithFile:(NSString*)file + error:(NSError**)error; +- (id)initWithFile:(NSString*)file delegate:(id)delegate; -- (id)initWithFile:(NSString *)file - error:(NSError **)error +- (id)initWithFile:(NSString*)file + error:(NSError**)error delegate:(id)delegate; -- (id)initWithFile:(NSString *)file +- (id)initWithFile:(NSString*)file useCache:(BOOL)useCache - error:(NSError **)error + error:(NSError**)error delegate:(id)delegate; -- (id)initWithFilePathURL:(NSURL *)aURL; -- (id)initWithFilePathURL:(NSURL *)aURL +- (id)initWithFilePathURL:(NSURL*)aURL; +- (id)initWithFilePathURL:(NSURL*)aURL useCache:(BOOL)useCache; -- (id)initWithFilePathURL:(NSURL *)aURL - error:(NSError **)error; -- (id)initWithFilePathURL:(NSURL *)aURL +- (id)initWithFilePathURL:(NSURL*)aURL + error:(NSError**)error; +- (id)initWithFilePathURL:(NSURL*)aURL delegate:(id)delegate; -- (id)initWithFilePathURL:(NSURL *)aURL +- (id)initWithFilePathURL:(NSURL*)aURL useCache:(BOOL)useCache - error:(NSError **)error + error:(NSError**)error delegate:(id)delegate; -- (NSImage *)imageWithSize:(NSSize)aSize; -- (NSImage *)imageWithSize:(NSSize)aSize - error:(NSError **)error; -- (NSImage *)imageWithSize:(NSSize)aSize - flipped:(BOOL)flipped; -- (NSImage *)imageByMaintainingAspectRatioWithSize:(NSSize)aSize - flipped:(BOOL)flipped - error:(NSError **)error; +- (NSImage*)imageWithSize:(NSSize)aSize; +- (NSImage*)imageWithSize:(NSSize)aSize + error:(NSError**)error; +- (NSImage*)imageWithSize:(NSSize)aSize + flipped:(BOOL)flipped; +- (NSImage*)imageByMaintainingAspectRatioWithSize:(NSSize)aSize + flipped:(BOOL)flipped + error:(NSError**)error; - (BOOL)drawAtPoint:(NSPoint)point size:(NSSize)size; - (BOOL)drawAtPoint:(NSPoint)point size:(NSSize)aSize - error:(NSError **)error; + error:(NSError**)error; - (BOOL)drawInRect:(NSRect)rect; - (BOOL)drawInRect:(NSRect)rect - error:(NSError **)error; + error:(NSError**)error; - (void)drawInRect:(NSRect)rect context:(CGContextRef)context; -- (NSData *)PDFData; -- (NSData *)PDFData:(NSError **)error; -- (NSData *)PDFDataWithRect:(NSRect)rect; -- (NSData *)PDFDataWithRect:(NSRect)rect - error:(NSError **)error; +- (NSData*)PDFData; +- (NSData*)PDFData:(NSError**)error; +- (NSData*)PDFDataWithRect:(NSRect)rect; +- (NSData*)PDFDataWithRect:(NSRect)rect + error:(NSError**)error; - (void)beginVectorDraw; - (void)endVectorDraw; @@ -166,5 +160,5 @@ withSVGString:(NSString *)subSVGString; - (void)setNeedsDisplay; // colors -- (IJSVGColorList *)computedColorList:(BOOL *)hasPatternFills; +- (IJSVGColorList*)computedColorList:(BOOL*)hasPatternFills; @end diff --git a/source/IJSVG.m b/source/IJSVG.m index bcaee55..dbdab65 100644 --- a/source/IJSVG.m +++ b/source/IJSVG.m @@ -8,8 +8,8 @@ #import "IJSVG.h" #import "IJSVGCache.h" -#import "IJSVGTransaction.h" #import "IJSVGExporter.h" +#import "IJSVGTransaction.h" @implementation IJSVG @@ -21,70 +21,62 @@ @implementation IJSVG - (void)dealloc { IJSVGBeginTransactionLock(); - [renderingBackingScaleHelper release], renderingBackingScaleHelper = nil; - [_group release], _group = nil; - [_layerTree release], _layerTree = nil; - [_replacementColors release], _replacementColors = nil; - [_quartzRenderer release], _quartzRenderer = nil; - [_style release], _style = nil; - [super dealloc]; + (void)([renderingBackingScaleHelper release]), + renderingBackingScaleHelper = nil; + (void)([_group release]), _group = nil; + (void)([_layerTree release]), _layerTree = nil; + (void)([_replacementColors release]), _replacementColors = nil; + (void)([_style release]), _style = nil; IJSVGEndTransactionLock(); + [super dealloc]; } -+ (id)svgNamed:(NSString *)string - error:(NSError **)error ++ (id)svgNamed:(NSString*)string error:(NSError**)error { - return [self.class svgNamed:string - error:error - delegate:nil]; + return [self.class svgNamed:string error:error delegate:nil]; } -+ (id)svgNamed:(NSString *)string ++ (id)svgNamed:(NSString*)string { - return [self.class svgNamed:string - error:nil]; + return [self.class svgNamed:string error:nil]; } -+ (id)svgNamed:(NSString *)string ++ (id)svgNamed:(NSString*)string useCache:(BOOL)useCache delegate:(id)delegate { return [self.class svgNamed:string - useCache:useCache - error:nil - delegate:delegate]; + useCache:useCache + error:nil + delegate:delegate]; } -+ (id)svgNamed:(NSString *)string - delegate:(id)delegate ++ (id)svgNamed:(NSString*)string delegate:(id)delegate { - return [self.class svgNamed:string - error:nil - delegate:delegate]; + return [self.class svgNamed:string error:nil delegate:delegate]; } -+ (id)svgNamed:(NSString *)string - error:(NSError **)error ++ (id)svgNamed:(NSString*)string + error:(NSError**)error delegate:(id)delegate { - return [self svgNamed:string - useCache:YES - error:error - delegate:delegate]; + return [self svgNamed:string useCache:YES error:error delegate:delegate]; } -+ (id)svgNamed:(NSString *)string ++ (id)svgNamed:(NSString*)string useCache:(BOOL)useCache - error:(NSError **)error + error:(NSError**)error delegate:(id)delegate { - NSBundle * bundle = NSBundle.mainBundle; - NSString * str = nil; - NSString * ext = [string pathExtension]; - if( ext == nil || ext.length == 0 ) { + NSBundle* bundle = NSBundle.mainBundle; + NSString* str = nil; + NSString* ext = [string pathExtension]; + if (ext == nil || ext.length == 0) { ext = @"svg"; } - if( ( str = [bundle pathForResource:[string stringByDeletingPathExtension] ofType:ext] ) != nil ) { + if ((str = [bundle pathForResource:[string stringByDeletingPathExtension] + ofType:ext]) + != nil) { return [[[self alloc] initWithFile:str useCache:useCache error:error @@ -93,58 +85,51 @@ + (id)svgNamed:(NSString *)string return nil; } -- (id)initWithImage:(NSImage *)image +- (id)initWithImage:(NSImage*)image { - __block IJSVGGroupLayer * layer = nil; - __block IJSVGImageLayer * imageLayer = nil; - + __block IJSVGGroupLayer* layer = nil; + __block IJSVGImageLayer* imageLayer = nil; + // make sure we obtain a lock, with whatever we do with layers! - IJSVGObtainTransactionLock(^{ - // create the layers we require - layer = [[[IJSVGGroupLayer alloc] init] autorelease]; - imageLayer = [[[IJSVGImageLayer alloc] initWithImage:image] autorelease]; - [layer addSublayer:imageLayer]; - }, NO); - + IJSVGBeginTransactionLock(); + // create the layers we require + layer = [[[IJSVGGroupLayer alloc] init] autorelease]; + imageLayer = + [[[IJSVGImageLayer alloc] initWithImage:image] autorelease]; + [layer addSublayer:imageLayer]; + IJSVGEndTransactionLock(); + // return the initialized SVG - return [self initWithSVGLayer:layer - viewBox:imageLayer.frame]; + return [self initWithSVGLayer:layer viewBox:imageLayer.frame]; } -- (id)initWithSVGLayer:(IJSVGGroupLayer *)group - viewBox:(NSRect)viewBox +- (id)initWithSVGLayer:(IJSVGGroupLayer*)group viewBox:(NSRect)viewBox { // this completely bypasses passing of files - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { // keep the layer tree _layerTree = [group retain]; _viewBox = viewBox; - + // any setups [self _setupBasicsFromAnyInitializer]; } return self; } - -- (id)initWithFile:(NSString *)file +- (id)initWithFile:(NSString*)file { - return [self initWithFile:file - delegate:nil]; + return [self initWithFile:file delegate:nil]; } -- (id)initWithFile:(NSString *)file - useCache:(BOOL)useCache +- (id)initWithFile:(NSString*)file useCache:(BOOL)useCache { - return [self initWithFile:file - useCache:useCache - error:nil - delegate:nil]; + return [self initWithFile:file useCache:useCache error:nil delegate:nil]; } -- (id)initWithFile:(NSString *)file +- (id)initWithFile:(NSString*)file useCache:(BOOL)useCache - error:(NSError **)error + error:(NSError**)error delegate:(id)delegate { return [self initWithFilePathURL:[NSURL fileURLWithPath:file] @@ -153,24 +138,18 @@ - (id)initWithFile:(NSString *)file delegate:delegate]; } -- (id)initWithFile:(NSString *)file - error:(NSError **)error +- (id)initWithFile:(NSString*)file error:(NSError**)error { - return [self initWithFile:file - error:error - delegate:nil]; + return [self initWithFile:file error:error delegate:nil]; } -- (id)initWithFile:(NSString *)file - delegate:(id)delegate +- (id)initWithFile:(NSString*)file delegate:(id)delegate { - return [self initWithFile:file - error:nil - delegate:delegate]; + return [self initWithFile:file error:nil delegate:delegate]; } -- (id)initWithFile:(NSString *)file - error:(NSError **)error +- (id)initWithFile:(NSString*)file + error:(NSError**)error delegate:(id)delegate { return [self initWithFilePathURL:[NSURL fileURLWithPath:file] @@ -179,16 +158,12 @@ - (id)initWithFile:(NSString *)file delegate:delegate]; } -- (id)initWithFilePathURL:(NSURL *)aURL +- (id)initWithFilePathURL:(NSURL*)aURL { - return [self initWithFilePathURL:aURL - useCache:YES - error:nil - delegate:nil]; + return [self initWithFilePathURL:aURL useCache:YES error:nil delegate:nil]; } -- (id)initWithFilePathURL:(NSURL *)aURL - error:(NSError **)error +- (id)initWithFilePathURL:(NSURL*)aURL error:(NSError**)error { return [self initWithFilePathURL:aURL useCache:YES @@ -196,8 +171,7 @@ - (id)initWithFilePathURL:(NSURL *)aURL delegate:nil]; } -- (id)initWithFilePathURL:(NSURL *)aURL - useCache:(BOOL)useCache +- (id)initWithFilePathURL:(NSURL*)aURL useCache:(BOOL)useCache { return [self initWithFilePathURL:aURL useCache:useCache @@ -205,8 +179,7 @@ - (id)initWithFilePathURL:(NSURL *)aURL delegate:nil]; } -- (id)initWithFilePathURL:(NSURL *)aURL - delegate:(id)delegate +- (id)initWithFilePathURL:(NSURL*)aURL delegate:(id)delegate { return [self initWithFilePathURL:aURL useCache:YES @@ -214,100 +187,92 @@ - (id)initWithFilePathURL:(NSURL *)aURL delegate:delegate]; } -- (id)initWithFilePathURL:(NSURL *)aURL +- (id)initWithFilePathURL:(NSURL*)aURL useCache:(BOOL)useCache - error:(NSError **)error + error:(NSError**)error delegate:(id)delegate { #ifndef __clang_analyzer__ - + // check the cache first - if( useCache && [IJSVGCache enabled] ) { - IJSVG * svg = nil; - if( ( svg = [IJSVGCache cachedSVGForFileURL:aURL] ) != nil ) { + if (useCache && [IJSVGCache enabled]) { + IJSVG* svg = nil; + if ((svg = [IJSVGCache cachedSVGForFileURL:aURL]) != nil) { // have to release, as this was called from an alloc..! [self release]; return [svg retain]; } } - + // create the object - if( ( self = [super init] ) != nil ) { - NSError * anError = nil; + if ((self = [super init]) != nil) { + NSError* anError = nil; _delegate = delegate; - + // this is a really quick check against the delegate // for methods that exist [self _checkDelegate]; - + // create the group - _group = [[IJSVGParser groupForFileURL:aURL - error:&anError - delegate:self] retain]; - + _group = [[IJSVGParser groupForFileURL:aURL error:&anError delegate:self] + retain]; + [self _setupBasicInfoFromGroup]; [self _setupBasicsFromAnyInitializer]; - + // something went wrong... - if( _group == nil ) { - if( error != NULL ) { + if (_group == nil) { + if (error != NULL) { *error = anError; } - [self release], self = nil; + (void)([self release]), self = nil; return nil; } - + // cache the file - if( useCache && [IJSVGCache enabled] ) { - [IJSVGCache cacheSVG:self - fileURL:aURL]; + if (useCache && [IJSVGCache enabled]) { + [IJSVGCache cacheSVG:self fileURL:aURL]; } - } #endif return self; } -- (id)initWithSVGString:(NSString *)string +- (id)initWithSVGString:(NSString*)string { - return [self initWithSVGString:string - error:nil - delegate:nil]; + return [self initWithSVGString:string error:nil delegate:nil]; } -- (id)initWithSVGString:(NSString *)string - error:(NSError **)error +- (id)initWithSVGString:(NSString*)string error:(NSError**)error { - return [self initWithSVGString:string - error:error - delegate:nil]; + return [self initWithSVGString:string error:error delegate:nil]; } -- (id)initWithSVGString:(NSString *)string - error:(NSError **)error +- (id)initWithSVGString:(NSString*)string + error:(NSError**)error delegate:(id)delegate { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { // this is basically the same as init with URL just // bypasses the loading of a file - NSError * anError = nil; + NSError* anError = nil; _delegate = delegate; [self _checkDelegate]; - + // setup the parser _group = [[IJSVGParser alloc] initWithSVGString:string error:&anError delegate:self]; - + [self _setupBasicInfoFromGroup]; [self _setupBasicsFromAnyInitializer]; - + // something went wrong :( - if(_group == nil) { - if(error != NULL) { + if (_group == nil) { + if (error != NULL) { *error = anError; } - [self release], self = nil; + (void)([self release]), self = nil; return nil; } } @@ -319,9 +284,9 @@ - (void)discardDOM // if we discard, we can no longer create a tree, so lets create tree // upfront before we kill anything [self layer]; - + // now clear memory - [_group release], _group = nil; + (void)([_group release]), _group = nil; } - (void)_setupBasicInfoFromGroup @@ -335,25 +300,28 @@ - (void)_setupBasicsFromAnyInitializer { self.style = [[[IJSVGRenderingStyle alloc] init] autorelease]; self.clipToViewport = YES; - self.renderQuality = IJSVGRenderQualityFullResolution; - + self.renderQuality = kIJSVGRenderQualityFullResolution; + // setup low level backing scale _lastProposedBackingScale = 0.f; - self.renderingBackingScaleHelper = ^CGFloat{ + self.renderingBackingScaleHelper = ^CGFloat { return 1.f; }; } -- (NSString *)identifier +- (NSString*)identifier { return _group.identifier; } - (void)_checkDelegate { - _respondsTo.shouldHandleForeignObject = [_delegate respondsToSelector:@selector(svg:shouldHandleForeignObject:)]; - _respondsTo.handleForeignObject = [_delegate respondsToSelector:@selector(svg:handleForeignObject:document:)]; - _respondsTo.shouldHandleSubSVG = [_delegate respondsToSelector:@selector(svg:foundSubSVG:withSVGString:)]; + _respondsTo.shouldHandleForeignObject = + [_delegate respondsToSelector:@selector(svg:shouldHandleForeignObject:)]; + _respondsTo.handleForeignObject = [_delegate + respondsToSelector:@selector(svg:handleForeignObject:document:)]; + _respondsTo.shouldHandleSubSVG = + [_delegate respondsToSelector:@selector(svg:foundSubSVG:withSVGString:)]; } - (NSRect)viewBox @@ -361,7 +329,7 @@ - (NSRect)viewBox return _viewBox; } -- (IJSVGGroup *)rootNode +- (IJSVGGroup*)rootNode { return _group; } @@ -371,137 +339,118 @@ - (BOOL)isFont return [_group isFont]; } -- (NSArray *)glyphs +- (NSArray*)glyphs { return [_group glyphs]; } -- (NSArray *)subSVGs:(BOOL)recursive +- (NSArray*)subSVGs:(BOOL)recursive { return [_group subSVGs:recursive]; } -- (NSString *)SVGStringWithOptions:(IJSVGExporterOptions)options +- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options { - IJSVGExporter * exporter = [[[IJSVGExporter alloc] initWithSVG:self - size:self.viewBox.size - options:options] autorelease]; + IJSVGExporter* exporter = + [[[IJSVGExporter alloc] initWithSVG:self + size:self.viewBox.size + options:options] autorelease]; return [exporter SVGString]; } -- (NSImage *)imageWithSize:(NSSize)aSize +- (NSImage*)imageWithSize:(NSSize)aSize { - return [self imageWithSize:aSize - flipped:NO - error:nil]; + return [self imageWithSize:aSize flipped:NO error:nil]; } -- (NSImage *)imageWithSize:(NSSize)aSize - error:(NSError **)error; +- (NSImage*)imageWithSize:(NSSize)aSize error:(NSError**)error; { - return [self imageWithSize:aSize - flipped:NO - error:error]; + return [self imageWithSize:aSize flipped:NO error:error]; } -- (NSImage *)imageWithSize:(NSSize)aSize - flipped:(BOOL)flipped +- (NSImage*)imageWithSize:(NSSize)aSize flipped:(BOOL)flipped { - return [self imageWithSize:aSize - flipped:flipped - error:nil]; + return [self imageWithSize:aSize flipped:flipped error:nil]; } - (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize { - [self _beginDraw:(NSRect) { - .origin = CGPointZero, - .size = aSize - }]; + [self _beginDraw:(NSRect){ .origin = CGPointZero, .size = aSize }]; return NSMakeRect(0.f, 0.f, _proposedViewSize.width * _clipScale, - _proposedViewSize.height * _clipScale); + _proposedViewSize.height * _clipScale); } -- (NSImage *)imageWithSize:(NSSize)aSize - flipped:(BOOL)flipped - error:(NSError **)error +- (NSImage*)imageWithSize:(NSSize)aSize + flipped:(BOOL)flipped + error:(NSError**)error { - NSImage * im = [[[NSImage alloc] initWithSize:aSize] autorelease]; + NSImage* im = [[[NSImage alloc] initWithSize:aSize] autorelease]; [im lockFocus]; CGContextRef ref = [[NSGraphicsContext currentContext] CGContext]; CGContextSaveGState(ref); - if(flipped) { + if (flipped) { CGContextTranslateCTM(ref, 0.f, aSize.height); CGContextScaleCTM(ref, 1.f, -1.f); } - [self drawAtPoint:NSMakePoint( 0.f, 0.f ) - size:aSize - error:error]; + [self drawAtPoint:NSMakePoint(0.f, 0.f) size:aSize error:error]; CGContextRestoreGState(ref); [im unlockFocus]; return im; } -- (NSImage *)imageByMaintainingAspectRatioWithSize:(NSSize)aSize - flipped:(BOOL)flipped - error:(NSError **)error +- (NSImage*)imageByMaintainingAspectRatioWithSize:(NSSize)aSize + flipped:(BOOL)flipped + error:(NSError**)error { NSRect rect = [self computeOriginalDrawingFrameWithSize:aSize]; - return [self imageWithSize:rect.size - flipped:flipped - error:error]; + return [self imageWithSize:rect.size flipped:flipped error:error]; } -- (NSData *)PDFData +- (NSData*)PDFData { return [self PDFData:nil]; } -- (NSData *)PDFData:(NSError **)error +- (NSData*)PDFData:(NSError**)error { - return [self PDFDataWithRect:(NSRect){ - .origin=NSZeroPoint, - .size=_viewBox.size - } error:error]; + return [self + PDFDataWithRect:(NSRect){ .origin = NSZeroPoint, .size = _viewBox.size } + error:error]; } -- (NSData *)PDFDataWithRect:(NSRect)rect +- (NSData*)PDFDataWithRect:(NSRect)rect { - return [self PDFDataWithRect:rect - error:nil]; + return [self PDFDataWithRect:rect error:nil]; } -- (NSData *)PDFDataWithRect:(NSRect)rect - error:(NSError **)error +- (NSData*)PDFDataWithRect:(NSRect)rect error:(NSError**)error { // create the data for the PDF - NSMutableData * data = [[[NSMutableData alloc] init] autorelease]; - + NSMutableData* data = [[[NSMutableData alloc] init] autorelease]; + // assign the data to the consumer CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)data); - const CGRect box = CGRectMake( rect.origin.x, rect.origin.y, - rect.size.width, rect.size.height ); - + const CGRect box = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, + rect.size.height); + // create the context - CGContextRef context = CGPDFContextCreate( dataConsumer, &box, NULL ); - - CGContextBeginPage( context, &box ); - + CGContextRef context = CGPDFContextCreate(dataConsumer, &box, NULL); + + CGContextBeginPage(context, &box); + // the context is currently upside down, doh! flip it... - CGContextScaleCTM( context, 1, -1 ); - CGContextTranslateCTM( context, 0, -box.size.height); - + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -box.size.height); + // make sure we set the masks to path bits n bobs - [self _beginVectorDraw]; { - // draw the icon - [self _drawInRect:(NSRect)box - context:context - error:error]; - } [self _endVectorDraw]; - + [self _beginVectorDraw]; + // draw the icon + [self _drawInRect:(NSRect)box context:context error:error]; + [self _endVectorDraw]; + CGContextEndPage(context); - - //clean up + + // clean up CGPDFContextClose(context); CGContextRelease(context); CGDataConsumerRelease(dataConsumer); @@ -522,66 +471,58 @@ - (void)_beginVectorDraw { // turn on converts masks to PDF's // as PDF context and layer masks dont work - void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) { - ((IJSVGLayer *)layer).convertMasksToPaths = YES; + void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer, BOOL isMask) { + ((IJSVGLayer*)layer).convertMasksToPaths = YES; }; - [IJSVGLayer recursivelyWalkLayer:self.layer - withBlock:block]; + [IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block]; } - (void)_endVectorDraw { // turn of convert masks to paths as not // needed for generic rendering - void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) { - ((IJSVGLayer *)layer).convertMasksToPaths = NO; + void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer, BOOL isMask) { + ((IJSVGLayer*)layer).convertMasksToPaths = NO; }; - [IJSVGLayer recursivelyWalkLayer:self.layer - withBlock:block]; + [IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block]; } -- (void)prepForDrawingInView:(NSView *)view +- (void)prepForDrawingInView:(NSView*)view { // kill the render - if(view == nil) { + if (view == nil) { self.renderingBackingScaleHelper = nil; return; } - + // construct the layer before drawing [self layer]; - + // set the scale - __block NSView * weakView = view; - self.renderingBackingScaleHelper = ^CGFloat{ + __block NSView* weakView = view; + self.renderingBackingScaleHelper = ^CGFloat { return weakView.window.screen.backingScaleFactor; }; } -- (BOOL)drawAtPoint:(NSPoint)point - size:(NSSize)aSize +- (BOOL)drawAtPoint:(NSPoint)point size:(NSSize)aSize { - return [self drawAtPoint:point - size:aSize - error:nil]; + return [self drawAtPoint:point size:aSize error:nil]; } -- (BOOL)drawAtPoint:(NSPoint)point - size:(NSSize)aSize - error:(NSError **)error +- (BOOL)drawAtPoint:(NSPoint)point size:(NSSize)aSize error:(NSError**)error { - return [self drawInRect:NSMakeRect( point.x, point.y, aSize.width, aSize.height ) - error:error]; + return + [self drawInRect:NSMakeRect(point.x, point.y, aSize.width, aSize.height) + error:error]; } - (BOOL)drawInRect:(NSRect)rect { - return [self drawInRect:rect - error:nil]; + return [self drawInRect:rect error:nil]; } -- (BOOL)drawInRect:(NSRect)rect - error:(NSError **)error +- (BOOL)drawInRect:(NSRect)rect error:(NSError**)error { return [self _drawInRect:rect context:[[NSGraphicsContext currentContext] CGContext] @@ -594,27 +535,19 @@ - (CGFloat)computeBackingScale:(CGFloat)actualScale return (CGFloat)(_scale + actualScale); } -- (NSRect)computeRectDrawingInRect:(NSRect)rect - isValid:(BOOL *)valid +- (NSRect)computeRectDrawingInRect:(NSRect)rect isValid:(BOOL*)valid { // we also need to calculate the viewport so we can clip // the drawing if needed NSRect viewPort = NSZeroRect; - viewPort.origin.x = round((rect.size.width/2-(_proposedViewSize.width/2)*_clipScale) + rect.origin.x); - viewPort.origin.y = round((rect.size.height/2-(_proposedViewSize.height/2)*_clipScale) + rect.origin.y); - viewPort.size.width = _proposedViewSize.width*_clipScale; - viewPort.size.height = _proposedViewSize.height*_clipScale; - + viewPort.origin.x = round((rect.size.width / 2 - (_proposedViewSize.width / 2) * _clipScale) + rect.origin.x); + viewPort.origin.y = round( + (rect.size.height / 2 - (_proposedViewSize.height / 2) * _clipScale) + rect.origin.y); + viewPort.size.width = _proposedViewSize.width * _clipScale; + viewPort.size.height = _proposedViewSize.height * _clipScale; + // check the viewport - if( NSEqualRects( _viewBox, NSZeroRect ) - || _viewBox.size.width <= 0 - || _viewBox.size.height <= 0 - || NSEqualRects( NSZeroRect, viewPort) - || CGRectIsEmpty(viewPort) - || CGRectIsNull(viewPort) - || viewPort.size.width <= 0 - || viewPort.size.height <= 0 ) - { + if (NSEqualRects(_viewBox, NSZeroRect) || _viewBox.size.width <= 0 || _viewBox.size.height <= 0 || NSEqualRects(NSZeroRect, viewPort) || CGRectIsEmpty(viewPort) || CGRectIsNull(viewPort) || viewPort.size.width <= 0 || viewPort.size.height <= 0) { *valid = NO; return NSZeroRect; } @@ -623,133 +556,125 @@ - (NSRect)computeRectDrawingInRect:(NSRect)rect return viewPort; } -- (void)drawInRect:(NSRect)rect - context:(CGContextRef)context +- (void)drawInRect:(NSRect)rect context:(CGContextRef)context { - [self _drawInRect:rect - context:context - error:nil]; + [self _drawInRect:rect context:context error:nil]; } - (BOOL)_drawInRect:(NSRect)rect context:(CGContextRef)ref - error:(NSError **)error + error:(NSError**)error { // prep for draw... - @synchronized (self) { - CGContextSaveGState(ref); - @try { - [self _beginDraw:rect]; - - // we also need to calculate the viewport so we can clip - // the drawing if needed - BOOL canDraw = NO; - NSRect viewPort = [self computeRectDrawingInRect:rect isValid:&canDraw]; - // check the viewport - if( canDraw == NO ) { - if( error != NULL ) { - *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain - code:IJSVGErrorDrawing - userInfo:nil] autorelease]; - } - } else { - // clip to mask - if(self.clipToViewport == YES) { - CGContextClipToRect( ref, viewPort); - } - - // add the origin back onto the viewport - viewPort.origin.x -= (_viewBox.origin.x)*_scale; - viewPort.origin.y -= (_viewBox.origin.y)*_scale; - - // transforms - CGContextTranslateCTM( ref, viewPort.origin.x, viewPort.origin.y); - CGContextScaleCTM( ref, _scale, _scale ); - - // render the layer, its really important we lock - // the transaction when drawing - IJSVGBeginTransactionLock(); - // do we need to update the backing scales on the - // layers? - if(self.renderingBackingScaleHelper != nil) { - [self _askHelperForBackingScale]; - } - - CGInterpolationQuality quality; - switch(self.renderQuality) { - case IJSVGRenderQualityLow: { - quality = kCGInterpolationLow; - break; - } - case IJSVGRenderQualityOptimized: { - quality = kCGInterpolationMedium; - break; - } - default: { - quality = kCGInterpolationHigh; - } - } - CGContextSetInterpolationQuality(ref, quality); - [self.layer renderInContext:ref]; - IJSVGEndTransactionLock(); - } - } - @catch (NSException *exception) { - // just catch and give back a drawing error to the caller - if( error != NULL ) { + CGContextSaveGState(ref); + @try { + [self _beginDraw:rect]; + + // we also need to calculate the viewport so we can clip + // the drawing if needed + BOOL canDraw = NO; + NSRect viewPort = [self computeRectDrawingInRect:rect isValid:&canDraw]; + // check the viewport + if (canDraw == NO) { + if (error != NULL) { *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain code:IJSVGErrorDrawing userInfo:nil] autorelease]; } + } else { + // clip to mask + if (self.clipToViewport == YES) { + CGContextClipToRect(ref, viewPort); + } + + // add the origin back onto the viewport + viewPort.origin.x -= (_viewBox.origin.x) * _scale; + viewPort.origin.y -= (_viewBox.origin.y) * _scale; + + // transforms + CGContextTranslateCTM(ref, viewPort.origin.x, viewPort.origin.y); + CGContextScaleCTM(ref, _scale, _scale); + + // render the layer, its really important we lock + // the transaction when drawing + IJSVGBeginTransactionLock(); + // do we need to update the backing scales on the + // layers? + if (self.renderingBackingScaleHelper != nil) { + [self _askHelperForBackingScale]; + } + + CGInterpolationQuality quality; + switch (self.renderQuality) { + case kIJSVGRenderQualityLow: { + quality = kCGInterpolationLow; + break; + } + case kIJSVGRenderQualityOptimized: { + quality = kCGInterpolationMedium; + break; + } + default: { + quality = kCGInterpolationHigh; + } + } + CGContextSetInterpolationQuality(ref, quality); + [self.layer renderInContext:ref]; + IJSVGEndTransactionLock(); + } + } @catch (NSException* exception) { + // just catch and give back a drawing error to the caller + if (error != NULL) { + *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain + code:IJSVGErrorDrawing + userInfo:nil] autorelease]; } - CGContextRestoreGState(ref); } + CGContextRestoreGState(ref); return (error == nil); } - (void)_askHelperForBackingScale { CGFloat scale = (self.renderingBackingScaleHelper)(); - if(scale < 1.f) { + if (scale < 1.f) { scale = 1.f; } - + // make sure we multiple the scale by the scale of the rendered clip // or it will be blurry for gradients and other bitmap drawing scale = (_scale * scale); - + // dont do anything, nothing has changed, no point of iterating over // every layer for no reason! - if(scale == _lastProposedBackingScale && renderQuality == _lastProposedRenderQuality) { + if (scale == _lastProposedBackingScale && renderQuality == _lastProposedRenderQuality) { return; } - + IJSVGRenderQuality quality = self.renderQuality; _lastProposedBackingScale = scale; _lastProposedRenderQuality = quality; - + // walk the tree - void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) { - IJSVGLayer * propLayer = ((IJSVGLayer *)layer); + void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer, BOOL isMask) { + IJSVGLayer* propLayer = ((IJSVGLayer*)layer); propLayer.renderQuality = quality; - if(propLayer.requiresBackingScaleHelp == YES) { + if (propLayer.requiresBackingScaleHelp == YES) { propLayer.backingScaleFactor = scale; } }; - + // gogogo - [IJSVGLayer recursivelyWalkLayer:self.layer - withBlock:block]; - + [IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block]; } -- (IJSVGLayer *)layerWithTree:(IJSVGLayerTree *)tree +- (IJSVGLayer*)layerWithTree:(IJSVGLayerTree*)tree { // clear memory - if(_layerTree != nil) { - [_layerTree release], _layerTree = nil; + if (_layerTree != nil) { + (void)([_layerTree release]), _layerTree = nil; } - + // force rebuild of the tree IJSVGBeginTransactionLock(); _layerTree = [[tree layerForNode:_group] retain]; @@ -757,57 +682,35 @@ - (IJSVGLayer *)layerWithTree:(IJSVGLayerTree *)tree return _layerTree; } -- (IJSVGLayer *)layer +- (IJSVGLayer*)layer { - if(_layerTree != nil) { + if (_layerTree != nil) { return _layerTree; } - + // create the renderer and assign default values // from this SVG object - IJSVGLayerTree * renderer = [[[IJSVGLayerTree alloc] init] autorelease]; + IJSVGLayerTree* renderer = [[[IJSVGLayerTree alloc] init] autorelease]; renderer.viewBox = self.viewBox; renderer.style = self.style; - + // return the rendered layer return [self layerWithTree:renderer]; } -- (void)setStyle:(IJSVGRenderingStyle *)style +- (void)setStyle:(IJSVGRenderingStyle*)style { - [self removeStyleObservers]; - [_style release], _style = nil; + (void)([_style release]), _style = nil; _style = style.retain; - [self addStyleObservers]; } -- (void)removeStyleObservers -{ - for(NSString * propertyName in IJSVGRenderingStyle.observableProperties) { - @try { - [_style removeObserver:self - forKeyPath:propertyName]; - } @catch(NSException * e) {} - } -} - -- (void)addStyleObservers -{ - for(NSString * propertyName in IJSVGRenderingStyle.observableProperties) { - [_style addObserver:self - forKeyPath:propertyName - options:0 - context:nil]; - } -} - -- (void)observeValueForKeyPath:(NSString *)keyPath +- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context + change:(NSDictionary*)change + context:(void*)context { // invalidate the tree if a style is set - if(object == _style) { + if (object == _style) { [self invalidateLayerTree]; } } @@ -819,59 +722,55 @@ - (void)setNeedsDisplay - (void)invalidateLayerTree { - [_layerTree release], _layerTree = nil; + (void)([_layerTree release]), _layerTree = nil; } -- (IJSVGColorList *)computedColorList:(BOOL *)hasPatternFills +- (IJSVGColorList*)computedColorList:(BOOL*)hasPatternFills { - IJSVGColorList * sheet = [[[IJSVGColorList alloc] init] autorelease]; - void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) { - if([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO && layer.isHidden == NO) { - IJSVGShapeLayer * sLayer = (IJSVGShapeLayer *)layer; - NSColor * color = nil; - if(sLayer.fillColor != nil) { + IJSVGColorList* sheet = [[[IJSVGColorList alloc] init] autorelease]; + void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer, + BOOL isMask) { + if ([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO && layer.isHidden == NO) { + IJSVGShapeLayer* sLayer = (IJSVGShapeLayer*)layer; + NSColor* color = nil; + if (sLayer.fillColor != nil) { color = [NSColor colorWithCGColor:sLayer.fillColor]; - if(color.alphaComponent != 0.f) { + if (color.alphaComponent != 0.f) { [sheet addColor:color]; } } - if(sLayer.strokeColor != nil) { + if (sLayer.strokeColor != nil) { color = [NSColor colorWithCGColor:sLayer.strokeColor]; color = [IJSVGColor computeColorSpace:color]; - if(color.alphaComponent != 0.f) { + if (color.alphaComponent != 0.f) { [sheet addColor:color]; } } - + // check for any patterns - if(sLayer.patternFillLayer != nil || - sLayer.gradientFillLayer != nil || - sLayer.gradientStrokeLayer != nil || - sLayer.patternStrokeLayer != nil) { - if(hasPatternFills != nil && *hasPatternFills != YES) { + if (sLayer.patternFillLayer != nil || sLayer.gradientFillLayer != nil || sLayer.gradientStrokeLayer != nil || sLayer.patternStrokeLayer != nil) { + if (hasPatternFills != nil && *hasPatternFills != YES) { *hasPatternFills = YES; } - + // add any colors from gradients - IJSVGGradientLayer * gradLayer = nil; - IJSVGGradientLayer * gradStrokeLayer = nil; - if((gradLayer = sLayer.gradientFillLayer) != nil) { - IJSVGColorList * gradSheet = gradLayer.gradient.computedColorList; + IJSVGGradientLayer* gradLayer = nil; + IJSVGGradientLayer* gradStrokeLayer = nil; + if ((gradLayer = sLayer.gradientFillLayer) != nil) { + IJSVGColorList* gradSheet = gradLayer.gradient.computedColorList; [sheet addColorsFromList:gradSheet]; } - if((gradStrokeLayer = sLayer.gradientStrokeLayer) != nil) { - IJSVGColorList * gradSheet = gradStrokeLayer.gradient.computedColorList; + if ((gradStrokeLayer = sLayer.gradientStrokeLayer) != nil) { + IJSVGColorList* gradSheet = gradStrokeLayer.gradient.computedColorList; [sheet addColorsFromList:gradSheet]; } - } } }; - + // walk - [IJSVGLayer recursivelyWalkLayer:self.layer - withBlock:block]; - + [IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block]; + // return the colours! return sheet; } @@ -883,25 +782,25 @@ - (void)_beginDraw:(NSRect)rect // to transform the paths into our viewbox NSSize dest = rect.size; NSSize source = _viewBox.size; - _clipScale = MIN(dest.width/_proposedViewSize.width, - dest.height/_proposedViewSize.height); - + _clipScale = MIN(dest.width / _proposedViewSize.width, + dest.height / _proposedViewSize.height); + // work out the actual scale based on the clip scale - CGFloat w = _proposedViewSize.width*_clipScale; - CGFloat h = _proposedViewSize.height*_clipScale; - _scale = MIN(w/source.width,h/source.height); + CGFloat w = _proposedViewSize.width * _clipScale; + CGFloat h = _proposedViewSize.height * _clipScale; + _scale = MIN(w / source.width, h / source.height); } #pragma mark NSPasteboard -- (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard +- (NSArray*)writableTypesForPasteboard:(NSPasteboard*)pasteboard { - return @[NSPasteboardTypePDF]; + return @[ NSPasteboardTypePDF ]; } -- (id)pasteboardPropertyListForType:(NSString *)type +- (id)pasteboardPropertyListForType:(NSString*)type { - if( [type isEqualToString:NSPasteboardTypePDF] ) { + if ([type isEqualToString:NSPasteboardTypePDF]) { return [self PDFData]; } return nil; @@ -909,34 +808,30 @@ - (id)pasteboardPropertyListForType:(NSString *)type #pragma mark IJSVGParserDelegate -- (void)svgParser:(IJSVGParser *)svg - foundSubSVG:(IJSVG *)subSVG - withSVGString:(NSString *)string +- (void)svgParser:(IJSVGParser*)svg + foundSubSVG:(IJSVG*)subSVG + withSVGString:(NSString*)string { - if(_delegate != nil && _respondsTo.shouldHandleSubSVG == 1) { - [_delegate svg:self - foundSubSVG:subSVG - withSVGString:string]; + if (_delegate != nil && _respondsTo.shouldHandleSubSVG == 1) { + [_delegate svg:self foundSubSVG:subSVG withSVGString:string]; } } -- (BOOL)svgParser:(IJSVGParser *)parser -shouldHandleForeignObject:(IJSVGForeignObject *)foreignObject +- (BOOL)svgParser:(IJSVGParser*)parser + shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject { - if( _delegate != nil && _respondsTo.shouldHandleForeignObject == 1 ) { + if (_delegate != nil && _respondsTo.shouldHandleForeignObject == 1) { return [_delegate svg:self shouldHandleForeignObject:foreignObject]; } return NO; } -- (void)svgParser:(IJSVGParser *)parser -handleForeignObject:(IJSVGForeignObject *)foreignObject - document:(NSXMLDocument *)document +- (void)svgParser:(IJSVGParser*)parser + handleForeignObject:(IJSVGForeignObject*)foreignObject + document:(NSXMLDocument*)document { - if( _delegate != nil && _respondsTo.handleForeignObject == 1 ) { - [_delegate svg:self - handleForeignObject:foreignObject - document:document]; + if (_delegate != nil && _respondsTo.handleForeignObject == 1) { + [_delegate svg:self handleForeignObject:foreignObject document:document]; } } diff --git a/source/IJSVGCache.h b/source/IJSVGCache.h index a1e211f..517f765 100644 --- a/source/IJSVGCache.h +++ b/source/IJSVGCache.h @@ -6,20 +6,19 @@ // Copyright (c) 2014 Curtis Hard. All rights reserved. // +#import "IJSVG.h" #import #import -#import "IJSVG.h" @interface IJSVGCache : NSObject { - } -+ (IJSVG *)cachedSVGForFileURL:(NSURL *)aURL; -+ (void)cacheSVG:(IJSVG *)svg fileURL:(NSURL *)aURL; ++ (IJSVG*)cachedSVGForFileURL:(NSURL*)aURL; ++ (void)cacheSVG:(IJSVG*)svg fileURL:(NSURL*)aURL; + (void)flushCache; + (BOOL)enabled; + (void)setEnabled:(BOOL)flag; -+ (void)purgeCachedSVGForFileURL:(NSURL *)aURL; ++ (void)purgeCachedSVGForFileURL:(NSURL*)aURL; + (void)setEvictItemsAfter:(NSInteger)count; @end diff --git a/source/IJSVGCache.m b/source/IJSVGCache.m index d345a0e..11b8e39 100644 --- a/source/IJSVGCache.m +++ b/source/IJSVGCache.m @@ -12,7 +12,7 @@ @implementation IJSVGCache static NSInteger _maxCacheItems = 20; -static NSCache * _cache = nil; +static NSCache* _cache = nil; static BOOL _enabled = YES; + (void)load @@ -26,23 +26,23 @@ + (void)setEvictItemsAfter:(NSInteger)count [_cache setTotalCostLimit:_maxCacheItems]; } -+ (IJSVG *)cachedSVGForFileURL:(NSURL *)aURL ++ (IJSVG*)cachedSVGForFileURL:(NSURL*)aURL { - if( ![self.class enabled] || _cache == nil ) + if (![self.class enabled] || _cache == nil) return nil; - IJSVG * svg = nil; - if( ( svg = [_cache objectForKey:aURL] ) == nil ) + IJSVG* svg = nil; + if ((svg = [_cache objectForKey:aURL]) == nil) return nil; return svg; } -+ (void)purgeCachedSVGForFileURL:(NSURL *)aURL ++ (void)purgeCachedSVGForFileURL:(NSURL*)aURL { [_cache removeObjectForKey:aURL]; } -+ (void)cacheSVG:(IJSVG *)svg - fileURL:(NSURL *)aURL ++ (void)cacheSVG:(IJSVG*)svg + fileURL:(NSURL*)aURL { [_cache setObject:svg forKey:aURL @@ -52,13 +52,13 @@ + (void)cacheSVG:(IJSVG *)svg + (void)setEnabled:(BOOL)flag { _enabled = flag; - if( !flag ) { + if (!flag) { [self.class flushCache]; return; } - + // create a new cache if allowed - if( _cache == nil ) { + if (_cache == nil) { _cache = [[NSCache alloc] init]; [_cache setTotalCostLimit:_maxCacheItems]; } diff --git a/source/IJSVGColor.m b/source/IJSVGColor.m deleted file mode 100644 index 84b4070..0000000 --- a/source/IJSVGColor.m +++ /dev/null @@ -1,797 +0,0 @@ -// -// IJSVGColor.m -// IconJar -// -// Created by Curtis Hard on 31/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGColor.h" -#import "IJSVGUtils.h" - -@implementation IJSVGColor - -static NSDictionary * _colorTree = nil; - -CGFloat * IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness) -{ - hue *= (1.f/360.f); - hue = (hue - floorf(hue)); - saturation *= 0.01; - lightness *= 0.01; - lightness *= 2.f; - - CGFloat s = saturation * ((lightness < 1.f) ? lightness : (2.f - lightness)); - CGFloat brightness = (lightness + s) * .5f; - if(s != 0.f) { - s = (2.f * s) / (lightness + s); - } - CGFloat * floats = (CGFloat *)malloc(3*sizeof(CGFloat)); - floats[0] = hue; - floats[1] = s; - floats[2] = brightness; - return floats; -}; - -+ (void)load -{ - [self.class _generateTree]; -} - -+ (NSColorSpace *)defaultColorSpace -{ - return NSColorSpace.deviceRGBColorSpace; -} - -+ (NSColor *)computeColorSpace:(NSColor *)color -{ - NSColorSpace * space = [self defaultColorSpace]; - if(color.colorSpace != space) { - color = [color colorUsingColorSpace:space]; - } - return color; -} - -+ (void)_generateTree -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _colorTree = [@{ - @"aliceblue":@(0xf0f8ff), - @"antiquewhite":@(0xfaebd7), - @"aqua":@(0x00ffff), - @"aquamarine":@(0x7fffd4), - @"azure":@(0xf0ffff), - @"beige":@(0xf5f5dc), - @"bisque":@(0xffe4c4), - @"black":@(0x000000), - @"blanchedalmond":@(0xffebcd), - @"blue":@(0x0000ff), - @"blueviolet":@(0x8a2be2), - @"brown":@(0xa52a2a), - @"burlywood":@(0xdeb887), - @"cadetblue":@(0x5f9ea0), - @"chartreuse":@(0x7fff00), - @"chocolate":@(0xd2691e), - @"coral":@(0xff7f50), - @"cornflowerblue":@(0x6495ed), - @"cornsilk":@(0xfff8dc), - @"crimson":@(0xdc143c), - @"currentcolor":@(0x000000), - @"cyan":@(0x00ffff), - @"darkblue":@(0x00008b), - @"darkcyan":@(0x008b8b), - @"darkgoldenrod":@(0xb8860b), - @"darkgray":@(0xa9a9a9), - @"darkgreen":@(0x006400), - @"darkgrey":@(0xa9a9a9), - @"darkkhaki":@(0xbdb76b), - @"darkmagenta":@(0x8b008b), - @"darkolivegreen":@(0x556b2f), - @"darkorange":@(0xff8c00), - @"darkorchid":@(0x9932cc), - @"darkred":@(0x8b0000), - @"darksalmon":@(0xe9967a), - @"darkseagreen":@(0x8fbc8f), - @"darkslateblue":@(0x483d8b), - @"darkslategray":@(0x2f4f4f), - @"darkturquoise":@(0x00ced1), - @"darkviolet":@(0x9400d3), - @"deeppink":@(0xff1493), - @"deepskyblue":@(0x00bfff), - @"dimgray":@(0x696969), - @"dimgrey":@(0x696969), - @"dodgerblue":@(0x1e90ff), - @"firebrick":@(0xb22222), - @"floralwhite":@(0xfffaf0), - @"forestgreen":@(0x228b22), - @"fuchsia":@(0xff00ff), - @"gainsboro":@(0xdcdcdc), - @"ghostwhite":@(0xf8f8ff), - @"gold":@(0xffd700), - @"goldenrod":@(0xdaa520), - @"gray":@(0x808080), - @"green":@(0x008000), - @"greenyellow":@(0xadff2f), - @"grey":@(0x808080), - @"honeydew":@(0xf0fff0), - @"hotpink":@(0xff69b4), - @"indianred":@(0xcd5c5c), - @"indigo":@(0x4b0082), - @"ivory":@(0xfffff0), - @"khaki":@(0xf0e68c), - @"lavender":@(0xe6e6fa), - @"lavenderblush":@(0xfff0f5), - @"lawngreen":@(0x7cfc00), - @"lemonchiffon":@(0xfffacd), - @"lightblue":@(0xadd8e6), - @"lightcoral":@(0xf08080), - @"lightcyan":@(0xe0ffff), - @"lightgoldenrodyellow":@(0xfafad2), - @"lightgray":@(0xd3d3d3), - @"lightgreen":@(0x90ee90), - @"lightgrey":@(0xd3d3d3), - @"lightpink":@(0xffb6c1), - @"lightsalmon":@(0xffa07a), - @"lightseagreen":@(0x20b2aa), - @"lightskyblue":@(0x87cefa), - @"lightslategray":@(0x778899), - @"lightsteelblue":@(0xb0c4de), - @"lightyellow":@(0xffffe0), - @"lime":@(0x00ff00), - @"limegreen":@(0x32cd32), - @"linen":@(0xfaf0e6), - @"magenta":@(0xff00ff), - @"maroon":@(0x800000), - @"mediumaquamarine":@(0x66cdaa), - @"mediumblue":@(0x0000cd), - @"mediumorchid":@(0xba55d3), - @"mediumpurple":@(0x9370db), - @"mediumseagreen":@(0x3cb371), - @"mediumslateblue":@(0x7b68ee), - @"mediumspringgreen":@(0x00fa9a), - @"mediumturquoise":@(0x48d1cc), - @"mediumvioletred":@(0xc71585), - @"midnightblue":@(0x191970), - @"mintcream":@(0xf5fffa), - @"mistyrose":@(0xffe4e1), - @"moccasin":@(0xffe4b5), - @"navajowhite":@(0xffdead), - @"navy":@(0x000080), - @"oldlace":@(0xfdf5e6), - @"olive":@(0x808000), - @"olivedrab":@(0x6b8e23), - @"orange":@(0xffa500), - @"orangered":@(0xff4500), - @"orchid":@(0xda70d6), - @"palegoldenrod":@(0xeee8aa), - @"palegreen":@(0x98fb98), - @"paleturquoise":@(0xafeeee), - @"palevioletred":@(0xdb7093), - @"papayawhip":@(0xffefd5), - @"peachpuff":@(0xffdab9), - @"peru":@(0xcd853f), - @"pink":@(0xffc0cb), - @"plum":@(0xdda0dd), - @"powderblue":@(0xb0e0e6), - @"purple":@(0x800080), - @"red":@(0xff0000), - @"rosybrown":@(0xbc8f8f), - @"royalblue":@(0x4169e1), - @"saddlebrown":@(0x8b4513), - @"salmon":@(0xfa8072), - @"sandybrown":@(0xf4a460), - @"seagreen":@(0x2e8b57), - @"seashell":@(0xfff5ee), - @"sienna":@(0xa0522d), - @"silver":@(0xc0c0c0), - @"skyblue":@(0x87ceeb), - @"slateblue":@(0x6a5acd), - @"slategrey":@(0x708090), - @"snow":@(0xfffafa), - @"springgreen":@(0x00ff7f), - @"steelblue":@(0x4682b4), - @"tan":@(0xd2b48c), - @"teal":@(0x008080), - @"thistle":@(0xd8bfd8), - @"tomato":@(0xff6347), - @"turquoise":@(0x40e0d0), - @"violet":@(0xee82ee), - @"wheat":@(0xf5deb3), - @"white":@(0xffffff), - @"whitesmoke":@(0xf5f5f5), - @"yellow":@(0xffff00), - @"yellowgreen":@(0x9acd32) - } retain]; - }); -} - -+ (NSColor *)computeColor:(id)colour -{ - if( [colour isKindOfClass:[NSColor class]] ) - return colour; - return nil; -} - -+ (NSColor *)colorFromRString:(NSString *)rString - gString:(NSString *)gString - bString:(NSString *)bString - aString:(NSString *)aString -{ - return [self colorFromRUnit:[IJSVGUnitLength unitWithString:rString] - gUnit:[IJSVGUnitLength unitWithString:gString] - bUnit:[IJSVGUnitLength unitWithString:bString] - aUnit:[IJSVGUnitLength unitWithString:aString]]; -} - -+ (NSColor *)colorFromRUnit:(IJSVGUnitLength *)rUnit - gUnit:(IJSVGUnitLength *)gUnit - bUnit:(IJSVGUnitLength *)bUnit - aUnit:(IJSVGUnitLength *)aUnit -{ - CGFloat r = rUnit.type == IJSVGUnitLengthTypePercentage ? - [rUnit computeValue:255.f] : [rUnit computeValue:1.f]; - CGFloat g = gUnit.type == IJSVGUnitLengthTypePercentage ? - [gUnit computeValue:255.f] : [gUnit computeValue:1.f]; - CGFloat b = bUnit.type == IJSVGUnitLengthTypePercentage ? - [bUnit computeValue:255.f] : [bUnit computeValue:1.f]; - CGFloat a = [aUnit computeValue:100.f]; - return [self computeColorSpace:[NSColor colorWithDeviceRed:(r/255.f) - green:(g/255.f) - blue:(b/255.f) - alpha:a]]; -} - -+ (NSColor *)colorFromString:(NSString *)string -{ - NSCharacterSet * set = NSCharacterSet.whitespaceAndNewlineCharacterSet; - string = [string stringByTrimmingCharactersInSet:set]; - - if( [string length] < 3 ) { - return nil; - } - - NSColor * color = nil; - string = [string lowercaseString]; - if([self.class isHex:string] == NO) { - color = [self.class colorFromPredefinedColorName:string]; - if( color != nil ) { - return color; - } - } - - // is simply a clear color, dont fill - if( [[string lowercaseString] isEqualToString:@"none"] ) { - return [self computeColorSpace:NSColor.clearColor]; - } - - // is it RGB? - if( [[string substringToIndex:3] isEqualToString:@"rgb"] ) { - NSRange range = [IJSVGUtils rangeOfParentheses:string]; - NSString * rgbString = [string substringWithRange:range]; - NSArray * parts = [rgbString ijsvg_componentsSeparatedByChars:","]; - NSString * alpha = @"100%"; - if(parts.count == 4) { - alpha = parts[3]; - } - return [self colorFromRString:parts[0] - gString:parts[1] - bString:parts[2] - aString:alpha]; - } - - // is it HSL? - if([[string substringToIndex:3] isEqualToString:@"hsl"]) { - NSInteger count = 0; - CGFloat * params = [IJSVGUtils commandParameters:string - count:&count]; - CGFloat alpha = 1; - if(count == 4) { - alpha = params[3]; - } - - // convert HSL to HSB - CGFloat * hsb = IJSVGColorCSSHSLToHSB(params[0], params[1], params[2]); - color = [NSColor colorWithDeviceHue:hsb[0] - saturation:hsb[1] - brightness:hsb[2] - alpha:alpha]; - - color = [self computeColorSpace:color]; - - // memory clean! - free(hsb); - free(params); - return color; - } - - color = [self.class colorFromHEXString:string]; - return color; -} - -+ (NSColor *)colorFromPredefinedColorName:(NSString *)name -{ - NSNumber * hex = nil; - name = [name.lowercaseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if((hex = _colorTree[name]) == nil ) { - return nil; - } - return [self.class colorFromHEXInteger:hex.integerValue]; -} - -+ (NSString *)colorStringFromColor:(NSColor *)color -{ - IJSVGColorStringOptions options = IJSVGColorStringOptionDefault; - return [self colorStringFromColor:color - options:options]; -} - -+ (NSString *)colorStringFromColor:(NSColor *)color - options:(IJSVGColorStringOptions)options -{ - // convert to RGB - color = [self computeColorSpace:color]; - - int red = color.redComponent * 0xFF; - int green = color.greenComponent * 0xFF; - int blue = color.blueComponent * 0xFF; - int alpha = (int)(color.alphaComponent*100); - - BOOL forceHex = (options & IJSVGColorStringOptionForceHEX) != 0; - BOOL allowShortHand = (options & IJSVGColorStringOptionAllowShortHand) != 0; - BOOL allowRRGGBBAA = (options & IJSVGColorStringOptionAllowRRGGBBAA) != 0; - - // jsut return none - if(alpha == 0 && forceHex == NO) { - return @"none"; - } - - // always return hex unless criteria is met - if(forceHex == YES || allowRRGGBBAA == YES || alpha == 100 || - (red == 0 && green == 0 && blue == 0 && alpha == 0) || - (red == 255 && green == 255 && blue == 255 && alpha == 100)) { - - // we need to make sure the last 2 chars - // are the same or we cant enable shorthand - if(allowRRGGBBAA == YES) { - NSString * alphaHexString = [NSString stringWithFormat:@"%02X", - (int)(color.alphaComponent * 0xFF)]; - if([alphaHexString characterAtIndex:0] != - [alphaHexString characterAtIndex:1]) { - allowShortHand = NO; - } - } - - if(allowShortHand == YES) { - NSString * r = [NSString stringWithFormat:@"%02X",red]; - NSString * g = [NSString stringWithFormat:@"%02X",green]; - NSString * b = [NSString stringWithFormat:@"%02X",blue]; - if([r characterAtIndex:0] == [r characterAtIndex:1] && - [g characterAtIndex:0] == [g characterAtIndex:1] && - [b characterAtIndex:0] == [b characterAtIndex:1]) { - // allow shorthand alpha - if(allowRRGGBBAA == YES && alpha != 100) { - NSString * a = [NSString stringWithFormat:@"%02X", - (int)(color.alphaComponent * 0xFF)]; - return [NSString stringWithFormat:@"#%c%c%c%c", - [r characterAtIndex:0], [g characterAtIndex:0], - [b characterAtIndex:0], [a characterAtIndex:0]]; - } - return [NSString stringWithFormat:@"#%c%c%c",[r characterAtIndex:0], - [g characterAtIndex:0],[b characterAtIndex:0]]; - } - } - if(allowRRGGBBAA == YES && alpha != 100) { - return [NSString stringWithFormat:@"#%02X%02X%02X%02X",red,green, - blue,(int)(color.alphaComponent * 0xFF)]; - } - return [NSString stringWithFormat:@"#%02X%02X%02X",red,green,blue]; - } - - // note the %g, CSS alpha is 0 to 1, not 0 - 100, my bad! - return [NSString stringWithFormat:@"rgba(%d,%d,%d,%g)",red, green, blue, - ((float)alpha/100.f)]; -} - -+ (NSString *)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color -{ - switch(color) - { - case IJSVGColorAliceblue: - return @"aliceblue"; - case IJSVGColorAntiquewhite: - return @"antiquewhite"; - case IJSVGColorAqua: - return @"aqua"; - case IJSVGColorAquamarine: - return @"aquamarine"; - case IJSVGColorAzure: - return @"azure"; - case IJSVGColorBeige: - return @"beige"; - case IJSVGColorBisque: - return @"bisque"; - case IJSVGColorBlack: - return @"black"; - case IJSVGColorBlanchedalmond: - return @"blanchedalmond"; - case IJSVGColorBlue: - return @"blue"; - case IJSVGColorBlueviolet: - return @"blueviolet"; - case IJSVGColorBrown: - return @"brown"; - case IJSVGColorBurlywood: - return @"burlywood"; - case IJSVGColorCadetblue: - return @"cadetblue"; - case IJSVGColorChartreuse: - return @"chartreuse"; - case IJSVGColorChocolate: - return @"chocolate"; - case IJSVGColorCoral: - return @"coral"; - case IJSVGColorCornflowerblue: - return @"cornflowerblue"; - case IJSVGColorCornsilk: - return @"cornsilk"; - case IJSVGColorCrimson: - return @"crimson"; - case IJSVGColorCyan: - return @"cyan"; - case IJSVGColorDarkblue: - return @"darkblue"; - case IJSVGColorDarkcyan: - return @"darkcyan"; - case IJSVGColorDarkgoldenrod: - return @"darkgoldenrod"; - case IJSVGColorDarkgray: - return @"darkgray"; - case IJSVGColorDarkgreen: - return @"darkgreen"; - case IJSVGColorDarkgrey: - return @"darkgrey"; - case IJSVGColorDarkkhaki: - return @"darkkhaki"; - case IJSVGColorDarkmagenta: - return @"darkmagenta"; - case IJSVGColorDarkolivegreen: - return @"darkolivegreen"; - case IJSVGColorDarkorange: - return @"darkorange"; - case IJSVGColorDarkorchid: - return @"darkorchid"; - case IJSVGColorDarkred: - return @"darkred"; - case IJSVGColorDarksalmon: - return @"darksalmon"; - case IJSVGColorDarkseagreen: - return @"darkseagreen"; - case IJSVGColorDarkslateblue: - return @"darkslateblue"; - case IJSVGColorDarkslategray: - return @"darkslategray"; - case IJSVGColorDarkslategrey: - return @"darkslategrey"; - case IJSVGColorDarkturquoise: - return @"darkturquoise"; - case IJSVGColorDarkviolet: - return @"darkviolet"; - case IJSVGColorDeeppink: - return @"deeppink"; - case IJSVGColorDeepskyblue: - return @"deepskyblue"; - case IJSVGColorDimgray: - return @"dimgray"; - case IJSVGColorDimgrey: - return @"dimgrey"; - case IJSVGColorDodgerblue: - return @"dodgerblue"; - case IJSVGColorFirebrick: - return @"firebrick"; - case IJSVGColorFloralwhite: - return @"floralwhite"; - case IJSVGColorForestgreen: - return @"forestgreen"; - case IJSVGColorFuchsia: - return @"fuchsia"; - case IJSVGColorGainsboro: - return @"gainsboro"; - case IJSVGColorGhostwhite: - return @"ghostwhite"; - case IJSVGColorGold: - return @"gold"; - case IJSVGColorGoldenrod: - return @"goldenrod"; - case IJSVGColorGray: - return @"gray"; - case IJSVGColorGreen: - return @"green"; - case IJSVGColorGreenyellow: - return @"greenyellow"; - case IJSVGColorGrey: - return @"grey"; - case IJSVGColorHoneydew: - return @"honeydew"; - case IJSVGColorHotpink: - return @"hotpink"; - case IJSVGColorIndianred: - return @"indianred"; - case IJSVGColorIndigo: - return @"indigo"; - case IJSVGColorIvory: - return @"ivory"; - case IJSVGColorKhaki: - return @"khaki"; - case IJSVGColorLavender: - return @"lavender"; - case IJSVGColorLavenderblush: - return @"lavenderblush"; - case IJSVGColorLawngreen: - return @"lawngreen"; - case IJSVGColorLemonchiffon: - return @"lemonchiffon"; - case IJSVGColorLightblue: - return @"lightblue"; - case IJSVGColorLightcoral: - return @"lightcoral"; - case IJSVGColorLightcyan: - return @"lightcyan"; - case IJSVGColorLightgoldenrodyellow: - return @"lightgoldenrodyellow"; - case IJSVGColorLightgray: - return @"lightgray"; - case IJSVGColorLightgreen: - return @"lightgreen"; - case IJSVGColorLightgrey: - return @"lightgrey"; - case IJSVGColorLightpink: - return @"lightpink"; - case IJSVGColorLightsalmon: - return @"lightsalmon"; - case IJSVGColorLightseagreen: - return @"lightseagreen"; - case IJSVGColorLightskyblue: - return @"lightskyblue"; - case IJSVGColorLightslategray: - return @"lightslategray"; - case IJSVGColorLightslategrey: - return @"lightslategrey"; - case IJSVGColorLightsteelblue: - return @"lightsteelblue"; - case IJSVGColorLightyellow: - return @"lightyellow"; - case IJSVGColorLime: - return @"lime"; - case IJSVGColorLimegreen: - return @"limegreen"; - case IJSVGColorLinen: - return @"linen"; - case IJSVGColorMagenta: - return @"magenta"; - case IJSVGColorMaroon: - return @"maroon"; - case IJSVGColorMediumaquamarine: - return @"mediumaquamarine"; - case IJSVGColorMediumblue: - return @"mediumblue"; - case IJSVGColorMediumorchid: - return @"mediumorchid"; - case IJSVGColorMediumpurple: - return @"mediumpurple"; - case IJSVGColorMediumseagreen: - return @"mediumseagreen"; - case IJSVGColorMediumslateblue: - return @"mediumslateblue"; - case IJSVGColorMediumspringgreen: - return @"mediumspringgreen"; - case IJSVGColorMediumturquoise: - return @"mediumturquoise"; - case IJSVGColorMediumvioletred: - return @"mediumvioletred"; - case IJSVGColorMidnightblue: - return @"midnightblue"; - case IJSVGColorMintcream: - return @"mintcream"; - case IJSVGColorMistyrose: - return @"mistyrose"; - case IJSVGColorMoccasin: - return @"moccasin"; - case IJSVGColorNavajowhite: - return @"navajowhite"; - case IJSVGColorNavy: - return @"navy"; - case IJSVGColorOldlace: - return @"oldlace"; - case IJSVGColorOlive: - return @"olive"; - case IJSVGColorOlivedrab: - return @"olivedrab"; - case IJSVGColorOrange: - return @"orange"; - case IJSVGColorOrangered: - return @"orangered"; - case IJSVGColorOrchid: - return @"orchid"; - case IJSVGColorPalegoldenrod: - return @"palegoldenrod"; - case IJSVGColorPalegreen: - return @"palegreen"; - case IJSVGColorPaleturquoise: - return @"paleturquoise"; - case IJSVGColorPalevioletred: - return @"palevioletred"; - case IJSVGColorPapayawhip: - return @"papayawhip"; - case IJSVGColorPeachpuff: - return @"peachpuff"; - case IJSVGColorPeru: - return @"peru"; - case IJSVGColorPink: - return @"pink"; - case IJSVGColorPlum: - return @"plum"; - case IJSVGColorPowderblue: - return @"powderblue"; - case IJSVGColorPurple: - return @"purple"; - case IJSVGColorRed: - return @"red"; - case IJSVGColorRosybrown: - return @"rosybrown"; - case IJSVGColorRoyalblue: - return @"royalblue"; - case IJSVGColorSaddlebrown: - return @"saddlebrown"; - case IJSVGColorSalmon: - return @"salmon"; - case IJSVGColorSandybrown: - return @"sandybrown"; - case IJSVGColorSeagreen: - return @"seagreen"; - case IJSVGColorSeashell: - return @"seashell"; - case IJSVGColorSienna: - return @"sienna"; - case IJSVGColorSilver: - return @"silver"; - case IJSVGColorSkyblue: - return @"skyblue"; - case IJSVGColorSlateblue: - return @"slateblue"; - case IJSVGColorSlategray: - return @"slategray"; - case IJSVGColorSlategrey: - return @"slategrey"; - case IJSVGColorSnow: - return @"snow"; - case IJSVGColorSpringgreen: - return @"springgreen"; - case IJSVGColorSteelblue: - return @"steelblue"; - case IJSVGColorTan: - return @"tan"; - case IJSVGColorTeal: - return @"teal"; - case IJSVGColorThistle: - return @"thistle"; - case IJSVGColorTomato: - return @"tomato"; - case IJSVGColorTurquoise: - return @"turquoise"; - case IJSVGColorViolet: - return @"violet"; - case IJSVGColorWheat: - return @"wheat"; - case IJSVGColorWhite: - return @"white"; - case IJSVGColorWhitesmoke: - return @"whitesmoke"; - case IJSVGColorYellow: - return @"yellow"; - case IJSVGColorYellowgreen: - return @"yellowgreen"; - } - return nil; -} - -+ (NSColor *)changeAlphaOnColor:(NSColor *)color - to:(CGFloat)alphaValue -{ - color = [self computeColorSpace:color]; - return [self computeColorSpace:[NSColor colorWithDeviceRed:color.redComponent - green:color.greenComponent - blue:color.blueComponent - alpha:alphaValue]]; -} - -+ (BOOL)isColor:(NSString *)string -{ - return [[string substringToIndex:1] isEqualToString:@"#"] || - [[string substringToIndex:3] isEqualToString:@"rgb"]; -} - -+ (BOOL)isHex:(NSString *)string -{ - const char * validList = "0123456789ABCDEFabcdef#"; - for(NSInteger i = 0; i < string.length; i++) { - char c = [string characterAtIndex:i]; - if(strchr(validList, c) == NULL) { - return NO; - } - } - return YES; -} - -+ (unsigned long)lengthOfHEXInteger:(NSUInteger)hex -{ - char * buffer; - asprintf(&buffer, "%lX", (long)hex); - unsigned long length = strlen(buffer); - free(buffer); - return length; -} - -+ (BOOL)HEXContainsAlphaComponent:(NSUInteger)hex -{ - return [self lengthOfHEXInteger:hex] == 8; -} - -+ (NSColor *)colorFromHEXInteger:(NSInteger)hex -{ - CGFloat alpha = 1.f; - if([self HEXContainsAlphaComponent:hex] == YES) { - alpha = (hex & 0xFF) / 255.f; - hex = hex >> 8; - } - return [self computeColorSpace:[NSColor colorWithDeviceRed:((hex >> 16) & 0xFF) / 255.f - green:((hex >> 8) & 0xFF) / 255.f - blue:(hex & 0xFF) / 255.f - alpha:alpha]]; -} - -+ (unsigned long)HEXFromArbitraryHexString:(NSString *)aString -{ - const char * hexString = [aString cStringUsingEncoding:NSUTF8StringEncoding]; - return strtoul(hexString, NULL, 16); -} - -+ (NSColor *)colorFromHEXString:(NSString *)string -{ - return [self colorFromHEXString:string - containsAlphaComponent:nil]; -} - -+ (NSColor *)colorFromHEXString:(NSString *)string - containsAlphaComponent:(BOOL *)containsAlphaComponent -{ - // absolutely no string - if( string == nil || string.length == 0 || ![self.class isHex:string] ) { - return nil; - } - - if( [[string substringToIndex:1] isEqualToString:@"#"] ) { - string = [string substringFromIndex:1]; - } - - // whats the length? - NSUInteger length = string.length; - if(length == 3 || length == 4) { - // shorthand... - NSMutableString * str = [[[NSMutableString alloc] init] autorelease]; - for( NSInteger i = 0; i < length; i++ ) { - NSString * sub = [string substringWithRange:NSMakeRange(i, 1)]; - [str appendFormat:@"%@%@",sub,sub]; - } - string = str; - } - - // now convert rest to hex - unsigned long hex = [self HEXFromArbitraryHexString:string]; - if(containsAlphaComponent != nil) { - *containsAlphaComponent = [self HEXContainsAlphaComponent:hex]; - } - return [self colorFromHEXInteger:hex]; -} - -@end diff --git a/source/IJSVGColorList.h b/source/IJSVGColorList.h deleted file mode 100644 index 113bb28..0000000 --- a/source/IJSVGColorList.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// IJSVGColorList.h -// IconJar -// -// Created by Curtis Hard on 07/07/2019. -// Copyright © 2019 Curtis Hard. All rights reserved. -// - -#import -#import "IJSVGColor.h" - -@interface IJSVGColorList : NSObject { - -@private - NSMutableDictionary * _replacementColorTree; - NSMutableSet * _colors; -} - -- (NSColor *)proposedColorForColor:(NSColor *)color; -- (void)removeAllReplacementColors; -- (void)removeReplacementColor:(NSColor *)color; -- (void)setReplacementColor:(NSColor *)newColor - forColor:(NSColor *)color; -- (void)setReplacementColors:(NSDictionary *)colors - clearExistingColors:(BOOL)clearExistingColors; - -- (void)addColorsFromList:(IJSVGColorList *)sheet; -- (NSSet *)colors; -- (void)addColor:(NSColor *)color; - -@end diff --git a/source/IJSVGCommand.h b/source/IJSVGCommand.h deleted file mode 100644 index 6e7c027..0000000 --- a/source/IJSVGCommand.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// IJSVGCommand.h -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import -#import "IJSVGPath.h" - -static const NSInteger IJSVGCustomVariableParameterCount = NSNotFound; - -typedef NS_ENUM( NSInteger, IJSVGCommandType ) { - IJSVGCommandTypeAbsolute, - IJSVGCommandTypeRelative -}; - -@interface IJSVGCommand : NSObject { - NSString * commandString; - NSString * command; - CGFloat * parameters; - NSInteger parameterCount; - NSMutableArray * subCommands; - NSInteger requiredParameters; - IJSVGCommandType type; - IJSVGCommand * previousCommand; - NSInteger _currentIndex; - BOOL isSubCommand; -} - -@property ( nonatomic, copy ) NSString * commandString; -@property ( nonatomic, copy ) NSString * command; -@property ( nonatomic, assign ) CGFloat * parameters; -@property ( nonatomic, assign ) NSInteger parameterCount; -@property ( nonatomic, assign ) NSInteger requiredParameters; -@property ( nonatomic, assign ) IJSVGCommandType type; -@property ( nonatomic, retain ) NSMutableArray * subCommands; -@property ( nonatomic, assign ) IJSVGCommand * previousCommand; -@property ( nonatomic, assign ) BOOL isSubCommand; - -+ (Class)commandClassForCommandChar:(char)aChar; -+ (NSInteger)requiredParameterCount; -+ (NSPoint)readCoordinatePair:(CGFloat *)pairs - index:(NSInteger)index; -+ (void)runWithParams:(CGFloat *)params - paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command - type:(IJSVGCommandType)type - path:(IJSVGPath *)path; -+ (void)parseParams:(CGFloat *)params - paramCount:(NSInteger)paramCount - intoArray:(NSMutableArray *)commands - parentCommand:(IJSVGCommand *)parentCommand; - -- (id)initWithCommandString:(NSString *)commandString; -- (IJSVGCommand *)subcommandWithParameters:(CGFloat *)subParams - previousCommand:(IJSVGCommand *)command; - -- (CGFloat)readFloat; -- (NSPoint)readPoint; -- (BOOL)readBOOL; -- (void)resetRead; - -@end diff --git a/source/IJSVGCommand.m b/source/IJSVGCommand.m deleted file mode 100644 index 411b1fe..0000000 --- a/source/IJSVGCommand.m +++ /dev/null @@ -1,200 +0,0 @@ -// -// IJSVGCommand.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGCommand.h" -#import "IJSVGUtils.h" - -#import "IJSVGCommandEllipticalArc.h" -#import "IJSVGCommandMove.h" -#import "IJSVGCommandClose.h" -#import "IJSVGCommandCurve.h" -#import "IJSVGCommandLineTo.h" -#import "IJSVGCommandVerticalLine.h" -#import "IJSVGCommandHorizontalLine.h" -#import "IJSVGCommandSmoothCurve.h" -#import "IJSVGCommandQuadraticCurve.h" -#import "IJSVGCommandSmoothQuadraticCurve.h" - -@implementation IJSVGCommand - -@synthesize commandString; -@synthesize command; -@synthesize parameterCount; -@synthesize parameters; -@synthesize subCommands; -@synthesize requiredParameters; -@synthesize type; -@synthesize previousCommand; -@synthesize isSubCommand; - -+ (BOOL)requiresCustomParameterParsing -{ - return NO; -} - -+ (NSInteger)requiredParameterCount -{ - return 1; -} - -+ (void)runWithParams:(CGFloat *)params - paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command - type:(IJSVGCommandType)type - path:(IJSVGPath *)path -{ -} - -+ (void)parseParams:(CGFloat *)params - paramCount:(NSInteger)paramCount - intoArray:(NSMutableArray *)commands - parentCommand:(IJSVGCommand *)parentCommand -{ -} - -+ (NSPoint)readCoordinatePair:(CGFloat *)pairs - index:(NSInteger)index -{ - return NSMakePoint( pairs[index*2], pairs[index*2+1]); -} - -+ (void)load -{ - // register here... -} - -+ (Class)commandClassForCommandChar:(char)aChar -{ - aChar = tolower(aChar); - switch(aChar) { - case 'a': return IJSVGCommandEllipticalArc.class; - case 'c': return IJSVGCommandCurve.class; - case 'h': return IJSVGCommandHorizontalLine.class; - case 'l': return IJSVGCommandLineTo.class; - case 'm': return IJSVGCommandMove.class; - case 'q': return IJSVGCommandQuadraticCurve.class; - case 's': return IJSVGCommandSmoothCurve.class; - case 't': return IJSVGCommandSmoothQuadraticCurve.class; - case 'v': return IJSVGCommandVerticalLine.class; - case 'z': return IJSVGCommandClose.class; - } - return nil; -} - -- (void)dealloc -{ - [commandString release], commandString = nil; - [command release], command = nil; - [subCommands release], subCommands = nil; - free(parameters), parameters = nil; - [super dealloc]; -} - -- (id)initWithCommandString:(NSString *)str -{ - if( ( self = [super init] ) != nil ) { - // work out the basics - _currentIndex = 0; - command = [[str substringToIndex:1] copy]; - type = [IJSVGUtils typeForCommandString:self.command]; - parameters = [IJSVGUtils commandParameters:str - count:¶meterCount]; - requiredParameters = [self.class requiredParameterCount]; - - // check what required params we need - if(requiredParameters == IJSVGCustomVariableParameterCount) { - // looks like we require variable params - subCommands = [[NSMutableArray alloc] init]; - - // parse the custom params - [self.class parseParams:parameters - paramCount:parameterCount - intoArray:subCommands - parentCommand:self]; - } else { - // now work out the sets of parameters we have - // each command could have a series of subcommands - // if there is a multiple of commands in a command - // then we need to work those out... - NSInteger sets = 1; - if(self.requiredParameters != 0) { - sets = (self.parameterCount/self.requiredParameters); - } - - subCommands = [[NSMutableArray alloc] initWithCapacity:sets]; - - // interate over the sets - IJSVGCommand * lastCommand = nil; - for( NSInteger i = 0; i < sets; i++ ) { - // memory for this will be handled by the created subcommand - CGFloat * subParams = 0; - if( self.requiredParameters != 0 ) { - subParams = (CGFloat*)malloc(self.requiredParameters*sizeof(CGFloat)); - for( NSInteger p = 0; p < self.requiredParameters; p++ ) { - subParams[p] = self.parameters[i*self.requiredParameters+p]; - } - } - - // generate the subcommand - IJSVGCommand * command = [self subcommandWithParameters:subParams - previousCommand:lastCommand]; - - // make sure we assign the last command or hell breaks - // lose and the firey demons will run wild, namely, commands will break - // if they are multiples of a set - lastCommand = command; - - // add it to our tree - [subCommands addObject:command]; - } - } - } - return self; -} - -- (IJSVGCommand *)subcommandWithParameters:(CGFloat *)subParams - previousCommand:(IJSVGCommand *)aPreviousCommand -{ - // create a subcommand per set - IJSVGCommand * c = [[[self.class alloc] init] autorelease]; - c.parameterCount = self.requiredParameters; - c.parameters = subParams; - c.type = self.type; - c.command = self.command; - c.previousCommand = aPreviousCommand; - c.isSubCommand = aPreviousCommand != nil; - return c; -} - -- (CGFloat)readFloat -{ - CGFloat f = parameters[_currentIndex]; - _currentIndex++; - return f; -} - -- (NSPoint)readPoint -{ - CGFloat x = parameters[_currentIndex]; - CGFloat y = parameters[_currentIndex+1]; - _currentIndex+=2; - return NSMakePoint( x, y ); -} - -- (BOOL)readBOOL -{ - return [self readFloat] == 1; -} - -- (void)resetRead -{ - _currentIndex = 0; -} - -@end diff --git a/source/IJSVGCommandCurve.m b/source/IJSVGCommandCurve.m deleted file mode 100644 index 7feac2c..0000000 --- a/source/IJSVGCommandCurve.m +++ /dev/null @@ -1,37 +0,0 @@ -// -// IJSVGCommandCurve.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGCommandCurve.h" - -@implementation IJSVGCommandCurve - -+ (NSInteger)requiredParameterCount -{ - return 6; -} - -+ (void)runWithParams:(CGFloat *)params - paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command - type:(IJSVGCommandType)type - path:(IJSVGPath *)path -{ - if( type == IJSVGCommandTypeAbsolute ) { - [[path currentSubpath] curveToPoint:NSMakePoint( params[4], params[5]) - controlPoint1:NSMakePoint( params[0], params[1]) - controlPoint2:NSMakePoint( params[2], params[3])]; - return; - } - [[path currentSubpath] relativeCurveToPoint:NSMakePoint( params[4], params[5]) - controlPoint1:NSMakePoint( params[0], params[1]) - controlPoint2:NSMakePoint( params[2], params[3])]; - -} - -@end diff --git a/source/IJSVGCommandHorizontalLine.m b/source/IJSVGCommandHorizontalLine.m deleted file mode 100644 index 6408a0a..0000000 --- a/source/IJSVGCommandHorizontalLine.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// IJSVGCommandHorizontalLine.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGCommandHorizontalLine.h" - -@implementation IJSVGCommandHorizontalLine - -+ (NSInteger)requiredParameterCount -{ - return 1; -} - -+ (void)runWithParams:(CGFloat *)params - paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command - type:(IJSVGCommandType)type - path:(IJSVGPath *)path -{ - if( type == IJSVGCommandTypeAbsolute ) - { - [[path currentSubpath] lineToPoint:NSMakePoint( params[0], [path currentSubpath].currentPoint.y)]; - return; - } - [[path currentSubpath] relativeLineToPoint:NSMakePoint( params[0], 0.f)]; -} - -@end diff --git a/source/IJSVGCommandSmoothCurve.m b/source/IJSVGCommandSmoothCurve.m deleted file mode 100644 index 8cff1bb..0000000 --- a/source/IJSVGCommandSmoothCurve.m +++ /dev/null @@ -1,64 +0,0 @@ -// -// IJSVGCommandSmoothCurve.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGCommandSmoothCurve.h" -#import "IJSVGCommandCurve.h" -#import "IJSVGUtils.h" - -@implementation IJSVGCommandSmoothCurve - -+ (NSInteger)requiredParameterCount -{ - return 4; -} - -+ (void)runWithParams:(CGFloat *)params - paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command - type:(IJSVGCommandType)type - path:(IJSVGPath *)path -{ - NSPoint firstControl = NSMakePoint( [path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y ); - if( command != nil ) { - if( command.class == [IJSVGCommandCurve class] || command.class == self.class ) { - if( command.class == [IJSVGCommandCurve class] ) { - if( command.type == IJSVGCommandTypeAbsolute ) { - firstControl = NSMakePoint(-1*command.parameters[2] + 2*[path currentSubpath].currentPoint.x, - -1*command.parameters[3] + 2*[path currentSubpath].currentPoint.y); - } else { - NSPoint oldPoint = NSMakePoint([path currentSubpath].currentPoint.x - command.parameters[4], - [path currentSubpath].currentPoint.y - command.parameters[5]); - firstControl = NSMakePoint(-1*(command.parameters[2] + oldPoint.x) + 2*[path currentSubpath].currentPoint.x, - -1*(command.parameters[3] + oldPoint.y) + 2*[path currentSubpath].currentPoint.y); - } - } else { - if( command.type == IJSVGCommandTypeAbsolute ) { - firstControl = NSMakePoint(-1*command.parameters[0] + 2*[path currentSubpath].currentPoint.x, - -1*command.parameters[1] + 2*[path currentSubpath].currentPoint.y); - } else { - NSPoint oldPoint = NSMakePoint([path currentSubpath].currentPoint.x - command.parameters[2], - [path currentSubpath].currentPoint.y - command.parameters[3]); - firstControl = NSMakePoint(-1*(command.parameters[0] + oldPoint.x) + 2*[path currentSubpath].currentPoint.x, - -1*(command.parameters[1] + oldPoint.y) + 2*[path currentSubpath].currentPoint.y); - } - } - } - } - if( type == IJSVGCommandTypeAbsolute ) { - [[path currentSubpath] curveToPoint:NSMakePoint( params[2], params[3]) - controlPoint1:NSMakePoint( firstControl.x, firstControl.y ) - controlPoint2:NSMakePoint(params[0], params[1])]; - return; - } - [[path currentSubpath] curveToPoint:NSMakePoint( [path currentSubpath].currentPoint.x + params[2], [path currentSubpath].currentPoint.y + params[3]) - controlPoint1:NSMakePoint( firstControl.x, firstControl.y ) - controlPoint2:NSMakePoint( [path currentSubpath].currentPoint.x + params[0], [path currentSubpath].currentPoint.y + params[1])]; -} - -@end diff --git a/source/IJSVGCommandSmoothQuadraticCurve.m b/source/IJSVGCommandSmoothQuadraticCurve.m deleted file mode 100644 index 632f6f7..0000000 --- a/source/IJSVGCommandSmoothQuadraticCurve.m +++ /dev/null @@ -1,56 +0,0 @@ -// -// IJSVGCommandCommandQuadraticCurve.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGCommandSmoothQuadraticCurve.h" -#import "IJSVGUtils.h" -#import "IJSVGCommandQuadraticCurve.h" - -@implementation IJSVGCommandSmoothQuadraticCurve - -+ (NSInteger)requiredParameterCount -{ - return 2; -} - -+ (void)runWithParams:(CGFloat *)params - paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command - type:(IJSVGCommandType)type - path:(IJSVGPath *)path -{ - NSPoint commandPoint = NSMakePoint( [path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y ); - if( command != nil ) { - if( command.class == IJSVGCommandQuadraticCurve.class ) { - // quadratic curve - if( command.type == IJSVGCommandTypeAbsolute ) { - commandPoint = NSMakePoint(-1*command.parameters[0] + 2*[path currentSubpath].currentPoint.x, - -1*command.parameters[1] + 2*[path currentSubpath].currentPoint.y); - } else { - NSPoint oldPoint = CGPointMake([path currentSubpath].currentPoint.x - command.parameters[2], - [path currentSubpath].currentPoint.y - command.parameters[3]); - commandPoint = CGPointMake(-1*(command.parameters[0] + oldPoint.x) + 2*([path currentSubpath].currentPoint.x), - -1*(command.parameters[1] + oldPoint.y) + 2*[path currentSubpath].currentPoint.y); - } - } else if(command.class == self.class) { - // smooth quadratic curve - commandPoint = CGPointMake(-1*(path.lastControlPoint.x) + 2*([path currentSubpath].currentPoint.x), - -1*(path.lastControlPoint.y) + 2*[path currentSubpath].currentPoint.y); - } - } - path.lastControlPoint = commandPoint; - if( type == IJSVGCommandTypeAbsolute ) { - [[path currentSubpath] addQuadCurveToPoint:NSMakePoint(params[0], params[1]) - controlPoint:commandPoint]; - return; - } - [[path currentSubpath] addQuadCurveToPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[0], [path currentSubpath].currentPoint.y + params[1]) - controlPoint:commandPoint]; -} - -@end diff --git a/source/IJSVGCommandVerticalLine.m b/source/IJSVGCommandVerticalLine.m deleted file mode 100644 index 48951d4..0000000 --- a/source/IJSVGCommandVerticalLine.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// IJSVGCommandVerticalLine.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGCommandVerticalLine.h" - -@implementation IJSVGCommandVerticalLine - -+ (NSInteger)requiredParameterCount -{ - return 1; -} - -+ (void)runWithParams:(CGFloat *)params - paramCount:(NSInteger)count - command:(IJSVGCommand *)currentCommand - previousCommand:(IJSVGCommand *)command - type:(IJSVGCommandType)type - path:(IJSVGPath *)path -{ - if( type == IJSVGCommandTypeAbsolute ) - { - [[path currentSubpath] lineToPoint:NSMakePoint( [path currentSubpath].currentPoint.x, params[0])]; - return; - } - [[path currentSubpath] relativeLineToPoint:NSMakePoint( 0.f, params[0])]; -} - -@end diff --git a/source/IJSVGError.h b/source/IJSVGError.h index be958b4..6594614 100644 --- a/source/IJSVGError.h +++ b/source/IJSVGError.h @@ -8,9 +8,9 @@ #import -static NSString * const IJSVGErrorDomain = @"IJSVGErrorDomain"; +static NSString* const IJSVGErrorDomain = @"IJSVGErrorDomain"; -NS_ENUM(NSInteger) { +NS_ENUM(NSInteger){ IJSVGErrorReadingFile, IJSVGErrorParsingFile, IJSVGErrorParsingSVG, diff --git a/source/IJSVGExporter.m b/source/IJSVGExporter.m deleted file mode 100644 index 9e2474c..0000000 --- a/source/IJSVGExporter.m +++ /dev/null @@ -1,1369 +0,0 @@ -// -// IJSVGExporter.m -// IJSVGExample -// -// Created by Curtis Hard on 06/01/2017. -// Copyright © 2017 Curtis Hard. All rights reserved. -// - -#import "IJSVGExporter.h" -#import "IJSVG.h" -#import "IJSVGGradientLayer.h" -#import "IJSVGRadialGradient.h" -#import "IJSVGLinearGradient.h" -#import "IJSVGPatternLayer.h" -#import "IJSVGImageLayer.h" -#import "IJSVGShapeLayer.h" -#import "IJSVGGroupLayer.h" -#import "IJSVGStrokeLayer.h" -#import "IJSVGMath.h" -#import "IJSVGExporterPathInstruction.h" - -@implementation IJSVGExporter - -#define XML_DOC_VERSION 1.1f -#define XML_DOC_NS @"http://www.w3.org/2000/svg" -#define XML_DOC_NSXLINK @"http://www.w3.org/1999/xlink" -#define XML_DOCTYPE_VERSION @"1.0" -#define XML_DOC_CHARSET @"UTF-8" -#define XML_DOC_GENERATOR @"Generated by IJSVG (https://github.com/iconjar/IJSVG)" - -@synthesize title; -@synthesize description; - -BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option) -{ - return (options & option) != 0; -}; - -const NSArray * IJSVGShortCharacterArray() -{ - static NSArray * _array; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _array = [@[@"a",@"b",@"c",@"d",@"e",@"f",@"g",@"h",@"i",@"j",@"k",@"l", - @"m",@"n",@"o",@"p",@"q",@"r",@"s",@"t",@"u",@"v",@"w",@"x",@"y",@"z", - @"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L", - @"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",@"U",@"V",@"W",@"X",@"Y",@"Z"] retain]; - }); - return _array; -} - -const NSArray * IJSVGInheritableAttributes() -{ - static NSArray * _attributes; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _attributes = [@[ - @"clip-rule", - @"color", - @"color-interpolation", - @"color-interpolation-filters", - @"color-profile", - @"color-rendering", - @"cursor", - @"direction", - @"fill", - @"fill-opacity", - @"fill-rule", - @"font", - @"font-family", - @"font-size", - @"font-size-adjust", - @"font-stretch", - @"font-style", - @"font-variant", - @"font-weight", - @"glyph-orientation-horizontal", - @"glyph-orientation-vertical", - @"image-rendering", - @"kerning", - @"letter-spacing", - @"marker", - @"marker-end", - @"marker-mid", - @"marker-start", - @"pointer-events", - @"shape-rendering", - @"stroke", - @"stroke-dasharray", - @"stroke-dashoffset", - @"stroke-linecap", - @"stroke-linejoin", - @"stroke-miterlimit", - @"stroke-opacity", - @"stroke-width", - @"text-anchor", - @"text-rendering", - @"visibility", - @"white-space", - @"word-spacing", - @"writing-mode"] retain]; - }); - return _attributes; -} - -void IJSVGApplyAttributesToElement(NSDictionary *attributes, NSXMLElement *element) { - [element setAttributesAsDictionary:attributes]; -}; - -NSDictionary * IJSVGElementAttributeDictionary(NSXMLElement * element) { - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - for(NSXMLNode * attribute in element.attributes) { - dict[attribute.name] = attribute.stringValue; - } - return dict; -}; - -NSString * IJSVGHashURL(NSString * key) { - return [NSString stringWithFormat:@"url(#%@)",key]; -}; - -NSString * IJSVGHash(NSString * key) { - return [@"#" stringByAppendingString:key]; -} - -- (void)dealloc -{ - [_scaledRootNode release], _scaledRootNode = nil; - [_svg release], _svg = nil; - [_dom release], _dom = nil; - [_defElement release], _defElement = nil; - [title release], title = nil; - [description release], description = nil; - [super dealloc]; -} - -- (id)initWithSVG:(IJSVG *)svg - size:(CGSize)size - options:(IJSVGExporterOptions)options -{ - if((self = [super init]) != nil) { - _options = options; - _size = size; - _svg = [svg retain]; - - // clear memory as soon as possible - @autoreleasepool { - [self _prepare]; - } - } - return self; -} - -- (NSXMLElement *)defElement -{ - if(_defElement != nil) { - return _defElement; - } - return _defElement = [[NSXMLElement alloc] initWithName:@"defs"]; -} - -- (NSString *)viewBoxWithRect:(NSRect)rect -{ - char * buffer; - asprintf(&buffer, "%g %g %g %g", rect.origin.x, rect.origin.y, - rect.size.width, rect.size.height); - NSString * viewBox = [NSString stringWithCString:buffer - encoding:NSUTF8StringEncoding]; - free(buffer); - return viewBox; -} - -- (NSXMLElement *)rootNode -{ - // generates the root document - NSXMLElement * root = [[[NSXMLElement alloc] initWithName:@"svg"] autorelease]; - - // sort out viewbox - NSRect viewBox = _svg.viewBox; - NSDictionary * attributes = @{ - @"viewBox":[self viewBoxWithRect:viewBox], - @"version": [NSString stringWithFormat:@"%g",XML_DOC_VERSION], - @"xmlns": XML_DOC_NS, - @"xmlns:xlink": XML_DOC_NSXLINK - }; - - // add on width and height unless specified otherwise - if((_options & IJSVGExporterOptionRemoveWidthHeightAttributes) == 0) { - NSMutableDictionary * attDict = [[attributes mutableCopy] autorelease]; - attDict[@"width"] = IJSVGShortFloatString(_size.width); - attDict[@"height"] = IJSVGShortFloatString(_size.height); - attributes = [[attDict copy] autorelease]; - } - - // was there a size set? - if(CGSizeEqualToSize(CGSizeZero, _size) == NO && - (_size.width != viewBox.size.width && _size.height != viewBox.size.height)) { - - // copy the attributes - NSMutableDictionary * att = [[attributes mutableCopy] autorelease]; - att[@"width"] = IJSVGShortFloatString(_size.width); - att[@"height"] = IJSVGShortFloatString(_size.height); - - // scale the whole SVG to fit the specified size - if((_options & IJSVGExporterOptionScaleToSizeIfNecessary) != 0) { - // work out the scale - CGFloat scale = MIN(_size.width/viewBox.size.width, - _size.height/viewBox.size.height); - - // actually do the scale - if(scale != 1.f) { - NSString * scaleString = [NSString stringWithFormat:@"scale(%g)",scale]; - NSDictionary * transform = @{@"transform":scaleString}; - - // create the main group and apply transform - _scaledRootNode = [[NSXMLElement alloc] initWithName:@"g"]; - IJSVGApplyAttributesToElement(transform, _scaledRootNode); - - // add it back onto root - [root addChild:_scaledRootNode]; - - // compute x and y, dont multiply 0 - const CGFloat x = viewBox.origin.x == 0.f ? 0.f : (viewBox.origin.x * scale); - const CGFloat y = viewBox.origin.y == 0.f ? 0.f : (viewBox.origin.y * scale); - - // reset the viewbox for the exported SVG - att[@"viewBox"] = [self viewBoxWithRect:(NSRect){ - .origin = NSMakePoint(x, y), - .size = NSMakeSize(_size.width, _size.height) - }]; - } - } - - // reset attributes - attributes = [[att copy] autorelease]; - } - - // apply the attributes - IJSVGApplyAttributesToElement(attributes, root); - return root; -} - -- (NSString *)generateID -{ - const NSArray * chars = IJSVGShortCharacterArray(); - if(_idCount < chars.count) { - return chars[_idCount++]; - } - - if((_idCount % chars.count) == 0) { - _shortIdCount++; - } - return [NSString stringWithFormat:@"%@%ld",chars[(_idCount++ % chars.count)],_shortIdCount]; -} - -- (void)_prepare -{ - // create the stand alone DOM - _dom = [[NSXMLDocument alloc] initWithRootElement:[self rootNode]]; - _dom.version = XML_DOCTYPE_VERSION; - _dom.characterEncoding = XML_DOC_CHARSET; - - // sort out header - - // sort out stuff, so here we go... - [self _recursiveParseFromLayer:_svg.layer - intoElement:(_scaledRootNode?:_dom.rootElement)]; - - // this needs to be added incase it needs to be cleaned - NSXMLElement * defNode = [self defElement]; - if(defNode.childCount != 0) { - [_dom.rootElement insertChild:[self defElement] - atIndex:0]; - } - - // cleanup - [self _cleanup]; - - // could had been removed during cleaning process needs to be added back in! - if(defNode.childCount != 0 && defNode.parent == nil) { - [_dom.rootElement insertChild:[self defElement] - atIndex:0]; - } - - // add generator - NSXMLNode * generatorNode = [[[NSXMLNode alloc] initWithKind:NSXMLCommentKind] autorelease]; - generatorNode.stringValue = XML_DOC_GENERATOR; - [_dom.rootElement insertChild:generatorNode - atIndex:0]; -} - -- (void)_cleanup -{ - // remove hidden elements - if((_options & IJSVGExporterOptionRemoveHiddenElements) != 0) { - [self _removeHiddenElements]; - } - - // convert any duplicate paths into use - if((_options & IJSVGExporterOptionCreateUseForPaths) != 0) { - [self _convertUseElements]; - } - - // cleanup def - if((_options & IJSVGExporterOptionRemoveUselessDef) != 0) { - [self _cleanDef]; - } - - // collapse groups - if((_options & IJSVGExporterOptionCollapseGroups) != 0) { - [self _collapseGroups]; - } - - // clean any blank groups - if((_options & IJSVGExporterOptionRemoveUselessGroups) != 0) { - [self _cleanEmptyGroups]; - } - - // sort attributes - if((_options & IJSVGExporterOptionSortAttributes) != 0) { - [self _sortAttributesOnElement:_dom.rootElement]; - } - - // compress groups together - if((_options & IJSVGExporterOptionCollapseGroups) != 0) { - [self _compressGroups]; - } - - // collapse gradients? - if((_options & IJSVGExporterOptionCollapseGradients) != 0) { - [self _collapseGradients]; - } - - // create classes? - if((_options & IJSVGExporterOptionCreateClasses) != 0) { - [self _createClasses]; - } - - // move attributes to group - if((_options & IJSVGExporterOptionMoveAttributesToGroup) != 0) { - [self _moveAttributesToGroupWithElement:_dom.rootElement]; - } -} - -- (void)_createClasses -{ - const NSArray * inhert = IJSVGInheritableAttributes(); - NSArray * elements = [_dom nodesForXPath:@"//*" - error:nil]; - NSMutableDictionary * rules = [[[NSMutableDictionary alloc] init] autorelease]; - for(NSXMLElement * element in elements) { - NSDictionary * inhertEl = [self intersectableAttributes:IJSVGElementAttributeDictionary(element) - inheritableAttributes:inhert]; - NSString * styles = [self styleSheetRulesFromDictionary:inhertEl]; - NSString * className = nil; - if((className = [rules objectForKey:styles]) == nil) { - className = [NSString stringWithFormat:@"%@",[self generateID]]; - rules[styles] = className; - } - - for(NSString * attributeName in inhertEl) { - [element removeAttributeForName:attributeName]; - } - IJSVGApplyAttributesToElement(@{@"class":className},element); - } - - // add styles to dom - NSXMLElement * styles = [[[NSXMLElement alloc] initWithName:@"style"] autorelease]; - NSXMLNode * node = [[[NSXMLNode alloc] initWithKind:NSXMLTextKind] autorelease]; - - NSMutableArray * classes = [[[NSMutableArray alloc] initWithCapacity:rules.count] autorelease]; - for(NSString * r in rules) { - [classes addObject:[NSString stringWithFormat:@".%@%@",rules[r],r]]; - } - node.stringValue = [classes componentsJoinedByString:@""]; - [styles addChild:node]; - [_dom.rootElement insertChild:styles atIndex:0]; -} - -- (NSString *)styleSheetRulesFromDictionary:(NSDictionary *)dict -{ - NSMutableArray * array = [[[NSMutableArray alloc] initWithCapacity:dict.count] autorelease]; - for(NSString * key in dict.allKeys) { - [array addObject:[NSString stringWithFormat:@"%@: %@;",key,dict[key]]]; - } - return [NSString stringWithFormat:@"{%@}",[array componentsJoinedByString:@" "]]; -} - -- (void)_sortAttributesOnElement:(NSXMLElement *)element -{ - // only apply to XML elements, not XMLNodes - if([element isKindOfClass:[NSXMLElement class]] == NO) { - return; - } - [self sortAttributesOnElement:element]; - for(NSXMLElement * child in element.children) { - [self _sortAttributesOnElement:child]; - } -} - -- (void)_removeHiddenElements -{ - // find any elements where they have a style, but the element itself - // must not be in the defs - NSArray * elements = [_dom nodesForXPath:@"//*[@display='none']" - error:nil]; - - for(NSXMLElement * element in elements) { - NSXMLElement * parent = (NSXMLElement *)element.parent; - [parent removeChildAtIndex:element.index]; - } -} - -- (void)_collapseGradients -{ - NSString * xPath = @"//defs/*[self::linearGradient or self::radialGradient]"; - NSArray * gradients = [_dom nodesForXPath:xPath error:nil]; - for(NSInteger i = 0; i < gradients.count; i++) { - if(i != 0) { - NSXMLElement * gradientA = gradients[i]; - NSXMLElement * gradientB = nil; - for(NSInteger s = (i - 1); s >= 0; s--) { - gradientB = gradients[s]; - if([self compareElementChildren:gradientA toElement:gradientB] == YES) { - NSString * idString = [gradientB attributeForName:@"id"].stringValue; - if(idString == nil || idString.length == 0) { - idString = [self generateID]; - IJSVGApplyAttributesToElement(@{@"id":idString}, gradientB); - } - NSDictionary * atts = @{@"xlink:href":IJSVGHash(idString)}; - IJSVGApplyAttributesToElement(atts, gradientA); - [gradientA setChildren:nil]; - break; - } - } - } - } -} - -- (BOOL)compareElementChildren:(NSXMLElement *)element - toElement:(NSXMLElement *)toElement -{ - NSArray * childrenA = element.children; - NSArray * childrenB = toElement.children; - if(childrenA.count != childrenB.count) { - return NO; - } - for(NSInteger i = 0; i < childrenA.count; i++) { - NSXMLElement * childA = childrenA[i]; - NSXMLElement * childB = childrenB[i]; - if([self compareElement:childA withElement:childB] == NO) { - return NO; - } - } - return YES; -} - -- (void)_moveAttributesToGroupWithElement:(NSXMLElement *)parentElement -{ - - const NSArray * excludedNodes = @[@"script",@"style",@"defs"]; - if([excludedNodes containsObject:parentElement.name] == YES) { - return; - } - - const NSArray * inheritableAttributes = IJSVGInheritableAttributes(); - - NSDictionary * intersection = @{}; - NSMutableArray * grouped = [[[NSMutableArray alloc] init] autorelease]; - - NSInteger counter = 0; - NSInteger size = parentElement.childCount - 1; - for(NSXMLElement * element in parentElement.children) { - - NSDictionary * attributes = [self intersectableAttributes:IJSVGElementAttributeDictionary(element) - inheritableAttributes:inheritableAttributes]; - - if(intersection.count == 0) { - intersection = attributes; - } - - NSDictionary * dict = [self intersectionInheritableAttributes:intersection - currentAttributes:attributes - inheritableAttributes:inheritableAttributes]; - - for(NSString * attributeToRemove in dict.allKeys) { - [element removeAttributeForName:attributeToRemove]; - } - if(dict != nil) { - [grouped addObject:element]; - } - - if(dict == nil || counter == size) { - if(grouped.count > 1) { - NSXMLElement * groupElement = [[[NSXMLElement alloc] initWithName:@"g"] autorelease]; - NSXMLElement * lastElement = (NSXMLElement *)grouped.lastObject; - NSInteger index = lastElement.index; - [parentElement replaceChildAtIndex:index withNode:groupElement]; - for(NSXMLElement * elementToGroup in grouped) { - [elementToGroup detach]; - [groupElement addChild:elementToGroup]; - } - IJSVGApplyAttributesToElement(intersection, groupElement); - } else { - if(grouped.count == 1) { - NSXMLElement * onlyElement = (NSXMLElement *)grouped.lastObject; - IJSVGApplyAttributesToElement(intersection, onlyElement); - } - } - intersection = @{}; - [grouped removeAllObjects]; - } - - counter++; - } -} - -- (NSDictionary *)intersectableAttributes:(NSDictionary *)atts - inheritableAttributes:(const NSArray *)inheritable -{ - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - for(NSString * key in atts.allKeys) { - if([inheritable containsObject:key]) { - dict[key] = atts[key]; - } - } - return dict; -} - -- (NSDictionary *)intersectionInheritableAttributes:(NSDictionary *)newAttributes - currentAttributes:(NSDictionary *)currentAttributes - inheritableAttributes:(const NSArray *)inheritableAtts -{ - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - for(NSString * key in newAttributes.allKeys) { - // make sure they are the same and - // they are inheritable - if([currentAttributes objectForKey:key] == nil) { - return nil; - } - - if([currentAttributes objectForKey:key] != nil && - [inheritableAtts containsObject:key] && - [newAttributes[key] isEqualToString:currentAttributes[key]]) { - dict[key] = currentAttributes[key]; - } - } - - // nothing to return, kill it - if(dict.count == 0) { - return nil; - } - return dict; -} - -- (void)_cleanDef -{ - NSXMLElement * defNode = [self defElement]; - if(defNode.children == 0) { - NSXMLElement * parent = (NSXMLElement *)defNode.parent; - [parent removeChildAtIndex:defNode.index]; - } -} - -- (void)_cleanEmptyGroups -{ - @autoreleasepool { - // cleanup any groups that are completely useless - NSArray * groups = [_dom nodesForXPath:@"//g" error:nil]; - for(NSXMLElement * element in groups) { - NSXMLElement * parent = (NSXMLElement *)element.parent; - if(element.childCount == 0) { - // empty group - [(NSXMLElement *)element.parent removeChildAtIndex:element.index]; - } else if(element.attributes.count == 0) { - // no useful data on the group - NSInteger index = element.index; - for(NSXMLElement * child in element.children) { - [(NSXMLElement *)child.parent removeChildAtIndex:child.index]; - [parent insertChild:child - atIndex:index++]; - } - [parent removeChildAtIndex:element.index]; - } - } - } -} - -- (void)_compressGroups -{ - NSArray * groups = [_dom nodesForXPath:@"//g" error:nil]; - for(NSXMLElement * group in groups) { - - // whats the next group? - if(group.parent == nil) { - continue; - } - - // compare each group with its next sibling - NSXMLElement * nextGroup = (NSXMLElement *)group.nextSibling; - while([self compareElement:group withElement:nextGroup]) { - // move each child into the older group - for(NSXMLElement * child in nextGroup.children) { - [nextGroup removeChildAtIndex:child.index]; - [group addChild:child]; - } - - // remove the newer - NSXMLElement * n = nextGroup; - nextGroup = (NSXMLElement *)nextGroup.nextSibling; - [(NSXMLElement *)n.parent removeChildAtIndex:n.index]; - } - } - -} - -- (void)_collapseGroups -{ - NSArray * groups = [_dom nodesForXPath:@"//g" error:nil]; - const NSArray * inheritable = IJSVGInheritableAttributes(); - for(NSXMLElement * group in groups) { - - // dont do anything due to it being referenced - if([group attributeForName:@"id"] != nil) { - return; - } - - if(group.attributes.count != 0 && group.children.count == 1) { - - // grab the first child as its a loner - NSXMLElement * child = (NSXMLElement *)group.children[0]; - if([child attributeForName:@"transform"] != nil) { - continue; - } - - for(NSXMLNode * gAttribute in group.attributes) { - - // if it just doesnt have the attriute, just add it - if([child attributeForName:gAttribute.name] == NO) { - // remove first, or throws a wobbly - [group removeAttributeForName:gAttribute.name]; - [child addAttribute:gAttribute]; - } else if([gAttribute.name isEqualToString:@"transform"]) { - // transform requires concatination - NSXMLNode * childTransform = [child attributeForName:@"transform"]; - childTransform.stringValue = [NSString stringWithFormat:@"%@ %@", - gAttribute.stringValue, childTransform.stringValue]; - - } else if([inheritable containsObject:gAttribute.name] == NO) { - // if its not inheritable, only remove it if its not equal - NSXMLNode * aAtt = [child attributeForName:gAttribute.name]; - if(aAtt == nil || (aAtt != nil && [aAtt.stringValue isEqualToString:gAttribute.stringValue] == NO)) { - continue; - } - } - [group removeAttributeForName:gAttribute.name]; - } - - // remove the group as its useless! - if(group.attributes.count == 0) { - [child detach]; - [(NSXMLElement *)group.parent replaceChildAtIndex:group.index - withNode:child]; - } - } - } -} - -- (BOOL)compareElement:(NSXMLElement *)element - withElement:(NSXMLElement *)anotherElement -{ - // not a matching element - if([element.name isEqualToString:anotherElement.name] == NO || - element.attributes.count != anotherElement.attributes.count) { - return NO; - } - - // compare attributes - for(NSXMLNode * attribute in element.attributes) { - NSString * compareString = [anotherElement attributeForName:attribute.name].stringValue; - if([attribute.stringValue isEqualToString:compareString] == NO) { - return NO; - } - } - return YES; -} - -- (void)_convertUseElements -{ - @autoreleasepool { - NSArray * paths = [_dom nodesForXPath:@"//path" - error:nil]; - - NSCountedSet * set = [[[NSCountedSet alloc] init] autorelease]; - for(NSXMLElement * element in paths) { - [set addObject:[element attributeForName:@"d"].stringValue]; - } - - NSMutableDictionary * defs = [[[NSMutableDictionary alloc] init] autorelease]; - - // now actually compute them - for(NSXMLElement * element in paths) { - NSString * data = [element attributeForName:@"d"].stringValue; - if([set countForObject:data] == 1) { - continue; - } - - // at this point, we know the path is being used more then once - NSXMLElement * defParentElement = nil; - if((defParentElement = [defs objectForKey:data]) == nil) { - // create the def - NSXMLElement * element = [[[NSXMLElement alloc] init] autorelease]; - element.name = @"path"; - - NSDictionary * atts = @{@"d":data, - @"id":[self generateID]}; - IJSVGApplyAttributesToElement(atts, element); - - // store it against the def - defs[data] = element; - defParentElement = element; - } - - // we know at this point, we need to swap out the path to a use - NSXMLElement * use = [[[NSXMLElement alloc] init] autorelease]; - use.name = @"use"; - - // grab the id - NSString * pathId = [defParentElement attributeForName:@"id"].stringValue; - - NSXMLNode * useAttribute = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; - useAttribute.name = @"xlink:href"; - useAttribute.stringValue = IJSVGHash(pathId); - [use addAttribute:useAttribute]; - - // remove the d attribute - for(NSXMLNode * attribute in element.attributes) { - if([attribute.name isEqualToString:@"d"]) { - continue; - } - [element removeAttributeForName:attribute.name]; - [use addAttribute:attribute]; - } - - // swap it out - [(NSXMLElement *)element.parent replaceChildAtIndex:element.index - withNode:use]; - } - - // add the defs back in - NSXMLElement * def = [self defElement]; - for(NSXMLElement * defElement in defs.allValues) { - [def addChild:defElement]; - } - } -} - -- (void)_recursiveParseFromLayer:(IJSVGLayer *)layer - intoElement:(NSXMLElement *)element -{ - // is a shape - if([layer class] == [IJSVGShapeLayer class]) { - NSXMLElement * child = [self elementForShape:(IJSVGShapeLayer *)layer - fromParent:element]; - if(child != nil) { - [element addChild:child]; - } - } else if([layer isKindOfClass:[IJSVGImageLayer class]]) { - NSXMLElement * child = [self elementForImage:(IJSVGImageLayer *)layer - fromParent:element]; - if(child != nil) { - [element addChild:child]; - } - } else if([layer isKindOfClass:[IJSVGGroupLayer class]]) { - // assume its probably a group? - NSXMLElement * child = [self elementForGroup:layer - fromParent:element]; - if(child != nil) { - [element addChild:child]; - } - } -} - -- (void)applyTransformToElement:(NSXMLElement *)element - fromLayer:(IJSVGLayer *)layer -{ - CGAffineTransform transform = layer.affineTransform; - if(CGAffineTransformEqualToTransform(transform, CGAffineTransformIdentity) == YES) { - return; - } - - // append the string - NSString * transformStr = [IJSVGTransform affineTransformToSVGMatrixString:transform]; - - // apply it to the node - IJSVGApplyAttributesToElement(@{@"transform":transformStr},element); -} - -- (NSXMLElement *)elementForGroup:(IJSVGLayer *)layer - fromParent:(NSXMLElement *)parent -{ - // create the element - NSXMLElement * e = [[[NSXMLElement alloc] init] autorelease]; - e.name = @"g"; - - // stick defaults - [self applyDefaultsToElement:e - fromLayer:layer]; - - // add group children - for(IJSVGLayer * childLayer in layer.sublayers) { - [self _recursiveParseFromLayer:childLayer - intoElement:e]; - } - - return e; -} - -- (NSString *)base64EncodedStringFromCGImage:(CGImageRef)image -{ - if(image == nil) { - return nil; - } - - // convert the CGImage into an NSImage - NSBitmapImageRep * rep = [[[NSBitmapImageRep alloc] initWithCGImage:image] autorelease]; - - // work out the data - NSData * data = [rep representationUsingType:NSBitmapImageFileTypePNG - properties:@{}]; - - NSString * base64String = [data base64EncodedStringWithOptions:0]; - return [@"data:image/png;base64," stringByAppendingString:base64String]; -} - -- (void)applyPatternFromLayer:(IJSVGPatternLayer *)layer - parentLayer:(IJSVGLayer *)parentLayer - stroke:(BOOL)stroke - toElement:(NSXMLElement *)element -{ - // now we need the pattern - IJSVGGroupLayer * patternLayer = (IJSVGGroupLayer *)layer.pattern; - - NSXMLElement * patternElement = [self elementForGroup:patternLayer - fromParent:nil]; - patternElement.name = @"pattern"; - - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - dict[@"id"] = [self generateID]; - dict[@"width"] = IJSVGShortFloatString(layer.patternNode.width.value); - dict[@"height"] = IJSVGShortFloatString(layer.patternNode.height.value); - - // sort out x and y position - IJSVGUnitLength * x = layer.patternNode.x; - IJSVGUnitLength * y = layer.patternNode.y; - - if(x.value != 0) { - dict[@"x"] = [layer.patternNode.x stringValue]; - } - - if(y.value != 0) { - dict[@"y"] = [layer.patternNode.y stringValue]; - } - - - IJSVGApplyAttributesToElement(dict, patternElement); - - [[self defElement] addChild:patternElement]; - - // now the use statement - NSXMLElement * useElement = [[[NSXMLElement alloc] init] autorelease]; - useElement.name = @"use"; - - // now add the fill - NSDictionary * aDict = nil; - if(stroke == NO) { - aDict = @{@"fill":IJSVGHashURL([patternElement attributeForName:@"id"].stringValue)}; - IJSVGApplyAttributesToElement(aDict, element); - - // fill opacity - if(patternLayer.opacity != 1.f) { - IJSVGApplyAttributesToElement(@{@"fill-opacity":IJSVGShortFloatString(patternLayer.opacity)}, element); - } - } else { - aDict = @{@"stroke":IJSVGHashURL([patternElement attributeForName:@"id"].stringValue)}; - IJSVGApplyAttributesToElement(aDict, element); - } -} - -- (void)applyGradientFromLayer:(IJSVGGradientLayer *)layer - parentLayer:(IJSVGLayer *)parentLayer - stroke:(BOOL)stroke - toElement:(NSXMLElement *)element -{ - IJSVGGradient * gradient = layer.gradient; - NSString * gradKey = [self generateID]; - NSXMLElement * gradientElement = [[[NSXMLElement alloc] init] autorelease]; - - // work out linear gradient - if([gradient isKindOfClass:[IJSVGLinearGradient class]]) { - - IJSVGLinearGradient * lGradient = (IJSVGLinearGradient *)gradient; - gradientElement.name = @"linearGradient"; - NSDictionary * dict = @{@"id":gradKey, - @"x1":lGradient.x1.stringValue, - @"y1":lGradient.y1.stringValue, - @"x2":lGradient.x2.stringValue, - @"y2":lGradient.y2.stringValue}; - - // give it the attibutes - IJSVGApplyAttributesToElement(dict, gradientElement); - } else { - - // assume radial - IJSVGRadialGradient * rGradient = (IJSVGRadialGradient *)gradient; - gradientElement.name = @"radialGradient"; - NSDictionary * dict = @{@"id":gradKey, - @"cx":rGradient.cx.stringValue, - @"cy":rGradient.cy.stringValue, - @"fx":rGradient.fx.stringValue, - @"fy":rGradient.fy.stringValue, - @"r":rGradient.radius.stringValue}; - - // give it the attributes - IJSVGApplyAttributesToElement(dict, gradientElement); - } - - // apply the units - if(layer.gradient.units == IJSVGUnitUserSpaceOnUse) { - IJSVGApplyAttributesToElement(@{@"gradientUnits":@"userSpaceOnUse"}, - gradientElement); - } - - // add the stops - NSGradient * grad = layer.gradient.gradient; - IJSVGColorList * sheet = layer.gradient.colorList; - NSInteger noStops = grad.numberOfColorStops; - for(NSInteger i = 0; i < noStops; i++) { - - // grab each color from the gradient - NSColor * aColor = nil; - CGFloat location; - [grad getColor:&aColor - location:&location - atIndex:i]; - - if(sheet != nil) { - aColor = [sheet proposedColorForColor:aColor]; - } - - // create the stop element - NSXMLElement * stop = [[[NSXMLElement alloc] init] autorelease]; - stop.name = @"stop"; - - NSMutableDictionary * atts = [[[NSMutableDictionary alloc] init] autorelease]; - atts[@"offset"] = [NSString stringWithFormat:@"%g%%",(location*100)]; - - // add the color - IJSVGColorStringOptions options = IJSVGColorStringOptionForceHEX|IJSVGColorStringOptionAllowShortHand; - NSString * stopColor = [IJSVGColor colorStringFromColor:aColor - options:options]; - if([stopColor isEqualToString:@"#000000"] == NO) { - atts[@"stop-color"] = stopColor; - } - - // we need to work out the color at this point, annoyingly... - CGFloat opacity = aColor.alphaComponent; - - // is opacity is equal to 1, no need to add it as spec - // defaults opacity to 1 anyway :) - if(opacity != 1.f) { - atts[@"stop-opacity"] = IJSVGShortFloatStringWithPrecision(opacity, 2); - } - - // att the attributes - - IJSVGApplyAttributesToElement(atts, stop); - - // append the stop the gradient - [gradientElement addChild:stop]; - } - - // append it to the defs - [[self defElement] addChild:gradientElement]; - - // work out the transform - NSArray * transforms = layer.gradient.transforms; - if(transforms.count != 0.f) { - CGAffineTransform transform = IJSVGConcatTransforms(transforms); - NSString * transformString = [IJSVGTransform affineTransformToSVGMatrixString:transform]; - IJSVGApplyAttributesToElement(@{@"gradientTransform":transformString}, gradientElement); - } - - // add it to the element passed in - if(stroke == NO) { - IJSVGApplyAttributesToElement(@{@"fill":IJSVGHashURL(gradKey)}, element); - - // fill opacity - if(layer.opacity != 1.f) { - IJSVGApplyAttributesToElement(@{@"fill-opacity":IJSVGShortFloatStringWithPrecision(layer.opacity,2)}, element); - } - } else { - IJSVGApplyAttributesToElement(@{@"stroke":IJSVGHashURL(gradKey)}, element); - } -} - -- (CGAffineTransform)affineTransformFromTransforms:(NSArray *)transforms -{ - CGAffineTransform t = CGAffineTransformIdentity; - for(IJSVGTransform * transform in transforms) { - t = CGAffineTransformConcat( t, [transform CGAffineTransform]); - } - return t; -} - -- (NSXMLElement *)elementForImage:(IJSVGImageLayer *)layer - fromParent:(NSXMLElement *)parent -{ - NSString * base64String = [self base64EncodedStringFromCGImage:(CGImageRef)layer.contents]; - if(base64String == nil || layer.contents == nil) { - return nil; - } - - // image element for the SVG - NSXMLElement * imageElement = [[[NSXMLElement alloc] init] autorelease]; - imageElement.name = @"image"; - - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - dict[@"id"] = [self generateID]; - dict[@"width"] = IJSVGShortFloatString(layer.frame.size.width); - dict[@"height"] = IJSVGShortFloatString(layer.frame.size.height); - dict[@"xlink:href"] = base64String; - - // work out any position - if(layer.frame.origin.x != 0.f) { - dict[@"x"] = IJSVGShortFloatString(layer.frame.origin.x); - } - if(layer.frame.origin.y != 0.f) { - dict[@"y"] = IJSVGShortFloatString(layer.frame.origin.y); - } - - // add the attributes - IJSVGApplyAttributesToElement(dict, imageElement); - return imageElement; -} - -- (IJSVGColorStringOptions)colorOptions -{ - IJSVGColorStringOptions options = IJSVGColorStringOptionDefault; - if((_options & IJSVGExporterOptionColorAllowRRGGBBAA) != 0) { - options |= IJSVGColorStringOptionAllowRRGGBBAA; - } - return options; -} - -- (NSXMLElement *)elementForShape:(IJSVGShapeLayer *)layer - fromParent:(NSXMLElement *)parent -{ - NSXMLElement * e = [[[NSXMLElement alloc] init] autorelease]; - e.name = @"path"; - CGPathRef path = layer.path; - - // copy the path as we want to translate - CGAffineTransform trans = CGAffineTransformMakeTranslation(layer.originalPathOrigin.x, - layer.originalPathOrigin.y); - CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &trans); - - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - - // path - dict[@"d"] = [self pathFromCGPath:transformPath]; - - CGPathRelease(transformPath); - - // work out even odd rule - if([layer.fillRule isEqualToString:kCAFillRuleNonZero] == NO) { - dict[@"fill-rule"] = @"evenodd"; - } - - // fill color - if(layer.fillColor != nil) { - NSColor * fillColor = [NSColor colorWithCGColor:layer.fillColor]; - NSString * colorString = [IJSVGColor colorStringFromColor:fillColor - options:[self colorOptions]]; - - // could be none - if(colorString != nil) { - dict[@"fill"] = colorString; - } - } - - // is there a gradient fill? - if(layer.gradientFillLayer != nil) { - [self applyGradientFromLayer:layer.gradientFillLayer - parentLayer:(IJSVGLayer *)layer - stroke:NO - toElement:e]; - } - - // is there a pattern? - if(layer.patternFillLayer != nil) { - [self applyPatternFromLayer:layer.patternFillLayer - parentLayer:(IJSVGLayer *)layer - stroke:NO - toElement:e]; - } - - // is there a stroke layer? - if(layer.strokeLayer != nil) { - // check the type - IJSVGStrokeLayer * strokeLayer = layer.strokeLayer; - if([strokeLayer isKindOfClass:[IJSVGShapeLayer class]]) { - // stroke - if(strokeLayer.lineWidth != 0.f) { - dict[@"stroke-width"] = IJSVGShortFloatString(strokeLayer.lineWidth); - } - - // stroke gradient - if(layer.gradientStrokeLayer != nil) { - [self applyGradientFromLayer:layer.gradientStrokeLayer - parentLayer:(IJSVGPatternLayer *)layer - stroke:YES - toElement:e]; - - } else if(layer.patternStrokeLayer != nil) { - // stroke pattern - [self applyPatternFromLayer:layer.patternStrokeLayer - parentLayer:(IJSVGPatternLayer *)layer - stroke:YES - toElement:e]; - - } else if(strokeLayer.strokeColor != nil) { - NSColor * strokeColor = [NSColor colorWithCGColor:strokeLayer.strokeColor]; - NSString * strokeColorString = [IJSVGColor colorStringFromColor:strokeColor - options:[self colorOptions]]; - - // could be none - if(strokeColorString != nil) { - dict[@"stroke"] = strokeColorString; - if([strokeColorString isEqualToString:@"none"] == YES) { - // remove the stroke width as its completely useless - [dict removeObjectForKey:@"stroke-width"]; - } - } - } - - // work out line cap - if([strokeLayer.lineCap isEqualToString:kCALineCapButt] == NO) { - NSString * capStyle = nil; - if([strokeLayer.lineCap isEqualToString:kCALineCapRound]) { - capStyle = @"round"; - } else if([strokeLayer.lineCap isEqualToString:kCALineCapSquare]) { - capStyle = @"square"; - } - if(capStyle != nil) { - dict[@"stroke-linecap"] = capStyle; - } - } - - // work out line join - if([strokeLayer.lineJoin isEqualToString:kCALineJoinMiter] == NO) { - NSString * joinStyle = nil; - if([strokeLayer.lineJoin isEqualToString:kCALineJoinBevel]) { - joinStyle = @"bevel"; - } else if([strokeLayer.lineJoin isEqualToString:kCALineJoinRound]) { - joinStyle = @"round"; - } - if(joinStyle != nil) { - dict[@"stroke-linejoin"] = joinStyle; - } - } - - // work out dash offset... - if(strokeLayer.lineDashPhase != 0.f) { - dict[@"stroke-dashoffset"] = IJSVGShortFloatString(strokeLayer.lineDashPhase); - } - - // work out dash array - if(strokeLayer.lineDashPattern.count != 0) { - dict[@"stroke-dasharray"] = [strokeLayer.lineDashPattern componentsJoinedByString:@" "]; - } - - } - } - - // apply the attributes - IJSVGApplyAttributesToElement(dict, e); - - // apple defaults - [self applyDefaultsToElement:e - fromLayer:(IJSVGLayer *)layer]; - return e; -} - -- (void)applyDefaultsToElement:(NSXMLElement *)element - fromLayer:(IJSVGLayer *)layer -{ - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - - // opacity - if(layer.opacity != 1.f) { - dict[@"opacity"] = IJSVGShortFloatStringWithPrecision(layer.opacity,2); - } - - // blendmode - we only every apply a stylesheet blend mode - NSMutableDictionary * style = [[[NSMutableDictionary alloc] init] autorelease]; - if(layer.blendingMode != kCGBlendModeNormal) { - NSString * str = [IJSVGUtils mixBlendingModeForBlendMode:(IJSVGBlendMode)layer.blendingMode]; - if(str != nil) { - style[@"mix-blend-mode"] = str; - } - } - - // hidden? - if(layer.isHidden) { - style[@"display"] = @"none"; - } - - if(style.count != 0) { - NSMutableString * styleString = [[[NSMutableString alloc] init] autorelease]; - for(NSString * styleKey in style.allKeys) { - NSString * format = [NSString stringWithFormat:@"%@:%@;",styleKey, style[styleKey]]; - [styleString appendString:format]; - } - dict[@"style"] = styleString; - } - - - // add atttributes - IJSVGApplyAttributesToElement(dict, element); - - // apply transforms - [self applyTransformToElement:element - fromLayer:layer]; - - // add any masks... - if(layer.mask != nil) { - [self applyMaskToElement:element - fromLayer:layer]; - } -} - -- (void)applyMaskToElement:(NSXMLElement *)element - fromLayer:(IJSVGLayer *)layer -{ - // create the element - NSXMLElement * mask = [[[NSXMLElement alloc] init] autorelease]; - mask.name = @"mask"; - - // create the key - NSString * maskKey = [self generateID]; - NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease]; - dict[@"id"] = maskKey; - dict[@"maskContentUnits"] = @"userSpaceOnUse"; - dict[@"maskUnits"] = @"objectBoundingBox"; - - if(layer.mask.frame.origin.x != 0.f) { - dict[@"x"] = IJSVGShortFloatString(layer.mask.frame.origin.x); - } - if(layer.mask.frame.origin.y != 0.f) { - dict[@"y"] = IJSVGShortFloatString(layer.mask.frame.origin.y); - } - - IJSVGApplyAttributesToElement(dict, mask); - - // add the cool stuff - [self _recursiveParseFromLayer:(IJSVGLayer *)layer.mask - intoElement:mask]; - - // add mask id to element - IJSVGApplyAttributesToElement(@{@"mask":IJSVGHashURL(maskKey)}, element); - - // add it defs - [[self defElement] addChild:mask]; -} - -- (NSString *)SVGString -{ - NSXMLNodeOptions options = NSXMLNodePrettyPrint; - if((_options & IJSVGExporterOptionCompressOutput) != 0) { - options = NSXMLNodeOptionsNone; - } - return [_dom XMLStringWithOptions:options]; -} - -- (NSData *)SVGData -{ - return [[self SVGString] dataUsingEncoding:NSUTF8StringEncoding]; -} - -#pragma mark CGPath stuff - -- (NSString *)pathFromCGPath:(CGPathRef)path -{ - // string to store the path in - NSArray * instructions = [IJSVGExporterPathInstruction instructionsFromPath:path]; - - // work out what to do... - if((_options & IJSVGExporterOptionCleanupPaths) != 0) { - [IJSVGExporterPathInstruction convertInstructionsToRelativeCoordinates:instructions]; - } - return [IJSVGExporterPathInstruction pathStringFromInstructions:instructions]; -} - -void IJSVGExporterPathCaller(void * info, const CGPathElement * pathElement) { - IJSVGCGPathHandler handler = (IJSVGCGPathHandler)info; - handler(pathElement); -}; - -- (void)sortAttributesOnElement:(NSXMLElement *)element -{ - const NSArray * order = @[@"id",@"width",@"height",@"x",@"x1",@"x2", - @"y",@"y1",@"y2",@"cx",@"cy",@"r",@"fill", - @"stroke",@"marker",@"d",@"points",@"transform", - @"gradientTransform", @"xlink:href"]; - - // grab the attributes - NSArray* attributes = element.attributes; - NSInteger count = attributes.count; - - // sort the attributes using a custom sort - NSArray * sorted = [attributes sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { - // tell compiler we are nodes - NSXMLNode * attribute1 = (NSXMLNode *)obj1; - NSXMLNode * attribute2 = (NSXMLNode *)obj2; - - // base index - float aIndex = count; - float bIndex = count; - - // loop around each order string - for(NSInteger i = 0; i < order.count; i++) { - if([attribute1.name isEqualToString:order[i]]) { - aIndex = i; - } else if([attribute1.name rangeOfString:[order[i] stringByAppendingString:@"-"]].location == 0) { - aIndex = i + .5; - } - if([attribute2.name isEqualToString:order[i]]) { - bIndex = i; - } else if([attribute2.name rangeOfString:[order[i] stringByAppendingString:@"-"]].location == 0) { - bIndex = i + .5; - } - } - - // return the comparison set - if(aIndex != bIndex) { - if(aIndex > bIndex) { - return NSOrderedDescending; - } else { - return NSOrderedAscending; - } - } - return [attribute1.name compare:attribute2.name]; - }]; - - // remove all attributes - for(NSXMLNode * node in attributes) { - [element removeAttributeForName:node.name]; - } - - // add them back on in order - for(NSXMLNode * attribute in sorted) { - [element addAttribute:attribute]; - } - -} - -@end - diff --git a/source/IJSVGExporterPathInstruction.m b/source/IJSVGExporterPathInstruction.m deleted file mode 100644 index d5b9185..0000000 --- a/source/IJSVGExporterPathInstruction.m +++ /dev/null @@ -1,374 +0,0 @@ -// -// IJSVGExporterPathInstruction.m -// IconJar -// -// Created by Curtis Hard on 08/01/2017. -// Copyright © 2017 Curtis Hard. All rights reserved. -// - -#import "IJSVGExporterPathInstruction.h" -#import "IJSVGExporter.h" - -@implementation IJSVGExporterPathInstruction - -- (void)dealloc -{ - if(_data != NULL) { - free(_data); - } - [super dealloc]; -} - -- (id)initWithInstruction:(char)instruction - dataCount:(NSInteger)floatCount -{ - if((self = [super init]) != nil) { - _instruction = instruction; - - // only allocate if not zero - if(floatCount != 0) { - _data = (CGFloat *)calloc(sizeof(CGFloat), floatCount); - } - } - return self; -} - -- (NSInteger)dataLength -{ - return _dataCount; -} - -- (void)setInstruction:(char)newInstruction -{ - _instruction = newInstruction; -} - -- (char)instruction -{ - return _instruction; -} - -- (CGFloat *)data -{ - return _data; -} - -+ (NSString *)pathStringFromInstructions:(NSArray *)instructions -{ - NSMutableArray * pathData = [[[NSMutableArray alloc] init] autorelease]; - for(IJSVGExporterPathInstruction * instruction in instructions) { - CGFloat * data = instruction.data; - NSString * str = nil; - switch(instruction.instruction) { - - // move - case 'M': - case 'm': { - char * buffer; - asprintf(&buffer, "%c%g,%g", instruction.instruction, data[0], data[1]); - str = [NSString stringWithCString:buffer - encoding:NSUTF8StringEncoding]; - free(buffer); - [pathData addObject:str]; - break; - } - - // vertical and horizonal line - case 'V': - case 'v': - case 'H': - case 'h': { - char * buffer; - asprintf(&buffer, "%c%g", instruction.instruction, data[0]); - str = [NSString stringWithCString:buffer - encoding:NSUTF8StringEncoding]; - free(buffer); - [pathData addObject:str]; - break; - } - - // line - case 'L': - case 'l': { - char * buffer; - asprintf(&buffer, "%c%g,%g",instruction.instruction, data[0], data[1]); - str = [NSString stringWithCString:buffer - encoding:NSUTF8StringEncoding]; - free(buffer); - [pathData addObject:str]; - break; - } - - // curve - case 'C': - case 'c': { - char * buffer; - asprintf(&buffer, "%c%g,%g %g,%g %g,%g", instruction.instruction, - data[0], data[1], data[2], data[3], data[4], data[5]); - str = [NSString stringWithCString:buffer - encoding:NSUTF8StringEncoding]; - free(buffer); - [pathData addObject:str]; - break; - } - - // quadratic curve - case 'Q': - case 'q': { - char * buffer; - asprintf(&buffer, "%c%g,%g %g,%g", instruction.instruction, - data[0], data[1], data[2], data[3]); - str = [NSString stringWithCString:buffer - encoding:NSUTF8StringEncoding]; - free(buffer); - [pathData addObject:str]; - break; - } - - // close path - case 'Z': - case 'z': { - str = [NSString stringWithFormat:@"%c",instruction.instruction]; - [pathData addObject:str]; - } - } - } - return [pathData componentsJoinedByString:@""]; -} - -+ (void)convertInstructionsToRelativeCoordinates:(NSArray *)instructions -{ - CGFloat point[2] = {0,0}; - CGFloat subpathPoint[2] = {0,0}; - - NSInteger index = 0; - for(IJSVGExporterPathInstruction * anInstruction in instructions) { - char instruction = anInstruction.instruction; - CGFloat * data = anInstruction.data; - NSInteger length = anInstruction.dataLength; - - if(data != NULL) { - - // already relative - if(instruction == 'm' || instruction == 'c' || instruction == 's' || - instruction == 'l' || instruction == 'q' || instruction == 't' || - instruction == 'a') { - - point[0] += data[length-2]; - point[1] += data[length-1]; - - if(instruction == 'm') { - subpathPoint[0] = point[0]; - subpathPoint[1] = point[1]; - } - - } else if(instruction == 'h') { - point[0] += data[0]; - } else if(instruction == 'v') { - point[1] += data[0]; - } - - // convert absolute to relative - if(instruction == 'M') { - if(index > 0) { - instruction = 'm'; - } - - data[0] -= point[0]; - data[1] -= point[1]; - - subpathPoint[0] = point[0] += data[0]; - subpathPoint[1] = point[1] += data[1]; - - } else if(instruction == 'L' || instruction == 'T') { - - instruction = tolower(instruction); - - data[0] -= point[0]; - data[1] -= point[1]; - - point[0] += data[0]; - point[1] += data[1]; - - } else if(instruction == 'C') { - - instruction = 'c'; - - data[0] -= point[0]; - data[1] -= point[1]; - data[2] -= point[0]; - data[3] -= point[1]; - data[4] -= point[0]; - data[5] -= point[1]; - - point[0] += data[4]; - point[1] += data[5]; - - } else if(instruction == 'S' || instruction == 'Q') { - - instruction = tolower(instruction); - - data[0] -= point[0]; - data[1] -= point[1]; - data[2] -= point[0]; - data[3] -= point[1]; - - point[0] += data[2]; - point[1] += data[3]; - - } else if(instruction == 'A') { - - instruction = 'a'; - - data[5] -= point[0]; - data[6] -= point[1]; - - point[0] += data[5]; - point[1] += data[6]; - - } else if(instruction == 'H') { - - instruction = 'h'; - - data[0] -= point[0]; - - point[0] += data[0]; - - } else if(instruction == 'V') { - - instruction = 'v'; - - data[0] -= point[1]; - - point[1] += data[0]; - - } - - // reset the instruction - [anInstruction setInstruction:instruction]; - - } else if(instruction == 'Z' || instruction == 'z') { - point[0] = subpathPoint[0]; - point[1] = subpathPoint[1]; - } - - // increment index - index++; - } -} - -+ (NSArray *)instructionsFromPath:(CGPathRef)path -{ - - // keep track of the current point - __block CGPoint currentPoint = CGPointZero; - NSMutableArray * instructions = [[[NSMutableArray alloc] init] autorelease]; - - // create the path callback - IJSVGCGPathHandler callback = ^(const CGPathElement * pathElement) { - IJSVGExporterPathInstruction * instruction = nil; - // work out what to do - switch(pathElement->type) { - - case kCGPathElementMoveToPoint: { - // move to command - instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'M' - dataCount:2] autorelease]; - CGPoint point = pathElement->points[0]; - instruction.data[0] = point.x; - instruction.data[1] = point.y; - currentPoint = point; - - [instructions addObject:instruction]; - break; - } - - case kCGPathElementAddLineToPoint: { - // line to command - CGPoint point = pathElement->points[0]; - if(point.x == currentPoint.x) { - instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'V' - dataCount:1] autorelease]; - instruction.data[0] = point.y; - } else if(point.y == currentPoint.y) { - instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'H' - dataCount:1] autorelease]; - instruction.data[0] = point.x; - } else { - instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'L' - dataCount:2] autorelease]; - instruction.data[0] = point.x; - instruction.data[1] = point.y; - } - currentPoint = point; - - [instructions addObject:instruction]; - break; - } - - case kCGPathElementAddQuadCurveToPoint: { - // quad curve to command - CGPoint controlPoint = pathElement->points[0]; - CGPoint point = pathElement->points[1]; - instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Q' - dataCount:4] autorelease]; - instruction.data[0] = controlPoint.x; - instruction.data[1] = controlPoint.y; - instruction.data[2] = point.x; - instruction.data[3] = point.y; - currentPoint = point; - - [instructions addObject:instruction]; - break; - } - - case kCGPathElementAddCurveToPoint: { - // curve to command - CGPoint controlPoint1 = pathElement->points[0]; - CGPoint controlPoint2 = pathElement->points[1]; - CGPoint point = pathElement->points[2]; - currentPoint = point; - instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'C' - dataCount:6] autorelease]; - instruction.data[0] = controlPoint1.x; - instruction.data[1] = controlPoint1.y; - instruction.data[2] = controlPoint2.x; - instruction.data[3] = controlPoint2.y; - instruction.data[4] = point.x; - instruction.data[5] = point.y; - - [instructions addObject:instruction]; - break; - } - - case kCGPathElementCloseSubpath: { - // close command - instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z' - dataCount:0] autorelease]; - [instructions addObject:instruction]; - break; - } - } - }; - - // apply the - CGPathApply(path, (__bridge void*)callback, IJSVGExporterPathCaller); - - // remove last instruction if it was Z -> M - IJSVGExporterPathInstruction * lastInstruction = instructions.lastObject; - if(lastInstruction.instruction == 'M' || - lastInstruction.instruction == 'm') { - if(instructions.count >= 2) { - NSInteger index = [instructions indexOfObject:lastInstruction]-1; - IJSVGExporterPathInstruction * prevInstruction = instructions[index]; - if(prevInstruction.instruction == 'z' || - prevInstruction.instruction == 'Z') { - [instructions removeLastObject]; - } - } - } - - return instructions; -} - -@end diff --git a/source/IJSVGFontConverter.h b/source/IJSVGFontConverter.h index b0e2142..2c80f8f 100644 --- a/source/IJSVGFontConverter.h +++ b/source/IJSVGFontConverter.h @@ -6,24 +6,24 @@ // Copyright (c) 2015 Curtis Hard. All rights reserved. // -#import #import "IJSVG.h" +#import -typedef void (^IJSVGFontConverterEnumerateBlock)(NSString * unicode, IJSVG * svg); +typedef void (^IJSVGFontConverterEnumerateBlock)(NSString* unicode, IJSVG* svg); @interface IJSVGFontConverter : NSObject { - + @private - NSURL * _url; - NSFont * _font; - NSMutableDictionary * _transformedPaths; + NSURL* _url; + NSFont* _font; + NSMutableDictionary* _transformedPaths; } -- (id)initWithFontAtFileURL:(NSURL *)url; -- (NSFont *)font; +- (id)initWithFontAtFileURL:(NSURL*)url; +- (NSFont*)font; - (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block; -+ (IJSVG *)convertIJSVGPathToSVG:(IJSVGPath *)path; -+ (IJSVG *)convertPathToSVG:(CGPathRef)path; ++ (IJSVG*)convertIJSVGPathToSVG:(IJSVGPath*)path; ++ (IJSVG*)convertPathToSVG:(CGPathRef)path; @end diff --git a/source/IJSVGFontConverter.m b/source/IJSVGFontConverter.m index 3d5aaa4..6a1e2b4 100644 --- a/source/IJSVGFontConverter.m +++ b/source/IJSVGFontConverter.m @@ -6,32 +6,32 @@ // Copyright (c) 2015 Curtis Hard. All rights reserved. // -#import "IJSVGFontConverter.h" #import "IJSVGBezierPathAdditions.h" +#import "IJSVGFontConverter.h" #import "IJSVGShapeLayer.h" @implementation IJSVGFontConverter - (void)dealloc { - [_transformedPaths release], _transformedPaths = nil; - [_url release], _url = nil; - [_font release], _font = nil; + (void)([_transformedPaths release]), _transformedPaths = nil; + (void)([_url release]), _url = nil; + (void)([_font release]), _font = nil; [super dealloc]; } -- (id)initWithFontAtFileURL:(NSURL *)url +- (id)initWithFontAtFileURL:(NSURL*)url { - if( ( self = [super init] ) != nil ) { + if ((self = [super init]) != nil) { _url = [url copy]; - + // load the font CGDataProviderRef dataProvider = CGDataProviderCreateWithURL((CFURLRef)_url); CGFontRef fontRef = CGFontCreateWithDataProvider(dataProvider); - CTFontRef font = CTFontCreateWithGraphicsFont( fontRef, 30.f, NULL, NULL ); - + CTFontRef font = CTFontCreateWithGraphicsFont(fontRef, 30.f, NULL, NULL); + // toll free bridge between NSFont at CTFont :) - _font = [(NSFont *)font copy]; + _font = [(NSFont*)font copy]; CGFontRelease(fontRef); CGDataProviderRelease(dataProvider); CFRelease(font); @@ -39,21 +39,21 @@ - (id)initWithFontAtFileURL:(NSURL *)url return self; } -- (NSFont *)font +- (NSFont*)font { return _font; } -- (NSArray *)allCharacters +- (NSArray*)allCharacters { - NSCharacterSet * charSet = _font.coveredCharacterSet; - NSMutableArray * array = [[[NSMutableArray alloc] init] autorelease]; + NSCharacterSet* charSet = _font.coveredCharacterSet; + NSMutableArray* array = [[[NSMutableArray alloc] init] autorelease]; NSStringEncoding encoding = NSUTF32LittleEndianStringEncoding; - for( int plane = 0; plane <= 16; plane++ ) { - if( [charSet hasMemberInPlane:plane] ) { + for (int plane = 0; plane <= 16; plane++) { + if ([charSet hasMemberInPlane:plane]) { UTF32Char c; - for( c = plane << 16; c < (plane+1) << 16; c++ ) { - if( [charSet longCharacterIsMember:c] ) { + for (c = plane << 16; c < (plane + 1) << 16; c++) { + if ([charSet longCharacterIsMember:c]) { UTF32Char c1 = NSSwapHostIntToLittle(c); [array addObject:[[[NSString alloc] initWithBytes:&c1 length:4 @@ -68,20 +68,20 @@ - (NSArray *)allCharacters - (void)generateMap { CTFontRef font = (CTFontRef)_font; - for( NSString * charString in [self allCharacters] ) { + for (NSString* charString in [self allCharacters]) { // get the characters in each char NSUInteger count = charString.length; unichar characters[count]; [charString getCharacters:characters - range:NSMakeRange( 0, count )]; - + range:NSMakeRange(0, count)]; + // get the glyphs CGGlyph glyphs[count]; - CTFontGetGlyphsForCharacters( font, characters, glyphs, count); - CGPathRef path = CTFontCreatePathForGlyph( font, glyphs[0], NULL ); - if(path != NULL) { + CTFontGetGlyphsForCharacters(font, characters, glyphs, count); + CGPathRef path = CTFontCreatePathForGlyph(font, glyphs[0], NULL); + if (path != NULL) { // add SVG to the dictionary - NSString * key = [NSString stringWithFormat:@"%04x",[charString characterAtIndex:0]]; + NSString* key = [NSString stringWithFormat:@"%04x", [charString characterAtIndex:0]]; CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:path]; _transformedPaths[key] = (id)flippedPath; CGPathRelease(flippedPath); @@ -92,38 +92,38 @@ - (void)generateMap - (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block { - if(_transformedPaths == nil) { + if (_transformedPaths == nil) { _transformedPaths = [[NSMutableDictionary alloc] init]; [self generateMap]; } - - for(NSString * key in _transformedPaths.allKeys) { + + for (NSString* key in _transformedPaths.allKeys) { block(key, [self.class convertPathToSVG:(CGPathRef)_transformedPaths[key]]); } } -+ (IJSVG *)convertIJSVGPathToSVG:(IJSVGPath *)path ++ (IJSVG*)convertIJSVGPathToSVG:(IJSVGPath*)path { CGPathRef cgPath = [IJSVGUtils newCGPathFromBezierPath:path.path]; CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:cgPath]; - IJSVG * svg = [self convertPathToSVG:flippedPath]; + IJSVG* svg = [self convertPathToSVG:flippedPath]; CGPathRelease(flippedPath); CGPathRelease(cgPath); return svg; } -+ (IJSVG *)convertPathToSVG:(CGPathRef)path ++ (IJSVG*)convertPathToSVG:(CGPathRef)path { - __block IJSVG * svg = nil; - IJSVGObtainTransactionLock(^{ - IJSVGGroupLayer * layer = [[[IJSVGGroupLayer alloc] init] autorelease]; - IJSVGShapeLayer * shape = [[[IJSVGShapeLayer alloc] init] autorelease]; - [layer addSublayer:shape]; - shape.path = path; - CGRect box = CGPathGetPathBoundingBox(path); - svg = [[IJSVG alloc] initWithSVGLayer:layer - viewBox:box]; - }, NO); + __block IJSVG* svg = nil; + IJSVGBeginTransactionLock(); + IJSVGGroupLayer* layer = [[[IJSVGGroupLayer alloc] init] autorelease]; + IJSVGShapeLayer* shape = [[[IJSVGShapeLayer alloc] init] autorelease]; + [layer addSublayer:shape]; + shape.path = path; + CGRect box = CGPathGetPathBoundingBox(path); + svg = [[IJSVG alloc] initWithSVGLayer:layer + viewBox:box]; + IJSVGEndTransactionLock(); return [svg autorelease]; } diff --git a/source/IJSVGImageRep.h b/source/IJSVGImageRep.h index 10772f7..047f0e2 100644 --- a/source/IJSVGImageRep.h +++ b/source/IJSVGImageRep.h @@ -6,15 +6,15 @@ // Copyright © 2019 Curtis Hard. All rights reserved. // -#import #import "IJSVGParser.h" +#import @class IJSVG; @interface IJSVGImageRep : NSImageRep { - + @private - IJSVG * _svg; + IJSVG* _svg; } @property (nonatomic, readonly) CGRect viewBox; diff --git a/source/IJSVGImageRep.m b/source/IJSVGImageRep.m index 25fb407..ee987c6 100644 --- a/source/IJSVGImageRep.m +++ b/source/IJSVGImageRep.m @@ -6,8 +6,8 @@ // Copyright © 2019 Curtis Hard. All rights reserved. // -#import "IJSVGImageRep.h" #import "IJSVG.h" +#import "IJSVGImageRep.h" @implementation IJSVGImageRep @@ -18,57 +18,57 @@ + (void)load [NSBitmapImageRep registerImageRepClass:self]; } -+ (BOOL)canInitWithData:(NSData *)data ++ (BOOL)canInitWithData:(NSData*)data { return [IJSVGParser isDataSVG:data]; } -+ (NSArray *)imageTypes ++ (NSArray*)imageTypes { - return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"]; + return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ]; } -+ (NSArray *)imageUnfilteredTypes ++ (NSArray*)imageUnfilteredTypes { - return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"]; + return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ]; } -+ (NSArray *)imageRepsWithData:(NSData *)data ++ (NSArray*)imageRepsWithData:(NSData*)data { - IJSVGImageRep * instance = [self imageRepWithData:data]; - if(instance == nil) { + IJSVGImageRep* instance = [self imageRepWithData:data]; + if (instance == nil) { return @[]; } - return @[instance]; + return @[ instance ]; } -+ (instancetype)imageRepWithData:(NSData *)data ++ (instancetype)imageRepWithData:(NSData*)data { return [[[self alloc] initWithData:data] autorelease]; } - (void)dealloc { - [_svg release], _svg = nil; + (void)([_svg release]), _svg = nil; [super dealloc]; } -- (instancetype)initWithData:(NSData *)data +- (instancetype)initWithData:(NSData*)data { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { // grab the string from the data // its more then likely UTF-8... - NSString * string = [[[NSString alloc] initWithData:data - encoding:NSUTF8StringEncoding] autorelease]; - + NSString* string = [[[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding] autorelease]; + _svg = [[IJSVG alloc] initWithSVGString:string]; - + // no valid SVG, just return nil; - if(_svg == nil) { + if (_svg == nil) { [self release]; return nil; } - + // set default properties self.pixelsWide = _svg.viewBox.size.width; self.pixelsHigh = _svg.viewBox.size.height; diff --git a/source/IJSVGLayer.m b/source/IJSVGLayer.m deleted file mode 100644 index d6930b1..0000000 --- a/source/IJSVGLayer.m +++ /dev/null @@ -1,184 +0,0 @@ -// -// IJSVGLayer.m -// IJSVGExample -// -// Created by Curtis Hard on 07/01/2017. -// Copyright © 2017 Curtis Hard. All rights reserved. -// - -#import "IJSVGLayer.h" -#import "IJSVGShapeLayer.h" -#import "IJSVGGroupLayer.h" -#import "IJSVG.h" - - -@implementation IJSVGLayer - -@synthesize gradientFillLayer; -@synthesize patternFillLayer; -@synthesize gradientStrokeLayer; -@synthesize patternStrokeLayer; -@synthesize strokeLayer; -@synthesize requiresBackingScaleHelp; -@synthesize backingScaleFactor; -@synthesize blendingMode; -@synthesize convertMasksToPaths; - -- (void)dealloc -{ - [_maskingLayer release], _maskingLayer = nil; - [super dealloc]; -} - -+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer -{ - NSMutableArray * arr = [[[NSMutableArray alloc] init] autorelease]; - for(CALayer * subLayer in layer.sublayers) { - if(subLayer.sublayers.count != 0) { - NSArray * moreLayers = [self deepestSublayersOfLayer:(IJSVGLayer *)subLayer]; - [arr addObjectsFromArray:moreLayers]; - } else { - [arr addObject:subLayer]; - } - } - return arr; -} - -+ (void)recursivelyWalkLayer:(CALayer *)layer - withBlock:(void (^)(CALayer * layer, BOOL isMask))block -{ - // call for layer and mask if there is one - block(layer, NO); - - // do the mask too! - if(layer.mask != nil) { - block(layer.mask, YES); - } - - // sublayers!! - for(CALayer * aLayer in layer.sublayers) { - [self recursivelyWalkLayer:aLayer - withBlock:block]; - } -} - -- (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]; -} - -- (id)actionForKey:(NSString *)event -{ - return nil; -} - -@end diff --git a/source/IJSVGNode.h b/source/IJSVGNode.h deleted file mode 100644 index e422825..0000000 --- a/source/IJSVGNode.h +++ /dev/null @@ -1,146 +0,0 @@ -// -// IJSVGNode.h -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import -#import "IJSVGStyle.h" -#import "IJSVGUnitLength.h" - -@class IJSVG; -@class IJSVGGroup; -@class IJSVGDef; -@class IJSVGGradient; -@class IJSVGGroup; -@class IJSVGPattern; -@class IJSVGTransform; - -typedef NS_ENUM( NSInteger, IJSVGNodeType ) { - IJSVGNodeTypeGroup, - IJSVGNodeTypePath, - IJSVGNodeTypeDef, - IJSVGNodeTypePolygon, - IJSVGNodeTypePolyline, - IJSVGNodeTypeRect, - IJSVGNodeTypeLine, - IJSVGNodeTypeCircle, - IJSVGNodeTypeEllipse, - IJSVGNodeTypeUse, - IJSVGNodeTypeLinearGradient, - IJSVGNodeTypeRadialGradient, - IJSVGNodeTypeClipPath, - IJSVGNodeTypeFont, - IJSVGNodeTypeGlyph, - IJSVGNodeTypeMask, - IJSVGNodeTypeImage, - IJSVGNodeTypePattern, - IJSVGNodeTypeSVG, - IJSVGNodeTypeText, - IJSVGNodeTypeTextSpan, - IJSVGNodeTypeStyle, - IJSVGNodeTypeSwitch, - IJSVGNodeTypeNotFound, -}; - -typedef NS_ENUM( NSInteger, IJSVGWindingRule ) { - IJSVGWindingRuleNonZero, - IJSVGWindingRuleEvenOdd, - IJSVGWindingRuleInherit -}; - -typedef NS_ENUM( NSInteger, IJSVGLineCapStyle ) { - IJSVGLineCapStyleNone, - IJSVGLineCapStyleButt, - IJSVGLineCapStyleRound, - IJSVGLineCapStyleSquare, - IJSVGLineCapStyleInherit -}; - -typedef NS_ENUM( NSInteger, IJSVGLineJoinStyle ) { - IJSVGLineJoinStyleNone, - IJSVGLineJoinStyleMiter, - IJSVGLineJoinStyleRound, - IJSVGLineJoinStyleBevel, - IJSVGLineJoinStyleInherit -}; - -typedef NS_OPTIONS( NSInteger, IJSVGFontTraits ) { - IJSVGFontTraitNone = 1 << 0, - IJSVGFontTraitBold = 1 << 1, - IJSVGFontTraitItalic = 1 << 2 -}; - -typedef NS_ENUM( NSInteger, IJSVGBlendMode) { - IJSVGBlendModeNormal = kCGBlendModeNormal, - IJSVGBlendModeMultiply = kCGBlendModeMultiply, - IJSVGBlendModeScreen = kCGBlendModeScreen, - IJSVGBlendModeOverlay = kCGBlendModeOverlay, - IJSVGBlendModeDarken = kCGBlendModeDarken, - IJSVGBlendModeLighten = kCGBlendModeLighten, - IJSVGBlendModeColorDodge = kCGBlendModeColorDodge, - IJSVGBlendModeColorBurn = kCGBlendModeColorBurn, - IJSVGBlendModeHardLight = kCGBlendModeHardLight, - IJSVGBlendModeSoftLight = kCGBlendModeSoftLight, - IJSVGBlendModeDifference = kCGBlendModeDifference, - IJSVGBlendModeExclusion = kCGBlendModeExclusion, - IJSVGBlendModeHue = kCGBlendModeHue, - IJSVGBlendModeSaturation = kCGBlendModeSaturation, - IJSVGBlendModeColor = kCGBlendModeColor, - IJSVGBlendModeLuminosity = kCGBlendModeLuminosity -}; - -static CGFloat IJSVGInheritedFloatValue = -99.9999991; - -@interface IJSVGNode : NSObject - -@property ( nonatomic, assign ) IJSVGNodeType type; -@property ( nonatomic, copy ) NSString * name; -@property ( nonatomic, copy ) NSString * className; -@property ( nonatomic, retain ) NSArray * classNameList; -@property ( nonatomic, copy ) NSString * unicode; -@property ( nonatomic, assign ) BOOL shouldRender; -@property ( nonatomic, assign ) BOOL usesDefaultFillColor; -@property ( nonatomic, retain ) IJSVGUnitLength * x; -@property ( nonatomic, retain ) IJSVGUnitLength * y; -@property ( nonatomic, retain ) IJSVGUnitLength * width; -@property ( nonatomic, retain ) IJSVGUnitLength * height; -@property ( nonatomic, retain ) IJSVGUnitLength * opacity; -@property ( nonatomic, retain ) IJSVGUnitLength * fillOpacity; -@property ( nonatomic, retain ) IJSVGUnitLength * strokeOpacity; -@property ( nonatomic, retain ) IJSVGUnitLength * strokeWidth; -@property ( nonatomic, retain ) NSColor * fillColor; -@property ( nonatomic, retain ) NSColor * strokeColor; -@property ( nonatomic, copy ) NSString * identifier; -@property ( nonatomic, assign ) IJSVGNode * parentNode; -@property ( nonatomic, assign ) IJSVGNode * intermediateParentNode; -@property ( nonatomic, retain ) IJSVGGroup * clipPath; -@property ( nonatomic, retain ) IJSVGGroup * mask; -@property ( nonatomic, assign ) IJSVGWindingRule windingRule; -@property ( nonatomic, assign ) IJSVGLineCapStyle lineCapStyle; -@property ( nonatomic, assign ) IJSVGLineJoinStyle lineJoinStyle; -@property ( nonatomic, retain ) NSArray * transforms; -@property ( nonatomic, retain ) IJSVGDef * def; -@property ( nonatomic, retain ) IJSVGGradient * fillGradient; -@property ( nonatomic, retain ) IJSVGPattern * fillPattern; -@property ( nonatomic, retain ) IJSVGGradient * strokeGradient; -@property ( nonatomic, retain ) IJSVGPattern * strokePattern; -@property ( nonatomic, assign ) CGFloat * strokeDashArray; -@property ( nonatomic, assign ) NSInteger strokeDashArrayCount; -@property ( nonatomic, retain ) IJSVGUnitLength * strokeDashOffset; -@property ( nonatomic, retain ) IJSVG * svg; -@property ( nonatomic, assign ) IJSVGUnitType contentUnits; -@property ( nonatomic, assign ) IJSVGUnitType units; -@property ( nonatomic, assign ) IJSVGBlendMode blendMode; - -+ (IJSVGNodeType)typeForString:(NSString *)string - kind:(NSXMLNodeKind)kind; - -- (void)applyPropertiesFromNode:(IJSVGNode *)node; -- (id)initWithDef:(BOOL)flag; -- (void)addDef:(IJSVGNode *)aDef; -- (IJSVGDef *)defForID:(NSString *)anID; - -@end diff --git a/source/IJSVGParser.h b/source/IJSVGParser.h deleted file mode 100644 index c185ed2..0000000 --- a/source/IJSVGParser.h +++ /dev/null @@ -1,130 +0,0 @@ -// -// IJSVGParser.h -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import -#import "IJSVGForeignObject.h" -#import "IJSVGGroup.h" -#import "IJSVGPath.h" -#import "IJSVGUtils.h" -#import "IJSVGCommand.h" -#import "IJSVGColor.h" -#import "IJSVGTransform.h" -#import "IJSVGDef.h" -#import "IJSVGLinearGradient.h" -#import "IJSVGRadialGradient.h" -#import "IJSVGError.h" -#import "IJSVGStyleSheet.h" -#import "IJSVGPattern.h" -#import "IJSVGImage.h" -#import "IJSVGText.h" - -static NSString const * IJSVGAttributeViewBox = @"viewBox"; -static NSString const * IJSVGAttributeID = @"id"; -static NSString const * IJSVGAttributeClass = @"class"; -static NSString const * IJSVGAttributeX = @"x"; -static NSString const * IJSVGAttributeY = @"y"; -static NSString const * IJSVGAttributeWidth = @"width"; -static NSString const * IJSVGAttributeHeight = @"height"; -static NSString const * IJSVGAttributeOpacity = @"opacity"; -static NSString const * IJSVGAttributeStrokeOpacity = @"stroke-opacity"; -static NSString const * IJSVGAttributeStrokeWidth = @"stroke-width"; -static NSString const * IJSVGAttributeStrokeDashOffset = @"stroke-dashoffset"; -static NSString const * IJSVGAttributeFillOpacity = @"fill-opacity"; -static NSString const * IJSVGAttributeClipPath = @"clip-path"; -static NSString const * IJSVGAttributeMask = @"mask"; -static NSString const * IJSVGAttributeGradientUnits = @"gradientUnits"; -static NSString const * IJSVGAttributeMaskUnits = @"maskUnits"; -static NSString const * IJSVGAttributeMaskContentUnits = @"maskContentUnits"; -static NSString const * IJSVGAttributeTransform = @"transform"; -static NSString const * IJSVGAttributeGradientTransform = @"gradientTransform"; -static NSString const * IJSVGAttributeUnicode = @"unicode"; -static NSString const * IJSVGAttributeStrokeLineCap = @"stroke-linecap"; -static NSString const * IJSVGAttributeLineJoin = @"stroke-linejoin"; -static NSString const * IJSVGAttributeStroke = @"stroke"; -static NSString const * IJSVGAttributeStrokeDashArray = @"stroke-dasharray"; -static NSString const * IJSVGAttributeFill = @"fill"; -static NSString const * IJSVGAttributeFillRule = @"fill-rule"; -static NSString const * IJSVGAttributeBlendMode = @"mix-blend-mode"; -static NSString const * IJSVGAttributeDisplay = @"display"; -static NSString const * IJSVGAttributeStyle = @"style"; -static NSString const * IJSVGAttributeD = @"d"; -static NSString const * IJSVGAttributeXLink = @"xlink:href"; -static NSString const * IJSVGAttributeX1 = @"x1"; -static NSString const * IJSVGAttributeX2 = @"x2"; -static NSString const * IJSVGAttributeY1 = @"y1"; -static NSString const * IJSVGAttributeY2 = @"y2"; -static NSString const * IJSVGAttributeRX = @"rx"; -static NSString const * IJSVGAttributeRY = @"ry"; -static NSString const * IJSVGAttributeCX = @"cx"; -static NSString const * IJSVGAttributeCY = @"cy"; -static NSString const * IJSVGAttributeR = @"r"; -static NSString const * IJSVGAttributePoints = @"points"; - -@class IJSVGParser; - -@protocol IJSVGParserDelegate - -@optional -- (BOOL)svgParser:(IJSVGParser *)svg -shouldHandleForeignObject:(IJSVGForeignObject *)foreignObject; -- (void)svgParser:(IJSVGParser *)svg -handleForeignObject:(IJSVGForeignObject *)foreignObject - document:(NSXMLDocument *)document; -- (void)svgParser:(IJSVGParser *)svg - foundSubSVG:(IJSVG *)subSVG - withSVGString:(NSString *)string; - -@end - -@interface IJSVGParser : IJSVGGroup { - - NSRect viewBox; - NSSize proposedViewSize; - -@private - id _delegate; - NSXMLDocument * _document; - NSMutableArray * _glyphs; - IJSVGStyleSheet * _styleSheet; - NSMutableArray * _parsedNodes; - NSMutableDictionary * _defNodes; - NSMutableDictionary * _baseDefNodes; - NSMutableArray * _svgs; - NSMutableArray * _definedGroups; - - struct { - unsigned int shouldHandleForeignObject: 1; - unsigned int handleForeignObject: 1; - unsigned int handleSubSVG: 1; - } _respondsTo; -} - -@property ( nonatomic, readonly ) NSRect viewBox; -@property ( nonatomic, readonly ) NSSize proposedViewSize; - -+ (BOOL)isDataSVG:(NSData *)data; - -- (id)initWithSVGString:(NSString *)string - error:(NSError **)error - delegate:(id)delegate; - -- (id)initWithFileURL:(NSURL *)aURL - error:(NSError **)error - delegate:(id)delegate; -+ (IJSVGParser *)groupForFileURL:(NSURL *)aURL; -+ (IJSVGParser *)groupForFileURL:(NSURL *)aURL - delegate:(id)delegate; -+ (IJSVGParser *)groupForFileURL:(NSURL *)aURL - error:(NSError **)error - delegate:(id)delegate; -- (NSSize)size; -- (BOOL)isFont; -- (NSArray *)glyphs; -- (NSArray *)subSVGs:(BOOL)recursive; - -@end diff --git a/source/IJSVGParser.m b/source/IJSVGParser.m deleted file mode 100644 index d796c77..0000000 --- a/source/IJSVGParser.m +++ /dev/null @@ -1,1310 +0,0 @@ -// -// IJSVGParser.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGParser.h" -#import "IJSVG.h" - -@implementation IJSVGParser - -@synthesize viewBox; -@synthesize proposedViewSize; - -+ (IJSVGParser *)groupForFileURL:(NSURL *)aURL -{ - return [self.class groupForFileURL:aURL - error:nil - delegate:nil]; -} - -+ (IJSVGParser *)groupForFileURL:(NSURL *)aURL - delegate:(id)delegate -{ - return [self.class groupForFileURL:aURL - error:nil - delegate:delegate]; -} - -+ (IJSVGParser *)groupForFileURL:(NSURL *)aURL - error:(NSError **)error - delegate:(id)delegate -{ - return [[[self.class alloc] initWithFileURL:aURL - error:error - delegate:delegate] autorelease]; -} - -- (void)dealloc -{ - [_glyphs release], _glyphs = nil; - [_styleSheet release], _styleSheet = nil; - [_parsedNodes release], _parsedNodes = nil; - [_defNodes release], _defNodes = nil; - [_baseDefNodes release], _baseDefNodes = nil; - [_definedGroups release], _definedGroups = nil; - [_svgs release], _svgs = nil; - [super dealloc]; -} - -- (id)initWithSVGString:(NSString *)string - error:(NSError **)error - delegate:(id)delegate -{ - if( ( self = [super init] ) != nil ) - { - _delegate = delegate; - - _respondsTo.handleForeignObject = [_delegate respondsToSelector:@selector(svgParser:handleForeignObject:document:)]; - _respondsTo.shouldHandleForeignObject = [_delegate respondsToSelector:@selector(svgParser:shouldHandleForeignObject:)]; - _respondsTo.handleSubSVG = [_delegate respondsToSelector:@selector(svgParser:foundSubSVG:withSVGString:)]; - - _glyphs = [[NSMutableArray alloc] init]; - _parsedNodes = [[NSMutableArray alloc] init]; - _defNodes = [[NSMutableDictionary alloc] init]; - _baseDefNodes = [[NSMutableDictionary alloc] init]; - _svgs = [[NSMutableArray alloc] init]; - - // load the document / file, assume its UTF8 - - - // use NSXMLDocument as its the easiest thing to do on OSX - NSError * anError = nil; - @try { - _document = [[NSXMLDocument alloc] initWithXMLString:string - options:0 - error:&anError]; - } - @catch (NSException *exception) { - } - - // error parsing the XML document - if( anError != nil ) { - return [self _handleErrorWithCode:IJSVGErrorParsingFile - error:error]; - } - - // attempt to parse the file - anError = nil; - @try { - [self _parse]; - } - @catch (NSException *exception) { - return [self _handleErrorWithCode:IJSVGErrorParsingSVG - error:error]; - } - - - // check the actual parsed SVG - anError = nil; - if( ![self _validateParse:&anError] ) { - *error = anError; - [_document release], _document = nil; - [self release], self = nil; - return nil; - } - - // we have actually finished with the document at this point - // so just get rid of it - [_document release], _document = nil; - - } - return self; - -} - -+ (BOOL)isDataSVG:(NSData *)data -{ - @try { - NSError * error; - NSXMLDocument * doc = [[[NSXMLDocument alloc] initWithData:data - options:0 - error:&error] autorelease]; - return doc != nil && error == nil; - } @catch(NSException * exception) {} - return NO; -} - -- (id)initWithFileURL:(NSURL *)aURL - error:(NSError **)error - delegate:(id)delegate -{ - NSError * anError = nil; - NSStringEncoding encoding; - NSString * str = [NSString stringWithContentsOfFile:aURL.path - usedEncoding:&encoding - error:&anError]; - - // error reading file - if(str == nil) { - return [self _handleErrorWithCode:IJSVGErrorReadingFile - error:error]; - } - - return [self initWithSVGString:str - error:error - delegate:delegate]; -} - -- (void *)_handleErrorWithCode:(NSUInteger)code - error:(NSError **)error -{ - if( error ) { - *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain - code:code - userInfo:nil] autorelease]; - } - [_document release], _document = nil; - [self release], self = nil; - return nil; -} - -- (BOOL)_validateParse:(NSError **)error -{ - // check is font - if( self.isFont ) - return YES; - - // check the viewbox - if( NSEqualRects( self.viewBox, NSZeroRect ) || - self.size.width == 0 || self.size.height == 0 ) { - if( error != NULL ) { - *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain - code:IJSVGErrorInvalidViewBox - userInfo:nil] autorelease]; - } - return NO; - } - return YES; -} - -- (NSSize)size -{ - return viewBox.size; -} - -- (void)_parse -{ - NSXMLElement * svgElement = [_document rootElement]; - - // parse common attributes on the SVG element - [self _parseElementForCommonAttributes:svgElement - node:self - ignoreAttributes:nil]; - - // find the sizebox! - NSXMLNode * attribute = nil; - if( ( attribute = [svgElement attributeForName:(NSString *)IJSVGAttributeViewBox] ) != nil ) { - // we have a viewbox... - CGFloat * box = [IJSVGUtils parseViewBox:[attribute stringValue]]; - viewBox = NSMakeRect( box[0], box[1], box[2], box[3]); - free(box); - } else { - // there is no view box so find the width and height - CGFloat w = [[[svgElement attributeForName:(NSString *)IJSVGAttributeWidth] stringValue] floatValue]; - CGFloat h = [[[svgElement attributeForName:(NSString *)IJSVGAttributeHeight] stringValue] floatValue]; - if( h == 0.f && w != 0.f ) { - h = w; - } else if( w == 0.f && h != 0.f ) { - w = h; - } - viewBox = NSMakeRect( 0.f, 0.f, w, h ); - } - - // parse the width and height.... - CGFloat w = [[[svgElement attributeForName:(NSString *)IJSVGAttributeWidth] stringValue] floatValue]; - CGFloat h = [[[svgElement attributeForName:(NSString *)IJSVGAttributeHeight] stringValue] floatValue]; - if( w == 0.f && h == 0.f ) { - w = viewBox.size.width; - h = viewBox.size.height; - } else if( w == 0 && h != 0.f ) { - w = viewBox.size.width; - } else if( h == 0 && w != 0.f ) { - h = viewBox.size.height; - } - proposedViewSize = NSMakeSize(w, h); - - // the root element is SVG, so iterate over its children - // recursively - self.name = svgElement.name; - [self _parseBlock:svgElement - intoGroup:self - def:NO]; - - // now everything has been done we need to compute the style tree - for(NSDictionary * dict in _parsedNodes) { - [self _postParseElementForCommonAttributes:dict[@"element"] - node:dict[@"node"] - ignoreAttributes:nil]; - } - - // dont need the style sheet or the parsed nodes as this point - [_styleSheet release], _styleSheet = nil; - [_parsedNodes release], _parsedNodes = nil; - [_defNodes release], _defNodes = nil; -} - -- (void)_postParseElementForCommonAttributes:(NSXMLElement *)element - node:(IJSVGNode *)node - ignoreAttributes:(NSArray *)ignoredAttributes -{ - - // first of all, compute a style sheet - IJSVGStyle * sheetStyle = nil; - __block IJSVGStyle * style = nil; - - // attribute helpers - typedef void (^cp)(NSString *); - void (^attr)(const NSString *, cp) = ^(NSString * key, cp block) { - if([ignoredAttributes containsObject:key]) { - return; - } - NSString * v = [style property:key] ?: - [element attributeForName:key].stringValue; - if(v != nil && v.length != 0) { - block(v); - } - }; - - typedef id (^cap)(NSString *); - void (^atts)(NSDictionary *, cap) = - ^(NSDictionary* kv, cap block) { - for(NSString * key in kv.allKeys) { - attr(key, ^(NSString * value) { - [node setValue:block(value) - forKey:kv[key]]; - }); - } - }; - - // id, this must be here for the style sheet to actually - // render and parse, basically it relies on ID/CSS selectors so these - // must be in place before its computed - attr(IJSVGAttributeID, ^(NSString * value) { - node.identifier = value; - _defNodes[node.identifier] = element; - }); - - // - attr(IJSVGAttributeClass, ^(NSString * value) { - node.className = value; - node.classNameList = [value componentsSeparatedByString:@" "]; - }); - - // work out the style sheet - if(_styleSheet != nil) { - sheetStyle = [_styleSheet styleForNode:node]; - } - - // is there a - attr(IJSVGAttributeStyle, ^(NSString * value) { - style = [IJSVGStyle parseStyleString:value]; - }); - - // merge to two together - if(sheetStyle != nil) { - style = [sheetStyle mergedStyle:style]; - } - - // floats - atts(@{IJSVGAttributeX:@"x", - IJSVGAttributeY:@"y", - IJSVGAttributeWidth:@"width", - IJSVGAttributeHeight:@"height", - IJSVGAttributeOpacity:@"opacity", - IJSVGAttributeStrokeOpacity:@"strokeOpacity", - IJSVGAttributeStrokeWidth:@"strokeWidth", - IJSVGAttributeStrokeDashOffset:@"strokeDashOffset", - IJSVGAttributeFillOpacity:@"fillOpacity"}, ^id (NSString * value) { - return [IJSVGUnitLength unitWithString:value]; - }); - - // nodes - atts(@{IJSVGAttributeClipPath:@"clipPath", - IJSVGAttributeMask:@"mask"}, ^id (NSString * value) { - NSString * url = [IJSVGUtils defURL:value]; - if(url != nil) { - return [self definedObjectForID:url]; - } - return nil; - }); - - // units - atts(@{IJSVGAttributeGradientUnits:@"units", - IJSVGAttributeMaskUnits:@"units", - IJSVGAttributeMaskContentUnits:@"contentUnits"}, ^id (NSString * value) { - return @([IJSVGUtils unitTypeForString:value]); - }); - - // transforms - atts(@{IJSVGAttributeTransform:@"transforms", - IJSVGAttributeGradientTransform:@"transforms"}, ^(NSString * value) { - NSMutableArray * tempTransforms = [[[NSMutableArray alloc] init] autorelease]; - [tempTransforms addObjectsFromArray:[IJSVGTransform transformsForString:value]]; - if(node.transforms != nil) { - [tempTransforms addObjectsFromArray:node.transforms]; - } - return tempTransforms; - }); - -#pragma mark attributes that require custom rules - - // unicode - attr(IJSVGAttributeUnicode, ^(NSString * value) { - node.unicode = [NSString stringWithFormat:@"%04x",[value characterAtIndex:0]]; - }); - - // linecap - attr(IJSVGAttributeStrokeLineCap, ^(NSString * value) { - node.lineCapStyle = [IJSVGUtils lineCapStyleForString:value]; - }); - - // line join - attr(IJSVGAttributeLineJoin, ^(NSString * value) { - node.lineJoinStyle = [IJSVGUtils lineJoinStyleForString:value]; - }); - - // stroke color - attr(IJSVGAttributeStroke, ^(NSString * value) { - NSString * fillDefID = [IJSVGUtils defURL:value]; - if(fillDefID != nil) { - // find the object - id obj = [self definedObjectForID:fillDefID]; - - // what type is it? - if([obj isKindOfClass:[IJSVGGradient class]]) { - node.strokeGradient = (IJSVGGradient *)obj; - } else if([obj isKindOfClass:[IJSVGPattern class]]) { - node.strokePattern = (IJSVGPattern *)obj; - } - } else { - // its a color - node.strokeColor = [IJSVGColor colorFromString:value]; - } - - }); - - // stroke dash array - attr(IJSVGAttributeStrokeDashArray, ^(NSString * value) { - // nothing specified - if([value isEqualToString:@"none"]) { - node.strokeDashArrayCount = 0; - return; - } - NSInteger paramCount = 0; - CGFloat * params = [IJSVGUtils commandParameters:value - count:¶mCount]; - node.strokeDashArray = params; - node.strokeDashArrayCount = paramCount; - }); - - // fill - seems kinda complicated for what it actually is - attr(IJSVGAttributeFill, ^(NSString * value) { - NSString * fillDefID = [IJSVGUtils defURL:value]; - if(fillDefID != nil) { - // find the object - id obj = [self definedObjectForID:fillDefID]; - - // what type is it? - if([obj isKindOfClass:[IJSVGGradient class]]) { - node.fillGradient = (IJSVGGradient *)obj; - } else if([obj isKindOfClass:[IJSVGPattern class]]) { - node.fillPattern = (IJSVGPattern *)obj; - } - } else { - node.fillColor = [IJSVGColor colorFromString:value]; - } - }); - - // fill opacity - attr(IJSVGAttributeFillOpacity, ^(NSString * value) { - if(node.fillOpacity.value != 1.f) { - node.fillColor = [IJSVGColor changeAlphaOnColor:node.fillColor - to:node.fillOpacity.value]; - } - }); - - // blendmode - attr(IJSVGAttributeBlendMode, ^(NSString * value) { - node.blendMode = [IJSVGUtils blendModeForString:value]; - }); - - // fill rule - attr(IJSVGAttributeFillRule, ^(NSString * value) { - node.windingRule = [IJSVGUtils windingRuleForString:value]; - }); - - // display - attr(IJSVGAttributeDisplay, ^(NSString * value) { - if([value.lowercaseString isEqualToString:@"none"]) { - node.shouldRender = NO; - } - }); -} - -- (id)definedObjectForID:(NSString *)anID - xmlElement:(NSXMLElement **)element -{ - // check base def nodes first, then check rest of document - NSXMLElement * parseElement = _baseDefNodes[anID] ?: _defNodes[anID]; - if(parseElement != nil) { - // parse the block - if(element != nil && element != NULL) { - *element = parseElement; - } - IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease]; - [self _parseBaseBlock:parseElement - intoGroup:group - def:NO]; - if(_definedGroups == nil) { - _definedGroups = [[NSMutableArray alloc] init]; - } - [_definedGroups addObject:group]; - return [group defForID:anID]; - } - return nil; -} - -- (id)definedObjectForID:(NSString *)anID -{ - return [self definedObjectForID:anID - xmlElement:nil]; -} - -- (BOOL)isFont -{ - return [_glyphs count] != 0; -} - -- (NSArray *)glyphs -{ - return _glyphs; -} - -- (void)addSubSVG:(IJSVG *)anSVG -{ - [_svgs addObject:anSVG]; -} - -- (NSArray *)subSVGs:(BOOL)recursive -{ - if(recursive == NO) { - return _svgs; - } - NSMutableArray * svgs = [[[NSMutableArray alloc] init] autorelease]; - for(IJSVG * anSVG in svgs) { - [svgs addObject:anSVG]; - [svgs addObjectsFromArray:[anSVG subSVGs:recursive]]; - } - return svgs; -} - -- (void)addGlyph:(IJSVGNode *)glyph -{ - [_glyphs addObject:glyph]; -} - -- (void)_parseElementForCommonAttributes:(NSXMLElement *)element - node:(IJSVGNode *)node - ignoreAttributes:(NSArray *)ignoredAttributes -{ - [self _postParseElementForCommonAttributes:element - node:node - ignoreAttributes:ignoredAttributes]; -} - -- (void)_setupDefaultsForNode:(IJSVGNode *)node -{ - switch(node.type) { - // mask - case IJSVGNodeTypeMask :{ - node.units = IJSVGUnitObjectBoundingBox; - break; - } - - // gradient - case IJSVGNodeTypeRadialGradient: - case IJSVGNodeTypeLinearGradient: { - node.units = IJSVGUnitObjectBoundingBox; - break; - } - - default: { - } - } -} - -- (void)parseDefsForElement:(NSXMLElement *)anElement -{ - // nothing found - if(anElement.childCount == 0) { - return; - } - - for(NSXMLElement * element in anElement.children) { - // not a def - if([IJSVGNode typeForString:element.localName - kind:element.kind] != IJSVGNodeTypeDef) { - continue; - } - - // store each object - for(NSXMLElement * childDef in element.children) { - // is there any stylesheets within this? - IJSVGNodeType childType = [IJSVGNode typeForString:childDef.localName - kind:element.kind]; - - switch(childType) { - case IJSVGNodeTypeStyle: - case IJSVGNodeTypeGlyph: - case IJSVGNodeTypeFont: { - [self _parseBaseBlock:childDef - intoGroup:self - def:NO]; - break; - } - case IJSVGNodeTypeNotFound: { - // ignore, this is insanely important - specially if its a comment - break; - } - default: { - // just a default def, continue on, as we are a def element, - // store these seperately to the default ID string ones - NSString * defID = [childDef attributeForName:@"id"].stringValue; - if(defID != nil) { - _baseDefNodes[defID] = childDef; - } - } - } - } - } -} - -- (void)_parseBaseBlock:(NSXMLElement *)element - intoGroup:(IJSVGGroup *)parentGroup - def:(BOOL)flag -{ - NSString * subName = element.localName; - NSXMLNodeKind nodeKind = element.kind; - IJSVGNodeType aType = [IJSVGNode typeForString:subName - kind:nodeKind]; - switch( aType ) { - - // do nothing - default: - case IJSVGNodeTypeNotFound: { - break; - } - - // style - case IJSVGNodeTypeStyle: { - // create the sheet - if(_styleSheet == nil) { - _styleSheet = [[IJSVGStyleSheet alloc] init]; - } - - // append the string - [_styleSheet parseStyleBlock:element.stringValue]; - break; - } - - // sub SVG - case IJSVGNodeTypeSVG: { - - IJSVGGroup * path = [[[IJSVGGroup alloc] init] autorelease]; - path.type = aType; - path.name = subName; - - // grab common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - - // if its a sub svg, we can remove the attributes for x and y - // this is required or it could go out of bounds before the exporter - // hits the layers from the groups :) - [element removeAttributeForName:@"x"]; - [element removeAttributeForName:@"y"]; - - // work out the SVG - NSError * error = nil; - NSString * SVGString = element.XMLString; - IJSVG * anSVG = [[[IJSVG alloc] initWithSVGString:SVGString - error:&error - delegate:nil] autorelease]; - - // handle sub SVG - if(error == nil && _respondsTo.handleSubSVG == 1) { - [_delegate svgParser:self - foundSubSVG:anSVG - withSVGString:SVGString]; - } - - // any error? - if(anSVG != nil && error == nil) { - path.svg = anSVG; - [parentGroup addChild:path]; - [parentGroup addDef:path]; - - // make sure we add this - [self addSubSVG:anSVG]; - } - break; - } - - // glyph - case IJSVGNodeTypeGlyph: { - - // no path data - if( [element attributeForName:(NSString *)IJSVGAttributeD] == nil || - [[element attributeForName:(NSString *)IJSVGAttributeD] stringValue].length == 0 ) { - break; - } - - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - // find common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - - // pass the commands for it - [self _parsePathCommandData:[[element attributeForName:(NSString *)IJSVGAttributeD] stringValue] - intoPath:path]; - - // check the size... - if( NSIsEmptyRect([path path].controlPointBounds) ) { - break; - } - - // add the glyph - [self addGlyph:path]; - break; - } - - // group - case IJSVGNodeTypeSwitch: - case IJSVGNodeTypeFont: - case IJSVGNodeTypeMask: - case IJSVGNodeTypeGroup: { - - // parse the defs - [self parseDefsForElement:element]; - - // create a new group - IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease]; - group.type = aType; - group.name = subName; - group.parentNode = parentGroup; - - // only groups get added to parent, rest is added as a def - - // also addition of switches - if(!flag && ((aType == IJSVGNodeTypeGroup) || - (aType == IJSVGNodeTypeSwitch))) { - [parentGroup addChild:group]; - } - - // find common attributes - [self _setupDefaultsForNode:group]; - [self _parseElementForCommonAttributes:element - node:group - ignoreAttributes:nil]; - - // recursively parse blocks - [self _parseBlock:element - intoGroup:group - def:NO]; - - [parentGroup addDef:group]; - break; - } - - - // path - case IJSVGNodeTypePath: { - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - if( !flag ) { - [parentGroup addChild:path]; - } - - // find common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - [self _parsePathCommandData:[[element attributeForName:(NSString *)IJSVGAttributeD] stringValue] - intoPath:path]; - - [parentGroup addDef:path]; - break; - } - - // polygon - case IJSVGNodeTypePolygon: { - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - if( !flag ) { - [parentGroup addChild:path]; - } - - // find common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - [self _parsePolygon:element - intoPath:path]; - [parentGroup addDef:path]; - break; - } - - // polyline - case IJSVGNodeTypePolyline: { - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - - if( !flag ) { - [parentGroup addChild:path]; - } - - // find common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - [self _parsePolyline:element - intoPath:path]; - [parentGroup addDef:path]; - break; - } - - // rect - case IJSVGNodeTypeRect: { - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - if( !flag ) { - [parentGroup addChild:path]; - } - - // find common attributes - [self _parseRect:element - intoPath:path]; - - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:@[@"x",@"y"]]; - [parentGroup addDef:path]; - break; - } - - // line - case IJSVGNodeTypeLine: { - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - - [parentGroup addChild:path]; - - // find common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - [self _parseLine:element - intoPath:path]; - [parentGroup addDef:path]; - break; - } - - // circle - case IJSVGNodeTypeCircle: { - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - - if( !flag ) { - [parentGroup addChild:path]; - } - - // find common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - [self _parseCircle:element - intoPath:path]; - [parentGroup addDef:path]; - break; - } - - // ellipse - case IJSVGNodeTypeEllipse: { - IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease]; - path.type = aType; - path.name = subName; - path.parentNode = parentGroup; - - if( !flag ) { - [parentGroup addChild:path]; - } - - // find common attributes - [self _setupDefaultsForNode:path]; - [self _parseElementForCommonAttributes:element - node:path - ignoreAttributes:nil]; - [self _parseEllipse:element - intoPath:path]; - [parentGroup addDef:path]; - break; - } - - // use - case IJSVGNodeTypeUse: { - - NSString * xlink = [[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue]; - NSString * xlinkID = [xlink substringFromIndex:1]; - IJSVGNode * node = [self definedObjectForID:xlinkID]; - - // there was no specified link ID, well, not that we could find, - // so just break - if(node == nil) { - break; - } - - // due to this being a carbon clone, we need to clear the ID - if([element attributeForName:(NSString *)IJSVGAttributeID] == nil) { - node.identifier = nil; - } - - // at this point, we need to create another group! - IJSVGGroup * subGroup = [[[IJSVGGroup alloc] init] autorelease]; - subGroup.parentNode = parentGroup; - [subGroup addChild:node]; - node.parentNode = subGroup; - node.intermediateParentNode = subGroup; - - // is there a width and height? - CGFloat x = [element attributeForName:(NSString *)IJSVGAttributeX].stringValue.floatValue; - CGFloat y = [element attributeForName:(NSString *)IJSVGAttributeY].stringValue.floatValue; - - // we need to add a transform to the subgroup - subGroup.transforms = @[[IJSVGTransform transformByTranslatingX:x y:y]]; - - if(!flag) { - [parentGroup addChild:subGroup]; - } - - // parse attributes from element onto group - but spec - // says ignore x, y, width, height and xlink:href... - [self _parseElementForCommonAttributes:element - node:node - ignoreAttributes:@[@"x",@"y",@"width", - @"height",@"xlink:href"]]; - - [parentGroup addDef:node]; - break; - } - - // linear gradient - case IJSVGNodeTypeLinearGradient: { - - NSString * xlink = [[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue]; - NSString * xlinkID = [xlink substringFromIndex:1]; - NSXMLElement * referenceElement; - IJSVGNode * node = [self definedObjectForID:xlinkID - xmlElement:&referenceElement]; - if( node != nil ) { - // we are a clone - NSXMLElement * elementCopy = [self mergedElement:element - withReferenceElement:referenceElement]; - - IJSVGLinearGradient * grad = [[[IJSVGLinearGradient alloc] init] autorelease]; - grad.type = aType; - [self _setupDefaultsForNode:grad]; - [self _parseElementForCommonAttributes:elementCopy - node:grad - ignoreAttributes:nil]; - grad.gradient = [IJSVGLinearGradient parseGradient:elementCopy - gradient:grad]; - [parentGroup addDef:grad]; - break; - } - - IJSVGLinearGradient * gradient = [[[IJSVGLinearGradient alloc] init] autorelease]; - gradient.type = aType; - [self _setupDefaultsForNode:gradient]; - [self _parseElementForCommonAttributes:element - node:gradient - ignoreAttributes:nil]; - gradient.gradient = [IJSVGLinearGradient parseGradient:element - gradient:gradient]; - [parentGroup addDef:gradient]; - break; - } - - // radial gradient - case IJSVGNodeTypeRadialGradient: { - - NSString * xlink = [[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue]; - NSString * xlinkID = [xlink substringFromIndex:1]; - NSXMLElement * referenceElement; - IJSVGNode * node = [self definedObjectForID:xlinkID - xmlElement:&referenceElement]; - if( node != nil ) { - // we are a clone - IJSVGRadialGradient * grad = [[[IJSVGRadialGradient alloc] init] autorelease]; - grad.type = aType; - - NSXMLElement * elementCopy = [self mergedElement:element - withReferenceElement:referenceElement]; - [self _setupDefaultsForNode:grad]; - [self _parseElementForCommonAttributes:elementCopy - node:grad - ignoreAttributes:nil]; - grad.gradient = [IJSVGRadialGradient parseGradient:elementCopy - gradient:grad]; - [parentGroup addDef:grad]; - break; - } - - IJSVGRadialGradient * gradient = [[[IJSVGRadialGradient alloc] init] autorelease]; - gradient.type = aType; - [self _setupDefaultsForNode:gradient]; - [self _parseElementForCommonAttributes:element - node:gradient - ignoreAttributes:nil]; - gradient.gradient = [IJSVGRadialGradient parseGradient:element - gradient:gradient]; - [parentGroup addDef:gradient]; - break; - } - - // clippath - case IJSVGNodeTypeClipPath: { - - IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease]; - group.type = aType; - group.name = subName; - group.parentNode = parentGroup; - - [self _setupDefaultsForNode:group]; - - // find common attributes - [self _parseElementForCommonAttributes:element - node:group - ignoreAttributes:nil]; - - // recursively parse blocks - [self _parseBlock:element - intoGroup:group - def:NO]; - [parentGroup addDef:group]; - break; - } - - // pattern - case IJSVGNodeTypePattern: { - IJSVGPattern * pattern = [[[IJSVGPattern alloc] init] autorelease]; - - [self _setupDefaultsForNode:pattern]; - - // find common attributes - [self _parseElementForCommonAttributes:element - node:pattern - ignoreAttributes:nil]; - - // pattern has children - [self _parseBlock:element - intoGroup:pattern - def:NO]; - - [parentGroup addDef:pattern]; - break; - } - - // image - case IJSVGNodeTypeImage: { - IJSVGImage * image = [[[IJSVGImage alloc] init] autorelease]; - - [self _setupDefaultsForNode:image]; - - // find common attributes - [self _parseElementForCommonAttributes:element - node:image - ignoreAttributes:nil]; - - // from base64 - [image loadFromBase64EncodedString:[[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue]]; - - // add to parent - [parentGroup addChild:image]; - [parentGroup addDef:image]; - break; - } - - } -} - -- (NSXMLElement *)mergedElement:(NSXMLElement *)element - withReferenceElement:(NSXMLElement *)reference -{ - NSXMLElement * copy = [[reference copy] autorelease]; - for(NSXMLNode * attribute in element.attributes) { - [copy removeAttributeForName:attribute.name]; - attribute = [[attribute copy] autorelease]; - [copy addAttribute:attribute]; - } - return copy; -} - -- (void)_parseBlock:(NSXMLElement *)anElement - intoGroup:(IJSVGGroup*)parentGroup - def:(BOOL)flag -{ - // parse the defs - [self parseDefsForElement:anElement]; - - // parse the children - for( NSXMLElement * element in [anElement children] ) { - [self _parseBaseBlock:element - intoGroup:parentGroup - def:flag]; - } -} - -#pragma mark Parser stuff! - -- (void)_parsePathCommandData:(NSString *)command - intoPath:(IJSVGPath *)path -{ - // invalid command - - if( command == nil || command.length == 0 ) { - return; - } - - NSUInteger len = [command length]; - - // allocate memory for the string buffer for reading - const char * buffer = [command cStringUsingEncoding:NSUTF8StringEncoding]; - - int defaultBufferSize = 200; - int currentBufferSize = 0; - int currentSize = defaultBufferSize; - - unichar * commandBuffer = NULL; - if(len != 0) { - commandBuffer = (unichar *)calloc(defaultBufferSize,sizeof(unichar)); - } - - IJSVGCommand * _currentCommand = nil; - for( int i = 0; i < len; i++ ) { - unichar currentChar = buffer[i]; - unichar nextChar = buffer[i+1]; - - BOOL atEnd = i == len-1; - BOOL isStartCommand = IJSVGIsLegalCommandCharacter(nextChar); - if( ( currentBufferSize + 1 ) == currentSize ) { - currentSize += defaultBufferSize; - commandBuffer = (unichar *)realloc(commandBuffer, sizeof(unichar)*currentSize); - } - commandBuffer[currentBufferSize++] = currentChar; - if(isStartCommand == YES || atEnd == YES) { - NSString * commandString = [NSString stringWithCharacters:commandBuffer - length:currentBufferSize]; - - // previous command is actual subcommand - IJSVGCommand * previousCommand = [_currentCommand subCommands].lastObject; - IJSVGCommand * cCommand = [self _parseCommandString:commandString - previousCommand:previousCommand - intoPath:path]; - - // retain the current one - if(cCommand != nil) { - _currentCommand = cCommand; - } - - if(atEnd == NO) { - currentBufferSize = 0; - memset(commandBuffer,'\0', sizeof(unichar)*currentSize); - } - } - } - - // free the buffer - free(commandBuffer); -} - -- (IJSVGCommand *)_parseCommandString:(NSString *)string - previousCommand:(IJSVGCommand *)previousCommand - intoPath:(IJSVGPath *)path -{ - // work out the last command - the reason this is so long is because the command - // could be a series of the same commands, so work it out by the number of parameters - // there is per command string - IJSVGCommand * preCommand = nil; - if( previousCommand ) { - preCommand = previousCommand; - } - - // main commands -// Class commandClass = [IJSVGCommand classFor] - Class commandClass = [IJSVGCommand commandClassForCommandChar:[string characterAtIndex:0]]; - IJSVGCommand * command = (IJSVGCommand *)[[[commandClass alloc] initWithCommandString:string] autorelease]; - for( IJSVGCommand * subCommand in [command subCommands]) { - [command.class runWithParams:subCommand.parameters - paramCount:subCommand.parameterCount - command:subCommand - previousCommand:preCommand - type:subCommand.type - path:path]; - preCommand = subCommand; - } - return command; -} - -- (void)_parseLine:(NSXMLElement *)element - intoPath:(IJSVGPath *)path -{ - // convert a line into a command, - // basically MX1 Y1LX2 Y2 - CGFloat x1 = [[[element attributeForName:(NSString *)IJSVGAttributeX1] stringValue] floatValue]; - CGFloat y1 = [[[element attributeForName:(NSString *)IJSVGAttributeY1] stringValue] floatValue]; - CGFloat x2 = [[[element attributeForName:(NSString *)IJSVGAttributeX2] stringValue] floatValue]; - CGFloat y2 = [[[element attributeForName:(NSString *)IJSVGAttributeY2] stringValue] floatValue]; - - // use sprintf as its quicker then stringWithFormat... - char buffer[50]; - sprintf( buffer, "M%.2f %.2fL%.2f %.2f",x1,y1,x2,y2); - NSString * command = [NSString stringWithCString:buffer - encoding:NSUTF8StringEncoding]; - [self _parsePathCommandData:command - intoPath:path]; -} - -- (void)_parseCircle:(NSXMLElement *)element - intoPath:(IJSVGPath *)path -{ - CGFloat cX = [[[element attributeForName:(NSString *)IJSVGAttributeCX] stringValue] floatValue]; - CGFloat cY = [[[element attributeForName:(NSString *)IJSVGAttributeCY] stringValue] floatValue]; - CGFloat r = [[[element attributeForName:(NSString *)IJSVGAttributeR] stringValue] floatValue]; - NSRect rect = NSMakeRect( cX - r, cY - r, r*2, r*2); - [path overwritePath:[NSBezierPath bezierPathWithOvalInRect:rect]]; -} - -- (void)_parseEllipse:(NSXMLElement *)element - intoPath:(IJSVGPath *)path -{ - CGFloat cX = [[[element attributeForName:(NSString *)IJSVGAttributeCX] stringValue] floatValue]; - CGFloat cY = [[[element attributeForName:(NSString *)IJSVGAttributeCY] stringValue] floatValue]; - CGFloat rX = [[[element attributeForName:(NSString *)IJSVGAttributeRX] stringValue] floatValue]; - CGFloat rY = [[[element attributeForName:(NSString *)IJSVGAttributeRY] stringValue] floatValue]; - NSRect rect = NSMakeRect( cX-rX, cY-rY, rX*2, rY*2); - [path overwritePath:[NSBezierPath bezierPathWithOvalInRect:rect]]; -} - -- (void)_parsePolyline:(NSXMLElement *)element - intoPath:(IJSVGPath *)path -{ - [self _parsePoly:element - intoPath:path - closePath:NO]; -} - -- (void)_parsePolygon:(NSXMLElement *)element - intoPath:(IJSVGPath *)path -{ - [self _parsePoly:element - intoPath:path - closePath:YES]; -} - -- (void)_parsePoly:(NSXMLElement *)element - intoPath:(IJSVGPath *)path - closePath:(BOOL)closePath -{ - NSString * points = [[element attributeForName:(NSString *)IJSVGAttributePoints] stringValue]; - NSInteger count = 0; - CGFloat * params = [IJSVGUtils commandParameters:points - count:&count]; - if( (count % 2) != 0 ) { - // error occured, free the params - free(params); - return; - } - - // construct a command - NSMutableString * str = [[[NSMutableString alloc] init] autorelease]; - [str appendFormat:@"M%f,%f L",params[0],params[1]]; - for( NSInteger i = 2; i < count; i+=2 ) { - [str appendFormat:@"%f,%f ",params[i],params[i+1]]; - } - if( closePath ) { - [str appendString:@"z"]; - } - [self _parsePathCommandData:str - intoPath:path]; - free(params); - -} - -- (void)_parseRect:(NSXMLElement *)element - intoPath:(IJSVGPath *)path -{ - - // width and height - CGFloat width = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeWidth] stringValue] - fallBackForPercent:self.viewBox.size.width]; - - - CGFloat height = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeHeight] stringValue] - fallBackForPercent:self.viewBox.size.height]; - - - // rect uses x and y as start of path, not move path object -_- - CGFloat x = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeX] stringValue] - fallBackForPercent:self.viewBox.size.width]; - CGFloat y = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeY] stringValue] - fallBackForPercent:self.viewBox.size.height]; - - // radius - CGFloat rX = [element attributeForName:(NSString *)IJSVGAttributeRX].stringValue.floatValue; - CGFloat rY = [element attributeForName:(NSString *)IJSVGAttributeRY].stringValue.floatValue; - if([element attributeForName:(NSString *)IJSVGAttributeRY] == nil) { - rY = rX; - } - - NSBezierPath * newPath = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect( x, y, width, height) - xRadius:rX - yRadius:rY]; - [path overwritePath:newPath]; -} - -@end diff --git a/source/IJSVGPath.h b/source/IJSVGPath.h deleted file mode 100644 index cbfbe7b..0000000 --- a/source/IJSVGPath.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// IJSVGPath.h -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import -#import "IJSVGBezierPathAdditions.h" -#import "IJSVGNode.h" - -@class IJSVGGroup; - -@interface IJSVGPath : IJSVGNode { - - NSBezierPath * path; - NSBezierPath * subpath; - CGPoint lastControlPoint; - -} - -@property ( nonatomic, readonly ) NSBezierPath * path; -@property ( nonatomic, readonly ) NSBezierPath * subpath; -@property ( nonatomic, assign ) CGPoint lastControlPoint; - -- (NSBezierPath *)currentSubpath; -- (void)close; -- (NSPoint)currentPoint; -- (void)overwritePath:(NSBezierPath *)aPath; -- (CGPathRef)newPathRefByAutoClosingPath:(BOOL)autoClose; - -@end diff --git a/source/IJSVGPath.m b/source/IJSVGPath.m deleted file mode 100644 index 2fb0ca6..0000000 --- a/source/IJSVGPath.m +++ /dev/null @@ -1,127 +0,0 @@ -// -// IJSVGPath.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGPath.h" -#import "IJSVGGroup.h" - -@implementation IJSVGPath - -@synthesize path; -@synthesize subpath; -@synthesize lastControlPoint; - -- (void)dealloc -{ - if(subpath!=nil) { - [subpath release], subpath = nil; - } - [super dealloc]; -} - -- (id)init -{ - if( ( self = [super init] ) != nil ) - { - subpath = [[NSBezierPath bezierPath] retain]; - path = subpath; // for legacy use - } - return self; -} - -- (id)copyWithZone:(NSZone *)zone -{ - IJSVGPath * node = [super copyWithZone:zone]; - [node overwritePath:self.path]; - return node; -} - -- (NSPoint)currentPoint -{ - return [subpath currentPoint]; -} - -- (NSBezierPath *)currentSubpath -{ - return subpath; -} - -- (void)close -{ - [subpath closePath]; -} - -- (void)overwritePath:(NSBezierPath *)aPath -{ - [subpath release], subpath = nil; - subpath = [aPath retain]; - path = subpath; -} - -- (CGPathRef)newPathRefByAutoClosingPath:(BOOL)autoClose -{ - NSInteger i = 0; - NSInteger numElements = [self.path elementCount]; - NSBezierPath * bezPath = self.path; - - // nothing to return - if(numElements == 0) { - return NULL; - } - - CGMutablePathRef aPath = CGPathCreateMutable(); - - NSPoint points[3]; - BOOL didClosePath = YES; - - for (i = 0; i < numElements; i++) { - switch ([bezPath elementAtIndex:i associatedPoints:points]) - { - - // move - case NSMoveToBezierPathElement: { - CGPathMoveToPoint(aPath, NULL, points[0].x, points[0].y); - break; - } - - // line - case NSLineToBezierPathElement: { - CGPathAddLineToPoint(aPath, NULL, points[0].x, points[0].y); - didClosePath = NO; - break; - } - - // curve - case NSCurveToBezierPathElement: { - CGPathAddCurveToPoint(aPath, NULL, points[0].x, points[0].y, - points[1].x, points[1].y, - points[2].x, points[2].y); - didClosePath = NO; - break; - } - - // close - case NSClosePathBezierPathElement: { - CGPathCloseSubpath(aPath); - didClosePath = YES; - break; - } - } - } - - if (!didClosePath && autoClose) { - CGPathCloseSubpath(aPath); - } - - // create immutable and release - CGPathRef pathToReturn = CGPathCreateCopy(aPath); - CGPathRelease(aPath); - - return pathToReturn; -} - -@end diff --git a/source/IJSVGRadialGradient.h b/source/IJSVGRadialGradient.h deleted file mode 100644 index 7885bec..0000000 --- a/source/IJSVGRadialGradient.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// IJSVGRadialGradient.h -// IJSVGExample -// -// Created by Curtis Hard on 03/09/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import -#import "IJSVGGradient.h" - -@interface IJSVGRadialGradient : IJSVGGradient - -@property ( nonatomic, retain ) IJSVGUnitLength * cx; -@property ( nonatomic, retain ) IJSVGUnitLength * cy; -@property ( nonatomic, retain ) IJSVGUnitLength * fx; -@property ( nonatomic, retain ) IJSVGUnitLength * fy; -@property ( nonatomic, retain ) IJSVGUnitLength * radius; - -+ (NSGradient *)parseGradient:(NSXMLElement *)element - gradient:(IJSVGRadialGradient *)gradient; - -@end diff --git a/source/IJSVGRenderingStyle.m b/source/IJSVGRenderingStyle.m deleted file mode 100644 index 909696e..0000000 --- a/source/IJSVGRenderingStyle.m +++ /dev/null @@ -1,56 +0,0 @@ -// -// IJSVGStyleList.m -// IconJar -// -// Created by Curtis Hard on 09/07/2019. -// Copyright © 2019 Curtis Hard. All rights reserved. -// - -#import "IJSVGRenderingStyle.h" - -@implementation IJSVGRenderingStyle - -@synthesize colorList = _colorList; -@synthesize lineCapStyle = _lineCapStyle; -@synthesize lineJoinStyle = _lineJoinStyle; -@synthesize lineWidth = _lineWidth; -@synthesize fillColor = _fillColor; -@synthesize strokeColor = _strokeColor; - -- (void)dealloc -{ - [_fillColor release], _fillColor = nil; - [_strokeColor release], _strokeColor = nil; - [_colorList release], _colorList = nil; - [super dealloc]; -} - -- (id)init -{ - if((self = [super init]) != nil) { - _lineCapStyle = IJSVGLineCapStyleNone; - _lineJoinStyle = IJSVGLineJoinStyleNone; - _lineWidth = IJSVGInheritedFloatValue; - _colorList = [[IJSVGColorList alloc] init]; - } - return self; -} - -+ (NSArray *)observableProperties -{ - unsigned int count; - objc_property_t * properties = class_copyPropertyList(IJSVGRenderingStyle.class, - &count); - NSMutableArray * names = [[[NSMutableArray alloc] initWithCapacity:count] autorelease]; - for(int i = 0; i < count; i++) { - objc_property_t property = properties[i]; - const char * name = property_getName(property); - NSString * stringName = [NSString stringWithCString:name - encoding:NSUTF8StringEncoding]; - [names addObject:stringName]; - } - free(properties); - return names; -} - -@end diff --git a/source/IJSVGTransaction.m b/source/IJSVGTransaction.m deleted file mode 100644 index d3af07e..0000000 --- a/source/IJSVGTransaction.m +++ /dev/null @@ -1,42 +0,0 @@ -// -// IJSVGTransaction.m -// IconJar -// -// Created by Curtis Hard on 11/01/2017. -// Copyright © 2017 Curtis Hard. All rights reserved. -// - -#import "IJSVGTransaction.h" - -void IJSVGBeginTransactionLock() { - if(NSThread.isMainThread == YES) { - return; - } - [CATransaction begin]; - if(@available(macOS 10.14, *)) {} else { - [CATransaction lock]; - } - [CATransaction setDisableActions:YES]; -}; - -void IJSVGEndTransactionLock() { - if(NSThread.isMainThread == YES) { - return; - } - - if(@available(macOS 10.14, *)) {} else { - [CATransaction unlock]; - } - [CATransaction commit]; -}; - -void IJSVGObtainTransactionLock(dispatch_block_t block, BOOL renderOnMainThread) -{ - IJSVGBeginTransactionLock(); - if(renderOnMainThread) { - dispatch_sync(dispatch_get_main_queue(), block); - } else { - block(); - } - IJSVGEndTransactionLock(); -}; diff --git a/source/IJSVGTransform.m b/source/IJSVGTransform.m deleted file mode 100644 index d637942..0000000 --- a/source/IJSVGTransform.m +++ /dev/null @@ -1,615 +0,0 @@ -// -// IJSVGTransform.m -// IconJar -// -// Created by Curtis Hard on 01/09/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGTransform.h" -#import "IJSVGMath.h" - -@implementation IJSVGTransform - -@synthesize command; -@synthesize parameters; -@synthesize parameterCount; -@synthesize sort; - -- (void)dealloc -{ - free(parameters); - [super dealloc]; -} - -- (id)copyWithZone:(NSZone *)zone -{ - IJSVGTransform * trans = [[self.class alloc] init]; - trans.command = self.command; - trans.parameters = (CGFloat*)malloc(sizeof(CGFloat)*self.parameterCount); - trans.sort = sort; - trans.parameterCount = self.parameterCount; - memcpy( trans.parameters, self.parameters, sizeof(CGFloat)*self.parameterCount); - return trans; -} - -NSString * IJSVGDebugAffineTransform(CGAffineTransform transform) -{ - NSMutableArray * strings = [[[NSMutableArray alloc] init] autorelease]; - [strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform]]; - return [strings componentsJoinedByString:@" "]; -} - -NSString * IJSVGDebugTransforms(NSArray * transforms) -{ - NSMutableArray * strings = [[[NSMutableArray alloc] init] autorelease]; - IJSVGApplyTransform(transforms, ^(IJSVGTransform *transform) { - [strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform.CGAffineTransform]]; - }); - return [strings componentsJoinedByString:@" "]; -} - -CGAffineTransform IJSVGConcatTransforms(NSArray * transforms) -{ - __block CGAffineTransform trans = CGAffineTransformIdentity; - IJSVGApplyTransform(transforms, ^(IJSVGTransform *transform) { - trans = CGAffineTransformConcat(trans, transform.CGAffineTransform); - }); - return trans; -} - -void IJSVGApplyTransform(NSArray * transforms, IJSVGTransformApplyBlock block) -{ - for(IJSVGTransform * transform in transforms) { - block(transform); - } -}; - -+ (IJSVGTransform *)transformByTranslatingX:(CGFloat)x - y:(CGFloat)y -{ - IJSVGTransform * transform = [[[self alloc] init] autorelease]; - transform.command = IJSVGTransformCommandTranslate; - transform.parameterCount = 2; - CGFloat * params = (CGFloat *)malloc(sizeof(CGFloat)*2); - params[0] = x; - params[1] = y; - transform.parameters = params; - return transform; -} - -- (void)recalculateWithBounds:(CGRect)bounds -{ - CGFloat max = bounds.size.width>bounds.size.height?bounds.size.width:bounds.size.height; - switch (self.command) { - case IJSVGTransformCommandRotate: { - if( self.parameterCount == 1 ) - return; - self.parameters[1] = self.parameters[1]*max; - self.parameters[2] = self.parameters[2]*max; - } - default: - return; - } -} - -+ (IJSVGTransformCommand)commandForCommandString:(NSString *)str -{ - str = str.lowercaseString; - if( [str isEqualToString:@"matrix"] ) - return IJSVGTransformCommandMatrix; - if( [str isEqualToString:@"translate"] ) - return IJSVGTransformCommandTranslate; - if([str isEqualToString:@"translatex"]) - return IJSVGTransformCommandTranslateX; - if([str isEqualToString:@"translatey"]) - return IJSVGTransformCommandTranslateY; - if( [str isEqualToString:@"scale"] ) - return IJSVGTransformCommandScale; - if( [str isEqualToString:@"skewx"]) - return IJSVGTransformCommandSkewX; - if( [str isEqualToString:@"skewy"]) - return IJSVGTransformCommandSkewY; - if( [str isEqualToString:@"rotate"] ) - return IJSVGTransformCommandRotate; - return IJSVGTransformCommandNotImplemented; -} - -+ (NSInteger)sortForTransformCommand:(IJSVGTransformCommand)command -{ - switch (command) { - case IJSVGTransformCommandScale: - return 0; - case IJSVGTransformCommandRotate: - return 1; - case IJSVGTransformCommandMatrix: - return 2; - case IJSVGTransformCommandTranslateX: - case IJSVGTransformCommandTranslateY: - case IJSVGTransformCommandTranslate: - return -1; - default: - return 10; - } - return 10; -} - -+ (NSArray *)transformsForString:(NSString *)string -{ - static NSRegularExpression * _reg = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z]+)\\(([^\\)]+)\\)" - options:0 - error:nil]; - }); - NSMutableArray * transforms = [[[NSMutableArray alloc] init] autorelease]; - @autoreleasepool { - [_reg enumerateMatchesInString:string - options:0 - range:NSMakeRange( 0, string.length ) - usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { - NSString * command = [string substringWithRange:[result rangeAtIndex:1]]; - IJSVGTransformCommand commandType = [self.class commandForCommandString:command]; - if( commandType == IJSVGTransformCommandNotImplemented ) { - return; - } - - - // create the transform - NSString * params = [string substringWithRange:[result rangeAtIndex:2]]; - IJSVGTransform * transform = [[[self.class alloc] init] autorelease]; - NSInteger count = 0; - transform.command = commandType; - transform.parameters = [IJSVGUtils commandParameters:params - count:&count]; - transform.parameterCount = count; - transform.sort = [self.class sortForTransformCommand:commandType]; - [transforms addObject:transform]; - }]; - } - return transforms; -} - -+ (NSBezierPath *)transformedPath:(IJSVGPath *)path -{ - if( path.transforms.count == 0 ) - return path.path; - NSBezierPath * cop = [[path.path copy] autorelease]; - for( IJSVGTransform * transform in path.transforms ) - { - NSAffineTransform * at = [NSAffineTransform transform]; - switch( transform.command ) - { - // matrix - case IJSVGTransformCommandMatrix: { - at.transformStruct = (NSAffineTransformStruct) { - .m11 = transform.parameters[0], - .m12 = transform.parameters[1], - .m21 = transform.parameters[2], - .m22 = transform.parameters[3], - .tX = transform.parameters[4], - .tY = transform.parameters[5], - }; - break; - } - - // skewX - case IJSVGTransformCommandSkewX: { - CGFloat degrees = transform.parameters[0]; - CGFloat radians = degrees * M_PI / 180.f; - at.transformStruct = (NSAffineTransformStruct) { - .m11 = 1.f, - .m12 = 0.f, - .m21 = tan(radians), - .m22 = 1.f, - .tX = 0.f, - .tY = 0.f - }; - break; - } - - // skewX - case IJSVGTransformCommandSkewY: { - CGFloat degrees = transform.parameters[0]; - CGFloat radians = degrees * M_PI / 180.f; - at.transformStruct = (NSAffineTransformStruct) { - .m11 = 1.f, - .m12 = tan(radians), - .m21 = 0.f, - .m22 = 1.f, - .tX = 0.f, - .tY = 0.f - }; - break; - } - - // translate - case IJSVGTransformCommandTranslate: { - if( transform.parameterCount == 1 ) - [at translateXBy:transform.parameters[0] - yBy:0]; - else - [at translateXBy:transform.parameters[0] - yBy:transform.parameters[1]]; - break; - } - - // translateX - case IJSVGTransformCommandTranslateX: { - [at translateXBy:transform.parameters[0] yBy:0.f]; - break; - } - - // translateY - case IJSVGTransformCommandTranslateY: { - [at translateXBy:0.f yBy:transform.parameters[0]]; - break; - } - - // scale - case IJSVGTransformCommandScale: { - if( transform.parameterCount == 1 ) - [at scaleBy:transform.parameters[0]]; - else - [at scaleXBy:transform.parameters[0] - yBy:transform.parameters[1]]; - break; - } - - // rotate - case IJSVGTransformCommandRotate: { - if( transform.parameterCount == 1 ) - [at rotateByDegrees:transform.parameters[0]]; - else { - CGFloat centerX = transform.parameters[1]; - CGFloat centerY = transform.parameters[2]; - CGFloat angle = transform.parameters[0]*(M_PI/180.f); - [at translateXBy:centerX - yBy:centerY]; - [at rotateByRadians:angle]; - [at translateXBy:-1.f*centerX - yBy:-1.f*centerY]; - } - break; - } - - // do nothing - case IJSVGTransformCommandNotImplemented: { - - } - - } - [cop transformUsingAffineTransform:at]; - } - return cop; -} - -- (CGAffineTransform)CGAffineTransform -{ - return [self CGAffineTransformWithModifier:nil]; -} - -- (CGAffineTransform)stackIdentity:(CGAffineTransform)identity -{ - switch(self.command) { - - // translate - case IJSVGTransformCommandTranslate: { - if(self.parameterCount == 1) { - return CGAffineTransformTranslate(identity, self.parameters[0], 0.f); - } - return CGAffineTransformTranslate(identity, self.parameters[0], self.parameters[1]); - } - - // translateX - case IJSVGTransformCommandTranslateX: { - return CGAffineTransformTranslate(identity, self.parameters[0], 0.f); - } - - // translateY - case IJSVGTransformCommandTranslateY: { - return CGAffineTransformTranslate(identity, 0.f, self.parameters[0]); - } - - // rotate - case IJSVGTransformCommandRotate: { - if(self.parameterCount == 1) { - return CGAffineTransformRotate(identity, (self.parameters[0]/180) * M_PI); - } - CGFloat p0 = self.parameters[0]; - CGFloat p1 = self.parameters[1]; - CGFloat p2 = self.parameters[2]; - CGFloat angle = p0*(M_PI/180.f); - - identity = CGAffineTransformTranslate(identity, p1, p2); - identity = CGAffineTransformRotate(identity, angle); - return CGAffineTransformTranslate(identity, -1.f*p1, -1.f*p2); - } - - // scale - case IJSVGTransformCommandScale: { - CGFloat p0 = self.parameters[0]; - CGFloat p1 = self.parameters[1]; - if(self.parameterCount == 1) { - return CGAffineTransformScale(identity, p0, p0); - } - return CGAffineTransformScale(identity, p0, p1); - } - - // matrix - case IJSVGTransformCommandMatrix: { - CGFloat p0 = self.parameters[0]; - CGFloat p1 = self.parameters[1]; - CGFloat p2 = self.parameters[2]; - CGFloat p3 = self.parameters[3]; - CGFloat p4 = self.parameters[4]; - CGFloat p5 = self.parameters[5]; - return CGAffineTransformMake(p0, p1, p2, p3, p4, p5); - } - - // skewX - case IJSVGTransformCommandSkewX: { - CGFloat degrees = self.parameters[0]; - CGFloat radians = degrees * M_PI / 180.f; - return CGAffineTransformMake( 1.f, 0.f, tan(radians), 1.f, 0.f, 0.f); - } - - // skewY - case IJSVGTransformCommandSkewY: { - CGFloat degrees = self.parameters[0]; - CGFloat radians = degrees * M_PI / 180.f; - return CGAffineTransformMake( 1.f, tan(radians), 0.f, 1.f, 0.f, 0.f); - } - - case IJSVGTransformCommandNotImplemented: { - return CGAffineTransformIdentity; - } - - } - return CGAffineTransformIdentity; -} - -- (CGAffineTransform)CGAffineTransformWithModifier:(IJSVGTransformParameterModifier)modifier -{ - switch(self.command) - { - // matrix - case IJSVGTransformCommandMatrix: { - CGFloat p0 = self.parameters[0]; - CGFloat p1 = self.parameters[1]; - CGFloat p2 = self.parameters[2]; - CGFloat p3 = self.parameters[3]; - CGFloat p4 = self.parameters[4]; - CGFloat p5 = self.parameters[5]; - if(modifier != nil) - { - p0 = modifier(0,p0); - p1 = modifier(1,p1); - p2 = modifier(2,p2); - p3 = modifier(3,p3); - p4 = modifier(4,p4); - p5 = modifier(5,p5); - } - return CGAffineTransformMake(p0, p1, p2, p3, p4, p5); - } - - // translate - case IJSVGTransformCommandTranslate: { - CGFloat p0 = self.parameters[0]; - CGFloat p1 = self.parameters[1]; - if(modifier != nil) - { - p0 = modifier(0,p0); - p1 = modifier(1,p1); - } - if(self.parameterCount == 1) - return CGAffineTransformMakeTranslation( p0, 0 ); - return CGAffineTransformMakeTranslation(p0, p1); - } - - // translateX - case IJSVGTransformCommandTranslateX: { - CGFloat p0 = self.parameters[0]; - if(modifier != nil) { - p0 = modifier(0, p0); - } - return CGAffineTransformMakeTranslation(p0, 0.f); - } - - // translateY - case IJSVGTransformCommandTranslateY: { - CGFloat p0 = self.parameters[0]; - if(modifier != nil) { - p0 = modifier(0, p0); - } - return CGAffineTransformMakeTranslation(0.f, p0); - } - - // scale - case IJSVGTransformCommandScale: { - CGFloat p0 = self.parameters[0]; - CGFloat p1 = self.parameters[1]; - if(modifier != nil) - { - p0 = modifier(0,p0); - p1 = modifier(1,p1); - } - if(self.parameterCount == 1) - return CGAffineTransformMakeScale( p0, p0); - return CGAffineTransformMakeScale( p0, p1); - } - - // skewX - case IJSVGTransformCommandSkewX: { - CGFloat degrees = self.parameters[0]; - if(modifier != nil) { - degrees = modifier(0,degrees); - } - CGFloat radians = degrees * M_PI / 180.f; - return CGAffineTransformMake( 1.f, 0.f, tan(radians), 1.f, 0.f, 0.f); - } - - // skewY - case IJSVGTransformCommandSkewY: { - CGFloat degrees = self.parameters[0]; - if(modifier != nil) { - degrees = modifier(0,degrees); - } - CGFloat radians = degrees * M_PI / 180.f; - return CGAffineTransformMake( 1.f, tan(radians), 0.f, 1.f, 0.f, 0.f); - } - - // rotate - case IJSVGTransformCommandRotate: { - if(self.parameterCount == 1) - return CGAffineTransformMakeRotation((self.parameters[0]/180) * M_PI); - else { - CGFloat p0 = self.parameters[0]; - CGFloat p1 = self.parameters[1]; - CGFloat p2 = self.parameters[2]; - if(modifier != nil) - { - p0 = modifier(0,p0); - p1 = modifier(1,p1); - p2 = modifier(2,p2); - } - CGFloat angle = p0*(M_PI/180.f); - CGAffineTransform def = CGAffineTransformIdentity; - def = CGAffineTransformTranslate(def, p1, p2); - def = CGAffineTransformRotate(def, angle); - def = CGAffineTransformTranslate(def, -1.f*p1, -1.f*p2); - return def; - } - break; - } - - // do nothing - case IJSVGTransformCommandNotImplemented: { - return CGAffineTransformIdentity; - } - } - return CGAffineTransformIdentity; -} - -+ (NSArray *)transformsFromAffineTransform:(CGAffineTransform)affineTransform -{ - NSArray * strings = [self affineTransformToSVGTransformAttributeString:affineTransform]; - return [self transformsForString:[strings componentsJoinedByString:@" "]]; -} - -+ (NSString *)affineTransformToSVGMatrixString:(CGAffineTransform)transform -{ - return [NSString stringWithFormat:@"matrix(%g,%g,%g,%g,%g,%g)", - transform.a, transform.b, transform.c, transform.d, - transform.tx, transform.ty]; -} - -// this is an Object-C version of the matrixToTransform method from SVGO -+ (NSArray *)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform -{ - const CGFloat data[6] = { - affineTransform.a, - affineTransform.b, - affineTransform.c, - affineTransform.d, - affineTransform.tx, - affineTransform.ty - }; - - CGFloat sx = sqrtf(data[0]*data[0] + data[1] * data[1]); - CGFloat sy = (data[0]*data[3] - data[1]*data[2])/sx; - - CGFloat colSum = data[0]*data[2] + data[1]*data[3]; - CGFloat rowSum = data[0]*data[1] + data[2]*data[3]; - BOOL scaleBefore = rowSum != 0.f || (sx == sy); - - NSMutableArray * trans = [[[NSMutableArray alloc] init] autorelease]; - - // translate - if(data[4] != 0.f || data[5] != 0.f) { - NSString * str = [NSString stringWithFormat:@"translate(%g, %g)",data[4],data[5]]; - [trans addObject:str]; - } - - // skewX - if(data[1] == 0.f && data[2] != 0.f) { - NSString * str = [NSString stringWithFormat:@"skewX(%g)",IJSVGMathAtan(data[2]/sy)]; - [trans addObject:str]; - - // skewY - } else if(data[1] != 0.f && data[2] == 0.f) { - NSString * str = [NSString stringWithFormat:@"skewY(%g)",IJSVGMathAtan(data[1]/data[0])]; - [trans addObject:str]; - sx = data[0]; - sy = data[3]; - } else if(colSum == 0.f || (sx == 1.f && sy == 1.f) || scaleBefore == NO) { - if(scaleBefore == NO) { - sx = (data[0] < 0.f ? -1.f : 1.f) * sqrtf(data[0] * data[0] + data[2] * data[2]); - sy = (data[3] < 0.f ? -1.f : 1.f) * sqrtf(data[1] * data[1] + data[3] * data[3]); - NSString * str = nil; - if(sx == sy) { - str = [NSString stringWithFormat:@"scale(%g)",sx]; - } else { - str = [NSString stringWithFormat:@"scale(%g, %g)",sx,sy]; - } - [trans addObject:str]; - } - - // rotate - CGFloat rotate = IJSVGMathAcos(data[0]/sx)*(data[1]*sy < 0.f ? -1.f : 1.f); - NSString * rotateString = nil; - if(rotate != 0.f) { - rotateString = [NSString stringWithFormat:@"rotate(%g)",rotate]; - } - - // skewX - if(rowSum != 0.f && colSum != 0.f) { - NSString * str = [NSString stringWithFormat:@"skewX(%g)",IJSVGMathAtan(colSum/(sx * sx))]; - [trans addObject:str]; - } - - // rotate around center - if(rotate != 0.f && (data[4] != 0.f || data[5] != 0.f)) { - [trans removeObjectAtIndex:0]; - - CGFloat cos = data[0]/sx; - CGFloat sin = data[1]/(scaleBefore ? sx : sy); - CGFloat x = data[4] * (scaleBefore ? 1.f : sy); - CGFloat y = data[5] * (scaleBefore ? 1.f : sx); - CGFloat denom = (powf(1.f - cos, 2.f) + powf(sin,2.f)) * (scaleBefore ? 1.f : sx * sy); - - CGFloat r1 = rotate; - CGFloat r2 = ((1.f - cos) * x - sin * y) / denom; - CGFloat r3 = ((1.f - cos) * y + sin * x) / denom; - - rotateString = [NSString stringWithFormat:@"rotate(%g, %g, %g)",r1,r2,r3]; - } - - if(rotateString != nil) { - [trans addObject:rotateString]; - } - } - - // scale - if((scaleBefore && (sx != 1.f || sy != 1.f)) || trans.count == 0.f) { - NSString * str = nil; - if(sx == sy) { - str = [NSString stringWithFormat:@"scale(%g)",sx]; - } else { - str = [NSString stringWithFormat:@"scale(%g, %g)",sx, sy]; - } - [trans addObject:str]; - } - - return trans; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@",[super description], - [self.class affineTransformToSVGTransformAttributeString:self.CGAffineTransform]]; -} - - -@end diff --git a/source/IJSVGUnitLength.m b/source/IJSVGUnitLength.m deleted file mode 100644 index de31dfd..0000000 --- a/source/IJSVGUnitLength.m +++ /dev/null @@ -1,104 +0,0 @@ -// -// IJSVGUnitLength.m -// IJSVGExample -// -// Created by Curtis Hard on 13/01/2017. -// Copyright © 2017 Curtis Hard. All rights reserved. -// - -#import "IJSVGUnitLength.h" -#import "IJSVGNode.h" - -@implementation IJSVGUnitLength - -@synthesize value; -@synthesize type; -@synthesize inherit; - -+ (IJSVGUnitLength *)unitWithFloat:(CGFloat)number -{ - IJSVGUnitLength * unit = [[[self alloc] init] autorelease]; - unit.value = number; - unit.type = IJSVGUnitLengthTypeNumber; - return unit; -} - -+ (IJSVGUnitLength *)unitWithString:(NSString *)string - fromUnitType:(IJSVGUnitType)units -{ - if(units == IJSVGUnitObjectBoundingBox) { - return [self unitWithPercentageString:string]; - } - return [self unitWithString:string]; -} - -+ (IJSVGUnitLength *)unitWithFloat:(CGFloat)number - type:(IJSVGUnitLengthType)type -{ - IJSVGUnitLength * unit = [[[self alloc] init] autorelease]; - unit.value = number; - unit.type = type; - return unit; -} - -+ (IJSVGUnitLength *)unitWithPercentageFloat:(CGFloat)number -{ - return [self unitWithFloat:number - type:IJSVGUnitLengthTypePercentage]; -} - -+ (IJSVGUnitLength *)unitWithPercentageString:(NSString *)string -{ - IJSVGUnitLength * unit = [self unitWithString:string]; - unit.type = IJSVGUnitLengthTypePercentage; - return unit; -} - -+ (IJSVGUnitLength *)unitWithString:(NSString *)string -{ - // just return noting for inherit, node will deal - // with the rest...hopefully - NSCharacterSet * cSet = NSCharacterSet.whitespaceCharacterSet; - string = [string stringByTrimmingCharactersInSet:cSet]; - - if([string isEqualToString:@"inherit"]) { - return nil; - } - - IJSVGUnitLength * unit = [[[self alloc] init] autorelease]; - unit.value = string.floatValue; - unit.type = IJSVGUnitLengthTypeNumber; - if([string hasSuffix:@"%"] == YES) { - unit.value /= 100.f; - unit.type = IJSVGUnitLengthTypePercentage; - } - return unit; -} - -- (CGFloat)computeValue:(CGFloat)anotherValue -{ - if(self.type == IJSVGUnitLengthTypePercentage) { - return ((anotherValue/100.f)*(self.value*100.f)); - } - return self.value; -} - -- (CGFloat)valueAsPercentage -{ - return self.value/100; -} - -- (NSString *)stringValue -{ - if(self.type == IJSVGUnitLengthTypePercentage) { - return [NSString stringWithFormat:@"%g%%",(self.value*100.f)]; - } - return [NSString stringWithFormat:@"%g",self.value]; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%f%@",self.value,(self.type == IJSVGUnitLengthTypePercentage ? @"%" : @"")]; -} - -@end diff --git a/source/IJSVGUtils.h b/source/IJSVGUtils.h deleted file mode 100644 index 6e6459f..0000000 --- a/source/IJSVGUtils.h +++ /dev/null @@ -1,59 +0,0 @@ -// -// IJSVGUtils.h -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import -#include -#import "IJSVGCommand.h" -#import "IJSVGGradientUnitLength.h" -#import "IJSVGStringAdditions.h" - -@interface IJSVGUtils : NSObject - -CGFloat magnitude(CGPoint point); -CGFloat ratio( CGPoint a, CGPoint b ); -CGFloat angle( CGPoint a, CGPoint b ); -CGFloat radians_to_degrees( CGFloat radians); -CGFloat degrees_to_radians( CGFloat degrees ); - -BOOL IJSVGIsCommonHTMLElementName(NSString * str); -NSArray * IJSVGCommonHTMLElementNames(); - -NSString * IJSVGShortFloatString(CGFloat f); -NSString * IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision); - -BOOL IJSVGIsLegalCommandCharacter(unichar aChar); -BOOL IJSVGIsSVGLayer(CALayer * layer); -+ (IJSVGCommandType)typeForCommandString:(NSString *)string; -+ (CGFloat *)commandParameters:(NSString *)command - count:(NSInteger *)count; -+ (CGFloat *)parseViewBox:(NSString *)string; -+ (IJSVGWindingRule)windingRuleForString:(NSString *)string; -+ (IJSVGLineJoinStyle)lineJoinStyleForString:(NSString *)string; -+ (IJSVGLineCapStyle)lineCapStyleForString:(NSString *)string; -+ (IJSVGUnitType)unitTypeForString:(NSString *)string; -+ (IJSVGBlendMode)blendModeForString:(NSString *)string; -+ (NSString *)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode; -+ (NSRange)rangeOfParentheses:(NSString *)string; - -+ (void)logParameters:(CGFloat *)param - count:(NSInteger)count; -+ (CGFloat)floatValue:(NSString *)string; -+ (CGFloat)angleBetweenPointA:(NSPoint)point - pointb:(NSPoint)point; -+ (NSString *)defURL:(NSString *)string; -+ (CGFloat)floatValue:(NSString *)string - fallBackForPercent:(CGFloat)viewBox; -+ (CGFloat *)scanFloatsFromString:(NSString *)string - size:(NSInteger *)length; -+ (IJSVGFontTraits)fontStyleStringForString:(NSString *)string; -+ (IJSVGFontTraits)fontWeightTraitForString:(NSString *)string - weight:(CGFloat *)weight; - -+ (CGPathRef)newFlippedCGPath:(CGPathRef)path; -+ (CGPathRef)newCGPathFromBezierPath:(NSBezierPath *)bezPath; -@end diff --git a/source/IJSVGUtils.m b/source/IJSVGUtils.m deleted file mode 100644 index d7ca977..0000000 --- a/source/IJSVGUtils.m +++ /dev/null @@ -1,631 +0,0 @@ -// -// IJSVGUtils.m -// IconJar -// -// Created by Curtis Hard on 30/08/2014. -// Copyright (c) 2014 Curtis Hard. All rights reserved. -// - -#import "IJSVGUtils.h" -#import "IJSVGLayer.h" -#import "IJSVGShapeLayer.h" - -@implementation IJSVGUtils - -BOOL IJSVGIsCommonHTMLElementName(NSString * str) -{ - str = str.lowercaseString; - return [IJSVGCommonHTMLElementNames() containsObject:str]; -}; - -NSArray * IJSVGCommonHTMLElementNames() -{ - static NSArray * names = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - names = [@[@"a", - @"abbr", - @"acronym", - @"abbr", - @"address", - @"applet", - @"embed", - @"object", - @"area", - @"article", - @"aside", - @"audio", - @"b", - @"base", - @"basefont", - @"bdi", - @"bdo", - @"big", - @"blockquote", - @"body", - @"br", - @"button", - @"canvas", - @"caption", - @"center", - @"cite", - @"code", - @"col", - @"colgroup", - @"colgroup", - @"datalist", - @"dd", - @"del", - @"details", - @"dfn", - @"dialog", - @"dir", - @"ul", - @"div", - @"dl", - @"dt", - @"em", - @"embed", - @"fieldset", - @"figcaption", - @"figure", - @"figure", - @"font", - @"footer", - @"form", - @"frame", - @"frameset", - @"h1", - @"h6", - @"head", - @"header", - @"hr", - @"html", - @"i", - @"iframe", - @"img", - @"input", - @"ins", - @"kbd", - @"label", - @"input", - @"legend", - @"fieldset", - @"li", - @"link", - @"main", - @"map", - @"mark", - @"menu", - @"menuitem", - @"meta", - @"meter", - @"nav", - @"noframes", - @"noscript", - @"object", - @"ol", - @"optgroup", - @"option", - @"output", - @"p", - @"param", - @"picture", - @"pre", - @"progress", - @"q", - @"rp", - @"rt", - @"ruby", - @"s", - @"samp", - @"script", - @"section", - @"select", - @"small", - @"source", - @"video", - @"audio", - @"span", - @"strike", - @"del", - @"s", - @"strong", - @"style", - @"sub", - @"summary", - @"details", - @"sup", - @"table", - @"tbody", - @"td", - @"template", - @"textarea", - @"tfoot", - @"th", - @"thead", - @"time", - @"title", - @"tr", - @"track", - @"video", - @"audio", - @"tt", - @"u", - @"ul", - @"var", - @"video", - @"wbr"] retain]; - }); - return names; -}; - -NSString * IJSVGShortFloatString(CGFloat f) -{ - return [NSString stringWithFormat:@"%g",f]; -}; - -NSString * IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision) -{ - NSString * format = [NSString stringWithFormat:@"%@.%ld%@",@"%",precision,@"f"]; - NSString * ret = [NSString stringWithFormat:format,f]; - // can it be reduced even more? - if(ret.floatValue == (float)ret.integerValue) { - ret = [NSString stringWithFormat:@"%ld",ret.integerValue]; - } - return ret; -}; - -BOOL IJSVGIsLegalCommandCharacter(unichar aChar) -{ - const char * validChars = "MmZzLlHhVvCcSsQqTtAa"; - return strchr(validChars, aChar) != NULL; -} - -BOOL IJSVGIsSVGLayer(CALayer * layer) -{ - return [layer isKindOfClass:IJSVGLayer.class] || - [layer isKindOfClass:IJSVGShapeLayer.class]; -} - -CGFloat angle( CGPoint a, CGPoint b ) { - return [IJSVGUtils angleBetweenPointA:a - pointb:b]; -} - -CGFloat ratio( CGPoint a, CGPoint b ) { - return (a.x * b.x + a.y * b.y) / (magnitude(a) * magnitude(b)); -} - -CGFloat magnitude(CGPoint point) -{ - return sqrtf(powf(point.x, 2) + powf(point.y, 2)); -} - -CGFloat radians_to_degrees(CGFloat radians) -{ - return ((radians) * (180.0 / M_PI)); -} - -CGFloat degrees_to_radians( CGFloat degrees ) -{ - return ( ( degrees ) / 180.0 * M_PI ); -} - -+ (IJSVGCommandType)typeForCommandString:(NSString *)string -{ - return isupper([string characterAtIndex:0]) ? IJSVGCommandTypeAbsolute : IJSVGCommandTypeRelative; -} - -+ (NSRange)rangeOfParentheses:(NSString *)string -{ - NSRange range = NSMakeRange(NSNotFound, 0); - const char * characters = string.UTF8String; - unsigned long length = strlen(characters); - for(NSInteger i = 0; i < length; i++) { - char c = characters[i]; - if(c == '(') { - range.location = i + 1; - } else if(c == ')') { - range.length = i - range.location; - } - } - return range; -} - -+ (NSString *)defURL:(NSString *)string -{ - // insta check for URL - NSCharacterSet * set = NSCharacterSet.whitespaceCharacterSet; - string = [string stringByTrimmingCharactersInSet:set]; - NSString * check = [string substringToIndex:3].lowercaseString; - if([check isEqualToString:@"url"] == NO) { - return nil; - } - - static NSRegularExpression * _reg = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _reg = [[NSRegularExpression alloc] initWithPattern:@"url\\(['\"]?([^)]+?)['\"]?\\)" - options:0 - error:nil]; - }); - __block NSString * foundID = nil; - [_reg enumerateMatchesInString:string - options:0 - range:NSMakeRange( 0, string.length ) - usingBlock:^(NSTextCheckingResult *result, - NSMatchingFlags flags, BOOL *stop) { - if((foundID = [string substringWithRange:[result rangeAtIndex:1]]) != nil) { - *stop = YES; - } - }]; - if([foundID hasPrefix:@"#"] == YES) { - foundID = [foundID substringFromIndex:1]; - } - return foundID; -} - -+ (IJSVGFontTraits)fontWeightTraitForString:(NSString *)string - weight:(CGFloat *)weight -{ - *weight = string.floatValue; - if([string isEqualToString:@"bold"]) - return IJSVGFontTraitBold; - return IJSVGFontTraitNone; -} - -+ (IJSVGFontTraits)fontStyleStringForString:(NSString *)string -{ - if([string isEqualToString:@"italic"]) - return IJSVGFontTraitItalic; - return IJSVGFontTraitNone; -} - -+ (IJSVGWindingRule)windingRuleForString:(NSString *)string -{ - if( [string isEqualToString:@"evenodd"] ) - return IJSVGWindingRuleEvenOdd; - if( [string isEqualToString:@"inherit"] ) - return IJSVGWindingRuleInherit; - return IJSVGWindingRuleNonZero; -} - -+ (IJSVGLineJoinStyle)lineJoinStyleForString:(NSString *)string -{ - if( [string isEqualToString:@"mitre"] ) - return IJSVGLineJoinStyleMiter; - if( [string isEqualToString:@"round"] ) - return IJSVGLineJoinStyleRound; - if( [string isEqualToString:@"bevel"] ) - return IJSVGLineJoinStyleBevel; - if( [string isEqualToString:@"inherit"] ) - return IJSVGLineJoinStyleInherit; - return IJSVGLineJoinStyleMiter; -} - -+ (IJSVGLineCapStyle)lineCapStyleForString:(NSString *)string -{ - if( [string isEqualToString:@"butt"] ) - return IJSVGLineCapStyleButt; - if( [string isEqualToString:@"square"] ) - return IJSVGLineCapStyleSquare; - if( [string isEqualToString:@"round"] ) - return IJSVGLineCapStyleRound; - if( [string isEqualToString:@"inherit"] ) - return IJSVGLineCapStyleInherit; - return IJSVGLineCapStyleButt; -} - -+ (IJSVGUnitType)unitTypeForString:(NSString *)string -{ - if([string isEqualToString:@"userSpaceOnUse"]) { - return IJSVGUnitUserSpaceOnUse; - } - return IJSVGUnitObjectBoundingBox; -} - -+ (IJSVGBlendMode)blendModeForString:(NSString *)string -{ - string = string.lowercaseString; - if([string isEqualToString:@"normal"]) - return IJSVGBlendModeNormal; - if([string isEqualToString:@"multiply"]) - return IJSVGBlendModeMultiply; - if([string isEqualToString:@"screen"]) - return IJSVGBlendModeScreen; - if([string isEqualToString:@"overlay"]) - return IJSVGBlendModeOverlay; - if([string isEqualToString:@"darken"]) - return IJSVGBlendModeDarken; - if([string isEqualToString:@"lighten"]) - return IJSVGBlendModeLighten; - if([string isEqualToString:@"color-dodge"]) - return IJSVGBlendModeColorDodge; - if([string isEqualToString:@"color-burn"]) - return IJSVGBlendModeColorBurn; - if([string isEqualToString:@"hard-light"]) - return IJSVGBlendModeHardLight; - if([string isEqualToString:@"soft-light"]) - return IJSVGBlendModeSoftLight; - if([string isEqualToString:@"difference"]) - return IJSVGBlendModeDifference; - if([string isEqualToString:@"exclusion"]) - return IJSVGBlendModeExclusion; - if([string isEqualToString:@"hue"]) - return IJSVGBlendModeHue; - if([string isEqualToString:@"saturation"]) - return IJSVGBlendModeSaturation; - if([string isEqualToString:@"color"]) - return IJSVGBlendModeColor; - if([string isEqualToString:@"luminosity"]) - return IJSVGBlendModeLuminosity; - return IJSVGBlendModeNormal; -} - -+ (NSString *)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode -{ - switch (blendMode) { - case IJSVGBlendModeMultiply: { - return @"multiple"; - } - case IJSVGBlendModeScreen: { - return @"screen"; - } - case IJSVGBlendModeOverlay: { - return @"overlay"; - } - case IJSVGBlendModeDarken: { - return @"darken"; - } - case IJSVGBlendModeLighten: { - return @"lighten"; - } - case IJSVGBlendModeColorDodge: { - return @"color-dodge"; - } - case IJSVGBlendModeColorBurn: { - return @"color-burn"; - } - case IJSVGBlendModeHardLight: { - return @"hard-light"; - } - case IJSVGBlendModeSoftLight: { - return @"soft-light"; - } - case IJSVGBlendModeDifference: { - return @"difference"; - } - case IJSVGBlendModeExclusion: { - return @"exclusion"; - } - case IJSVGBlendModeHue: { - return @"hue"; - } - case IJSVGBlendModeSaturation: { - return @"saturation"; - } - case IJSVGBlendModeColor: { - return @"color"; - } - case IJSVGBlendModeLuminosity: { - return @"luminosity"; - } - case IJSVGBlendModeNormal: - default: { - return nil; - } - } -} - -+ (CGFloat *)commandParameters:(NSString *)command - count:(NSInteger *)count -{ - if( [command isKindOfClass:[NSNumber class]] ) { - CGFloat * ret = (CGFloat *)malloc(1*sizeof(CGFloat)); - ret[0] = [(NSNumber *)command floatValue]; - *count = 1; - return ret; - } - return [self.class scanFloatsFromString:command - size:count]; -} - -+ (CGFloat *)scanFloatsFromString:(NSString *)string - size:(NSInteger *)length -{ - // default sizes and memory - // sizes for the string buffer - const NSInteger defFloatSize = 30; - const NSInteger defSize = 15; - - // default memory size for the float - NSInteger size = defSize; - NSInteger floatSize = defFloatSize; - - NSInteger i = 0; - NSInteger counter = 0; - - const char * cString = [string cStringUsingEncoding:NSUTF8StringEncoding]; - const char * validChars = "0123456789eE+-."; - - NSInteger sLength = strlen(cString); - - // buffer for the returned floats - CGFloat * floats = (CGFloat *)malloc(sizeof(CGFloat)*defFloatSize); - - char * buffer = NULL; - bool isDecimal = false; - int bufferCount = 0; - - while(i < sLength) { - char currentChar = cString[i]; - - // work out next char - char nextChar = (char)0; - if(i < (sLength-1)) { - nextChar = cString[i+1]; - } - - bool isValid = strchr(validChars, currentChar) != NULL; - - // in order to work out the split, its either because the next char is - // a hyphen or a plus, or next char is a decimal and the current number is a decimal - bool isE = currentChar == 'e' || currentChar == 'E'; - bool wantsEnd = nextChar == '-' || nextChar == '+' || - (nextChar == '.' && isDecimal); - - // could be a float like 5.334e-5 so dont break on the hypen - if(wantsEnd && isE && (nextChar == '-' || nextChar == '+')) { - wantsEnd = false; - } - - // make sure its a valid string - if(isValid) { - // alloc the buffer if needed - if(buffer == NULL) { - buffer = (char *)calloc(sizeof(char),size); - } else if((bufferCount+1) == size) { - // realloc the buffer, incase the string is overflowing the - // allocated memory - size += defSize; - buffer = (char *)realloc(buffer, sizeof(char)*size); - } - // set the actual char against it - if(currentChar == '.') { - isDecimal = true; - } - buffer[bufferCount++] = currentChar; - } else { - // if its an invalid char, just stop it - wantsEnd = true; - } - - // is at end of string, or wants to be stopped - // buffer has to actually exist or its completly - // useless and will cause a crash - if((buffer != NULL && bufferCount != 0) && (wantsEnd || i == sLength-1)) { - // make sure there is enough room in the float pool - if((counter+1) == floatSize) { - floatSize += defFloatSize; - floats = (CGFloat *)realloc(floats, sizeof(CGFloat)*floatSize); - } - - // add the float - floats[counter++] = strtod_l(buffer, NULL, NULL); - - // memory clean and counter resets - memset(buffer, '\0', sizeof(*buffer)*size); - isDecimal = false; - bufferCount = 0; - } - i++; - } - if(buffer != NULL) { - free(buffer); - } - *length = counter; - return floats; -} - -+ (CGFloat *)parseViewBox:(NSString *)string -{ - NSInteger size = 0; - return [self.class scanFloatsFromString:string - size:&size]; -} - -+ (CGFloat)floatValue:(NSString *)string - fallBackForPercent:(CGFloat)fallBack -{ - CGFloat val = [string floatValue]; - if( [string rangeOfString:@"%"].location != NSNotFound ) - val = (fallBack * val)/100; - return val; -} - -+ (void)logParameters:(CGFloat *)param - count:(NSInteger)count -{ - NSMutableString * str = [[[NSMutableString alloc] init] autorelease]; - for( NSInteger i = 0; i < count; i++ ) - { - [str appendFormat:@"%f ",param[i]]; - } - NSLog(@"%@",str); -} - -+ (CGFloat)floatValue:(NSString *)string -{ - if( [string isEqualToString:@"inherit"] ) - return IJSVGInheritedFloatValue; - return [string floatValue]; -} - -+ (CGFloat)angleBetweenPointA:(NSPoint)point1 - pointb:(NSPoint)point2 -{ - return (point1.x * point2.y < point1.y * point2.x ? -1 : 1) * acosf(ratio(point1, point2)); -} - -+ (CGPathRef)newFlippedCGPath:(CGPathRef)path -{ - CGRect boundingBox = CGPathGetPathBoundingBox(path); - CGAffineTransform scale = CGAffineTransformMakeScale(1.f, -1.f); - CGAffineTransform translate = CGAffineTransformTranslate(scale, 0.f, boundingBox.size.height); - CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &translate); - return transformPath; -} - -+ (CGPathRef)newCGPathFromBezierPath:(NSBezierPath *)bezPath -{ - CGPathRef immutablePath = NULL; - // Then draw the path elements. - NSInteger numElements = bezPath.elementCount; - if (numElements > 0) { - CGMutablePathRef path = CGPathCreateMutable(); - NSPoint points[3]; - BOOL didClosePath = YES; - - for (NSInteger i = 0; i < numElements; i++) { - switch ([bezPath elementAtIndex:i associatedPoints:points]) { - case NSMoveToBezierPathElement: { - CGPathMoveToPoint(path, NULL, points[0].x, points[0].y); - break; - } - - case NSLineToBezierPathElement: { - CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y); - didClosePath = NO; - break; - } - - case NSCurveToBezierPathElement: { - CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y, - points[1].x, points[1].y, - points[2].x, points[2].y); - didClosePath = NO; - break; - } - - case NSClosePathBezierPathElement: { - CGPathCloseSubpath(path); - didClosePath = YES; - break; - } - } - } - - // Be sure the path is closed or Quartz may not do valid hit detection. - if (didClosePath == NO) { - CGPathCloseSubpath(path); - } - - // memory clean - immutablePath = CGPathCreateCopy(path); - CGPathRelease(path); - } - return immutablePath; -} - -@end diff --git a/source/IJSVGView.h b/source/IJSVGView.h index 01677f7..dd7ec66 100644 --- a/source/IJSVGView.h +++ b/source/IJSVGView.h @@ -6,20 +6,20 @@ // Copyright © 2017 Curtis Hard. All rights reserved. // -#import #import "IJSVG.h" +#import IB_DESIGNABLE @interface IJSVGView : NSView { - IBInspectable NSString * imageName; - IBInspectable NSColor * tintColor; - - IJSVG * SVG; + IBInspectable NSString* imageName; + IBInspectable NSColor* tintColor; + + IJSVG* SVG; } -@property (nonatomic, retain) IJSVG * SVG; +@property (nonatomic, retain) IJSVG* SVG; -+ (IJSVGView *)viewWithSVGNamed:(NSString *)name; -- (id)initWithSVG:(IJSVG *)anSvg; ++ (IJSVGView*)viewWithSVGNamed:(NSString*)name; +- (id)initWithSVG:(IJSVG*)anSvg; @end diff --git a/source/IJSVGView.m b/source/IJSVGView.m index 49a8cd0..d80f283 100644 --- a/source/IJSVGView.m +++ b/source/IJSVGView.m @@ -17,20 +17,20 @@ - (void)dealloc // make sure we call this, or block may get called for a view // that doesnt exist [SVG prepForDrawingInView:nil]; - [imageName release], imageName = nil; - [SVG release], SVG = nil; + (void)([imageName release]), imageName = nil; + (void)([SVG release]), SVG = nil; [super dealloc]; } -+ (IJSVGView *)viewWithSVGNamed:(NSString *)name ++ (IJSVGView*)viewWithSVGNamed:(NSString*)name { - IJSVG * anSVG = [IJSVG svgNamed:name]; + IJSVG* anSVG = [IJSVG svgNamed:name]; return [[[self alloc] initWithSVG:anSVG] autorelease]; } -- (id)initWithSVG:(IJSVG *)anSvg +- (id)initWithSVG:(IJSVG*)anSvg { - if((self = [super init]) != nil) { + if ((self = [super init]) != nil) { self.SVG = anSvg; } return self; @@ -39,23 +39,23 @@ - (id)initWithSVG:(IJSVG *)anSvg - (void)awakeFromNib { // image was set via IB - if(imageName != nil) { - IJSVG * anSVG = [IJSVG svgNamed:imageName]; - if(tintColor != nil) { + if (imageName != nil) { + IJSVG* anSVG = [IJSVG svgNamed:imageName]; + if (tintColor != nil) { anSVG.style.fillColor = tintColor; } self.SVG = anSVG; } } -- (void)setSVG:(IJSVG *)anSVG +- (void)setSVG:(IJSVG*)anSVG { // memory clean - if(SVG != nil) { - [SVG release], SVG = nil; + if (SVG != nil) { + (void)([SVG release]), SVG = nil; } SVG = [anSVG retain]; - + // redisplay ourself! [SVG prepForDrawingInView:self]; [self setNeedsDisplay:YES]; @@ -69,10 +69,10 @@ - (BOOL)isFlipped - (void)drawRect:(NSRect)dirtyRect { // only draw if there is actually an SVG - if(self.SVG == nil) { + if (self.SVG == nil) { return; } - + // draw the svg [self.SVG drawInRect:self.bounds]; } diff --git a/source/IJSVGWriter.h b/source/IJSVGWriter.h index a1f278b..a5c2d6f 100644 --- a/source/IJSVGWriter.h +++ b/source/IJSVGWriter.h @@ -6,15 +6,14 @@ // Copyright (c) 2015 Curtis Hard. All rights reserved. // -#import #import "IJSVGPath.h" +#import @interface IJSVGWriter : NSObject { - } -+ (NSString *)SVGDocumentStringForSVGGlyph:(IJSVGPath *)node; -+ (NSString *)SVGDocumentStringForBezierPath:(NSBezierPath *)path; -+ (NSXMLDocument *)SVGDocumentForBezierPath:(NSBezierPath *)path; ++ (NSString*)SVGDocumentStringForSVGGlyph:(IJSVGPath*)node; ++ (NSString*)SVGDocumentStringForBezierPath:(NSBezierPath*)path; ++ (NSXMLDocument*)SVGDocumentForBezierPath:(NSBezierPath*)path; @end diff --git a/source/IJSVGWriter.m b/source/IJSVGWriter.m index 68f50dd..fd99695 100644 --- a/source/IJSVGWriter.m +++ b/source/IJSVGWriter.m @@ -10,63 +10,63 @@ @implementation IJSVGWriter -+ (NSString *)SVGDocumentStringForSVGGlyph:(IJSVGPath *)node ++ (NSString*)SVGDocumentStringForSVGGlyph:(IJSVGPath*)node { - NSBezierPath * path = [node path]; + NSBezierPath* path = [node path]; // we need to flip it - NSAffineTransform * trans = [NSAffineTransform transform]; + NSAffineTransform* trans = NSAffineTransform.transform; [trans scaleXBy:1.f yBy:-1.f]; [trans translateXBy:0.f yBy:path.controlPointBounds.size.height]; path = [trans transformBezierPath:path]; return [self.class SVGDocumentStringForBezierPath:path]; } -+ (NSString *)SVGDocumentStringForBezierPath:(NSBezierPath *)path ++ (NSString*)SVGDocumentStringForBezierPath:(NSBezierPath*)path { return [self.class SVGDocumentForBezierPath:path].XMLString; } -+ (NSXMLDocument *)SVGDocumentForBezierPath:(NSBezierPath *)path ++ (NSXMLDocument*)SVGDocumentForBezierPath:(NSBezierPath*)path { - NSXMLElement * root = [self.class rootElementForPath:path]; - + NSXMLElement* root = [self.class rootElementForPath:path]; + // create the path data - NSXMLElement * p = [[[NSXMLElement alloc] initWithName:@"path"] autorelease]; - + NSXMLElement* p = [[[NSXMLElement alloc] initWithName:@"path"] autorelease]; + // add the drawing command - NSXMLNode * n = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; + NSXMLNode* n = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; [n setName:@"d"]; [n setStringValue:[self.class SVGPathStringForBezierPath:path]]; [p addAttribute:n]; - + // add the drawing path to the root [root addChild:p]; return [[[NSXMLDocument alloc] initWithRootElement:root] autorelease]; } -+ (NSXMLElement *)rootElementForPath:(NSBezierPath *)path ++ (NSXMLElement*)rootElementForPath:(NSBezierPath*)path { - NSXMLElement * element = [[[NSXMLElement alloc] initWithName:@"svg"] autorelease]; + NSXMLElement* element = [[[NSXMLElement alloc] initWithName:@"svg"] autorelease]; NSRect bounds = path.controlPointBounds; - + // width - NSXMLNode * att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; + NSXMLNode* att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; [att setName:@"width"]; - [att setStringValue:[NSString stringWithFormat:@"%f",bounds.size.width]]; + [att setStringValue:[NSString stringWithFormat:@"%f", bounds.size.width]]; [element addAttribute:att]; - + // height att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; [att setName:@"height"]; - [att setStringValue:[NSString stringWithFormat:@"%f",bounds.size.height]]; + [att setStringValue:[NSString stringWithFormat:@"%f", bounds.size.height]]; [element addAttribute:att]; - + // viewbox att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; [att setName:@"viewBox"]; - [att setStringValue:[NSString stringWithFormat:@"%f %f %f %f",bounds.origin.x,bounds.origin.y,bounds.size.width,bounds.size.height]]; + [att setStringValue:[NSString stringWithFormat:@"%f %f %f %f", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height]]; [element addAttribute:att]; - + // namespace att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease]; [att setName:@"xmlns"]; @@ -75,44 +75,38 @@ + (NSXMLElement *)rootElementForPath:(NSBezierPath *)path return element; } -+ (NSString *)SVGPathStringForBezierPath:(NSBezierPath *)path ++ (NSString*)SVGPathStringForBezierPath:(NSBezierPath*)path { - NSMutableString * str = [[[NSMutableString alloc] init] autorelease]; - for( NSInteger i = 0; i < path.elementCount; i++ ) - { + NSMutableString* str = [[[NSMutableString alloc] init] autorelease]; + for (NSInteger i = 0; i < path.elementCount; i++) { NSBezierPathElement element = [path elementAtIndex:i]; - switch( element ) - { - // move - case NSMoveToBezierPathElement: - { - NSPoint points[1]; - [path elementAtIndex:i associatedPoints:points]; - [str appendFormat:@"M%f %f",points[0].x,points[0].y]; - break; - } - // line - case NSLineToBezierPathElement: - { - NSPoint points[1]; - [path elementAtIndex:i associatedPoints:points]; - [str appendFormat:@"L%f %f",points[0].x,points[0].y]; - break; - } - // curve - case NSCurveToBezierPathElement: - { - NSPoint points[3]; - [path elementAtIndex:i associatedPoints:points]; - [str appendFormat:@"C%f %f %f %f %f %f",points[0].x,points[0].y,points[1].x,points[1].y,points[2].x,points[2].y]; - break; - } - // close - case NSClosePathBezierPathElement: - { - [str appendFormat:@"Z"]; - break; - } + switch (element) { + // move + case NSMoveToBezierPathElement: { + NSPoint points[1]; + [path elementAtIndex:i associatedPoints:points]; + [str appendFormat:@"M%f %f", points[0].x, points[0].y]; + break; + } + // line + case NSLineToBezierPathElement: { + NSPoint points[1]; + [path elementAtIndex:i associatedPoints:points]; + [str appendFormat:@"L%f %f", points[0].x, points[0].y]; + break; + } + // curve + case NSCurveToBezierPathElement: { + NSPoint points[3]; + [path elementAtIndex:i associatedPoints:points]; + [str appendFormat:@"C%f %f %f %f %f %f", points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y]; + break; + } + // close + case NSClosePathBezierPathElement: { + [str appendFormat:@"Z"]; + break; + } } } return str;