Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 68393b296b | |||
| 1cfcb596d9 | |||
| 69077e49cf | |||
| 3bdf2151ca | |||
| f7e28a2962 | |||
| 2c07cfabdd | |||
| 3e356b3fdc | |||
| 49f759edc0 | |||
| 38e314eb99 | |||
| d0eb015cf1 | |||
| 080626a022 | |||
| 36c20bc55c | |||
| 4d89631e9a | |||
| 65f62007f3 | |||
| af5f16288d | |||
| 08e0f9288d | |||
| 7650f6205c | |||
| 263768af5b | |||
| 4b1be17f9a | |||
| 6b0d6b1452 | |||
| f80d4145bb | |||
| f68c83285b | |||
| 1f4bd989d8 | |||
| 5b5d0b738b | |||
| bd82c5d81b | |||
| 145bbb17f8 | |||
| d9f40551a4 | |||
| 4448f6aeaf | |||
| 6834abba19 | |||
| a86b4e80ba | |||
| 2e8d039599 | |||
| 4ba6bb776d | |||
| 9c80412e88 | |||
| 509f0e0b0a | |||
| ce30877a26 | |||
| 122271bf36 | |||
| 28b4c6b85c | |||
| 4b308d3a3e | |||
| d3ee05d8ac | |||
| 204b516e77 | |||
| a832a986fd | |||
| f875714609 | |||
| b8f166f4c1 | |||
| 7901c9eafe | |||
| 5de88cb1d7 | |||
| 6216b61c19 | |||
| e05f5a0884 | |||
| 849807d3c5 | |||
| eeb03bd89c | |||
| fdc0859e3f | |||
| e2a7f51507 | |||
| ab69ed94dc | |||
| c5be83f57f | |||
| ed00aca06e | |||
| f51fda5f1e | |||
| dd655053ca | |||
| 8c89627f74 | |||
| eb1d27decd | |||
| e6141d7a0f | |||
| 3b7ad40794 | |||
| 674d17863f | |||
| a59072fa1d | |||
| 910b90cd4e | |||
| bb3b9c5378 | |||
| 6d10b172e7 | |||
| c6e59a9280 | |||
| df5b3219ca | |||
| 2c1ae8d0f3 | |||
| 7ba939aabf | |||
| 24e097fedf | |||
| 025ac84958 | |||
| ac9ccdda25 | |||
| 14641ddd60 | |||
| 5f32d03744 | |||
| af086622b1 | |||
| 79187326bc | |||
| ee570eb77f | |||
| d8e1ce8d70 | |||
| a900e2dc50 | |||
| 21f97babec | |||
| 0273a491de | |||
| 488a0c3654 | |||
| 7f7321e6a7 |
@@ -7,10 +7,20 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5919E65723F47FF60051873A /* IJSVGUnitRect.h in Headers */ = {isa = PBXBuildFile; fileRef = 5919E65523F47FF60051873A /* IJSVGUnitRect.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
5919E65823F47FF60051873A /* IJSVGUnitRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 5919E65623F47FF60051873A /* IJSVGUnitRect.m */; };
|
||||
5919E65B23F480330051873A /* IJSVGUnitPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 5919E65923F480330051873A /* IJSVGUnitPoint.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
5919E65C23F480330051873A /* IJSVGUnitPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 5919E65A23F480330051873A /* IJSVGUnitPoint.m */; };
|
||||
594A10DA248D7C90001A3181 /* NSImage+IJSVGAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 594A10D8248D7C90001A3181 /* NSImage+IJSVGAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
594A10DB248D7C90001A3181 /* NSImage+IJSVGAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 594A10D9248D7C90001A3181 /* NSImage+IJSVGAdditions.m */; };
|
||||
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 */; };
|
||||
59A24EBC23F480EA0090C374 /* IJSVGUnitSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 59A24EBA23F480EA0090C374 /* IJSVGUnitSize.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59A24EBD23F480EA0090C374 /* IJSVGUnitSize.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A24EBB23F480EA0090C374 /* IJSVGUnitSize.m */; };
|
||||
59E7CFAF23B148600077D599 /* IJSVGCommandParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 59E7CFAD23B148600077D599 /* IJSVGCommandParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59E7CFB023B148600077D599 /* IJSVGCommandParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E7CFAE23B148600077D599 /* IJSVGCommandParser.m */; };
|
||||
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 */; };
|
||||
@@ -57,7 +67,6 @@
|
||||
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 */; };
|
||||
@@ -100,7 +109,6 @@
|
||||
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 */; };
|
||||
@@ -127,22 +135,32 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5919E65523F47FF60051873A /* IJSVGUnitRect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitRect.h; sourceTree = "<group>"; };
|
||||
5919E65623F47FF60051873A /* IJSVGUnitRect.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitRect.m; sourceTree = "<group>"; };
|
||||
5919E65923F480330051873A /* IJSVGUnitPoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitPoint.h; sourceTree = "<group>"; };
|
||||
5919E65A23F480330051873A /* IJSVGUnitPoint.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitPoint.m; sourceTree = "<group>"; };
|
||||
594A10D8248D7C90001A3181 /* NSImage+IJSVGAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSImage+IJSVGAdditions.h"; sourceTree = "<group>"; };
|
||||
594A10D9248D7C90001A3181 /* NSImage+IJSVGAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSImage+IJSVGAdditions.m"; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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; };
|
||||
59A24EBA23F480EA0090C374 /* IJSVGUnitSize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitSize.h; sourceTree = "<group>"; };
|
||||
59A24EBB23F480EA0090C374 /* IJSVGUnitSize.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitSize.m; sourceTree = "<group>"; };
|
||||
59E7CFAD23B148600077D599 /* IJSVGCommandParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IJSVGCommandParser.h; path = IJSVG/Source/Parsing/IJSVGCommandParser.h; sourceTree = SOURCE_ROOT; };
|
||||
59E7CFAE23B148600077D599 /* IJSVGCommandParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = IJSVGCommandParser.m; path = IJSVG/Source/Parsing/IJSVGCommandParser.m; sourceTree = SOURCE_ROOT; };
|
||||
59EB756523905F6B00F5AE63 /* IJSVGLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLayer.h; sourceTree = "<group>"; };
|
||||
59EB756623905F6B00F5AE63 /* IJSVGGradientLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradientLayer.h; sourceTree = "<group>"; };
|
||||
59EB756723905F6B00F5AE63 /* IJSVGStyleSheetRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetRule.m; sourceTree = "<group>"; };
|
||||
59EB756823905F6B00F5AE63 /* IJSVGCommandLineTo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandLineTo.h; sourceTree = "<group>"; };
|
||||
59EB756923905F6B00F5AE63 /* IJSVGDef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGDef.m; sourceTree = "<group>"; };
|
||||
59EB756A23905F6B00F5AE63 /* IJSVG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVG.h; path = ../../../../source/IJSVG.h; sourceTree = "<group>"; };
|
||||
59EB756A23905F6B00F5AE63 /* IJSVG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVG.h; sourceTree = "<group>"; };
|
||||
59EB756B23905F6B00F5AE63 /* IJSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGText.h; sourceTree = "<group>"; };
|
||||
59EB756C23905F6B00F5AE63 /* IJSVGCommandQuadraticCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandQuadraticCurve.m; sourceTree = "<group>"; };
|
||||
59EB756D23905F6C00F5AE63 /* IJSVGCommandVerticalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandVerticalLine.h; sourceTree = "<group>"; };
|
||||
59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGWriter.h; path = ../../../../source/IJSVGWriter.h; sourceTree = "<group>"; };
|
||||
59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGWriter.h; sourceTree = "<group>"; };
|
||||
59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheet.h; sourceTree = "<group>"; };
|
||||
59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandSmoothCurve.h; sourceTree = "<group>"; };
|
||||
59EB757123905F6C00F5AE63 /* IJSVGColorList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorList.m; sourceTree = "<group>"; };
|
||||
@@ -156,20 +174,20 @@
|
||||
59EB757923905F6C00F5AE63 /* IJSVGTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGTransaction.h; sourceTree = "<group>"; };
|
||||
59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGShapeLayer.m; sourceTree = "<group>"; };
|
||||
59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLayer.m; sourceTree = "<group>"; };
|
||||
59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGFontConverter.m; path = ../../../../source/IJSVGFontConverter.m; sourceTree = "<group>"; };
|
||||
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGImageRep.m; path = ../../../../source/IJSVGImageRep.m; sourceTree = "<group>"; };
|
||||
59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGFontConverter.m; sourceTree = "<group>"; };
|
||||
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImageRep.m; sourceTree = "<group>"; };
|
||||
59EB757E23905F6C00F5AE63 /* IJSVGCommandQuadraticCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandQuadraticCurve.h; sourceTree = "<group>"; };
|
||||
59EB757F23905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetSelectorRaw.h; sourceTree = "<group>"; };
|
||||
59EB758023905F6C00F5AE63 /* IJSVGUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGUtils.m; sourceTree = "<group>"; };
|
||||
59EB758123905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetSelectorRaw.m; sourceTree = "<group>"; };
|
||||
59EB758223905F6C00F5AE63 /* IJSVGGroupLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroupLayer.m; sourceTree = "<group>"; };
|
||||
59EB758323905F6C00F5AE63 /* IJSVGColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGColor.h; sourceTree = "<group>"; };
|
||||
59EB758423905F6C00F5AE63 /* IJSVGError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGError.h; path = ../../../../source/IJSVGError.h; sourceTree = "<group>"; };
|
||||
59EB758423905F6C00F5AE63 /* IJSVGError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGError.h; sourceTree = "<group>"; };
|
||||
59EB758523905F6C00F5AE63 /* IJSVGColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGColor.m; sourceTree = "<group>"; };
|
||||
59EB758623905F6C00F5AE63 /* IJSVGDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGDef.h; sourceTree = "<group>"; };
|
||||
59EB758723905F6C00F5AE63 /* IJSVGCommandHorizontalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandHorizontalLine.m; sourceTree = "<group>"; };
|
||||
59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGFontConverter.h; path = ../../../../source/IJSVGFontConverter.h; sourceTree = "<group>"; };
|
||||
59EB758923905F6D00F5AE63 /* IJSVGWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGWriter.m; path = ../../../../source/IJSVGWriter.m; sourceTree = "<group>"; };
|
||||
59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGFontConverter.h; sourceTree = "<group>"; };
|
||||
59EB758923905F6D00F5AE63 /* IJSVGWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGWriter.m; sourceTree = "<group>"; };
|
||||
59EB758A23905F6D00F5AE63 /* IJSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPath.m; sourceTree = "<group>"; };
|
||||
59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGroup.h; sourceTree = "<group>"; };
|
||||
59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPatternLayer.m; sourceTree = "<group>"; };
|
||||
@@ -179,7 +197,6 @@
|
||||
59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLayerTree.m; sourceTree = "<group>"; };
|
||||
59EB759123905F6D00F5AE63 /* IJSVGCommandVerticalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandVerticalLine.m; sourceTree = "<group>"; };
|
||||
59EB759223905F6D00F5AE63 /* IJSVGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGNode.h; sourceTree = "<group>"; };
|
||||
59EB759323905F6D00F5AE63 /* IJSVGCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGCache.m; path = ../../../../source/IJSVGCache.m; sourceTree = "<group>"; };
|
||||
59EB759423905F6D00F5AE63 /* IJSVGUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGUtils.h; sourceTree = "<group>"; };
|
||||
59EB759523905F6D00F5AE63 /* IJSVGCommandHorizontalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandHorizontalLine.h; sourceTree = "<group>"; };
|
||||
59EB759623905F6D00F5AE63 /* IJSVGNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGNode.m; sourceTree = "<group>"; };
|
||||
@@ -194,8 +211,8 @@
|
||||
59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLinearGradient.h; sourceTree = "<group>"; };
|
||||
59EB75A023905F6E00F5AE63 /* IJSVGCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommand.m; sourceTree = "<group>"; };
|
||||
59EB75A123905F6E00F5AE63 /* IJSVGRenderingStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRenderingStyle.h; sourceTree = "<group>"; };
|
||||
59EB75A223905F6E00F5AE63 /* IJSVG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVG.m; path = ../../../../source/IJSVG.m; sourceTree = "<group>"; };
|
||||
59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGImageRep.h; path = ../../../../source/IJSVGImageRep.h; sourceTree = "<group>"; };
|
||||
59EB75A223905F6E00F5AE63 /* IJSVG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVG.m; sourceTree = "<group>"; };
|
||||
59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImageRep.h; sourceTree = "<group>"; };
|
||||
59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStrokeLayer.h; sourceTree = "<group>"; };
|
||||
59EB75A523905F6E00F5AE63 /* IJSVGParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGParser.m; sourceTree = "<group>"; };
|
||||
59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRadialGradient.m; sourceTree = "<group>"; };
|
||||
@@ -222,10 +239,9 @@
|
||||
59EB75BB23905F7000F5AE63 /* IJSVGPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGPattern.h; sourceTree = "<group>"; };
|
||||
59EB75BC23905F7000F5AE63 /* IJSVGLayerTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLayerTree.h; sourceTree = "<group>"; };
|
||||
59EB75BD23905F7000F5AE63 /* IJSVGExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporter.m; sourceTree = "<group>"; };
|
||||
59EB75BE23905F7000F5AE63 /* IJSVGCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGCache.h; path = ../../../../source/IJSVGCache.h; sourceTree = "<group>"; };
|
||||
59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGPatternLayer.h; sourceTree = "<group>"; };
|
||||
59EB75C023905F7100F5AE63 /* IJSVGText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGText.m; sourceTree = "<group>"; };
|
||||
59EB75C123905F7100F5AE63 /* IJSVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGView.m; path = ../../../../source/IJSVGView.m; sourceTree = "<group>"; };
|
||||
59EB75C123905F7100F5AE63 /* IJSVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGView.m; sourceTree = "<group>"; };
|
||||
59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLinearGradient.m; sourceTree = "<group>"; };
|
||||
59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGBezierPathAdditions.h; sourceTree = "<group>"; };
|
||||
59EB75C423905F7100F5AE63 /* IJSVGStyleSheetSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetSelector.m; sourceTree = "<group>"; };
|
||||
@@ -237,7 +253,7 @@
|
||||
59EB75CA23905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandSmoothQuadraticCurve.h; sourceTree = "<group>"; };
|
||||
59EB75CB23905F7200F5AE63 /* IJSVGCommandEllipticalArc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandEllipticalArc.m; sourceTree = "<group>"; };
|
||||
59EB75CC23905F7200F5AE63 /* IJSVGGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroup.m; sourceTree = "<group>"; };
|
||||
59EB75CD23905F7200F5AE63 /* IJSVGView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGView.h; path = ../../../../source/IJSVGView.h; sourceTree = "<group>"; };
|
||||
59EB75CD23905F7200F5AE63 /* IJSVGView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGView.h; sourceTree = "<group>"; };
|
||||
59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGForeignObject.h; sourceTree = "<group>"; };
|
||||
59EB75CF23905F7200F5AE63 /* IJSVGExporterPathInstruction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporterPathInstruction.m; sourceTree = "<group>"; };
|
||||
59EB75D023905F7200F5AE63 /* IJSVGImageLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImageLayer.h; sourceTree = "<group>"; };
|
||||
@@ -346,6 +362,8 @@
|
||||
592ABBE62397A00C00F44380 /* Parsing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59E7CFAD23B148600077D599 /* IJSVGCommandParser.h */,
|
||||
59E7CFAE23B148600077D599 /* IJSVGCommandParser.m */,
|
||||
59EB75A723905F6F00F5AE63 /* IJSVGParser.h */,
|
||||
59EB75A523905F6E00F5AE63 /* IJSVGParser.m */,
|
||||
);
|
||||
@@ -394,6 +412,12 @@
|
||||
59EB75BA23905F7000F5AE63 /* IJSVGUnitLength.m */,
|
||||
59EB759423905F6D00F5AE63 /* IJSVGUtils.h */,
|
||||
59EB758023905F6C00F5AE63 /* IJSVGUtils.m */,
|
||||
5919E65523F47FF60051873A /* IJSVGUnitRect.h */,
|
||||
5919E65623F47FF60051873A /* IJSVGUnitRect.m */,
|
||||
5919E65923F480330051873A /* IJSVGUnitPoint.h */,
|
||||
5919E65A23F480330051873A /* IJSVGUnitPoint.m */,
|
||||
59A24EBA23F480EA0090C374 /* IJSVGUnitSize.h */,
|
||||
59A24EBB23F480EA0090C374 /* IJSVGUnitSize.m */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
@@ -429,6 +453,8 @@
|
||||
59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */,
|
||||
59EB75B823905F7000F5AE63 /* IJSVGStringAdditions.h */,
|
||||
59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */,
|
||||
594A10D8248D7C90001A3181 /* NSImage+IJSVGAdditions.h */,
|
||||
594A10D9248D7C90001A3181 /* NSImage+IJSVGAdditions.m */,
|
||||
);
|
||||
path = Additions;
|
||||
sourceTree = "<group>";
|
||||
@@ -470,9 +496,28 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
59DD1FD123A22CFD00E28C56 /* Core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59EB756A23905F6B00F5AE63 /* IJSVG.h */,
|
||||
59EB75A223905F6E00F5AE63 /* IJSVG.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 = Core;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
59EB756423905F3100F5AE63 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59DD1FD123A22CFD00E28C56 /* Core */,
|
||||
592ABBEB2397A11800F44380 /* Additions */,
|
||||
592ABBEA2397A10000F44380 /* Rendering */,
|
||||
592ABBE92397A08500F44380 /* Exporter */,
|
||||
@@ -483,19 +528,6 @@
|
||||
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 = "<group>";
|
||||
@@ -537,7 +569,6 @@
|
||||
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 */,
|
||||
@@ -559,9 +590,14 @@
|
||||
59EB761823905F7300F5AE63 /* IJSVGParser.h in Headers */,
|
||||
59EB761E23905F7300F5AE63 /* IJSVGGroupLayer.h in Headers */,
|
||||
59EB761D23905F7300F5AE63 /* IJSVGStyle.h in Headers */,
|
||||
5919E65723F47FF60051873A /* IJSVGUnitRect.h in Headers */,
|
||||
5919E65B23F480330051873A /* IJSVGUnitPoint.h in Headers */,
|
||||
59A24EBC23F480EA0090C374 /* IJSVGUnitSize.h in Headers */,
|
||||
59EB764523905F7300F5AE63 /* IJSVGExporter.h in Headers */,
|
||||
59E7CFAF23B148600077D599 /* IJSVGCommandParser.h in Headers */,
|
||||
59EB762823905F7300F5AE63 /* IJSVGCommandClose.h in Headers */,
|
||||
59EB75E423905F7300F5AE63 /* IJSVGGradientUnitLength.h in Headers */,
|
||||
594A10DA248D7C90001A3181 /* NSImage+IJSVGAdditions.h in Headers */,
|
||||
59EB762D23905F7300F5AE63 /* IJSVGLayerTree.h in Headers */,
|
||||
59EB760B23905F7300F5AE63 /* IJSVGStyleSheetSelector.h in Headers */,
|
||||
);
|
||||
@@ -594,7 +630,7 @@
|
||||
594CF466238FF38E009B251B /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1100;
|
||||
LastUpgradeCheck = 1220;
|
||||
ORGANIZATIONNAME = "Curtis Hard";
|
||||
TargetAttributes = {
|
||||
594CF46E238FF38E009B251B = {
|
||||
@@ -636,6 +672,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
59EB763123905F7300F5AE63 /* IJSVGText.m in Sources */,
|
||||
59A24EBD23F480EA0090C374 /* IJSVGUnitSize.m in Sources */,
|
||||
59EB760223905F7300F5AE63 /* IJSVGCommandVerticalLine.m in Sources */,
|
||||
59EB75FD23905F7300F5AE63 /* IJSVGPatternLayer.m in Sources */,
|
||||
59EB763923905F7300F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m in Sources */,
|
||||
@@ -646,6 +683,7 @@
|
||||
59EB761123905F7300F5AE63 /* IJSVGCommand.m in Sources */,
|
||||
59EB760923905F7300F5AE63 /* IJSVGCommandCurve.m in Sources */,
|
||||
59EB763323905F7300F5AE63 /* IJSVGLinearGradient.m in Sources */,
|
||||
594A10DB248D7C90001A3181 /* NSImage+IJSVGAdditions.m in Sources */,
|
||||
59EB761923905F7300F5AE63 /* IJSVGCommandSmoothCurve.m in Sources */,
|
||||
59EB761323905F7300F5AE63 /* IJSVG.m in Sources */,
|
||||
59EB763623905F7300F5AE63 /* IJSVGImageLayer.m in Sources */,
|
||||
@@ -653,10 +691,11 @@
|
||||
59EB75E523905F7300F5AE63 /* IJSVGStrokeLayer.m in Sources */,
|
||||
59EB763223905F7300F5AE63 /* IJSVGView.m in Sources */,
|
||||
59EB763523905F7300F5AE63 /* IJSVGStyleSheetSelector.m in Sources */,
|
||||
59E7CFB023B148600077D599 /* IJSVGCommandParser.m in Sources */,
|
||||
59EB760723905F7300F5AE63 /* IJSVGNode.m in Sources */,
|
||||
5919E65C23F480330051873A /* IJSVGUnitPoint.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 */,
|
||||
@@ -666,6 +705,7 @@
|
||||
59EB75EB23905F7300F5AE63 /* IJSVGShapeLayer.m in Sources */,
|
||||
59EB75F623905F7300F5AE63 /* IJSVGColor.m in Sources */,
|
||||
59EB75F323905F7300F5AE63 /* IJSVGGroupLayer.m in Sources */,
|
||||
5919E65823F47FF60051873A /* IJSVGUnitRect.m in Sources */,
|
||||
59EB762523905F7300F5AE63 /* IJSVGTransform.m in Sources */,
|
||||
59EB760023905F7300F5AE63 /* IJSVGGradientLayer.m in Sources */,
|
||||
59EB762B23905F7300F5AE63 /* IJSVGUnitLength.m in Sources */,
|
||||
@@ -723,6 +763,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -738,6 +779,7 @@
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREFIX_HEADER = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
@@ -784,6 +826,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -797,6 +840,7 @@
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREFIX_HEADER = "";
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -820,6 +864,7 @@
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
DEFINES_MODULE = NO;
|
||||
DEVELOPMENT_TEAM = 9KTR4W9XX6;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -832,7 +877,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1;
|
||||
MARKETING_VERSION = 2.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -847,6 +892,7 @@
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
DEFINES_MODULE = NO;
|
||||
DEVELOPMENT_TEAM = 9KTR4W9XX6;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -859,7 +905,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1;
|
||||
MARKETING_VERSION = 2.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
||||
BIN
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1120"
|
||||
LastUpgradeVersion = "1220"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>594CF46E238FF38E009B251B</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
<true />
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2019 Curtis Hard. All rights reserved.</string>
|
||||
<string>Copyright © 2020 Curtis Hard. All rights reserved.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -14,4 +14,6 @@
|
||||
- (void)addQuadCurveToPoint:(NSPoint)aPoint
|
||||
controlPoint:(NSPoint)cp;
|
||||
|
||||
- (CGPathRef)newCGPathRef:(BOOL)autoClose;
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,4 +23,65 @@
|
||||
controlPoint2:CP2];
|
||||
}
|
||||
|
||||
- (CGPathRef)newCGPathRef:(BOOL)autoClose
|
||||
{
|
||||
NSInteger i = 0;
|
||||
NSInteger numElements = self.elementCount;
|
||||
NSBezierPath* bezPath = self;
|
||||
|
||||
// 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
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
|
||||
@interface NSString (IJSVGAdditions)
|
||||
|
||||
- (NSArray<NSString *> *)ijsvg_componentsSeparatedByChars:(char *)aChar;
|
||||
- (NSArray<NSString*>*)ijsvg_componentsSeparatedByChars:(const char*)aChar;
|
||||
- (BOOL)ijsvg_isNumeric;
|
||||
- (BOOL)ijsvg_containsAlpha;
|
||||
- (NSArray*)ijsvg_componentsSplitByWhiteSpace;
|
||||
- (BOOL)ijsvg_isHexString;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@implementation NSString (IJSVGAdditions)
|
||||
|
||||
- (NSArray<NSString*>*)ijsvg_componentsSeparatedByChars:(char*)aChar
|
||||
- (NSArray<NSString*>*)ijsvg_componentsSeparatedByChars:(const char*)aChar
|
||||
{
|
||||
NSMutableArray* comp = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSInteger length = self.length;
|
||||
@@ -18,25 +18,13 @@
|
||||
|
||||
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) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
};
|
||||
const char* buffer = self.UTF8String;
|
||||
|
||||
for (NSInteger i = 0; i < length; i++) {
|
||||
|
||||
// the char
|
||||
unichar theChar = [self characterAtIndex:i];
|
||||
unichar theChar = buffer[i];
|
||||
|
||||
// start the buffer
|
||||
BOOL isEqualToChar = charsContainsChar(theChar);
|
||||
BOOL isEqualToChar = strchr(aChar, theChar) != NULL;
|
||||
if (isEqualToChar == NO) {
|
||||
startedString = YES;
|
||||
chars[ind++] = theChar;
|
||||
@@ -48,11 +36,10 @@
|
||||
|
||||
// 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 = memset(chars, '\0', sizeof(unichar) * ind);
|
||||
}
|
||||
}
|
||||
free(chars);
|
||||
@@ -62,9 +49,9 @@
|
||||
- (BOOL)ijsvg_containsAlpha
|
||||
{
|
||||
const char* buffer = self.UTF8String;
|
||||
unsigned long length = strlen(buffer);
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (isalpha(buffer[i])) {
|
||||
char currentChar;
|
||||
while((currentChar = *buffer++) ) {
|
||||
if (isalpha(currentChar)) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
@@ -74,9 +61,9 @@
|
||||
- (BOOL)ijsvg_isNumeric
|
||||
{
|
||||
const char* buffer = self.UTF8String;
|
||||
unsigned long length = strlen(buffer);
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (!isnumber(buffer[i])) {
|
||||
char currentChar;
|
||||
while((currentChar = *buffer++) ) {
|
||||
if (!isnumber(currentChar)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
@@ -88,4 +75,20 @@
|
||||
return [self ijsvg_componentsSeparatedByChars:"\t\n\r "];
|
||||
}
|
||||
|
||||
- (BOOL)ijsvg_isHexString
|
||||
{
|
||||
const char* chars = self.UTF8String;
|
||||
char c;
|
||||
while((c = *chars++)) {
|
||||
BOOL flag = ((c == '#') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F'));
|
||||
if(flag == NO) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// NSImage+IJSVGAdditions.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 07/06/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
IJSVG* IJSVGGetFromNSImage(NSImage* image);
|
||||
|
||||
@interface NSImage (IJSVGAdditions)
|
||||
|
||||
+ (NSImage*)SVGImageNamed:(NSString*)imageName;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// NSImage+IJSVGAdditions.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 07/06/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGImageRep.h"
|
||||
#import "NSImage+IJSVGAdditions.h"
|
||||
|
||||
IJSVG* IJSVGGetFromNSImage(NSImage* image)
|
||||
{
|
||||
for (NSImageRep* rep in image.representations) {
|
||||
if ([rep isKindOfClass:IJSVGImageRep.class]) {
|
||||
return ((IJSVGImageRep*)rep).SVG;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@implementation NSImage (IJSVGAdditions)
|
||||
|
||||
+ (NSImage*)SVGImageNamed:(NSString*)imageName
|
||||
{
|
||||
// find the image
|
||||
NSBundle* bundle = NSBundle.mainBundle;
|
||||
NSString* str = nil;
|
||||
NSString* ext = imageName.pathExtension;
|
||||
if (ext == nil || ext.length == 0) {
|
||||
ext = @"svg";
|
||||
}
|
||||
|
||||
if ((str = [bundle pathForResource:imageName.stringByDeletingPathExtension
|
||||
ofType:ext])
|
||||
!= nil) {
|
||||
|
||||
// work out if we can get the data
|
||||
NSData* data = [[[NSData alloc] initWithContentsOfFile:str] autorelease];
|
||||
if (data == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// grab the image rep
|
||||
IJSVGImageRep* rep = [[[IJSVGImageRep alloc] initWithData:data] autorelease];
|
||||
NSImage* image = [[[NSImage alloc] init] autorelease];
|
||||
[image addRepresentation:rep];
|
||||
return image;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "IJSVGColor.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import "IJSVGStringAdditions.h"
|
||||
|
||||
@implementation IJSVGColor
|
||||
|
||||
@@ -385,8 +386,8 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
|
||||
}
|
||||
|
||||
// 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)];
|
||||
return [NSString stringWithFormat:@"rgba(%d,%d,%d,%@)", red, green, blue,
|
||||
IJSVGShortFloatString((float)alpha / 100.f)];
|
||||
}
|
||||
|
||||
+ (NSString*)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color
|
||||
@@ -707,14 +708,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
|
||||
|
||||
+ (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;
|
||||
return string.ijsvg_isHexString;
|
||||
}
|
||||
|
||||
+ (unsigned long)lengthOfHEXInteger:(NSUInteger)hex
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGCommandParser.h"
|
||||
#import "IJSVGPath.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@@ -16,14 +17,9 @@ typedef NS_ENUM(NSInteger, IJSVGCommandType) {
|
||||
kIJSVGCommandTypeRelative
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, IJSVGPathDataSequence) {
|
||||
kIJSVGPathDataSequenceTypeFloat,
|
||||
kIJSVGPathDataSequenceTypeFlag
|
||||
};
|
||||
|
||||
@interface IJSVGCommand : NSObject {
|
||||
NSString* commandString;
|
||||
NSString* command;
|
||||
char command;
|
||||
CGFloat* parameters;
|
||||
NSInteger parameterCount;
|
||||
NSArray<IJSVGCommand*>* subCommands;
|
||||
@@ -35,10 +31,9 @@ typedef NS_ENUM(NSUInteger, IJSVGPathDataSequence) {
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) NSString* commandString;
|
||||
@property (nonatomic, copy) NSString* command;
|
||||
@property (nonatomic, assign) char 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<IJSVGCommand*>* subCommands;
|
||||
@property (nonatomic, assign) IJSVGCommand* previousCommand;
|
||||
@@ -60,8 +55,10 @@ typedef NS_ENUM(NSUInteger, IJSVGPathDataSequence) {
|
||||
intoArray:(NSMutableArray<IJSVGCommand*>*)commands
|
||||
parentCommand:(IJSVGCommand*)parentCommand;
|
||||
|
||||
- (id)initWithCommandString:(NSString*)commandString;
|
||||
- (id)initWithCommandStringBuffer:(const char*)str
|
||||
dataStream:(IJSVGPathDataStream*)dataStream;
|
||||
- (IJSVGCommand*)subcommandWithParameters:(CGFloat*)subParams
|
||||
paramCount:(NSInteger)paramCount
|
||||
previousCommand:(IJSVGCommand*)command;
|
||||
|
||||
- (CGFloat)readFloat;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
@synthesize parameterCount;
|
||||
@synthesize parameters;
|
||||
@synthesize subCommands;
|
||||
@synthesize requiredParameters;
|
||||
@synthesize type;
|
||||
@synthesize previousCommand;
|
||||
@synthesize isSubCommand;
|
||||
@@ -105,7 +104,6 @@
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([commandString release]), commandString = nil;
|
||||
(void)([command release]), command = nil;
|
||||
(void)([subCommands release]), subCommands = nil;
|
||||
if (parameters) {
|
||||
(void)(free(parameters)), parameters = nil;
|
||||
@@ -113,25 +111,27 @@
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithCommandString:(NSString*)str
|
||||
- (id)initWithCommandStringBuffer:(const char*)str
|
||||
dataStream:(IJSVGPathDataStream*)dataStream
|
||||
{
|
||||
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];
|
||||
command = str[0];
|
||||
type = [IJSVGUtils typeForCommandChar:command];
|
||||
NSInteger sets = 0;
|
||||
NSInteger paramCount = [self.class requiredParameterCount];
|
||||
IJSVGPathDataSequence* sequence = [self.class pathDataSequence];
|
||||
parameters = IJSVGParsePathDataSequence(str, sequence, requiredParameters, &sets);
|
||||
parameters = IJSVGParsePathDataStreamSequence(str, strlen(str),
|
||||
dataStream, sequence, [self.class requiredParameterCount], &sets);
|
||||
|
||||
if (sets <= 1) {
|
||||
CGFloat* subParams = [self parametersFromIndexOffset:0];
|
||||
IJSVGCommand* command = [self subcommandWithParameters:subParams
|
||||
paramCount:paramCount
|
||||
previousCommand:nil];
|
||||
subCommands = @[ command ].retain;
|
||||
} else {
|
||||
|
||||
NSMutableArray<IJSVGCommand*>* subCommandArray = nil;
|
||||
subCommandArray = [[NSMutableArray alloc] initWithCapacity:sets].autorelease;
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
|
||||
// generate the subcommand
|
||||
IJSVGCommand* command = [self subcommandWithParameters:subParams
|
||||
paramCount:paramCount
|
||||
previousCommand:lastCommand];
|
||||
|
||||
// make sure we assign the last command or hell breaks
|
||||
@@ -162,7 +163,7 @@
|
||||
- (CGFloat*)parametersFromIndexOffset:(NSInteger)index
|
||||
{
|
||||
CGFloat* subParams = 0;
|
||||
NSInteger req = self.requiredParameters;
|
||||
NSInteger req = [self.class requiredParameterCount];
|
||||
if (req != 0) {
|
||||
subParams = (CGFloat*)malloc(req * sizeof(CGFloat));
|
||||
memcpy(subParams, &self.parameters[index * req], sizeof(CGFloat) * req);
|
||||
@@ -171,11 +172,12 @@
|
||||
}
|
||||
|
||||
- (IJSVGCommand*)subcommandWithParameters:(CGFloat*)subParams
|
||||
paramCount:(NSInteger)paramCount
|
||||
previousCommand:(IJSVGCommand*)aPreviousCommand
|
||||
{
|
||||
// create a subcommand per set
|
||||
IJSVGCommand* c = [[[self.class alloc] init] autorelease];
|
||||
c.parameterCount = self.requiredParameters;
|
||||
c.parameterCount = paramCount;
|
||||
c.parameters = subParams;
|
||||
c.type = self.type;
|
||||
c.command = self.command;
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
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])];
|
||||
[path.path 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])];
|
||||
[path.path relativeCurveToPoint:NSMakePoint(params[4], params[5])
|
||||
controlPoint1:NSMakePoint(params[0], params[1])
|
||||
controlPoint2:NSMakePoint(params[2], params[3])];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,8 +44,8 @@ static IJSVGPathDataSequence* _sequence;
|
||||
CGPoint arcEndPoint = CGPointZero;
|
||||
CGPoint arcStartPoint = path.currentPoint;
|
||||
CGFloat xAxisRotation = 0;
|
||||
BOOL largeArcFlag = 0;
|
||||
BOOL sweepFlag = 0;
|
||||
BOOL largeArcFlag = NO;
|
||||
BOOL sweepFlag = NO;
|
||||
|
||||
radii = [currentCommand readPoint];
|
||||
xAxisRotation = [currentCommand readFloat];
|
||||
@@ -91,34 +91,26 @@ static IJSVGPathDataSequence* _sequence;
|
||||
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 translateXBy:-centerPoint.x
|
||||
yBy:-centerPoint.y];
|
||||
[trans rotateByRadians:-xAxisRotation];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
|
||||
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 scaleXBy:scale.x yBy:scale.y];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
[trans scaleXBy:(1 / scale.x)
|
||||
yBy:(1 / scale.y)];
|
||||
[path.path transformUsingAffineTransform:trans];
|
||||
|
||||
[path.path appendBezierPathWithArcWithCenter:NSZeroPoint
|
||||
radius:radius
|
||||
startAngle:radians_to_degrees(startAngle)
|
||||
endAngle:radians_to_degrees(startAngle + angleDelta)
|
||||
clockwise:!sweepFlag];
|
||||
|
||||
trans = NSAffineTransform.transform;
|
||||
[trans scaleXBy:scale.x
|
||||
yBy:scale.y];
|
||||
[trans rotateByRadians:xAxisRotation];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
|
||||
trans = NSAffineTransform.transform;
|
||||
[trans translateXBy:centerPoint.x yBy:centerPoint.y];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
[trans translateXBy:centerPoint.x
|
||||
yBy:centerPoint.y];
|
||||
[path.path transformUsingAffineTransform:trans];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
path:(IJSVGPath*)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[[path currentSubpath] lineToPoint:NSMakePoint(params[0], [path currentSubpath].currentPoint.y)];
|
||||
[path.path lineToPoint:NSMakePoint(params[0], path.currentPoint.y)];
|
||||
return;
|
||||
}
|
||||
[[path currentSubpath] relativeLineToPoint:NSMakePoint(params[0], 0.f)];
|
||||
[path.path relativeLineToPoint:NSMakePoint(params[0], 0.f)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
path:(IJSVGPath*)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[[path currentSubpath] lineToPoint:NSMakePoint(params[0], params[1])];
|
||||
[path.path lineToPoint:NSMakePoint(params[0], params[1])];
|
||||
return;
|
||||
}
|
||||
NSPoint point = NSMakePoint([path currentSubpath].currentPoint.x + params[0],
|
||||
[path currentSubpath].currentPoint.y + params[1]);
|
||||
[[path currentSubpath] lineToPoint:point];
|
||||
NSPoint point = NSMakePoint(path.currentPoint.x + params[0],
|
||||
path.currentPoint.y + params[1]);
|
||||
[path.path lineToPoint:point];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -35,17 +35,16 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// actual move to command
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[[path currentSubpath] moveToPoint:NSMakePoint(params[0], params[1])];
|
||||
// actual move to command - do a moveToPoint only
|
||||
// if the type is absolute, or its possible the type is
|
||||
// relative but there is no previous command which means
|
||||
// there is no current point. Asking for current point on an empty
|
||||
// path will result in an exception being thrown
|
||||
if (type == kIJSVGCommandTypeAbsolute || command == nil) {
|
||||
[path.path moveToPoint:NSMakePoint(params[0], params[1])];
|
||||
return;
|
||||
}
|
||||
@try {
|
||||
[[path currentSubpath] relativeMoveToPoint:NSMakePoint(params[0], params[1])];
|
||||
}
|
||||
@catch (NSException* exception) {
|
||||
[[path currentSubpath] moveToPoint:NSMakePoint(params[0], params[1])];
|
||||
}
|
||||
[path.path relativeMoveToPoint:NSMakePoint(params[0], params[1])];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
path:(IJSVGPath*)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[[path currentSubpath] addQuadCurveToPoint:NSMakePoint(params[2], params[3])
|
||||
controlPoint:NSMakePoint(params[0], params[1])];
|
||||
[path.path 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])
|
||||
controlPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[0], [path currentSubpath].currentPoint.y + params[1])];
|
||||
[path.path addQuadCurveToPoint:NSMakePoint(path.currentPoint.x + params[2], path.currentPoint.y + params[3])
|
||||
controlPoint:NSMakePoint(path.currentPoint.x + params[0], path.currentPoint.y + params[1])];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,41 +24,41 @@
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
{
|
||||
NSPoint firstControl = NSMakePoint([path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y);
|
||||
NSPoint firstControl = NSMakePoint(path.currentPoint.x, path.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);
|
||||
firstControl = NSMakePoint(-1 * command.parameters[2] + 2 * path.currentPoint.x,
|
||||
-1 * command.parameters[3] + 2 * path.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);
|
||||
NSPoint oldPoint = NSMakePoint(path.currentPoint.x - command.parameters[4],
|
||||
path.currentPoint.y - command.parameters[5]);
|
||||
firstControl = NSMakePoint(-1 * (command.parameters[2] + oldPoint.x) + 2 * path.currentPoint.x,
|
||||
-1 * (command.parameters[3] + oldPoint.y) + 2 * path.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);
|
||||
firstControl = NSMakePoint(-1 * command.parameters[0] + 2 * path.currentPoint.x,
|
||||
-1 * command.parameters[1] + 2 * path.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);
|
||||
NSPoint oldPoint = NSMakePoint(path.currentPoint.x - command.parameters[2],
|
||||
path.currentPoint.y - command.parameters[3]);
|
||||
firstControl = NSMakePoint(-1 * (command.parameters[0] + oldPoint.x) + 2 * path.currentPoint.x,
|
||||
-1 * (command.parameters[1] + oldPoint.y) + 2 * path.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])];
|
||||
[path.path 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])];
|
||||
[path.path curveToPoint:NSMakePoint(path.currentPoint.x + params[2], path.currentPoint.y + params[3])
|
||||
controlPoint1:NSMakePoint(firstControl.x, firstControl.y)
|
||||
controlPoint2:NSMakePoint(path.currentPoint.x + params[0], path.currentPoint.y + params[1])];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,33 +24,33 @@
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
{
|
||||
NSPoint commandPoint = NSMakePoint([path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y);
|
||||
NSPoint commandPoint = NSMakePoint(path.currentPoint.x, path.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);
|
||||
commandPoint = NSMakePoint(-1 * command.parameters[0] + 2 * path.currentPoint.x,
|
||||
-1 * command.parameters[1] + 2 * path.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);
|
||||
NSPoint oldPoint = CGPointMake(path.currentPoint.x - command.parameters[2],
|
||||
path.currentPoint.y - command.parameters[3]);
|
||||
commandPoint = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * (path.currentPoint.x),
|
||||
-1 * (command.parameters[1] + oldPoint.y) + 2 * path.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);
|
||||
commandPoint = CGPointMake(-1 * (path.lastControlPoint.x) + 2 * (path.currentPoint.x),
|
||||
-1 * (path.lastControlPoint.y) + 2 * path.currentPoint.y);
|
||||
}
|
||||
}
|
||||
path.lastControlPoint = commandPoint;
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[[path currentSubpath] addQuadCurveToPoint:NSMakePoint(params[0], params[1])
|
||||
controlPoint:commandPoint];
|
||||
[path.path 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];
|
||||
[path.path addQuadCurveToPoint:NSMakePoint(path.currentPoint.x + params[0], path.currentPoint.y + params[1])
|
||||
controlPoint:commandPoint];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
path:(IJSVGPath*)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[[path currentSubpath] lineToPoint:NSMakePoint([path currentSubpath].currentPoint.x, params[0])];
|
||||
[path.path lineToPoint:NSMakePoint(path.currentPoint.x, params[0])];
|
||||
return;
|
||||
}
|
||||
[[path currentSubpath] relativeLineToPoint:NSMakePoint(0.f, params[0])];
|
||||
[path.path relativeLineToPoint:NSMakePoint(0.f, params[0])];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
id<IJSVGDelegate> _delegate;
|
||||
IJSVGLayer* _layerTree;
|
||||
CGRect _viewBox;
|
||||
CGSize _proposedViewSize;
|
||||
CGFloat _backingScaleFactor;
|
||||
CGFloat _lastProposedBackingScale;
|
||||
IJSVGRenderQuality _lastProposedRenderQuality;
|
||||
CGFloat _backingScale;
|
||||
@@ -67,7 +67,10 @@
|
||||
// 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* renderingStyle;
|
||||
@property (nonatomic, readonly) IJSVGUnitSize * intrinsicSize;
|
||||
@property (nonatomic, copy) NSString* title;
|
||||
@property (nonatomic, copy) NSString* desc;
|
||||
|
||||
- (void)prepForDrawingInView:(NSView*)view;
|
||||
- (BOOL)isFont;
|
||||
@@ -79,6 +82,8 @@
|
||||
- (IJSVGLayer*)layerWithTree:(IJSVGLayerTree*)tree;
|
||||
- (NSArray<IJSVG*>*)subSVGs:(BOOL)recursive;
|
||||
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options;
|
||||
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
|
||||
- (CGFloat)computeBackingScale:(CGFloat)scale;
|
||||
- (void)discardDOM;
|
||||
@@ -86,9 +91,6 @@
|
||||
+ (id)svgNamed:(NSString*)string;
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
useCache:(BOOL)useCache
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
|
||||
- (id)initWithImage:(NSImage*)image;
|
||||
|
||||
@@ -103,8 +105,10 @@
|
||||
- (id)initWithSVGString:(NSString*)string
|
||||
error:(NSError**)error;
|
||||
|
||||
- (id)initWithFile:(NSString*)file
|
||||
useCache:(BOOL)useCache;
|
||||
- (id)initWithSVGData:(NSData*)data;
|
||||
- (id)initWithSVGData:(NSData*)data
|
||||
error:(NSError**)error;
|
||||
|
||||
- (id)initWithFile:(NSString*)file;
|
||||
- (id)initWithFile:(NSString*)file
|
||||
error:(NSError**)error;
|
||||
@@ -113,19 +117,12 @@
|
||||
- (id)initWithFile:(NSString*)file
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
- (id)initWithFile:(NSString*)file
|
||||
useCache:(BOOL)useCache
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL;
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
useCache:(BOOL)useCache;
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
error:(NSError**)error;
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
useCache:(BOOL)useCache
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
- (NSImage*)imageWithSize:(NSSize)aSize;
|
||||
@@ -133,9 +130,16 @@
|
||||
error:(NSError**)error;
|
||||
- (NSImage*)imageWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped;
|
||||
- (NSImage*)imageWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError**)error;
|
||||
- (NSImage*)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError**)error;
|
||||
- (CGImageRef)newCGImageRefWithSize:(CGSize)size
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError**)error;
|
||||
|
||||
- (BOOL)drawAtPoint:(NSPoint)point
|
||||
size:(NSSize)size;
|
||||
- (BOOL)drawAtPoint:(NSPoint)point
|
||||
@@ -161,4 +165,5 @@
|
||||
|
||||
// colors
|
||||
- (IJSVGColorList*)computedColorList:(BOOL*)hasPatternFills;
|
||||
- (void)performBlock:(dispatch_block_t)block;
|
||||
@end
|
||||
@@ -7,64 +7,63 @@
|
||||
//
|
||||
|
||||
#import "IJSVG.h"
|
||||
#import "IJSVGCache.h"
|
||||
#import "IJSVGExporter.h"
|
||||
#import "IJSVGTransaction.h"
|
||||
|
||||
@implementation IJSVG
|
||||
|
||||
@synthesize title = _title;
|
||||
@synthesize desc = _desc;
|
||||
@synthesize renderingBackingScaleHelper;
|
||||
@synthesize clipToViewport;
|
||||
@synthesize renderQuality;
|
||||
@synthesize style = _style;
|
||||
@synthesize renderingStyle = _renderingStyle;
|
||||
@synthesize intrinsicSize = _intrinsicSize;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
IJSVGBeginTransactionLock();
|
||||
// this can all be called on the background thread to be released
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
(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();
|
||||
(void)([_renderingStyle release]), _renderingStyle = nil;
|
||||
(void)([_group release]), _group = nil;
|
||||
(void)([_intrinsicSize release]), _intrinsicSize = nil;
|
||||
(void)([_desc release]), _desc = nil;
|
||||
(void)([_title release]), _title = nil;
|
||||
|
||||
// kill any memory that has been around
|
||||
(void)([_layerTree release]), _layerTree = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string error:(NSError**)error
|
||||
{
|
||||
return [self.class svgNamed:string error:error delegate:nil];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
{
|
||||
return [self.class svgNamed:string error:nil];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
useCache:(BOOL)useCache
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self.class svgNamed:string
|
||||
useCache:useCache
|
||||
error:nil
|
||||
delegate:delegate];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self.class svgNamed:string error:nil delegate:delegate];
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self svgNamed:string useCache:YES error:error delegate:delegate];
|
||||
return [self.class svgNamed:string
|
||||
error:error
|
||||
delegate:nil];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
{
|
||||
return [self.class svgNamed:string
|
||||
error:nil];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self.class svgNamed:string
|
||||
error:nil
|
||||
delegate:delegate];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
useCache:(BOOL)useCache
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
@@ -78,7 +77,6 @@
|
||||
ofType:ext])
|
||||
!= nil) {
|
||||
return [[[self alloc] initWithFile:str
|
||||
useCache:useCache
|
||||
error:error
|
||||
delegate:delegate] autorelease];
|
||||
}
|
||||
@@ -90,20 +88,23 @@
|
||||
__block IJSVGGroupLayer* layer = nil;
|
||||
__block IJSVGImageLayer* imageLayer = nil;
|
||||
|
||||
// make sure we obtain a lock, with whatever we do with layers!
|
||||
IJSVGBeginTransactionLock();
|
||||
// create the layers we require
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
layer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
imageLayer =
|
||||
[[[IJSVGImageLayer alloc] initWithImage:image] autorelease];
|
||||
[layer addSublayer:imageLayer];
|
||||
IJSVGEndTransactionLock();
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -119,91 +120,63 @@
|
||||
|
||||
- (id)initWithFile:(NSString*)file
|
||||
{
|
||||
return [self initWithFile:file delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFile:(NSString*)file useCache:(BOOL)useCache
|
||||
{
|
||||
return [self initWithFile:file useCache:useCache error:nil delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFile:(NSString*)file
|
||||
useCache:(BOOL)useCache
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self initWithFilePathURL:[NSURL fileURLWithPath:file]
|
||||
useCache:useCache
|
||||
error:error
|
||||
delegate:delegate];
|
||||
}
|
||||
|
||||
- (id)initWithFile:(NSString*)file error:(NSError**)error
|
||||
{
|
||||
return [self initWithFile:file error:error delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFile:(NSString*)file delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self initWithFile:file error:nil delegate:delegate];
|
||||
return [self initWithFile:file
|
||||
error:nil
|
||||
delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFile:(NSString*)file
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self initWithFilePathURL:[NSURL fileURLWithPath:file]
|
||||
useCache:YES
|
||||
return [self initWithFilePathURL:[NSURL fileURLWithPath:file isDirectory:NO]
|
||||
error:error
|
||||
delegate:delegate];
|
||||
}
|
||||
|
||||
- (id)initWithFile:(NSString*)file
|
||||
error:(NSError**)error
|
||||
{
|
||||
return [self initWithFile:file
|
||||
error:error
|
||||
delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFile:(NSString*)file
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self initWithFile:file
|
||||
error:nil
|
||||
delegate:delegate];
|
||||
}
|
||||
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
{
|
||||
return [self initWithFilePathURL:aURL useCache:YES error:nil delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL error:(NSError**)error
|
||||
{
|
||||
return [self initWithFilePathURL:aURL
|
||||
useCache:YES
|
||||
error:error
|
||||
delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL useCache:(BOOL)useCache
|
||||
{
|
||||
return [self initWithFilePathURL:aURL
|
||||
useCache:useCache
|
||||
error:nil
|
||||
delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL delegate:(id<IJSVGDelegate>)delegate
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
error:(NSError**)error
|
||||
{
|
||||
return [self initWithFilePathURL:aURL
|
||||
error:error
|
||||
delegate:nil];
|
||||
}
|
||||
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [self initWithFilePathURL:aURL
|
||||
useCache:YES
|
||||
error:nil
|
||||
delegate:delegate];
|
||||
}
|
||||
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
useCache:(BOOL)useCache
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
#ifndef __clang_analyzer__
|
||||
|
||||
// check the cache first
|
||||
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;
|
||||
@@ -214,8 +187,9 @@
|
||||
[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];
|
||||
@@ -228,24 +202,38 @@
|
||||
(void)([self release]), self = nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// cache the file
|
||||
if (useCache && [IJSVGCache enabled]) {
|
||||
[IJSVGCache cacheSVG:self fileURL:aURL];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithSVGData:(NSData*)data
|
||||
{
|
||||
return [self initWithSVGData:data
|
||||
error:nil];
|
||||
}
|
||||
|
||||
- (id)initWithSVGData:(NSData*)data
|
||||
error:(NSError**)error
|
||||
{
|
||||
NSString* svgString = [[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding];
|
||||
return [self initWithSVGString:svgString.autorelease
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (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
|
||||
@@ -279,6 +267,15 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)performBlock:(dispatch_block_t)block
|
||||
{
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
block();
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)discardDOM
|
||||
{
|
||||
// if we discard, we can no longer create a tree, so lets create tree
|
||||
@@ -291,24 +288,43 @@
|
||||
|
||||
- (void)_setupBasicInfoFromGroup
|
||||
{
|
||||
// store the viewbox
|
||||
_viewBox = _group.viewBox;
|
||||
_proposedViewSize = _group.proposedViewSize;
|
||||
_intrinsicSize = _group.intrinsicSize.retain;
|
||||
}
|
||||
|
||||
- (void)_setupBasicsFromAnyInitializer
|
||||
{
|
||||
self.style = [[[IJSVGRenderingStyle alloc] init] autorelease];
|
||||
self.renderingStyle = [[[IJSVGRenderingStyle alloc] init] autorelease];
|
||||
self.clipToViewport = YES;
|
||||
self.renderQuality = kIJSVGRenderQualityFullResolution;
|
||||
|
||||
// setup low level backing scale
|
||||
_lastProposedBackingScale = 0.f;
|
||||
self.renderingBackingScaleHelper = ^CGFloat {
|
||||
return 1.f;
|
||||
return NSScreen.mainScreen.backingScaleFactor;
|
||||
};
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSString*)title
|
||||
{
|
||||
_group.title = title;
|
||||
}
|
||||
|
||||
- (NSString*)title
|
||||
{
|
||||
return _group.title;
|
||||
}
|
||||
|
||||
- (void)setDesc:(NSString*)description
|
||||
{
|
||||
_group.desc = description;
|
||||
}
|
||||
|
||||
- (NSString*)desc
|
||||
{
|
||||
return _group.desc;
|
||||
}
|
||||
|
||||
- (NSString*)identifier
|
||||
{
|
||||
return _group.identifier;
|
||||
@@ -351,51 +367,117 @@
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
IJSVGExporter* exporter = [[[IJSVGExporter alloc] initWithSVG:self
|
||||
size:self.viewBox.size
|
||||
options:options
|
||||
floatingPointOptions:floatingPointOptions] autorelease];
|
||||
return [exporter SVGString];
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (NSSize)computeSVGSizeWithRenderSize:(NSSize)size
|
||||
{
|
||||
IJSVGUnitSize* svgSize = _intrinsicSize;
|
||||
return NSMakeSize([svgSize.width computeValue:size.width],
|
||||
[svgSize.height computeValue:size.height]);
|
||||
}
|
||||
|
||||
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize
|
||||
{
|
||||
[self _beginDraw:(NSRect){ .origin = CGPointZero, .size = aSize }];
|
||||
return NSMakeRect(0.f, 0.f, _proposedViewSize.width * _clipScale,
|
||||
_proposedViewSize.height * _clipScale);
|
||||
NSSize propSize = [self computeSVGSizeWithRenderSize:aSize];
|
||||
[self _beginDraw:(NSRect) { .origin = CGPointZero, .size = aSize }];
|
||||
return NSMakeRect(0.f, 0.f, propSize.width * _clipScale,
|
||||
propSize.height * _clipScale);
|
||||
}
|
||||
|
||||
- (CGImageRef)newCGImageRefWithSize:(CGSize)size
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError**)error
|
||||
{
|
||||
// setup the drawing rect, this is used for both the intial drawing
|
||||
// and the backing scale helper block
|
||||
NSRect rect = (CGRect) {
|
||||
.origin = CGPointZero,
|
||||
.size = (CGSize)size
|
||||
};
|
||||
|
||||
// this is highly important this is setup
|
||||
[self _beginDraw:rect];
|
||||
|
||||
// make sure we setup the scale based on the backing scale factor
|
||||
CGFloat scale = [self backingScaleFactor:NULL];
|
||||
|
||||
// create the context and colorspace
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef ref = CGBitmapContextCreate(NULL, (int)size.width * scale,
|
||||
(int)size.height * scale, 8, 0, colorSpace,
|
||||
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
|
||||
|
||||
// scale the context
|
||||
CGContextScaleCTM(ref, scale, scale);
|
||||
|
||||
if (flipped == YES) {
|
||||
CGContextTranslateCTM(ref, 0.f, size.height);
|
||||
CGContextScaleCTM(ref, 1.f, -1.f);
|
||||
}
|
||||
|
||||
// draw the SVG into the context
|
||||
[self _drawInRect:rect
|
||||
context:ref
|
||||
error:error];
|
||||
|
||||
// create the image from the context
|
||||
CGImageRef imageRef = CGBitmapContextCreateImage(ref);
|
||||
|
||||
// release all things!
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
CGContextRelease(ref);
|
||||
return imageRef;
|
||||
}
|
||||
|
||||
- (NSImage*)imageWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError**)error
|
||||
{
|
||||
NSImage* im = [[[NSImage alloc] initWithSize:aSize] autorelease];
|
||||
[im lockFocus];
|
||||
CGContextRef ref = [[NSGraphicsContext currentContext] CGContext];
|
||||
CGContextSaveGState(ref);
|
||||
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];
|
||||
CGContextRestoreGState(ref);
|
||||
[im unlockFocus];
|
||||
return im;
|
||||
CGImageRef ref = [self newCGImageRefWithSize:aSize
|
||||
flipped:flipped
|
||||
error:error];
|
||||
|
||||
NSImage* image = [[NSImage alloc] initWithCGImage:ref
|
||||
size:aSize];
|
||||
CGImageRelease(ref);
|
||||
return image.autorelease;
|
||||
}
|
||||
|
||||
- (NSImage*)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
|
||||
@@ -414,7 +496,7 @@
|
||||
- (NSData*)PDFData:(NSError**)error
|
||||
{
|
||||
return [self
|
||||
PDFDataWithRect:(NSRect){ .origin = NSZeroPoint, .size = _viewBox.size }
|
||||
PDFDataWithRect:(NSRect) { .origin = NSZeroPoint, .size = _viewBox.size }
|
||||
error:error];
|
||||
}
|
||||
|
||||
@@ -423,7 +505,8 @@
|
||||
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];
|
||||
@@ -505,15 +588,21 @@
|
||||
};
|
||||
}
|
||||
|
||||
- (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)
|
||||
[self drawInRect:NSMakeRect(point.x, point.y,
|
||||
aSize.width, aSize.height)
|
||||
error:error];
|
||||
}
|
||||
|
||||
@@ -522,10 +611,17 @@
|
||||
return [self drawInRect:rect error:nil];
|
||||
}
|
||||
|
||||
- (BOOL)drawInRect:(NSRect)rect error:(NSError**)error
|
||||
- (BOOL)drawInRect:(NSRect)rect
|
||||
error:(NSError**)error
|
||||
{
|
||||
CGContextRef currentCGContext;
|
||||
if (@available(macOS 10.10, *)) {
|
||||
currentCGContext = NSGraphicsContext.currentContext.CGContext;
|
||||
} else {
|
||||
currentCGContext = NSGraphicsContext.currentContext.graphicsPort;
|
||||
}
|
||||
return [self _drawInRect:rect
|
||||
context:[[NSGraphicsContext currentContext] CGContext]
|
||||
context:currentCGContext
|
||||
error:error];
|
||||
}
|
||||
|
||||
@@ -535,16 +631,18 @@
|
||||
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);
|
||||
NSSize propSize = [self computeSVGSizeWithRenderSize:rect.size];
|
||||
viewPort.origin.x = round((rect.size.width / 2 - (propSize.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;
|
||||
(rect.size.height / 2 - (propSize.height / 2) * _clipScale) + rect.origin.y);
|
||||
viewPort.size.width = propSize.width * _clipScale;
|
||||
viewPort.size.height = propSize.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) {
|
||||
@@ -556,7 +654,8 @@
|
||||
return viewPort;
|
||||
}
|
||||
|
||||
- (void)drawInRect:(NSRect)rect context:(CGContextRef)context
|
||||
- (void)drawInRect:(NSRect)rect
|
||||
context:(CGContextRef)context
|
||||
{
|
||||
[self _drawInRect:rect context:context error:nil];
|
||||
}
|
||||
@@ -595,14 +694,9 @@
|
||||
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];
|
||||
}
|
||||
[self backingScaleFactor:nil];
|
||||
|
||||
CGInterpolationQuality quality;
|
||||
switch (self.renderQuality) {
|
||||
@@ -619,8 +713,11 @@
|
||||
}
|
||||
}
|
||||
CGContextSetInterpolationQuality(ref, quality);
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
[self.layer renderInContext:ref];
|
||||
IJSVGEndTransactionLock();
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
}
|
||||
} @catch (NSException* exception) {
|
||||
// just catch and give back a drawing error to the caller
|
||||
@@ -634,12 +731,14 @@
|
||||
return (error == nil);
|
||||
}
|
||||
|
||||
- (void)_askHelperForBackingScale
|
||||
- (CGFloat)backingScaleFactor:(CGFloat* _Nullable)proposedBackingScale
|
||||
{
|
||||
CGFloat scale = (self.renderingBackingScaleHelper)();
|
||||
__block CGFloat scale = 1.f;
|
||||
scale = (self.renderingBackingScaleHelper)();
|
||||
if (scale < 1.f) {
|
||||
scale = 1.f;
|
||||
}
|
||||
_backingScaleFactor = scale;
|
||||
|
||||
// make sure we multiple the scale by the scale of the rendered clip
|
||||
// or it will be blurry for gradients and other bitmap drawing
|
||||
@@ -648,12 +747,15 @@
|
||||
// dont do anything, nothing has changed, no point of iterating over
|
||||
// every layer for no reason!
|
||||
if (scale == _lastProposedBackingScale && renderQuality == _lastProposedRenderQuality) {
|
||||
return;
|
||||
return _backingScaleFactor;
|
||||
}
|
||||
|
||||
IJSVGRenderQuality quality = self.renderQuality;
|
||||
_lastProposedBackingScale = scale;
|
||||
_lastProposedRenderQuality = quality;
|
||||
if (proposedBackingScale != nil && proposedBackingScale != NULL) {
|
||||
*proposedBackingScale = scale;
|
||||
}
|
||||
|
||||
// walk the tree
|
||||
void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer, BOOL isMask) {
|
||||
@@ -665,20 +767,27 @@
|
||||
};
|
||||
|
||||
// gogogo
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
[IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block];
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
return _backingScaleFactor;
|
||||
}
|
||||
|
||||
- (IJSVGLayer*)layerWithTree:(IJSVGLayerTree*)tree
|
||||
{
|
||||
// clear memory
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
if (_layerTree != nil) {
|
||||
(void)([_layerTree release]), _layerTree = nil;
|
||||
}
|
||||
|
||||
// force rebuild of the tree
|
||||
IJSVGBeginTransactionLock();
|
||||
_layerTree = [[tree layerForNode:_group] retain];
|
||||
IJSVGEndTransactionLock();
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
return _layerTree;
|
||||
}
|
||||
|
||||
@@ -692,16 +801,16 @@
|
||||
// from this SVG object
|
||||
IJSVGLayerTree* renderer = [[[IJSVGLayerTree alloc] init] autorelease];
|
||||
renderer.viewBox = self.viewBox;
|
||||
renderer.style = self.style;
|
||||
renderer.style = self.renderingStyle;
|
||||
|
||||
// return the rendered layer
|
||||
return [self layerWithTree:renderer];
|
||||
}
|
||||
|
||||
- (void)setStyle:(IJSVGRenderingStyle*)style
|
||||
- (void)setRenderingStyle:(IJSVGRenderingStyle*)style
|
||||
{
|
||||
(void)([_style release]), _style = nil;
|
||||
_style = style.retain;
|
||||
(void)([_renderingStyle release]), _renderingStyle = nil;
|
||||
_renderingStyle = style.retain;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString*)keyPath
|
||||
@@ -710,7 +819,7 @@
|
||||
context:(void*)context
|
||||
{
|
||||
// invalidate the tree if a style is set
|
||||
if (object == _style) {
|
||||
if (object == _renderingStyle) {
|
||||
[self invalidateLayerTree];
|
||||
}
|
||||
}
|
||||
@@ -782,12 +891,13 @@
|
||||
// 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);
|
||||
NSSize propSize = [self computeSVGSizeWithRenderSize:rect.size];
|
||||
_clipScale = MIN(dest.width / propSize.width,
|
||||
dest.height / propSize.height);
|
||||
|
||||
// work out the actual scale based on the clip scale
|
||||
CGFloat w = _proposedViewSize.width * _clipScale;
|
||||
CGFloat h = _proposedViewSize.height * _clipScale;
|
||||
CGFloat w = propSize.width * _clipScale;
|
||||
CGFloat h = propSize.height * _clipScale;
|
||||
_scale = MIN(w / source.width, h / source.height);
|
||||
}
|
||||
|
||||
@@ -813,7 +923,9 @@
|
||||
withSVGString:(NSString*)string
|
||||
{
|
||||
if (_delegate != nil && _respondsTo.shouldHandleSubSVG == 1) {
|
||||
[_delegate svg:self foundSubSVG:subSVG withSVGString:string];
|
||||
[_delegate svg:self
|
||||
foundSubSVG:subSVG
|
||||
withSVGString:string];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,7 +933,8 @@
|
||||
shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject
|
||||
{
|
||||
if (_delegate != nil && _respondsTo.shouldHandleForeignObject == 1) {
|
||||
return [_delegate svg:self shouldHandleForeignObject:foreignObject];
|
||||
return [_delegate svg:self
|
||||
shouldHandleForeignObject:foreignObject];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
@@ -831,7 +944,9 @@
|
||||
document:(NSXMLDocument*)document
|
||||
{
|
||||
if (_delegate != nil && _respondsTo.handleForeignObject == 1) {
|
||||
[_delegate svg:self handleForeignObject:foreignObject document:document];
|
||||
[_delegate svg:self
|
||||
handleForeignObject:foreignObject
|
||||
document:document];
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -104,7 +104,7 @@
|
||||
|
||||
+ (IJSVG*)convertIJSVGPathToSVG:(IJSVGPath*)path
|
||||
{
|
||||
CGPathRef cgPath = [IJSVGUtils newCGPathFromBezierPath:path.path];
|
||||
CGPathRef cgPath = [path.path newCGPathRef:NO];
|
||||
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:cgPath];
|
||||
IJSVG* svg = [self convertPathToSVG:flippedPath];
|
||||
CGPathRelease(flippedPath);
|
||||
@@ -115,7 +115,6 @@
|
||||
+ (IJSVG*)convertPathToSVG:(CGPathRef)path
|
||||
{
|
||||
__block IJSVG* svg = nil;
|
||||
IJSVGBeginTransactionLock();
|
||||
IJSVGGroupLayer* layer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
IJSVGShapeLayer* shape = [[[IJSVGShapeLayer alloc] init] autorelease];
|
||||
[layer addSublayer:shape];
|
||||
@@ -123,7 +122,6 @@
|
||||
CGRect box = CGPathGetPathBoundingBox(path);
|
||||
svg = [[IJSVG alloc] initWithSVGLayer:layer
|
||||
viewBox:box];
|
||||
IJSVGEndTransactionLock();
|
||||
return [svg autorelease];
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
IJSVG* _svg;
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData*)data;
|
||||
|
||||
@property (nonatomic, readonly) CGRect viewBox;
|
||||
@property (nonatomic, readonly) IJSVG* SVG;
|
||||
|
||||
@end
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
@implementation IJSVGImageRep
|
||||
|
||||
@synthesize viewBox = _viewBox;
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[NSBitmapImageRep registerImageRepClass:self];
|
||||
@@ -25,12 +23,20 @@
|
||||
|
||||
+ (NSArray<NSString*>*)imageTypes
|
||||
{
|
||||
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
|
||||
if (@available(macOS 10.10, *)) {
|
||||
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
|
||||
} else {
|
||||
return @[ @"public.svg-image", @"svg" ];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSArray<NSString*>*)imageUnfilteredTypes
|
||||
{
|
||||
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
|
||||
if (@available(macOS 10.10, *)) {
|
||||
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
|
||||
} else {
|
||||
return @[ @"public.svg-image", @"svg" ];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSArray<NSImageRep*>*)imageRepsWithData:(NSData*)data
|
||||
@@ -101,4 +107,9 @@
|
||||
return _svg.viewBox;
|
||||
}
|
||||
|
||||
- (IJSVG*)SVG
|
||||
{
|
||||
return _svg;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -42,7 +42,7 @@
|
||||
if (imageName != nil) {
|
||||
IJSVG* anSVG = [IJSVG svgNamed:imageName];
|
||||
if (tintColor != nil) {
|
||||
anSVG.style.fillColor = tintColor;
|
||||
anSVG.renderingStyle.fillColor = tintColor;
|
||||
}
|
||||
self.SVG = anSVG;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@class IJSVG;
|
||||
|
||||
@@ -32,11 +33,19 @@ typedef NS_OPTIONS(NSInteger, IJSVGExporterOptions) {
|
||||
IJSVGExporterOptionRemoveWidthHeightAttributes = 1 << 13,
|
||||
IJSVGExporterOptionColorAllowRRGGBBAA = 1 << 14,
|
||||
IJSVGExporterOptionRemoveComments = 1 << 15,
|
||||
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef | IJSVGExporterOptionRemoveUselessGroups | IJSVGExporterOptionCreateUseForPaths | IJSVGExporterOptionMoveAttributesToGroup | IJSVGExporterOptionSortAttributes | IJSVGExporterOptionCollapseGroups | IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements | IJSVGExporterOptionScaleToSizeIfNecessary | IJSVGExporterOptionCompressOutput | IJSVGExporterOptionCollapseGradients | IJSVGExporterOptionRemoveWidthHeightAttributes | IJSVGExporterOptionColorAllowRRGGBBAA | IJSVGExporterOptionRemoveComments
|
||||
IJSVGExporterOptionCenterWithinViewBox = 1 << 16,
|
||||
IJSVGExporterOptionRemoveXMLDeclaration = 1 << 17,
|
||||
IJSVGExporterOptionConvertArcs = 1 << 18,
|
||||
IJSVGExporterOptionConvertShapesToPaths = 1 << 19,
|
||||
IJSVGExporterOptionRoundTransforms = 1 << 20,
|
||||
IJSVGExporterOptionRemoveDefaultValues = 1 << 21,
|
||||
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef | IJSVGExporterOptionRemoveUselessGroups | IJSVGExporterOptionCreateUseForPaths | IJSVGExporterOptionMoveAttributesToGroup | IJSVGExporterOptionSortAttributes | IJSVGExporterOptionCollapseGroups | IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements | IJSVGExporterOptionScaleToSizeIfNecessary | IJSVGExporterOptionCompressOutput | IJSVGExporterOptionCollapseGradients | IJSVGExporterOptionRemoveWidthHeightAttributes | IJSVGExporterOptionColorAllowRRGGBBAA | IJSVGExporterOptionRemoveComments | IJSVGExporterOptionCenterWithinViewBox | IJSVGExporterOptionRemoveXMLDeclaration | IJSVGExporterOptionConvertArcs | IJSVGExporterOptionConvertShapesToPaths | IJSVGExporterOptionRoundTransforms | IJSVGExporterOptionRemoveDefaultValues
|
||||
};
|
||||
|
||||
BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option);
|
||||
void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlock enumBlock);
|
||||
const NSArray<NSString*>* IJSVGShortCharacterArray(void);
|
||||
const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes(void);
|
||||
|
||||
@interface IJSVGExporter : NSObject {
|
||||
|
||||
@@ -46,18 +55,25 @@ void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlo
|
||||
IJSVGExporterOptions _options;
|
||||
NSXMLDocument* _dom;
|
||||
NSXMLElement* _defElement;
|
||||
NSXMLElement* _scaledRootNode;
|
||||
NSInteger _idCount;
|
||||
NSInteger _shortIdCount;
|
||||
BOOL _appliedXLink;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) IJSVGFloatingPointOptions floatingPointOptions;
|
||||
@property (nonatomic, copy) NSString* title;
|
||||
@property (nonatomic, copy) NSString* description;
|
||||
|
||||
- (id)initWithSVG:(IJSVG*)svg
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options;
|
||||
- (id)initWithSVG:(IJSVG*)svg
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
|
||||
- (NSString*)SVGString;
|
||||
- (NSData*)SVGData;
|
||||
- (IJSVG*)SVG:(NSError**)error;
|
||||
|
||||
@end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,25 +8,60 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef struct {
|
||||
char instruction;
|
||||
NSArray<NSString*>* params;
|
||||
} IJSVGExporterPathInstructionCommand;
|
||||
|
||||
typedef struct {
|
||||
CGPoint center;
|
||||
CGFloat radius;
|
||||
} IJSVGExporterPathInstructionCircle;
|
||||
|
||||
@interface IJSVGExporterPathInstruction : NSObject {
|
||||
|
||||
@private
|
||||
NSInteger _dataCount;
|
||||
char _instruction;
|
||||
CGFloat* _data;
|
||||
CGFloat* _base;
|
||||
CGFloat* _coords;
|
||||
}
|
||||
|
||||
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path;
|
||||
@property (nonatomic, assign) char instruction;
|
||||
|
||||
void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length, IJSVGFloatingPointOptions options);
|
||||
CGFloat IJSVGExporterPathFloatToFixed(CGFloat number, int precision);
|
||||
IJSVGExporterPathInstructionCommand* IJSVGExporterPathInstructionCommandCopy(IJSVGExporterPathInstructionCommand command);
|
||||
void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand* _Nullable command);
|
||||
|
||||
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
|
||||
- (id)initWithInstruction:(char)instruction
|
||||
dataCount:(NSInteger)floatCount;
|
||||
|
||||
- (void)setInstruction:(char)newInstruction;
|
||||
- (char)instruction;
|
||||
- (CGFloat*)data;
|
||||
- (NSInteger)dataLength;
|
||||
|
||||
+ (void)convertInstructionsToRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions;
|
||||
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions;
|
||||
+ (NSArray<IJSVGExporterPathInstruction*>*)convertInstructionsCurves:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
+ (void)convertInstructionsToMixedAbsoluteRelative:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
+ (void)convertInstructionsDataToRounded:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
+ (void)convertInstructionsToRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
+ (NSString*)pathStringWithInstructionSet:(NSArray<NSValue*>*)instructionSets
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
static NSInteger const kIJSVGExporterPathInstructionFloatPrecision = 3;
|
||||
static CGFloat const kIJSVGExporterPathInstructionErrorThreshold = 1e-2;
|
||||
|
||||
#define IJ_SVG_EXPORT_ROUND(value) IJSVGExporterPathFloatToFixed(value, kIJSVGExporterPathInstructionFloatPrecision)
|
||||
|
||||
@@ -8,13 +8,23 @@
|
||||
|
||||
#import "IJSVGExporter.h"
|
||||
#import "IJSVGExporterPathInstruction.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import <math.h>
|
||||
|
||||
@implementation IJSVGExporterPathInstruction
|
||||
|
||||
@synthesize instruction = _instruction;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_data != NULL) {
|
||||
free(_data);
|
||||
(void)free(_data), _data = NULL;
|
||||
}
|
||||
if (_base != NULL) {
|
||||
(void)free(_base), _base = NULL;
|
||||
}
|
||||
if (_coords != NULL) {
|
||||
(void)free(_coords), _coords = NULL;
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -27,8 +37,13 @@
|
||||
|
||||
// only allocate if not zero
|
||||
if (floatCount != 0) {
|
||||
_dataCount = floatCount;
|
||||
_data = (CGFloat*)calloc(sizeof(CGFloat), floatCount);
|
||||
}
|
||||
|
||||
// setup base and coords
|
||||
_base = (CGFloat*)malloc(sizeof(CGFloat) * 2);
|
||||
_coords = (CGFloat*)malloc(sizeof(CGFloat) * 2);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -38,108 +53,343 @@
|
||||
return _dataCount;
|
||||
}
|
||||
|
||||
- (void)setInstruction:(char)newInstruction
|
||||
{
|
||||
_instruction = newInstruction;
|
||||
}
|
||||
|
||||
- (char)instruction
|
||||
{
|
||||
return _instruction;
|
||||
}
|
||||
|
||||
- (CGFloat*)data
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
- (CGFloat*)base
|
||||
{
|
||||
NSMutableArray* pathData = [[[NSMutableArray alloc] init] autorelease];
|
||||
return _base;
|
||||
}
|
||||
|
||||
- (CGFloat*)coords
|
||||
{
|
||||
return _coords;
|
||||
}
|
||||
|
||||
IJSVGExporterPathInstructionCommand* IJSVGExporterPathInstructionCommandCopy(IJSVGExporterPathInstructionCommand command)
|
||||
{
|
||||
IJSVGExporterPathInstructionCommand* copy = NULL;
|
||||
copy = (IJSVGExporterPathInstructionCommand*)malloc(sizeof(IJSVGExporterPathInstructionCommand));
|
||||
copy->instruction = command.instruction;
|
||||
copy->params = command.params;
|
||||
return copy;
|
||||
}
|
||||
|
||||
void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand* _Nullable command)
|
||||
{
|
||||
if (command != NULL) {
|
||||
free(command);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString*)pathStringWithInstructionSet:(NSArray<NSValue*>*)instructionSets
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
IJSVGExporterPathInstructionCommand* lastCommand = NULL;
|
||||
NSMutableString* string = [[[NSMutableString alloc] init] autorelease];
|
||||
for (NSValue* value in instructionSets) {
|
||||
// read back the bytes
|
||||
IJSVGExporterPathInstructionCommand command;
|
||||
[value getValue:&command];
|
||||
|
||||
// add on the instruction character only if there is no current command
|
||||
// or the last command is not the same as the current command
|
||||
// if they both are the same, we still need to seperate them via a space
|
||||
if (lastCommand == nil || (lastCommand != nil && lastCommand->instruction != command.instruction)) {
|
||||
[string appendFormat:@"%c", command.instruction];
|
||||
} else {
|
||||
[string appendString:@" "];
|
||||
}
|
||||
|
||||
// compresses the floats
|
||||
NSString* compressedFloats = IJSVGCompressFloatParameterArray(command.params);
|
||||
[string appendString:compressedFloats];
|
||||
|
||||
// store last command
|
||||
IJSVGExporterPathInstructionCommandFree(lastCommand);
|
||||
lastCommand = IJSVGExporterPathInstructionCommandCopy(command);
|
||||
}
|
||||
|
||||
IJSVGExporterPathInstructionCommandFree(lastCommand);
|
||||
return string;
|
||||
}
|
||||
|
||||
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
NSMutableArray* pathInstructions = [[[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':
|
||||
const char lowerInstruction = tolower(instruction.instruction);
|
||||
NSArray<NSString*>* set = nil;
|
||||
switch (lowerInstruction) {
|
||||
case 't':
|
||||
case 'm':
|
||||
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];
|
||||
set = @[
|
||||
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions)
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
case 'v':
|
||||
case 'h': {
|
||||
set = @[
|
||||
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions)
|
||||
];
|
||||
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];
|
||||
set = @[
|
||||
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[2], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[3], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[4], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[5], floatingPointOptions)
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
// quadratic curve
|
||||
case 'Q':
|
||||
case 's':
|
||||
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];
|
||||
set = @[
|
||||
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[2], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[3], floatingPointOptions)
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a': {
|
||||
set = @[
|
||||
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[2], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[3], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[4], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[5], floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(data[6], floatingPointOptions),
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
// close path
|
||||
case 'Z':
|
||||
case 'z': {
|
||||
str = [NSString stringWithFormat:@"%c", instruction.instruction];
|
||||
[pathData addObject:str];
|
||||
set = @[];
|
||||
}
|
||||
}
|
||||
|
||||
// wrap into the command and give to the array
|
||||
IJSVGExporterPathInstructionCommand wrapper;
|
||||
wrapper.instruction = instruction.instruction;
|
||||
wrapper.params = set ?: @[];
|
||||
|
||||
// encode and store
|
||||
NSValue* value = [NSValue valueWithBytes:&wrapper
|
||||
objCType:@encode(IJSVGExporterPathInstructionCommand)];
|
||||
[pathInstructions addObject:value];
|
||||
}
|
||||
return [self pathStringWithInstructionSet:pathInstructions
|
||||
floatingPointOptions:floatingPointOptions];
|
||||
}
|
||||
|
||||
CGFloat IJSVGExporterPathFloatToFixed(CGFloat number, int precision)
|
||||
{
|
||||
return floorf(pow(10, precision) * number) / pow(10, precision);
|
||||
}
|
||||
|
||||
void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
|
||||
IJSVGFloatingPointOptions options)
|
||||
{
|
||||
for (NSInteger i = length; i-- > 0;) {
|
||||
CGFloat d = data[i];
|
||||
CGFloat proposed = IJSVGExporterPathFloatToFixed(d, options.precision);
|
||||
if (proposed != d) {
|
||||
CGFloat rounded = +IJSVGExporterPathFloatToFixed(d, options.precision - 1);
|
||||
data[i] = IJSVGExporterPathFloatToFixed(+fabs(rounded - d), options.precision + 1)
|
||||
>= kIJSVGExporterPathInstructionErrorThreshold
|
||||
? +IJSVGExporterPathFloatToFixed(d, options.precision)
|
||||
: rounded;
|
||||
}
|
||||
}
|
||||
return [pathData componentsJoinedByString:@""];
|
||||
}
|
||||
|
||||
+ (void)convertInstructionsToRoundRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
CGFloat relSubPoint[2] = { 0.f, 0.f };
|
||||
for (IJSVGExporterPathInstruction* instruction in instructions) {
|
||||
char instructionChar = instruction.instruction;
|
||||
NSInteger length = instruction.dataLength;
|
||||
CGFloat* data = instruction.data;
|
||||
if (strchr("mltqsc", instructionChar) != NULL) {
|
||||
for (NSInteger i = length; i--;) {
|
||||
data[i] += instruction.base[i % 2] - relSubPoint[i % 2];
|
||||
}
|
||||
} else if (instructionChar == 'h') {
|
||||
data[0] += instruction.base[0] - relSubPoint[0];
|
||||
} else if (instructionChar == 'v') {
|
||||
data[0] += instruction.base[1] - relSubPoint[1];
|
||||
} else if (instructionChar == 'a') {
|
||||
data[5] += instruction.base[0] - relSubPoint[0];
|
||||
data[5] += instruction.base[1] - relSubPoint[1];
|
||||
}
|
||||
IJSVGExporterPathInstructionRoundData(data, length, floatingPointOptions);
|
||||
if (instructionChar == 'h') {
|
||||
relSubPoint[0] += data[0];
|
||||
} else if (instructionChar == 'v') {
|
||||
relSubPoint[1] += data[0];
|
||||
} else {
|
||||
relSubPoint[0] += data[length - 2];
|
||||
relSubPoint[1] += data[length - 1];
|
||||
}
|
||||
IJSVGExporterPathInstructionRoundData(relSubPoint, 2, floatingPointOptions);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)convertInstructionsToMixedAbsoluteRelative:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
IJSVGExporterPathInstruction* prevInstruction = nil;
|
||||
for (IJSVGExporterPathInstruction* instruction in instructions) {
|
||||
if (prevInstruction == nil || instruction.dataLength == 0) {
|
||||
prevInstruction = instruction;
|
||||
continue;
|
||||
}
|
||||
|
||||
char instructionChar = instruction.instruction;
|
||||
CGFloat* data = instruction.data;
|
||||
NSInteger length = instruction.dataLength;
|
||||
CGFloat* adata = (CGFloat*)malloc(sizeof(CGFloat) * length);
|
||||
memcpy(adata, data, sizeof(CGFloat) * length);
|
||||
|
||||
if (strchr("mltqsc", instructionChar) != NULL) {
|
||||
for (NSInteger i = length; i--;) {
|
||||
adata[i] += instruction.base[i % 2];
|
||||
}
|
||||
} else if (instructionChar == 'h') {
|
||||
adata[0] += instruction.base[0];
|
||||
} else if (instructionChar == 'v') {
|
||||
adata[0] += instruction.base[1];
|
||||
} else if (instructionChar == 'a') {
|
||||
adata[5] += instruction.base[0];
|
||||
adata[6] += instruction.base[1];
|
||||
}
|
||||
|
||||
IJSVGExporterPathInstructionRoundData(adata, length, floatingPointOptions);
|
||||
|
||||
IJSVGExporterPathInstruction* ainstruction = nil;
|
||||
ainstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:instructionChar
|
||||
dataCount:length] autorelease];
|
||||
memcpy(ainstruction.data, adata, sizeof(CGFloat) * length);
|
||||
|
||||
// run these through our default string runner
|
||||
// to compare the outputs
|
||||
NSString* orig = [self pathStringFromInstructions:@[ instruction ]
|
||||
floatingPointOptions:floatingPointOptions];
|
||||
NSString* comp = [self pathStringFromInstructions:@[ ainstruction ]
|
||||
floatingPointOptions:floatingPointOptions];
|
||||
|
||||
if (comp.length < orig.length && !(instructionChar == prevInstruction.instruction && prevInstruction.instruction > 96 && comp.length == orig.length - 1 && data[0] < 0.f && fmod(prevInstruction.data[prevInstruction.dataLength - 1], 1) != 0.f)) {
|
||||
instruction.instruction = toupper(instructionChar);
|
||||
memcpy(data, adata, sizeof(CGFloat) * length);
|
||||
}
|
||||
(void)free(adata), adata = NULL;
|
||||
prevInstruction = instruction;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)convertInstructionsDataToRounded:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
for (IJSVGExporterPathInstruction* instruction in instructions) {
|
||||
CGFloat* data = instruction.data;
|
||||
IJSVGExporterPathInstructionRoundData(data, instruction.dataLength,
|
||||
floatingPointOptions);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSArray<IJSVGExporterPathInstruction*>*)convertInstructionsCurves:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
NSMutableArray<IJSVGExporterPathInstruction*>* nInstructions = nil;
|
||||
nInstructions = [[[NSMutableArray alloc] initWithCapacity:instructions.count] autorelease];
|
||||
IJSVGExporterPathInstruction* lastInstruction = nil;
|
||||
for (IJSVGExporterPathInstruction* instruction in instructions) {
|
||||
lastInstruction = nInstructions.lastObject;
|
||||
if (lastInstruction == nil) {
|
||||
[nInstructions addObject:instruction];
|
||||
continue;
|
||||
}
|
||||
if (instruction.instruction == 'c') {
|
||||
if (lastInstruction.instruction == 'c' && instruction.data[0] == -(lastInstruction.data[2] - lastInstruction.data[4]) && instruction.data[1] == -(lastInstruction.data[3] - lastInstruction.data[5])) {
|
||||
IJSVGExporterPathInstruction* nInstruction = nil;
|
||||
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
|
||||
dataCount:4] autorelease];
|
||||
nInstruction.data[0] = instruction.data[2];
|
||||
nInstruction.data[1] = instruction.data[3];
|
||||
nInstruction.data[2] = instruction.data[4];
|
||||
nInstruction.data[3] = instruction.data[5];
|
||||
[nInstructions addObject:nInstruction];
|
||||
continue;
|
||||
} else if (lastInstruction.instruction == 's' && instruction.data[0] == -(lastInstruction.data[0] - lastInstruction.data[2]) && instruction.data[1] == -(lastInstruction.data[1] - lastInstruction.data[3])) {
|
||||
IJSVGExporterPathInstruction* nInstruction = nil;
|
||||
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
|
||||
dataCount:4] autorelease];
|
||||
nInstruction.data[0] = instruction.data[2];
|
||||
nInstruction.data[1] = instruction.data[3];
|
||||
nInstruction.data[2] = instruction.data[4];
|
||||
nInstruction.data[3] = instruction.data[5];
|
||||
[nInstructions addObject:nInstruction];
|
||||
continue;
|
||||
} else if (lastInstruction.instruction != 'c' && lastInstruction.instruction != 's' && instruction.data[0] == 0.f && instruction.data[1] == 0.f) {
|
||||
IJSVGExporterPathInstruction* nInstruction = nil;
|
||||
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
|
||||
dataCount:4] autorelease];
|
||||
nInstruction.data[0] = instruction.data[2];
|
||||
nInstruction.data[1] = instruction.data[3];
|
||||
nInstruction.data[2] = instruction.data[4];
|
||||
nInstruction.data[3] = instruction.data[5];
|
||||
[nInstructions addObject:nInstruction];
|
||||
continue;
|
||||
}
|
||||
} else if (instruction.instruction == 'q') {
|
||||
if (lastInstruction.instruction == 'q' && instruction.data[0] == (lastInstruction.data[2] - lastInstruction.data[0]) && instruction.data[1] == (lastInstruction.data[3] - lastInstruction.data[1])) {
|
||||
IJSVGExporterPathInstruction* nInstruction = nil;
|
||||
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
|
||||
dataCount:2] autorelease];
|
||||
nInstruction.data[0] = instruction.data[3];
|
||||
nInstruction.data[1] = instruction.data[4];
|
||||
[nInstructions addObject:nInstruction];
|
||||
continue;
|
||||
} else if (lastInstruction.instruction == 't' && instruction.data[2] == lastInstruction.data[0] && instruction.data[3] == lastInstruction.data[1]) {
|
||||
IJSVGExporterPathInstruction* nInstruction = nil;
|
||||
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
|
||||
dataCount:2] autorelease];
|
||||
nInstruction.data[0] = instruction.data[3];
|
||||
nInstruction.data[1] = instruction.data[4];
|
||||
[nInstructions addObject:nInstruction];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
[nInstructions addObject:instruction];
|
||||
}
|
||||
return nInstructions;
|
||||
}
|
||||
|
||||
+ (void)convertInstructionsToRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
CGFloat point[2] = { 0, 0 };
|
||||
CGFloat subpathPoint[2] = { 0, 0 };
|
||||
IJSVGExporterPathInstruction* baseInstruction = nil;
|
||||
IJSVGExporterPathInstruction* prevInstruction = nil;
|
||||
|
||||
NSInteger index = 0;
|
||||
for (IJSVGExporterPathInstruction* anInstruction in instructions) {
|
||||
@@ -158,6 +408,8 @@
|
||||
if (instruction == 'm') {
|
||||
subpathPoint[0] = point[0];
|
||||
subpathPoint[1] = point[1];
|
||||
|
||||
baseInstruction = anInstruction;
|
||||
}
|
||||
|
||||
} else if (instruction == 'h') {
|
||||
@@ -178,8 +430,8 @@
|
||||
subpathPoint[0] = point[0] += data[0];
|
||||
subpathPoint[1] = point[1] += data[1];
|
||||
|
||||
baseInstruction = anInstruction;
|
||||
} else if (instruction == 'L' || instruction == 'T') {
|
||||
|
||||
instruction = tolower(instruction);
|
||||
|
||||
data[0] -= point[0];
|
||||
@@ -187,9 +439,7 @@
|
||||
|
||||
point[0] += data[0];
|
||||
point[1] += data[1];
|
||||
|
||||
} else if (instruction == 'C') {
|
||||
|
||||
instruction = 'c';
|
||||
|
||||
data[0] -= point[0];
|
||||
@@ -201,9 +451,7 @@
|
||||
|
||||
point[0] += data[4];
|
||||
point[1] += data[5];
|
||||
|
||||
} else if (instruction == 'S' || instruction == 'Q') {
|
||||
|
||||
instruction = tolower(instruction);
|
||||
|
||||
data[0] -= point[0];
|
||||
@@ -213,9 +461,7 @@
|
||||
|
||||
point[0] += data[2];
|
||||
point[1] += data[3];
|
||||
|
||||
} else if (instruction == 'A') {
|
||||
|
||||
instruction = 'a';
|
||||
|
||||
data[5] -= point[0];
|
||||
@@ -223,38 +469,51 @@
|
||||
|
||||
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];
|
||||
anInstruction.instruction = instruction;
|
||||
CGFloat* coords = anInstruction.coords;
|
||||
coords[0] = point[0];
|
||||
coords[1] = point[1];
|
||||
|
||||
} else if (instruction == 'Z' || instruction == 'z') {
|
||||
if (baseInstruction != nil) {
|
||||
CGFloat* coords = anInstruction.coords;
|
||||
coords[0] = baseInstruction.coords[0];
|
||||
coords[1] = baseInstruction.coords[1];
|
||||
}
|
||||
point[0] = subpathPoint[0];
|
||||
point[1] = subpathPoint[1];
|
||||
}
|
||||
|
||||
CGFloat* base = anInstruction.base;
|
||||
if (prevInstruction != nil) {
|
||||
base[0] = prevInstruction.coords[0];
|
||||
base[1] = prevInstruction.coords[1];
|
||||
} else {
|
||||
base[0] = 0.f;
|
||||
base[1] = 0.f;
|
||||
}
|
||||
|
||||
// increment index
|
||||
prevInstruction = anInstruction;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
|
||||
// keep track of the current point
|
||||
@@ -324,6 +583,7 @@
|
||||
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];
|
||||
@@ -362,7 +622,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,13 @@
|
||||
#import "IJSVGNode.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGDef : IJSVGNode {
|
||||
@interface IJSVGDef : NSObject {
|
||||
|
||||
@private
|
||||
NSMutableDictionary* _dict;
|
||||
}
|
||||
|
||||
- (void)addDef:(IJSVGNode*)aDef;
|
||||
- (IJSVGDef*)defForID:(NSString*)anID;
|
||||
|
||||
@end
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super initWithDef:NO]) != nil) {
|
||||
if ((self = [super init]) != nil) {
|
||||
_dict = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
@@ -29,13 +29,12 @@
|
||||
if (aDef.identifier == nil) {
|
||||
return;
|
||||
}
|
||||
[_dict setObject:aDef
|
||||
forKey:aDef.identifier];
|
||||
_dict[aDef.identifier] = aDef;
|
||||
}
|
||||
|
||||
- (IJSVGDef*)defForID:(NSString*)anID
|
||||
{
|
||||
return [_dict objectForKey:anID];
|
||||
return _dict[anID];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -43,6 +43,8 @@ typedef NS_ENUM(NSInteger, IJSVGNodeType) {
|
||||
IJSVGNodeTypeTextSpan,
|
||||
IJSVGNodeTypeStyle,
|
||||
IJSVGNodeTypeSwitch,
|
||||
IJSVGNodeTypeTitle,
|
||||
IJSVGNodeTypeDesc,
|
||||
IJSVGNodeTypeNotFound,
|
||||
};
|
||||
|
||||
@@ -97,6 +99,8 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991;
|
||||
|
||||
@interface IJSVGNode : NSObject <NSCopying>
|
||||
|
||||
@property (nonatomic, copy) NSString* title;
|
||||
@property (nonatomic, copy) NSString* desc;
|
||||
@property (nonatomic, assign) IJSVGNodeType type;
|
||||
@property (nonatomic, copy) NSString* name;
|
||||
@property (nonatomic, copy) NSString* className;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
@implementation IJSVGNode
|
||||
|
||||
@synthesize title;
|
||||
@synthesize desc;
|
||||
@synthesize shouldRender;
|
||||
@synthesize type;
|
||||
@synthesize name;
|
||||
@@ -73,6 +75,8 @@
|
||||
(void)([identifier release]), identifier = nil;
|
||||
(void)([def release]), def = nil;
|
||||
(void)([name release]), name = nil;
|
||||
(void)([title release]), title = nil;
|
||||
(void)([desc release]), desc = nil;
|
||||
(void)([className release]), className = nil;
|
||||
(void)([classNameList release]), classNameList = nil;
|
||||
(void)([fillPattern release]), fillPattern = nil;
|
||||
@@ -133,6 +137,12 @@
|
||||
if ([string isEqualToString:@"tspan"] || kind == NSXMLTextKind) {
|
||||
return IJSVGNodeTypeTextSpan;
|
||||
}
|
||||
if([string isEqualToString:@"title"]) {
|
||||
return IJSVGNodeTypeTitle;
|
||||
}
|
||||
if([string isEqualToString:@"desc"]) {
|
||||
return IJSVGNodeTypeDesc;
|
||||
}
|
||||
|
||||
// are we commong HTML? - if so just treat as a group
|
||||
if (IJSVGIsCommonHTMLElementName(string) == YES) {
|
||||
@@ -152,6 +162,9 @@
|
||||
|
||||
- (void)applyPropertiesFromNode:(IJSVGNode*)node
|
||||
{
|
||||
self.title = node.title;
|
||||
self.desc = node.desc;
|
||||
|
||||
self.name = node.name;
|
||||
self.type = node.type;
|
||||
self.unicode = node.unicode;
|
||||
|
||||
@@ -13,32 +13,27 @@
|
||||
@class IJSVGGroup;
|
||||
|
||||
typedef NS_ENUM(NSInteger, IJSVGPrimitivePathType) {
|
||||
IJSVGPrimitivePathTypePath,
|
||||
IJSVGPrimitivePathTypeRect,
|
||||
IJSVGPrimitivePathTypePolygon,
|
||||
IJSVGPrimitivePathTypePolyLine,
|
||||
IJSVGPrimitivePathTypeCircle,
|
||||
IJSVGPrimitivePathTypeEllipse,
|
||||
IJSVGPrimitivePathTypeLine
|
||||
kIJSVGPrimitivePathTypePath,
|
||||
kIJSVGPrimitivePathTypeRect,
|
||||
kIJSVGPrimitivePathTypePolygon,
|
||||
kIJSVGPrimitivePathTypePolyLine,
|
||||
kIJSVGPrimitivePathTypeCircle,
|
||||
kIJSVGPrimitivePathTypeEllipse,
|
||||
kIJSVGPrimitivePathTypeLine
|
||||
};
|
||||
|
||||
@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, retain) NSBezierPath* path;
|
||||
@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
|
||||
|
||||
@@ -11,30 +11,26 @@
|
||||
|
||||
@implementation IJSVGPath
|
||||
|
||||
@synthesize path;
|
||||
@synthesize subpath;
|
||||
@synthesize path = _path;
|
||||
@synthesize lastControlPoint;
|
||||
@synthesize CGPath = _CGPath;
|
||||
@synthesize primitiveType = _primitiveType;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if(_CGPath != nil) {
|
||||
if (_CGPath != nil) {
|
||||
CGPathRelease(_CGPath);
|
||||
_CGPath = nil;
|
||||
}
|
||||
if (subpath != nil) {
|
||||
(void)([subpath release]), subpath = nil;
|
||||
}
|
||||
((void)[_path release]), _path = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
_primitiveType = IJSVGPrimitivePathTypePath;
|
||||
subpath = NSBezierPath.bezierPath.retain;
|
||||
path = subpath; // for legacy use
|
||||
_primitiveType = kIJSVGPrimitivePathTypePath;
|
||||
_path = NSBezierPath.bezierPath.retain;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -42,99 +38,34 @@
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
IJSVGPath* node = [super copyWithZone:zone];
|
||||
[node overwritePath:self.path];
|
||||
node.path = [self.path.copy autorelease];
|
||||
return node;
|
||||
}
|
||||
|
||||
- (NSPoint)currentPoint
|
||||
{
|
||||
return [subpath currentPoint];
|
||||
}
|
||||
|
||||
- (NSBezierPath*)currentSubpath
|
||||
{
|
||||
return subpath;
|
||||
return _path.currentPoint;
|
||||
}
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[subpath closePath];
|
||||
[_path closePath];
|
||||
}
|
||||
|
||||
- (void)invlidateCGPath
|
||||
{
|
||||
if (_CGPath != nil) {
|
||||
CGPathRelease(_CGPath);
|
||||
}
|
||||
_CGPath = nil;
|
||||
}
|
||||
|
||||
- (CGPathRef)CGPath
|
||||
{
|
||||
if(_CGPath == nil) {
|
||||
_CGPath = [self newPathRefByAutoClosingPath:NO];
|
||||
if (_CGPath == nil) {
|
||||
_CGPath = [_path newCGPathRef: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
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// IJSVGCommandParser.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 23/12/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <xlocale.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, IJSVGPathDataSequence) {
|
||||
kIJSVGPathDataSequenceTypeFloat,
|
||||
kIJSVGPathDataSequenceTypeFlag
|
||||
};
|
||||
|
||||
static NSUInteger const IJSVG_STREAM_FLOAT_BLOCK_SIZE = 50;
|
||||
static NSUInteger const IJSVG_STREAM_CHAR_BLOCK_SIZE = 20;
|
||||
|
||||
typedef struct {
|
||||
CGFloat* floatBuffer;
|
||||
NSInteger floatCount;
|
||||
char* charBuffer;
|
||||
NSInteger charCount;
|
||||
} IJSVGPathDataStream;
|
||||
|
||||
@interface IJSVGCommandParser : NSObject
|
||||
|
||||
IJSVGPathDataStream* IJSVGPathDataStreamCreateDefault(void);
|
||||
IJSVGPathDataStream* IJSVGPathDataStreamCreate(NSUInteger floatCount, NSUInteger charCount);
|
||||
void IJSVGPathDataStreamRelease(IJSVGPathDataStream* buffer);
|
||||
|
||||
IJSVGPathDataSequence* IJSVGPathDataSequenceCreateWithType(IJSVGPathDataSequence type, NSInteger length);
|
||||
CGFloat* _Nullable IJSVGParsePathDataStreamSequence(const char* commandChars, NSInteger commandCharLength,
|
||||
IJSVGPathDataStream* dataStream, IJSVGPathDataSequence* _Nullable sequence,
|
||||
NSInteger commandLength, NSInteger* _Nullable commandsFound);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,249 @@
|
||||
//
|
||||
// IJSVGCommandParser.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 23/12/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGCommandParser.h"
|
||||
|
||||
@implementation IJSVGCommandParser
|
||||
|
||||
#define VALID_DIGIT(c) ((c ^ '0') <= 9)
|
||||
|
||||
IJSVGPathDataSequence* IJSVGPathDataSequenceCreateWithType(IJSVGPathDataSequence type, NSInteger length)
|
||||
{
|
||||
size_t size = sizeof(IJSVGPathDataSequence) * length;
|
||||
IJSVGPathDataSequence* sequence = (IJSVGPathDataSequence*)malloc(size);
|
||||
memset(sequence, (int)type, size);
|
||||
return sequence;
|
||||
};
|
||||
|
||||
// Datastreams work by setting up one stream of bits/memory per SVG
|
||||
// so that each SVG has a reusable memory block to read and parse paths into.
|
||||
// As its all linear and one SVG per thread, this saves alot of memory allocation
|
||||
// calls as we simple can just reuse the buffer that already exists - this also
|
||||
// allows us to specify the default allocation size, so when parsing viewBox we
|
||||
// can simply allocate (4*sizeof(CGFloat)) instead of the default 50 slots
|
||||
IJSVGPathDataStream* IJSVGPathDataStreamCreateDefault(void)
|
||||
{
|
||||
return IJSVGPathDataStreamCreate(IJSVG_STREAM_FLOAT_BLOCK_SIZE,
|
||||
IJSVG_STREAM_CHAR_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
IJSVGPathDataStream* IJSVGPathDataStreamCreate(NSUInteger floatCount, NSUInteger charCount)
|
||||
{
|
||||
floatCount = floatCount ?: IJSVG_STREAM_FLOAT_BLOCK_SIZE;
|
||||
charCount = charCount ?: IJSVG_STREAM_CHAR_BLOCK_SIZE;
|
||||
IJSVGPathDataStream* buffer = (IJSVGPathDataStream*)malloc(sizeof(IJSVGPathDataStream));
|
||||
buffer->floatBuffer = (CGFloat*)malloc(sizeof(CGFloat) * floatCount);
|
||||
buffer->floatCount = floatCount;
|
||||
buffer->charBuffer = (char*)calloc(sizeof(char), charCount);
|
||||
buffer->charCount = charCount;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void IJSVGPathDataStreamRelease(IJSVGPathDataStream* buffer)
|
||||
{
|
||||
free(buffer->charBuffer);
|
||||
free(buffer->floatBuffer);
|
||||
free(buffer);
|
||||
};
|
||||
|
||||
CGFloat* _Nullable IJSVGParsePathDataStreamSequence(const char* commandChars, NSInteger commandCharLength,
|
||||
IJSVGPathDataStream* dataStream, IJSVGPathDataSequence* _Nullable sequence,
|
||||
NSInteger commandLength, NSInteger* _Nullable 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 memory size for the float
|
||||
NSInteger i = 0;
|
||||
NSInteger counter = 0;
|
||||
|
||||
const char* cString = commandChars;
|
||||
const char* validChars = "+-.";
|
||||
|
||||
// this is much faster then doing strlen as it doesnt need
|
||||
// to compute the length
|
||||
NSInteger sLength = commandCharLength;
|
||||
NSInteger sLengthMinusOne = sLength - 1;
|
||||
|
||||
bool isDecimal = false;
|
||||
int bufferCount = 0;
|
||||
|
||||
while (i < sLength) {
|
||||
char currentChar = *cString++;
|
||||
|
||||
// work out next char
|
||||
char nextChar = (char)0;
|
||||
if (i < sLengthMinusOne) {
|
||||
nextChar = *cString++;
|
||||
cString--;
|
||||
}
|
||||
|
||||
// check for validator
|
||||
bool isE = (currentChar | ('E' ^ 'e')) == 'e';
|
||||
bool isValid = VALID_DIGIT(currentChar) || isE || 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 nIsSign = nextChar == '-' || nextChar == '+';
|
||||
bool wantsEnd = nIsSign || (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')) {
|
||||
return NULL;
|
||||
}
|
||||
wantsEnd = YES;
|
||||
}
|
||||
|
||||
// could be a float like 5.334e-5 so dont break on the hypen
|
||||
if (wantsEnd && isE && nIsSign) {
|
||||
wantsEnd = false;
|
||||
}
|
||||
|
||||
// make sure its a valid string
|
||||
if (isValid == YES) {
|
||||
// alloc the buffer if needed
|
||||
if ((bufferCount + 1) == dataStream->charCount) {
|
||||
// realloc the buffer, incase the string is overflowing the
|
||||
// allocated memory
|
||||
dataStream->charCount += IJSVG_STREAM_CHAR_BLOCK_SIZE;
|
||||
dataStream->charBuffer = (char*)realloc(dataStream->charBuffer,
|
||||
sizeof(char) * dataStream->charCount);
|
||||
}
|
||||
// set the actual char against it
|
||||
if (currentChar == '.') {
|
||||
isDecimal = true;
|
||||
}
|
||||
dataStream->charBuffer[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 (bufferCount != 0 && (wantsEnd || i == sLengthMinusOne)) {
|
||||
// make sure there is enough room in the float pool
|
||||
if ((counter + 1) == dataStream->floatCount) {
|
||||
dataStream->floatCount += IJSVG_STREAM_FLOAT_BLOCK_SIZE;
|
||||
dataStream->floatBuffer = (CGFloat*)realloc(dataStream->floatBuffer,
|
||||
sizeof(CGFloat) * dataStream->floatCount);
|
||||
}
|
||||
|
||||
// add the float - for performance reasons, we can simply set the
|
||||
// null value of the end of the string instead of nulling out
|
||||
// with memset \0 - huzzah!
|
||||
dataStream->charBuffer[bufferCount] = '\0';
|
||||
dataStream->floatBuffer[counter++] = IJSVGParseFloat(dataStream->charBuffer);
|
||||
|
||||
// reset
|
||||
isDecimal = false;
|
||||
bufferCount = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// set commands found - only if there is one
|
||||
if (commandsFound != NULL) {
|
||||
*commandsFound = (NSInteger)round(counter / commandLength);
|
||||
}
|
||||
|
||||
// allocate the new buffer from memory
|
||||
CGFloat* floats = (CGFloat*)malloc(sizeof(CGFloat) * counter);
|
||||
memcpy(floats, dataStream->floatBuffer, counter * sizeof(CGFloat));
|
||||
|
||||
// return the floats just set into the memory
|
||||
return floats;
|
||||
}
|
||||
|
||||
// this method is finely tuned to just handle the buffer
|
||||
// that IJSVGParsePathDataSequence produces for each float
|
||||
// it does not look or skip white space as the previous method
|
||||
// handles this for us
|
||||
// inspired and modified from http://www.leapsecond.com/tools/fast_atof.c
|
||||
CGFloat IJSVGParseFloat(char* buffer)
|
||||
{
|
||||
int fraction;
|
||||
double sign, value, scale;
|
||||
|
||||
// work out a sign, if any, might not be, who knows
|
||||
sign = 1.f;
|
||||
if (*buffer == '-') {
|
||||
sign = -1.f;
|
||||
buffer += 1;
|
||||
} else if (*buffer == '+') {
|
||||
buffer += 1;
|
||||
}
|
||||
|
||||
// get numbers before decimal point or exponent
|
||||
for (value = 0.f; VALID_DIGIT(*buffer); buffer += 1) {
|
||||
value = value * 10.f + (*buffer - '0');
|
||||
}
|
||||
|
||||
// get digits after decimal point
|
||||
if (*buffer == '.') {
|
||||
double pow10 = 10.f;
|
||||
buffer += 1;
|
||||
while (VALID_DIGIT(*buffer)) {
|
||||
value += (*buffer - '0') / pow10;
|
||||
pow10 *= 10.f;
|
||||
buffer += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// handle exponent
|
||||
fraction = 0;
|
||||
scale = 1.f;
|
||||
if ((*buffer | ('E' ^ 'e')) == 'e') {
|
||||
unsigned int exponent;
|
||||
buffer += 1;
|
||||
if (*buffer == '-') {
|
||||
fraction = 1;
|
||||
buffer += 1;
|
||||
} else if (*buffer == '+') {
|
||||
buffer += 1;
|
||||
}
|
||||
for (exponent = 0; VALID_DIGIT(*buffer); buffer += 1) {
|
||||
exponent = exponent * 10 + (*buffer - '0');
|
||||
}
|
||||
if (exponent > 308) {
|
||||
exponent = 308;
|
||||
}
|
||||
while (exponent >= 50) {
|
||||
scale *= 1E50;
|
||||
exponent -= 50;
|
||||
}
|
||||
while (exponent >= 8) {
|
||||
scale *= 1E8;
|
||||
exponent -= 8;
|
||||
}
|
||||
while (exponent > 0) {
|
||||
scale *= 10.f;
|
||||
exponent -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we cast this to a CGFloat before return
|
||||
return (CGFloat)(sign * (fraction ? (value / scale) : (value * scale)));
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -20,6 +20,7 @@
|
||||
#import "IJSVGStyleSheet.h"
|
||||
#import "IJSVGText.h"
|
||||
#import "IJSVGTransform.h"
|
||||
#import "IJSVGUnitRect.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -85,28 +86,28 @@ static NSString const* IJSVGAttributePoints = @"points";
|
||||
@interface IJSVGParser : IJSVGGroup {
|
||||
|
||||
NSRect viewBox;
|
||||
NSSize proposedViewSize;
|
||||
IJSVGUnitSize* intrinsicSize;
|
||||
|
||||
@private
|
||||
id<IJSVGParserDelegate> _delegate;
|
||||
NSXMLDocument* _document;
|
||||
NSMutableArray* _glyphs;
|
||||
NSMutableArray<IJSVGNode*>* _glyphs;
|
||||
IJSVGStyleSheet* _styleSheet;
|
||||
NSMutableArray* _parsedNodes;
|
||||
NSMutableDictionary* _defNodes;
|
||||
NSMutableDictionary* _baseDefNodes;
|
||||
NSMutableDictionary<NSString*, NSXMLElement*>* _defNodes;
|
||||
NSMutableDictionary<NSString*, NSXMLElement*>* _baseDefNodes;
|
||||
NSMutableArray<IJSVG*>* _svgs;
|
||||
NSMutableArray* _definedGroups;
|
||||
|
||||
struct {
|
||||
unsigned int shouldHandleForeignObject : 1;
|
||||
unsigned int handleForeignObject : 1;
|
||||
unsigned int handleSubSVG : 1;
|
||||
} _respondsTo;
|
||||
|
||||
IJSVGPathDataStream* _commandDataStream;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) NSRect viewBox;
|
||||
@property (nonatomic, readonly) NSSize proposedViewSize;
|
||||
@property (nonatomic, readonly) IJSVGUnitSize* intrinsicSize;
|
||||
|
||||
+ (BOOL)isDataSVG:(NSData*)data;
|
||||
|
||||
|
||||
@@ -12,7 +12,36 @@
|
||||
@implementation IJSVGParser
|
||||
|
||||
@synthesize viewBox;
|
||||
@synthesize proposedViewSize;
|
||||
@synthesize intrinsicSize = _intrinsicSize;
|
||||
|
||||
static NSDictionary* _IJSVGAttributeDictionaryFloats = nil;
|
||||
static NSDictionary* _IJSVGAttributeDictionaryNodes = nil;
|
||||
static NSDictionary* _IJSVGAttributeDictionaryUnits = nil;
|
||||
static NSDictionary* _IJSVGAttributeDictionaryTransforms = nil;
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
_IJSVGAttributeDictionaryFloats = [@{
|
||||
(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" } retain];
|
||||
_IJSVGAttributeDictionaryNodes = [@{
|
||||
(NSString*)IJSVGAttributeClipPath : @"clipPath",
|
||||
(NSString*)IJSVGAttributeMask : @"mask" } retain];
|
||||
_IJSVGAttributeDictionaryUnits = [@{
|
||||
(NSString*)IJSVGAttributeGradientUnits : @"units",
|
||||
(NSString*)IJSVGAttributeMaskUnits : @"units",
|
||||
(NSString*)IJSVGAttributeMaskContentUnits : @"contentUnits"} retain];
|
||||
_IJSVGAttributeDictionaryTransforms = [@{
|
||||
(NSString*)IJSVGAttributeTransform : @"transforms",
|
||||
(NSString*)IJSVGAttributeGradientTransform : @"transforms" } retain];
|
||||
}
|
||||
|
||||
+ (IJSVGParser*)groupForFileURL:(NSURL*)aURL
|
||||
{
|
||||
@@ -42,11 +71,13 @@
|
||||
{
|
||||
(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;
|
||||
(void)([_intrinsicSize release]), _intrinsicSize = nil;
|
||||
if (_commandDataStream != NULL) {
|
||||
(void)IJSVGPathDataStreamRelease(_commandDataStream), _commandDataStream = nil;
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -61,11 +92,8 @@
|
||||
_respondsTo.shouldHandleForeignObject = [_delegate respondsToSelector:@selector(svgParser:shouldHandleForeignObject:)];
|
||||
_respondsTo.handleSubSVG = [_delegate respondsToSelector:@selector(svgParser:foundSubSVG:withSVGString:)];
|
||||
|
||||
_glyphs = [[NSMutableArray alloc] init];
|
||||
_parsedNodes = [[NSMutableArray alloc] init];
|
||||
_commandDataStream = IJSVGPathDataStreamCreateDefault();
|
||||
_defNodes = [[NSMutableDictionary alloc] init];
|
||||
_baseDefNodes = [[NSMutableDictionary alloc] init];
|
||||
_svgs = [[NSMutableArray alloc] init];
|
||||
|
||||
// load the document / file, assume its UTF8
|
||||
|
||||
@@ -199,8 +227,12 @@
|
||||
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;
|
||||
NSString* wAtt = [svgElement attributeForName:(NSString*)IJSVGAttributeWidth].stringValue;
|
||||
NSString* hAtt = [svgElement attributeForName:(NSString*)IJSVGAttributeHeight].stringValue;
|
||||
IJSVGUnitLength* wLength = [IJSVGUnitLength unitWithString:wAtt];
|
||||
IJSVGUnitLength* hLength = [IJSVGUnitLength unitWithString:hAtt];
|
||||
CGFloat w = wLength.value;
|
||||
CGFloat h = hLength.value;
|
||||
if (h == 0.f && w != 0.f) {
|
||||
h = w;
|
||||
} else if (w == 0.f && h != 0.f) {
|
||||
@@ -210,17 +242,22 @@
|
||||
}
|
||||
|
||||
// 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;
|
||||
NSString* w = [svgElement attributeForName:(NSString*)IJSVGAttributeWidth].stringValue;
|
||||
NSString* h = [svgElement attributeForName:(NSString*)IJSVGAttributeHeight].stringValue;
|
||||
|
||||
// by default just the the width and height from the viewbox unless
|
||||
// specified otherwise
|
||||
IJSVGUnitLength* wl = [IJSVGUnitLength unitWithFloat:viewBox.size.width];
|
||||
IJSVGUnitLength* hl = [IJSVGUnitLength unitWithFloat:viewBox.size.height];
|
||||
if (w != nil) {
|
||||
wl = [IJSVGUnitLength unitWithString:w];
|
||||
}
|
||||
proposedViewSize = NSMakeSize(w, h);
|
||||
if (h != nil) {
|
||||
hl = [IJSVGUnitLength unitWithString:h];
|
||||
}
|
||||
|
||||
// store the width and height
|
||||
_intrinsicSize = [IJSVGUnitSize sizeWithWidth:wl height:hl].retain;
|
||||
|
||||
// the root element is SVG, so iterate over its children
|
||||
// recursively
|
||||
@@ -229,17 +266,10 @@
|
||||
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)IJSVGPathDataStreamRelease(_commandDataStream), _commandDataStream = NULL;
|
||||
}
|
||||
|
||||
- (void)_postParseElementForCommonAttributes:(NSXMLElement*)element
|
||||
@@ -313,22 +343,13 @@
|
||||
}
|
||||
|
||||
// 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" },
|
||||
atts(_IJSVGAttributeDictionaryFloats,
|
||||
^id(NSString* value) {
|
||||
return [IJSVGUnitLength unitWithString:value];
|
||||
});
|
||||
|
||||
// nodes
|
||||
atts(@{ (NSString*)IJSVGAttributeClipPath : @"clipPath",
|
||||
(NSString*)IJSVGAttributeMask : @"mask" },
|
||||
atts(_IJSVGAttributeDictionaryNodes,
|
||||
^id(NSString* value) {
|
||||
NSString* url = [IJSVGUtils defURL:value];
|
||||
if (url != nil) {
|
||||
@@ -338,16 +359,13 @@
|
||||
});
|
||||
|
||||
// units
|
||||
atts(@{ (NSString*)IJSVGAttributeGradientUnits : @"units",
|
||||
(NSString*)IJSVGAttributeMaskUnits : @"units",
|
||||
(NSString*)IJSVGAttributeMaskContentUnits : @"contentUnits" },
|
||||
atts(_IJSVGAttributeDictionaryUnits,
|
||||
^id(NSString* value) {
|
||||
return @([IJSVGUtils unitTypeForString:value]);
|
||||
});
|
||||
|
||||
// transforms
|
||||
atts(@{ (NSString*)IJSVGAttributeTransform : @"transforms",
|
||||
(NSString*)IJSVGAttributeGradientTransform : @"transforms" },
|
||||
atts(_IJSVGAttributeDictionaryTransforms,
|
||||
^(NSString* value) {
|
||||
NSMutableArray* tempTransforms = [[[NSMutableArray alloc] init] autorelease];
|
||||
[tempTransforms addObjectsFromArray:[IJSVGTransform transformsForString:value]];
|
||||
@@ -450,6 +468,24 @@
|
||||
node.shouldRender = NO;
|
||||
}
|
||||
});
|
||||
|
||||
// is there a title or desc?
|
||||
for(NSXMLElement* childElement in element.children) {
|
||||
IJSVGNodeType type = [IJSVGNode typeForString:childElement.localName
|
||||
kind:childElement.kind];
|
||||
switch(type) {
|
||||
case IJSVGNodeTypeTitle: {
|
||||
node.title = childElement.stringValue;
|
||||
break;
|
||||
}
|
||||
case IJSVGNodeTypeDesc: {
|
||||
node.desc = childElement.stringValue;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id)definedObjectForID:(NSString*)anID
|
||||
@@ -466,10 +502,6 @@
|
||||
[self _parseBaseBlock:parseElement
|
||||
intoGroup:group
|
||||
def:NO];
|
||||
if (_definedGroups == nil) {
|
||||
_definedGroups = [[NSMutableArray alloc] init];
|
||||
}
|
||||
[_definedGroups addObject:group];
|
||||
return [group defForID:anID];
|
||||
}
|
||||
return nil;
|
||||
@@ -483,25 +515,28 @@
|
||||
|
||||
- (BOOL)isFont
|
||||
{
|
||||
return [_glyphs count] != 0;
|
||||
return _glyphs != nil && [_glyphs count] != 0;
|
||||
}
|
||||
|
||||
- (NSArray*)glyphs
|
||||
{
|
||||
return _glyphs;
|
||||
return _glyphs ?: @[];
|
||||
}
|
||||
|
||||
- (void)addSubSVG:(IJSVG*)anSVG
|
||||
{
|
||||
if (_svgs == nil) {
|
||||
_svgs = [[NSMutableArray alloc] init];
|
||||
}
|
||||
[_svgs addObject:anSVG];
|
||||
}
|
||||
|
||||
- (NSArray<IJSVG*>*)subSVGs:(BOOL)recursive
|
||||
{
|
||||
if (recursive == NO) {
|
||||
return _svgs;
|
||||
return _svgs ?: @[];
|
||||
}
|
||||
NSMutableArray* svgs = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSMutableArray<IJSVG*>* svgs = [[[NSMutableArray alloc] init] autorelease];
|
||||
for (IJSVG* anSVG in svgs) {
|
||||
[svgs addObject:anSVG];
|
||||
[svgs addObjectsFromArray:[anSVG subSVGs:recursive]];
|
||||
@@ -511,6 +546,9 @@
|
||||
|
||||
- (void)addGlyph:(IJSVGNode*)glyph
|
||||
{
|
||||
if (_glyphs == nil) {
|
||||
_glyphs = [[NSMutableArray alloc] init];
|
||||
}
|
||||
[_glyphs addObject:glyph];
|
||||
}
|
||||
|
||||
@@ -581,6 +619,9 @@
|
||||
default: {
|
||||
// just a default def, continue on, as we are a def element,
|
||||
// store these seperately to the default ID string ones
|
||||
if (_baseDefNodes == nil) {
|
||||
_baseDefNodes = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
NSString* defID = [childDef attributeForName:@"id"].stringValue;
|
||||
if (defID != nil) {
|
||||
_baseDefNodes[defID] = childDef;
|
||||
@@ -891,7 +932,7 @@
|
||||
// use
|
||||
case IJSVGNodeTypeUse: {
|
||||
|
||||
NSString* xlink = [[element attributeForName:(NSString*)IJSVGAttributeXLink] stringValue];
|
||||
NSString* xlink = [[self resolveXLinkAttributeForElement:element] stringValue];
|
||||
NSString* xlinkID = [xlink substringFromIndex:1];
|
||||
IJSVGNode* node = [self definedObjectForID:xlinkID];
|
||||
|
||||
@@ -938,7 +979,7 @@
|
||||
// linear gradient
|
||||
case IJSVGNodeTypeLinearGradient: {
|
||||
|
||||
NSString* xlink = [[element attributeForName:(NSString*)IJSVGAttributeXLink] stringValue];
|
||||
NSString* xlink = [[self resolveXLinkAttributeForElement:element] stringValue];
|
||||
NSString* xlinkID = [xlink substringFromIndex:1];
|
||||
NSXMLElement* referenceElement;
|
||||
IJSVGNode* node = [self definedObjectForID:xlinkID
|
||||
@@ -975,7 +1016,7 @@
|
||||
// radial gradient
|
||||
case IJSVGNodeTypeRadialGradient: {
|
||||
|
||||
NSString* xlink = [[element attributeForName:(NSString*)IJSVGAttributeXLink] stringValue];
|
||||
NSString* xlink = [[self resolveXLinkAttributeForElement:element] stringValue];
|
||||
NSString* xlinkID = [xlink substringFromIndex:1];
|
||||
NSXMLElement* referenceElement;
|
||||
IJSVGNode* node = [self definedObjectForID:xlinkID
|
||||
@@ -1064,8 +1105,8 @@
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// from base64
|
||||
NSString* string = [element attributeForName:(NSString*)IJSVGAttributeXLink].stringValue;
|
||||
[image loadFromBase64EncodedString:string];
|
||||
NSXMLNode* attributeNode = [self resolveXLinkAttributeForElement:element];
|
||||
[image loadFromBase64EncodedString:attributeNode.stringValue];
|
||||
|
||||
// add to parent
|
||||
[parentGroup addChild:image];
|
||||
@@ -1075,6 +1116,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSXMLNode*)resolveXLinkAttributeForElement:(NSXMLElement*)element
|
||||
{
|
||||
NSString* const namespaceURI = @"http://www.w3.org/1999/xlink";
|
||||
NSXMLNode* attributeNode = [element attributeForLocalName:@"href"
|
||||
URI:namespaceURI];
|
||||
if (attributeNode == nil) {
|
||||
attributeNode = [element attributeForName:(NSString*)IJSVGAttributeXLink];
|
||||
}
|
||||
return attributeNode;
|
||||
}
|
||||
|
||||
- (NSXMLElement*)mergedElement:(NSXMLElement*)element
|
||||
withReferenceElement:(NSXMLElement*)reference
|
||||
{
|
||||
@@ -1104,70 +1156,71 @@
|
||||
|
||||
#pragma mark Parser stuff!
|
||||
|
||||
- (void)_parsePathCommandData:(NSString*)command
|
||||
intoPath:(IJSVGPath*)path
|
||||
- (void)_parsePathCommandDataBuffer:(const char*)buffer
|
||||
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));
|
||||
}
|
||||
NSUInteger len = strlen(buffer);
|
||||
NSUInteger lastIndex = len - 1;
|
||||
|
||||
// make sure we plus 1 for the null byte
|
||||
char* charBuffer = (char*)malloc(sizeof(char)*(len + 1));
|
||||
NSInteger start = 0;
|
||||
IJSVGCommand* _currentCommand = nil;
|
||||
for (int i = 0; i < len; i++) {
|
||||
unichar currentChar = buffer[i];
|
||||
unichar nextChar = buffer[i + 1];
|
||||
|
||||
BOOL atEnd = i == len - 1;
|
||||
for (NSInteger i = 0; i < len; i++) {
|
||||
char nextChar = buffer[i + 1];
|
||||
BOOL atEnd = i == lastIndex;
|
||||
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];
|
||||
|
||||
// copy memory from current buffer
|
||||
NSInteger index = ((i + 1) - start);
|
||||
memcpy(&charBuffer[0], &buffer[start], sizeof(char)*index);
|
||||
charBuffer[index] = '\0';
|
||||
|
||||
// create the command from the substring
|
||||
unsigned long length = index + 1;
|
||||
size_t mlength = sizeof(char)*length;
|
||||
char* commandString = (char*)malloc(mlength);
|
||||
memcpy(commandString, &charBuffer[0], mlength);
|
||||
|
||||
// reset start position
|
||||
start = (i + 1);
|
||||
|
||||
// previous command is actual subcommand
|
||||
IJSVGCommand* previousCommand = [_currentCommand subCommands].lastObject;
|
||||
IJSVGCommand* cCommand = [self _parseCommandString:commandString
|
||||
previousCommand:previousCommand
|
||||
intoPath:path];
|
||||
IJSVGCommand* previousCommand = _currentCommand.subCommands.lastObject;
|
||||
IJSVGCommand* cCommand = [self _parseCommandStringBuffer:commandString
|
||||
previousCommand:previousCommand
|
||||
intoPath:path];
|
||||
|
||||
// free the memory as at this point, we are done with it
|
||||
(void)free(commandString), commandString = NULL;
|
||||
|
||||
// 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);
|
||||
(void)free(charBuffer), charBuffer = NULL;
|
||||
}
|
||||
|
||||
- (IJSVGCommand*)_parseCommandString:(NSString*)string
|
||||
previousCommand:(IJSVGCommand*)previousCommand
|
||||
intoPath:(IJSVGPath*)path
|
||||
- (void)_parsePathCommandData:(NSString*)command
|
||||
intoPath:(IJSVGPath*)path
|
||||
{
|
||||
// invalid command
|
||||
if (command == nil || command.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate memory for the string buffer for reading
|
||||
const char* buffer = command.UTF8String;
|
||||
[self _parsePathCommandDataBuffer:buffer
|
||||
intoPath:path];
|
||||
}
|
||||
|
||||
- (IJSVGCommand*)_parseCommandStringBuffer:(const char*)buffer
|
||||
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
|
||||
@@ -1179,9 +1232,11 @@
|
||||
|
||||
// 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]) {
|
||||
Class commandClass = [IJSVGCommand commandClassForCommandChar:buffer[0]];
|
||||
IJSVGCommand* command = nil;
|
||||
command = (IJSVGCommand*)[[[commandClass alloc] initWithCommandStringBuffer:buffer
|
||||
dataStream:_commandDataStream] autorelease];
|
||||
for (IJSVGCommand* subCommand in command.subCommands) {
|
||||
[command.class runWithParams:subCommand.parameters
|
||||
paramCount:subCommand.parameterCount
|
||||
command:subCommand
|
||||
@@ -1198,48 +1253,47 @@
|
||||
{
|
||||
// convert a line into a command,
|
||||
// basically MX1 Y1LX2 Y2
|
||||
path.primitiveType = IJSVGPrimitivePathTypeLine;
|
||||
path.primitiveType = kIJSVGPrimitivePathTypeLine;
|
||||
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];
|
||||
char* buffer;
|
||||
asprintf(&buffer, "M%.2f %.2fL%.2f %.2f", x1, y1, x2, y2);
|
||||
[self _parsePathCommandDataBuffer:buffer
|
||||
intoPath:path];
|
||||
(void)free(buffer);
|
||||
}
|
||||
|
||||
- (void)_parseCircle:(NSXMLElement*)element
|
||||
intoPath:(IJSVGPath*)path
|
||||
{
|
||||
path.primitiveType = IJSVGPrimitivePathTypeCircle;
|
||||
path.primitiveType = kIJSVGPrimitivePathTypeCircle;
|
||||
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]];
|
||||
path.path = [NSBezierPath bezierPathWithOvalInRect:rect];
|
||||
}
|
||||
|
||||
- (void)_parseEllipse:(NSXMLElement*)element
|
||||
intoPath:(IJSVGPath*)path
|
||||
{
|
||||
path.primitiveType = IJSVGPrimitivePathTypeEllipse;
|
||||
path.primitiveType = kIJSVGPrimitivePathTypeEllipse;
|
||||
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]];
|
||||
path.path = [NSBezierPath bezierPathWithOvalInRect:rect];
|
||||
}
|
||||
|
||||
- (void)_parsePolyline:(NSXMLElement*)element
|
||||
intoPath:(IJSVGPath*)path
|
||||
{
|
||||
path.primitiveType = IJSVGPrimitivePathTypePolyLine;
|
||||
path.primitiveType = kIJSVGPrimitivePathTypePolyLine;
|
||||
[self _parsePoly:element
|
||||
intoPath:path
|
||||
closePath:NO];
|
||||
@@ -1248,7 +1302,7 @@
|
||||
- (void)_parsePolygon:(NSXMLElement*)element
|
||||
intoPath:(IJSVGPath*)path
|
||||
{
|
||||
path.primitiveType = IJSVGPrimitivePathTypePolygon;
|
||||
path.primitiveType = kIJSVGPrimitivePathTypePolygon;
|
||||
[self _parsePoly:element
|
||||
intoPath:path
|
||||
closePath:YES];
|
||||
@@ -1268,29 +1322,52 @@
|
||||
free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
// construct a command
|
||||
NSInteger capacity = count / 2;
|
||||
if (closePath == YES) {
|
||||
capacity += 1;
|
||||
|
||||
const int defBufferSize = 5;
|
||||
char* buffer;
|
||||
asprintf(&buffer, "M%f %f L", params[0], params[1]);
|
||||
|
||||
// compute a default buffer
|
||||
size_t bSize = strlen(buffer);
|
||||
size_t strLength = bSize;
|
||||
|
||||
// for every pair of coordinates
|
||||
for(int i = 2; i < count; i+= 2) {
|
||||
char* subbuf;
|
||||
asprintf(&subbuf, "%f %f ", params[i], params[i + 1]);
|
||||
size_t sSize = strlen(subbuf);
|
||||
|
||||
// if the new size of the string is large than the buffer
|
||||
// increase the buffer up another def size
|
||||
if((strLength + sSize + 1) > bSize) {
|
||||
size_t nLength = MAX(sSize, defBufferSize) + 2;
|
||||
buffer = realloc(buffer, sizeof(char)*(bSize+nLength));
|
||||
bSize += nLength;
|
||||
}
|
||||
|
||||
// append thr string onto the buffer, increment the
|
||||
// string length and free the subbuffer memory
|
||||
strcat(buffer, subbuf);
|
||||
strLength += sSize;
|
||||
(void)free(subbuf), subbuf = NULL;
|
||||
}
|
||||
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 == YES) {
|
||||
strcat(buffer, "z");
|
||||
}
|
||||
if (closePath) {
|
||||
[str appendString:@"z"];
|
||||
}
|
||||
[self _parsePathCommandData:str
|
||||
intoPath:path];
|
||||
free(params);
|
||||
|
||||
// actually perform the parse
|
||||
[self _parsePathCommandDataBuffer:buffer
|
||||
intoPath:path];
|
||||
|
||||
// free the params
|
||||
(void)free(buffer), buffer = NULL;
|
||||
(void)free(params), params = NULL;
|
||||
}
|
||||
|
||||
- (void)_parseRect:(NSXMLElement*)element
|
||||
intoPath:(IJSVGPath*)path
|
||||
{
|
||||
path.primitiveType = IJSVGPrimitivePathTypeRect;
|
||||
path.primitiveType = kIJSVGPrimitivePathTypeRect;
|
||||
// width and height
|
||||
CGFloat width = [IJSVGUtils floatValue:[element attributeForName:(NSString*)IJSVGAttributeWidth].stringValue
|
||||
fallBackForPercent:self.viewBox.size.width];
|
||||
@@ -1310,11 +1387,9 @@
|
||||
if ([element attributeForName:(NSString*)IJSVGAttributeRY] == nil) {
|
||||
rY = rX;
|
||||
}
|
||||
|
||||
NSBezierPath* newPath = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(x, y, width, height)
|
||||
xRadius:rX
|
||||
yRadius:rY];
|
||||
[path overwritePath:newPath];
|
||||
path.path = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(x, y, width, height)
|
||||
xRadius:rX
|
||||
yRadius:rY];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -623,8 +623,6 @@
|
||||
if (node.clipPath.units == IJSVGUnitObjectBoundingBox) {
|
||||
[self adjustLayer:clip
|
||||
toParentLayerFrame:layer];
|
||||
} else {
|
||||
clip.affineTransform = [self absoluteTransform:node];
|
||||
}
|
||||
|
||||
// add the layer
|
||||
@@ -639,8 +637,6 @@
|
||||
if (node.mask.units == IJSVGUnitObjectBoundingBox) {
|
||||
[self adjustLayer:mask
|
||||
toParentLayerFrame:layer];
|
||||
} else {
|
||||
mask.affineTransform = [self absoluteTransform:node];
|
||||
}
|
||||
|
||||
// add the layer
|
||||
@@ -648,8 +644,9 @@
|
||||
}
|
||||
|
||||
// recursive colourize for each item
|
||||
NSColor* color = [IJSVGColor computeColorSpace:NSColor.whiteColor];
|
||||
[self _recursiveColorLayersFromLayer:maskLayer
|
||||
withColor:[IJSVGColor computeColorSpace:NSColor.whiteColor].CGColor];
|
||||
withColor:color.CGColor];
|
||||
|
||||
// add the mask
|
||||
layer.mask = maskLayer;
|
||||
@@ -743,19 +740,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ (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++];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,5 +17,6 @@ CGFloat IJSVGMathSin(CGFloat val);
|
||||
CGFloat IJSVGMathAsin(CGFloat val);
|
||||
CGFloat IJSVGMathTan(CGFloat val);
|
||||
CGFloat IJSVGMathAtan(CGFloat val);
|
||||
CGFloat IJSVGMathToFixed(CGFloat val, NSInteger decimalPlaces);
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "IJSVGMath.h"
|
||||
#import "IJSVGCommandParser.h"
|
||||
|
||||
@implementation IJSVGMath
|
||||
|
||||
@@ -20,6 +21,12 @@ CGFloat IJSVGMathDeg(CGFloat val)
|
||||
return val * 180.f / M_PI;
|
||||
};
|
||||
|
||||
CGFloat IJSVGMathToFixed(CGFloat val, NSInteger decimalPlaces)
|
||||
{
|
||||
int p = pow(10, decimalPlaces);
|
||||
return (CGFloat)floor(p * val) / p;
|
||||
}
|
||||
|
||||
CGFloat IJSVGMathAcos(CGFloat val)
|
||||
{
|
||||
return IJSVGMathDeg(acosf(val));
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
BOOL IJSVGIsMainThread(void);
|
||||
void IJSVGBeginTransactionLock(void);
|
||||
void IJSVGEndTransactionLock(void);
|
||||
BOOL IJSVGBeginTransaction(void);
|
||||
void IJSVGEndTransaction(void);
|
||||
|
||||
@@ -7,22 +7,23 @@
|
||||
//
|
||||
|
||||
#import "IJSVGTransaction.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
BOOL IJSVGIsMainThread(void) { return NSThread.isMainThread; };
|
||||
|
||||
void IJSVGBeginTransactionLock(void)
|
||||
BOOL IJSVGBeginTransaction(void)
|
||||
{
|
||||
if (IJSVGIsMainThread()) {
|
||||
return;
|
||||
if(IJSVGIsMainThread() == YES) {
|
||||
return NO;
|
||||
}
|
||||
// use nsanimationcontext as this sets a private flag of 0x4
|
||||
// of the catransaction for background composites
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
return YES;
|
||||
};
|
||||
|
||||
void IJSVGEndTransactionLock(void)
|
||||
void IJSVGEndTransaction(void)
|
||||
{
|
||||
if (IJSVGIsMainThread()) {
|
||||
return;
|
||||
}
|
||||
[CATransaction commit];
|
||||
};
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGUtils.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGTransform;
|
||||
|
||||
typedef CGFloat (^IJSVGTransformParameterModifier)(NSInteger index, CGFloat value);
|
||||
typedef void (^IJSVGTransformApplyBlock)(IJSVGTransform * transform);
|
||||
typedef void (^IJSVGTransformApplyBlock)(IJSVGTransform* transform);
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, IJSVGTransformCommand) {
|
||||
IJSVGTransformCommandMatrix,
|
||||
@@ -27,34 +27,39 @@ typedef NS_OPTIONS(NSInteger, IJSVGTransformCommand) {
|
||||
};
|
||||
|
||||
@interface IJSVGTransform : NSObject {
|
||||
|
||||
|
||||
IJSVGTransformCommand command;
|
||||
CGFloat * parameters;
|
||||
CGFloat* parameters;
|
||||
NSInteger parameterCount;
|
||||
NSInteger sort;
|
||||
|
||||
}
|
||||
|
||||
@property ( nonatomic, assign ) IJSVGTransformCommand command;
|
||||
@property ( nonatomic, assign ) CGFloat * parameters;
|
||||
@property ( nonatomic, assign ) NSInteger parameterCount;
|
||||
@property ( nonatomic, assign ) NSInteger sort;
|
||||
@property (nonatomic, assign) IJSVGTransformCommand command;
|
||||
@property (nonatomic, assign) CGFloat* parameters;
|
||||
@property (nonatomic, assign) NSInteger parameterCount;
|
||||
@property (nonatomic, assign) NSInteger sort;
|
||||
|
||||
NSString * IJSVGDebugAffineTransform(CGAffineTransform transform);
|
||||
NSString * IJSVGDebugTransforms(NSArray<IJSVGTransform *> * transforms);
|
||||
void IJSVGApplyTransform(NSArray<IJSVGTransform *> * transforms, IJSVGTransformApplyBlock block);
|
||||
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform *> * transforms);
|
||||
void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApplyBlock block);
|
||||
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform*>* transforms);
|
||||
NSString* IJSVGTransformAttributeString(CGAffineTransform transform);
|
||||
|
||||
+ (NSArray<IJSVGTransform *> *)transformsFromAffineTransform:(CGAffineTransform)affineTransform;
|
||||
+ (NSArray *)transformsForString:(NSString *)string;
|
||||
+ (NSBezierPath *)transformedPath:(IJSVGPath *)path;
|
||||
+ (NSArray<NSString *> *)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform;
|
||||
+ (NSString *)affineTransformToSVGMatrixString:(CGAffineTransform)affineTransform;
|
||||
+ (NSArray<NSDictionary*>*)affineTransformToSVGTransformComponents:(CGAffineTransform)transform;
|
||||
+ (NSString*)affineTransformToSVGTransformComponentString:(CGAffineTransform)transform
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
+ (NSString*)affineTransformToSVGTransformComponentString:(CGAffineTransform)transform;
|
||||
+ (NSArray<IJSVGTransform*>*)transformsFromAffineTransform:(CGAffineTransform)affineTransform;
|
||||
+ (NSArray<IJSVGTransform*>*)transformsForString:(NSString*)string;
|
||||
+ (NSBezierPath*)transformedPath:(IJSVGPath*)path;
|
||||
+ (NSString*)affineTransformToSVGMatrixString:(CGAffineTransform)affineTransform;
|
||||
+ (NSString*)affineTransformToSVGMatrixString:(CGAffineTransform)transform
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
- (CGAffineTransform)CGAffineTransform;
|
||||
- (CGAffineTransform)CGAffineTransformWithModifier:(IJSVGTransformParameterModifier)modifier;
|
||||
- (CGAffineTransform)stackIdentity:(CGAffineTransform)identity;
|
||||
- (void)recalculateWithBounds:(CGRect)bounds;
|
||||
+ (IJSVGTransform *)transformByTranslatingX:(CGFloat)x
|
||||
y:(CGFloat)y;
|
||||
+ (IJSVGTransform*)transformByTranslatingX:(CGFloat)x
|
||||
y:(CGFloat)y;
|
||||
+ (IJSVGTransform*)transformByScaleX:(CGFloat)x
|
||||
y:(CGFloat)y;
|
||||
|
||||
@end
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(parameters);
|
||||
(void)free(parameters);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -33,22 +33,6 @@
|
||||
return trans;
|
||||
}
|
||||
|
||||
NSString* IJSVGDebugAffineTransform(CGAffineTransform transform)
|
||||
{
|
||||
NSMutableArray* strings = [[[NSMutableArray alloc] init] autorelease];
|
||||
[strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform]];
|
||||
return [strings componentsJoinedByString:@" "];
|
||||
}
|
||||
|
||||
NSString* IJSVGDebugTransforms(NSArray<IJSVGTransform*>* transforms)
|
||||
{
|
||||
NSMutableArray* strings = [[[NSMutableArray alloc] init] autorelease];
|
||||
IJSVGApplyTransform(transforms, ^(IJSVGTransform* transform) {
|
||||
[strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform.CGAffineTransform]];
|
||||
});
|
||||
return [strings componentsJoinedByString:@" "];
|
||||
}
|
||||
|
||||
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform*>* transforms)
|
||||
{
|
||||
__block CGAffineTransform trans = CGAffineTransformIdentity;
|
||||
@@ -58,6 +42,11 @@ CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform*>* transforms)
|
||||
return trans;
|
||||
}
|
||||
|
||||
NSString* IJSVGTransformAttributeString(CGAffineTransform transform)
|
||||
{
|
||||
return [IJSVGTransform affineTransformToSVGMatrixString:transform];
|
||||
}
|
||||
|
||||
void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApplyBlock block)
|
||||
{
|
||||
for (IJSVGTransform* transform in transforms) {
|
||||
@@ -78,13 +67,27 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
return transform;
|
||||
}
|
||||
|
||||
+ (IJSVGTransform*)transformByScaleX:(CGFloat)x
|
||||
y:(CGFloat)y
|
||||
{
|
||||
IJSVGTransform* transform = [[[self alloc] init] autorelease];
|
||||
transform.command = IJSVGTransformCommandScale;
|
||||
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)
|
||||
if (self.parameterCount == 1) {
|
||||
return;
|
||||
}
|
||||
self.parameters[1] = self.parameters[1] * max;
|
||||
self.parameters[2] = self.parameters[2] * max;
|
||||
}
|
||||
@@ -134,53 +137,90 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
return 10;
|
||||
}
|
||||
|
||||
+ (NSArray*)transformsForString:(NSString*)string
|
||||
+ (NSArray<IJSVGTransform*>*)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];
|
||||
}];
|
||||
NSMutableArray<IJSVGTransform*>* array = nil;
|
||||
array = [[[NSMutableArray alloc] init] autorelease];
|
||||
|
||||
// setup the buffer for the string to be stored in
|
||||
const char* charString = string.UTF8String;
|
||||
unsigned long length = strlen(charString);
|
||||
char* buffer = (char*)calloc(sizeof(char), length);
|
||||
char* originBuffer = buffer;
|
||||
int bufferIndex = 0;
|
||||
|
||||
// each command requires a name and parameters, store for later use
|
||||
NSString* commandName = nil;
|
||||
NSString* params = nil;
|
||||
for(int i = 0; i < length; i++) {
|
||||
char currentChar = *charString++;
|
||||
|
||||
// start of params - store the command name as its current in the buffer
|
||||
if(currentChar == '(') {
|
||||
// rest the pointer to beginning
|
||||
buffer = originBuffer;
|
||||
IJSVGTrimCharBuffer(buffer);
|
||||
commandName = [NSString stringWithUTF8String:buffer];
|
||||
// write null up until the limit we reached
|
||||
memset(buffer, '\0', bufferIndex);
|
||||
bufferIndex = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// end of params - store the params into the buffer
|
||||
if(currentChar == ')') {
|
||||
// rest the pointer to beginning
|
||||
buffer = originBuffer;
|
||||
params = [NSString stringWithUTF8String:buffer];
|
||||
// write null up until the limit we reached
|
||||
memset(buffer, '\0', bufferIndex);
|
||||
bufferIndex = 0;
|
||||
|
||||
// at this point we can just add the command
|
||||
IJSVGTransformCommand commandType = [self.class commandForCommandString:commandName];
|
||||
if(commandType == IJSVGTransformCommandNotImplemented) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create a new transform object and parse the parameters
|
||||
NSInteger count = 0;
|
||||
IJSVGTransform* transform = [[[self.class alloc] init] autorelease];
|
||||
transform.command = commandType;
|
||||
transform.sort = [self.class sortForTransformCommand:commandType];
|
||||
transform.parameters = [IJSVGUtils commandParameters:params
|
||||
count:&count];
|
||||
transform.parameterCount = count;
|
||||
|
||||
// add to the list of transforms to return
|
||||
[array addObject:transform];
|
||||
|
||||
// reset these values
|
||||
commandName = nil;
|
||||
params = nil;
|
||||
continue;
|
||||
}
|
||||
|
||||
// increment the buffer count
|
||||
*buffer++ = currentChar;
|
||||
bufferIndex++;
|
||||
}
|
||||
return transforms;
|
||||
buffer = originBuffer;
|
||||
(void)free(buffer), buffer = NULL;
|
||||
return array;
|
||||
}
|
||||
|
||||
+ (NSBezierPath*)transformedPath:(IJSVGPath*)path
|
||||
{
|
||||
if (path.transforms.count == 0)
|
||||
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){
|
||||
at.transformStruct = (NSAffineTransformStruct) {
|
||||
.m11 = transform.parameters[0],
|
||||
.m12 = transform.parameters[1],
|
||||
.m21 = transform.parameters[2],
|
||||
@@ -195,7 +235,7 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
case IJSVGTransformCommandSkewX: {
|
||||
CGFloat degrees = transform.parameters[0];
|
||||
CGFloat radians = degrees * M_PI / 180.f;
|
||||
at.transformStruct = (NSAffineTransformStruct){
|
||||
at.transformStruct = (NSAffineTransformStruct) {
|
||||
.m11 = 1.f,
|
||||
.m12 = 0.f,
|
||||
.m21 = tan(radians),
|
||||
@@ -210,7 +250,7 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
case IJSVGTransformCommandSkewY: {
|
||||
CGFloat degrees = transform.parameters[0];
|
||||
CGFloat radians = degrees * M_PI / 180.f;
|
||||
at.transformStruct = (NSAffineTransformStruct){
|
||||
at.transformStruct = (NSAffineTransformStruct) {
|
||||
.m11 = 1.f,
|
||||
.m12 = tan(radians),
|
||||
.m21 = 0.f,
|
||||
@@ -325,10 +365,10 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
// scale
|
||||
case IJSVGTransformCommandScale: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p1 = self.parameters[1];
|
||||
if (self.parameterCount == 1) {
|
||||
return CGAffineTransformScale(identity, p0, p0);
|
||||
}
|
||||
CGFloat p1 = self.parameters[1];
|
||||
return CGAffineTransformScale(identity, p0, p1);
|
||||
}
|
||||
|
||||
@@ -389,13 +429,14 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
// translate
|
||||
case IJSVGTransformCommandTranslate: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
if (self.parameterCount == 1) {
|
||||
return CGAffineTransformMakeTranslation(p0, 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);
|
||||
}
|
||||
|
||||
@@ -420,13 +461,14 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
// scale
|
||||
case IJSVGTransformCommandScale: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
if (self.parameterCount == 1) {
|
||||
return CGAffineTransformMakeScale(p0, p0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -452,9 +494,9 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// rotate
|
||||
case IJSVGTransformCommandRotate: {
|
||||
if (self.parameterCount == 1)
|
||||
if (self.parameterCount == 1) {
|
||||
return CGAffineTransformMakeRotation((self.parameters[0] / 180) * M_PI);
|
||||
else {
|
||||
} else {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p2 = self.parameters[2];
|
||||
@@ -483,121 +525,209 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
+ (NSArray<IJSVGTransform*>*)transformsFromAffineTransform:(CGAffineTransform)affineTransform
|
||||
{
|
||||
NSArray* strings = [self affineTransformToSVGTransformAttributeString:affineTransform];
|
||||
return [self transformsForString:[strings componentsJoinedByString:@" "]];
|
||||
NSString* matrix = [self affineTransformToSVGMatrixString:affineTransform];
|
||||
return [self transformsForString:matrix];
|
||||
}
|
||||
|
||||
+ (NSString*)affineTransformToSVGTransformComponentString:(CGAffineTransform)transform
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
NSArray<NSDictionary*>* trans = [self affineTransformToSVGTransformComponents:transform];
|
||||
trans = [self filterUselessAffineTransformComponents:trans];
|
||||
NSMutableArray<NSString*>* strings = [[[NSMutableArray alloc] initWithCapacity:trans.count] autorelease];
|
||||
for (NSDictionary* dict in trans) {
|
||||
NSArray<NSNumber*>* data = dict[@"data"];
|
||||
NSString* method = dict[@"name"];
|
||||
NSMutableArray* dataStrings = [[[NSMutableArray alloc] initWithCapacity:data.count] autorelease];
|
||||
for (NSNumber* number in data) {
|
||||
[dataStrings addObject:IJSVGShortFloatStringWithOptions(number.floatValue,
|
||||
floatingPointOptions)];
|
||||
}
|
||||
[strings addObject:[NSString stringWithFormat:@"%@(%@)", method,
|
||||
IJSVGCompressFloatParameterArray(dataStrings)]];
|
||||
}
|
||||
NSString* componentsString = [strings componentsJoinedByString:@" "];
|
||||
NSString* matrixString = [self affineTransformToSVGMatrixString:transform
|
||||
floatingPointOptions:floatingPointOptions];
|
||||
return componentsString.length < matrixString.length ? componentsString : matrixString;
|
||||
}
|
||||
|
||||
+ (NSString*)affineTransformToSVGTransformComponentString:(CGAffineTransform)transform
|
||||
{
|
||||
NSArray<NSDictionary*>* trans = [self affineTransformToSVGTransformComponents:transform];
|
||||
trans = [self filterUselessAffineTransformComponents:trans];
|
||||
NSMutableArray<NSString*>* strings = [[[NSMutableArray alloc] initWithCapacity:trans.count] autorelease];
|
||||
for (NSDictionary* dict in trans) {
|
||||
NSArray<NSNumber*>* data = dict[@"data"];
|
||||
NSString* method = dict[@"name"];
|
||||
NSMutableArray* dataStrings = [[[NSMutableArray alloc] initWithCapacity:data.count] autorelease];
|
||||
for (NSNumber* number in data) {
|
||||
[dataStrings addObject:IJSVGShortFloatString(number.floatValue)];
|
||||
}
|
||||
[strings addObject:[NSString stringWithFormat:@"%@(%@)", method,
|
||||
IJSVGCompressFloatParameterArray(dataStrings)]];
|
||||
}
|
||||
NSString* componentsString = [strings componentsJoinedByString:@" "];
|
||||
NSString* matrixString = [self affineTransformToSVGMatrixString:transform];
|
||||
return componentsString.length < matrixString.length ? componentsString : matrixString;
|
||||
}
|
||||
|
||||
+ (NSString*)affineTransformToSVGMatrixString:(CGAffineTransform)transform
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
NSArray<NSString*>* numbers = @[
|
||||
IJSVGShortFloatStringWithOptions(transform.a, floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(transform.b, floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(transform.c, floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(transform.d, floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(transform.tx, floatingPointOptions),
|
||||
IJSVGShortFloatStringWithOptions(transform.ty, floatingPointOptions)
|
||||
];
|
||||
return [NSString stringWithFormat:@"matrix(%@)", IJSVGCompressFloatParameterArray(numbers)];
|
||||
}
|
||||
|
||||
+ (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];
|
||||
NSArray<NSString*>* numbers = @[
|
||||
IJSVGShortFloatString(transform.a),
|
||||
IJSVGShortFloatString(transform.b),
|
||||
IJSVGShortFloatString(transform.c),
|
||||
IJSVGShortFloatString(transform.d),
|
||||
IJSVGShortFloatString(transform.tx),
|
||||
IJSVGShortFloatString(transform.ty)
|
||||
];
|
||||
return [NSString stringWithFormat:@"matrix(%@)",
|
||||
IJSVGCompressFloatParameterArray(numbers)];
|
||||
}
|
||||
|
||||
// this is an Object-C version of the matrixToTransform method from SVGO
|
||||
+ (NSArray<NSString*>*)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform
|
||||
+ (NSArray<NSDictionary*>*)filterUselessAffineTransformComponents:(NSArray<NSDictionary*>*)components
|
||||
{
|
||||
const CGFloat data[6] = {
|
||||
affineTransform.a,
|
||||
affineTransform.b,
|
||||
affineTransform.c,
|
||||
affineTransform.d,
|
||||
affineTransform.tx,
|
||||
affineTransform.ty
|
||||
NSMutableArray* comps = [[[NSMutableArray alloc] initWithCapacity:components.count] autorelease];
|
||||
NSArray<NSString*>* names = @[ @"translate", @"rotate", @"skewX", @"skewY" ];
|
||||
for (NSDictionary* transform in components) {
|
||||
NSString* name = transform[@"name"];
|
||||
NSArray<NSNumber*>* data = transform[@"data"];
|
||||
if ([names containsObject:name] && (data.count == 1 || [name isEqualToString:@"rotate"]) && data[0].floatValue == 0.f) {
|
||||
continue;
|
||||
} else if ([name isEqualToString:@"translate"] && data[0].floatValue == 0.f && data[1].floatValue == 0.f) {
|
||||
continue;
|
||||
} else if ([name isEqualToString:@"scale"] && data[0].floatValue == 1.f && (data.count < 2 || (data.count == 2 && data[1].floatValue == 1.f))) {
|
||||
continue;
|
||||
} else if ([name isEqualToString:@"matrix"] && data[0].floatValue == 1.f && data[3].floatValue == 1.f && !(data[1].floatValue != 0.f || data[2].floatValue != 0.f || data[4].floatValue != 0.f || data[5].floatValue != 0.f)) {
|
||||
continue;
|
||||
}
|
||||
[comps addObject:transform];
|
||||
}
|
||||
return comps;
|
||||
}
|
||||
|
||||
+ (NSArray<NSDictionary*>*)affineTransformToSVGTransformComponents:(CGAffineTransform)transform
|
||||
{
|
||||
const NSUInteger precision = 5;
|
||||
CGFloat data[6] = {
|
||||
IJSVGMathToFixed(transform.a, precision),
|
||||
IJSVGMathToFixed(transform.b, precision),
|
||||
IJSVGMathToFixed(transform.c, precision),
|
||||
IJSVGMathToFixed(transform.d, precision),
|
||||
IJSVGMathToFixed(transform.tx, precision),
|
||||
IJSVGMathToFixed(transform.ty, precision)
|
||||
};
|
||||
|
||||
CGFloat sx = sqrtf(data[0] * data[0] + data[1] * data[1]);
|
||||
CGFloat sy = (data[0] * data[3] - data[1] * data[2]) / sx;
|
||||
|
||||
CGFloat sx = IJSVGMathToFixed(hypotf(data[0], data[1]), precision);
|
||||
CGFloat sy = IJSVGMathToFixed(((data[0] * data[3] - data[1] * data[2]) / sx), precision);
|
||||
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);
|
||||
BOOL scaleBefore = rowSum != 0.f || sx == sy;
|
||||
|
||||
NSMutableArray* trans = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSMutableArray* transforms = [[[NSMutableArray alloc] init] autorelease];
|
||||
|
||||
// translate
|
||||
// tx, ty -> translate
|
||||
if (data[4] != 0.f || data[5] != 0.f) {
|
||||
NSString* str = [NSString stringWithFormat:@"translate(%g, %g)", data[4], data[5]];
|
||||
[trans addObject:str];
|
||||
[transforms addObject:@{
|
||||
@"name" : @"translate",
|
||||
@"data" : @[ @(data[4]), @(data[5]) ]
|
||||
}];
|
||||
}
|
||||
|
||||
// skewX
|
||||
// [sx, 0, tan(a).sy, sy, 0, 0] -> skewX(a).scale(sx,sy)
|
||||
if (data[1] == 0.f && data[2] != 0.f) {
|
||||
NSString* str = [NSString stringWithFormat:@"skewX(%g)", IJSVGMathAtan(data[2] / sy)];
|
||||
[trans addObject:str];
|
||||
[transforms addObject:@{
|
||||
@"name" : @"skewX",
|
||||
@"data" : @[ @(IJSVGMathToFixed(IJSVGMathAtan(data[2] / sy), precision)) ]
|
||||
}];
|
||||
|
||||
// skewY
|
||||
// [sx, sy.tan(a), 0, sy, 0, 0] -> skewX(a).scale(sx, sy)
|
||||
} else if (data[1] != 0.f && data[2] == 0.f) {
|
||||
NSString* str = [NSString stringWithFormat:@"skewY(%g)", IJSVGMathAtan(data[1] / data[0])];
|
||||
[trans addObject:str];
|
||||
[transforms addObject:@{
|
||||
@"name" : @"skewY",
|
||||
@"data" : @[ @(IJSVGMathToFixed(IJSVGMathAtan(data[1] / data[0]), precision)) ]
|
||||
}];
|
||||
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];
|
||||
} else if (colSum == 0.f || (sx == 1.f && sy == 1.f) || !scaleBefore) {
|
||||
if (!scaleBefore) {
|
||||
sx = (data[0] < 0.f ? -1.f : 1.f) * hypotf(data[0], data[2]);
|
||||
sy = (data[3] < 0.f ? -1.f : 1.f) * hypotf(data[1], data[3]);
|
||||
if (sx != 1.f || sy != 1.f) {
|
||||
[transforms addObject:@{
|
||||
@"name" : @"scale",
|
||||
@"data" : (sx == sy) ? @[ @(sx) ] : @[ @(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];
|
||||
CGFloat angle = MIN(MAX(-1.f, data[0] / sx), 1.f);
|
||||
NSMutableArray<NSNumber*>* rotate = [[[NSMutableArray alloc] initWithCapacity:3] autorelease];
|
||||
[rotate addObject:@(IJSVGMathToFixed(IJSVGMathAcos(angle), precision) * ((scaleBefore ? 1.f : sy) * data[1] < 0.f ? -1.f : 1.f))];
|
||||
|
||||
if (rotate[0].floatValue != 0.f) {
|
||||
[transforms addObject:@{
|
||||
@"name" : @"rotate",
|
||||
@"data" : rotate
|
||||
}];
|
||||
}
|
||||
|
||||
// skewX
|
||||
if (rowSum != 0.f && colSum != 0.f) {
|
||||
NSString* str = [NSString stringWithFormat:@"skewX(%g)", IJSVGMathAtan(colSum / (sx * sx))];
|
||||
[trans addObject:str];
|
||||
[transforms addObject:@{
|
||||
@"name" : @"skewX",
|
||||
@"data" : @[ @(IJSVGMathToFixed(IJSVGMathAtan(colSum / (sx * sx)), precision)) ]
|
||||
}];
|
||||
}
|
||||
|
||||
// rotate around center
|
||||
if (rotate != 0.f && (data[4] != 0.f || data[5] != 0.f)) {
|
||||
[trans removeObjectAtIndex:0];
|
||||
|
||||
// rotate can consume translate
|
||||
if (rotate[0].floatValue != 0.f && (data[4] != 0.f || data[5] != 0.f)) {
|
||||
[transforms 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];
|
||||
CGFloat denom = (powf(1.f - cos, 2.f) + powf(sin, 2.f)) * (scaleBefore ? 1.f : (sx * sy));
|
||||
[rotate addObject:@(((1.f - cos) * x - sin * y) / denom)];
|
||||
[rotate addObject:@(((1.f - cos) * y + sin * x) / denom)];
|
||||
}
|
||||
} else if (data[1] != 0.f || data[2] != 0.f) {
|
||||
NSDictionary* trans = @{
|
||||
@"name" : @"matrix",
|
||||
@"data" : @[ @(data[0]), @(data[1]), @(data[2]), @(data[3]), @(data[4]), @(data[5]) ]
|
||||
};
|
||||
return @[ trans ];
|
||||
}
|
||||
|
||||
// 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];
|
||||
if (scaleBefore == YES && ((sx != 1.f || sy != 1.f) || transforms.count == 0)) {
|
||||
NSDictionary* trans = @{
|
||||
@"name" : @"scale",
|
||||
@"data" : (sx == sy) ? @[ @(sx) ] : @[ @(sx), @(sy) ]
|
||||
};
|
||||
[transforms addObject:trans];
|
||||
}
|
||||
|
||||
return trans;
|
||||
return transforms;
|
||||
}
|
||||
|
||||
- (NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ %@", [super description],
|
||||
[self.class affineTransformToSVGTransformAttributeString:self.CGAffineTransform]];
|
||||
[self.class affineTransformToSVGMatrixString:self.CGAffineTransform]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,9 +8,20 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef struct {
|
||||
BOOL round;
|
||||
int precision;
|
||||
} IJSVGFloatingPointOptions;
|
||||
|
||||
typedef NS_ENUM(NSInteger, IJSVGUnitLengthType) {
|
||||
IJSVGUnitLengthTypeNumber,
|
||||
IJSVGUnitLengthTypePercentage
|
||||
IJSVGUnitLengthTypePercentage,
|
||||
IJSVGUnitLengthTypeCM,
|
||||
IJSVGUnitLengthTypeMM,
|
||||
IJSVGUnitLengthTypeIN,
|
||||
IJSVGUnitLengthTypePT,
|
||||
IJSVGUnitLengthTypePC,
|
||||
IJSVGUnitLengthTypePX
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, IJSVGUnitType) {
|
||||
@@ -22,6 +33,7 @@ typedef NS_ENUM(NSInteger, IJSVGUnitType) {
|
||||
@interface IJSVGUnitLength : NSObject
|
||||
|
||||
@property (nonatomic, assign) IJSVGUnitLengthType type;
|
||||
@property (nonatomic, assign) IJSVGUnitLengthType originalType;
|
||||
@property (nonatomic, assign) CGFloat value;
|
||||
@property (nonatomic, assign) BOOL inherit;
|
||||
|
||||
@@ -38,5 +50,6 @@ typedef NS_ENUM(NSInteger, IJSVGUnitType) {
|
||||
- (CGFloat)valueAsPercentage;
|
||||
- (CGFloat)computeValue:(CGFloat)anotherValue;
|
||||
- (NSString*)stringValue;
|
||||
- (NSString*)stringValueWithFloatingPointOptions:(IJSVGFloatingPointOptions)options;
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGUnitLength.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@implementation IJSVGUnitLength
|
||||
|
||||
@synthesize value;
|
||||
@synthesize type;
|
||||
@synthesize inherit;
|
||||
@synthesize originalType;
|
||||
|
||||
+ (IJSVGUnitLength*)unitWithFloat:(CGFloat)number
|
||||
{
|
||||
@@ -54,6 +56,64 @@
|
||||
return unit;
|
||||
}
|
||||
|
||||
+ (IJSVGUnitLengthType)typeForString:(NSString*)string
|
||||
{
|
||||
if([string hasSuffix:@"%"] == YES) {
|
||||
return IJSVGUnitLengthTypePercentage;
|
||||
}
|
||||
if([string hasSuffix:@"cm"] == YES) {
|
||||
return IJSVGUnitLengthTypeCM;
|
||||
}
|
||||
if([string hasSuffix:@"mm"] == YES) {
|
||||
return IJSVGUnitLengthTypeMM;
|
||||
}
|
||||
if([string hasSuffix:@"in"] == YES) {
|
||||
return IJSVGUnitLengthTypeIN;
|
||||
}
|
||||
if([string hasSuffix:@"pt"] == YES) {
|
||||
return IJSVGUnitLengthTypePT;
|
||||
}
|
||||
if([string hasSuffix:@"pc"] == YES) {
|
||||
return IJSVGUnitLengthTypePC;
|
||||
}
|
||||
if([string hasSuffix:@"px"] == YES) {
|
||||
return IJSVGUnitLengthTypePX;
|
||||
}
|
||||
return IJSVGUnitLengthTypeNumber;
|
||||
}
|
||||
|
||||
+ (CGFloat)convertUnitValue:(CGFloat)unit
|
||||
toBaseFromUnitLengthType:(IJSVGUnitLengthType)type
|
||||
{
|
||||
switch(type) {
|
||||
case IJSVGUnitLengthTypeCM: {
|
||||
return unit * (96.f / 2.54f);
|
||||
}
|
||||
case IJSVGUnitLengthTypeMM: {
|
||||
return [self convertUnitValue:unit
|
||||
toBaseFromUnitLengthType:IJSVGUnitLengthTypeCM] / 10.f;
|
||||
}
|
||||
case IJSVGUnitLengthTypePercentage: {
|
||||
return unit / 100.f;
|
||||
}
|
||||
case IJSVGUnitLengthTypeIN: {
|
||||
// 1in = 96px
|
||||
return unit * 96.f;
|
||||
}
|
||||
case IJSVGUnitLengthTypePT: {
|
||||
// 1pt = 1.333...px
|
||||
return unit * 1.3333333f;
|
||||
}
|
||||
case IJSVGUnitLengthTypePC: {
|
||||
// 1pc = 16px
|
||||
return unit * 16.f;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
+ (IJSVGUnitLength*)unitWithString:(NSString*)string
|
||||
{
|
||||
// just return noting for inherit, node will deal
|
||||
@@ -68,9 +128,20 @@
|
||||
IJSVGUnitLength* unit = [[[self alloc] init] autorelease];
|
||||
unit.value = string.floatValue;
|
||||
unit.type = IJSVGUnitLengthTypeNumber;
|
||||
if ([string hasSuffix:@"%"] == YES) {
|
||||
unit.value /= 100.f;
|
||||
unit.type = IJSVGUnitLengthTypePercentage;
|
||||
|
||||
IJSVGUnitLengthType type = [self typeForString:string];
|
||||
unit.originalType = type;
|
||||
switch(type) {
|
||||
case IJSVGUnitLengthTypePercentage: {
|
||||
unit.value = [self convertUnitValue:unit.value
|
||||
toBaseFromUnitLengthType:type];
|
||||
unit.type = IJSVGUnitLengthTypePercentage;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
unit.value = [self convertUnitValue:unit.value
|
||||
toBaseFromUnitLengthType:type];
|
||||
break;
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
@@ -91,14 +162,25 @@
|
||||
- (NSString*)stringValue
|
||||
{
|
||||
if (self.type == IJSVGUnitLengthTypePercentage) {
|
||||
return [NSString stringWithFormat:@"%g%%", (self.value * 100.f)];
|
||||
return [NSString stringWithFormat:@"%@%%",
|
||||
IJSVGShortFloatString(self.value * 100.f)];
|
||||
}
|
||||
return [NSString stringWithFormat:@"%g", self.value];
|
||||
return IJSVGShortFloatString(self.value);
|
||||
}
|
||||
|
||||
- (NSString*)stringValueWithFloatingPointOptions:(IJSVGFloatingPointOptions)options
|
||||
{
|
||||
if (self.type == IJSVGUnitLengthTypePercentage) {
|
||||
return [NSString stringWithFormat:@"%@%%",
|
||||
IJSVGShortFloatStringWithOptions(self.value * 100.f, options)];
|
||||
}
|
||||
return IJSVGShortFloatStringWithOptions(self.value, options);
|
||||
}
|
||||
|
||||
- (NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%f%@", self.value, (self.type == IJSVGUnitLengthTypePercentage ? @"%" : @"")];
|
||||
return [NSString stringWithFormat:@"%f%@",
|
||||
self.value, (self.type == IJSVGUnitLengthTypePercentage ? @"%" : @"")];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// IJSVGUnitPoint.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 12/02/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitLength.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGUnitPoint : NSObject
|
||||
|
||||
@property (nonatomic, retain) IJSVGUnitLength* x;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* y;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// IJSVGUnitPoint.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 12/02/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitPoint.h"
|
||||
|
||||
@implementation IJSVGUnitPoint
|
||||
|
||||
@synthesize x = _x;
|
||||
@synthesize y = _y;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_x release], _x = nil;
|
||||
(void)[_y release], _y = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (IJSVGUnitPoint*)pointWithX:(IJSVGUnitLength*)x
|
||||
y:(IJSVGUnitLength*)y
|
||||
{
|
||||
IJSVGUnitPoint* point = [[[self alloc] init] autorelease];
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
return point;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// IJSVGUnitRect.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 12/02/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitPoint.h"
|
||||
#import "IJSVGUnitSize.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGUnitRect : NSObject
|
||||
|
||||
@property (nonatomic, retain) IJSVGUnitSize* size;
|
||||
@property (nonatomic, retain) IJSVGUnitPoint* origin;
|
||||
|
||||
+ (IJSVGUnitRect*)rectWithOrigin:(IJSVGUnitPoint*)origin
|
||||
size:(IJSVGUnitSize*)size;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// IJSVGUnitRect.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 12/02/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitRect.h"
|
||||
|
||||
@implementation IJSVGUnitRect
|
||||
|
||||
@synthesize size = _size;
|
||||
@synthesize origin = _origin;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_size release], _size = nil;
|
||||
(void)[_origin release], _origin = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (IJSVGUnitRect*)rectWithOrigin:(IJSVGUnitPoint*)origin
|
||||
size:(IJSVGUnitSize*)size
|
||||
{
|
||||
IJSVGUnitRect* rect = [[[self alloc] init] autorelease];
|
||||
rect.origin = origin;
|
||||
rect.size = size;
|
||||
return rect;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// IJSVGUnitSize.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 12/02/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitLength.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGUnitSize : NSObject
|
||||
|
||||
@property (nonatomic, retain) IJSVGUnitLength* width;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* height;
|
||||
|
||||
+ (IJSVGUnitSize*)sizeWithWidth:(IJSVGUnitLength*)width
|
||||
height:(IJSVGUnitLength*)height;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// IJSVGUnitSize.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 12/02/2020.
|
||||
// Copyright © 2020 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitSize.h"
|
||||
|
||||
@implementation IJSVGUnitSize
|
||||
|
||||
@synthesize width = _width;
|
||||
@synthesize height = _height;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_width release], _width = nil;
|
||||
(void)[_height release], _height = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (IJSVGUnitSize*)sizeWithWidth:(IJSVGUnitLength*)width
|
||||
height:(IJSVGUnitLength*)height
|
||||
{
|
||||
IJSVGUnitSize* size = [[[self alloc] init] autorelease];
|
||||
size.width = width;
|
||||
size.height = height;
|
||||
return size;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -10,7 +10,8 @@
|
||||
#import "IJSVGGradientUnitLength.h"
|
||||
#import "IJSVGStringAdditions.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <xlocale.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface IJSVGUtils : NSObject
|
||||
|
||||
@@ -20,20 +21,24 @@ CGFloat angle(CGPoint a, CGPoint b);
|
||||
CGFloat radians_to_degrees(CGFloat radians);
|
||||
CGFloat degrees_to_radians(CGFloat degrees);
|
||||
|
||||
void IJSVGTrimCharBuffer(char* buffer);
|
||||
|
||||
BOOL IJSVGIsCommonHTMLElementName(NSString* str);
|
||||
NSArray* IJSVGCommonHTMLElementNames(void);
|
||||
|
||||
IJSVGFloatingPointOptions IJSVGFloatingPointOptionsDefault(void);
|
||||
IJSVGFloatingPointOptions IJSVGFloatingPointOptionsMake(BOOL round, int precision);
|
||||
|
||||
NSString* IJSVGCompressFloatParameterArray(NSArray<NSString*>* stringToCompress);
|
||||
NSString* IJSVGShortFloatStringWithOptions(CGFloat f, IJSVGFloatingPointOptions options);
|
||||
NSString* IJSVGShortenFloatString(NSString* string);
|
||||
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;
|
||||
+ (IJSVGCommandType)typeForCommandChar:(char)commandChar;
|
||||
+ (CGFloat*)commandParameters:(NSString*)command
|
||||
count:(NSInteger*)count;
|
||||
+ (CGFloat*)parseViewBox:(NSString*)string;
|
||||
@@ -42,7 +47,7 @@ BOOL IJSVGIsSVGLayer(CALayer* layer);
|
||||
+ (IJSVGLineCapStyle)lineCapStyleForString:(NSString*)string;
|
||||
+ (IJSVGUnitType)unitTypeForString:(NSString*)string;
|
||||
+ (IJSVGBlendMode)blendModeForString:(NSString*)string;
|
||||
+ (NSString*)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode;
|
||||
+ (NSString* _Nullable)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode;
|
||||
+ (NSRange)rangeOfParentheses:(NSString*)string;
|
||||
|
||||
+ (void)logParameters:(CGFloat*)param
|
||||
@@ -50,7 +55,7 @@ BOOL IJSVGIsSVGLayer(CALayer* layer);
|
||||
+ (CGFloat)floatValue:(NSString*)string;
|
||||
+ (CGFloat)angleBetweenPointA:(NSPoint)point
|
||||
pointb:(NSPoint)point;
|
||||
+ (NSString*)defURL:(NSString*)string;
|
||||
+ (NSString* _Nullable)defURL:(NSString*)string;
|
||||
+ (CGFloat)floatValue:(NSString*)string
|
||||
fallBackForPercent:(CGFloat)viewBox;
|
||||
+ (CGFloat*)scanFloatsFromString:(NSString*)string
|
||||
@@ -60,5 +65,5 @@ BOOL IJSVGIsSVGLayer(CALayer* layer);
|
||||
weight:(CGFloat*)weight;
|
||||
|
||||
+ (CGPathRef)newFlippedCGPath:(CGPathRef)path;
|
||||
+ (CGPathRef)newCGPathFromBezierPath:(NSBezierPath*)bezPath;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -9,9 +9,24 @@
|
||||
#import "IJSVGLayer.h"
|
||||
#import "IJSVGShapeLayer.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import "IJSVGExporterPathInstruction.h"
|
||||
|
||||
@implementation IJSVGUtils
|
||||
|
||||
void IJSVGTrimCharBuffer(char* buffer)
|
||||
{
|
||||
char* ptr = buffer;
|
||||
unsigned long length = strlen(ptr);
|
||||
while(length-1 > 0 && isspace(ptr[length-1])) {
|
||||
ptr[--length] = '\0';
|
||||
}
|
||||
while(*ptr && isspace(*ptr)) {
|
||||
++ptr;
|
||||
--length;
|
||||
}
|
||||
memmove(buffer, ptr, length+1);
|
||||
}
|
||||
|
||||
BOOL IJSVGIsCommonHTMLElementName(NSString* str)
|
||||
{
|
||||
str = str.lowercaseString;
|
||||
@@ -160,166 +175,98 @@ NSArray* IJSVGCommonHTMLElementNames(void)
|
||||
return names;
|
||||
};
|
||||
|
||||
NSString* IJSVGShortenFloatString(NSString* string)
|
||||
{
|
||||
const char* chars = string.UTF8String;
|
||||
if (chars[0] == '-' && chars[1] == '0' && strstr(chars, ".") != NULL) {
|
||||
return [NSString stringWithFormat:@"-%@", [string substringFromIndex:2]];
|
||||
} else if (chars[0] == '0' && chars[1] == '.') {
|
||||
return [string substringFromIndex:1];
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
IJSVGFloatingPointOptions IJSVGFloatingPointOptionsDefault(void)
|
||||
{
|
||||
return IJSVGFloatingPointOptionsMake(NO, kIJSVGExporterPathInstructionFloatPrecision);
|
||||
}
|
||||
|
||||
IJSVGFloatingPointOptions IJSVGFloatingPointOptionsMake(BOOL round, int precision)
|
||||
{
|
||||
return (IJSVGFloatingPointOptions) {
|
||||
.round = round,
|
||||
.precision = precision
|
||||
};
|
||||
}
|
||||
|
||||
NSString* IJSVGShortFloatStringWithOptions(CGFloat f, IJSVGFloatingPointOptions options)
|
||||
{
|
||||
if (options.round == YES) {
|
||||
f = IJSVGExporterPathFloatToFixed(f, options.precision);
|
||||
}
|
||||
return IJSVGShortFloatString(f);
|
||||
};
|
||||
|
||||
NSString* IJSVGShortFloatString(CGFloat f)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%g", f];
|
||||
return IJSVGShortenFloatString([NSString stringWithFormat:@"%g", f]);
|
||||
};
|
||||
|
||||
NSString* IJSVGCompressFloatParameterArray(NSArray<NSString*>* strings)
|
||||
{
|
||||
char* lastCommandChars = NULL;
|
||||
NSInteger index = 0;
|
||||
NSMutableString* string = [[[NSMutableString alloc] init] autorelease];
|
||||
for (NSString* dataString in strings) {
|
||||
const char* chars = dataString.UTF8String;
|
||||
|
||||
// work out if the command is signed and or decimal
|
||||
BOOL isSigned = chars[0] == '-';
|
||||
BOOL isDecimal = (isSigned == NO && chars[0] == '.') || (isSigned == YES && chars[1] == '.');
|
||||
|
||||
// we also need to know if the previous command was a decimal or not
|
||||
BOOL lastWasDecimal = NO;
|
||||
if (lastCommandChars != NULL) {
|
||||
lastWasDecimal = strchr(lastCommandChars, '.') != NULL;
|
||||
}
|
||||
|
||||
// we only need a space if the current command is not signed
|
||||
// a decimal and the previous command was decimal too
|
||||
if (index++ == 0 || isSigned || (isDecimal == YES && lastWasDecimal == YES)) {
|
||||
[string appendString:dataString];
|
||||
} else {
|
||||
[string appendFormat:@" %@", dataString];
|
||||
}
|
||||
|
||||
// store last command chars
|
||||
lastCommandChars = (char*)chars;
|
||||
}
|
||||
return string;
|
||||
};
|
||||
|
||||
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;
|
||||
return IJSVGShortenFloatString(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)];
|
||||
return [NSString stringWithFormat:@"%@ %@",
|
||||
IJSVGShortFloatString(point.x),
|
||||
IJSVGShortFloatString(point.y)];
|
||||
};
|
||||
|
||||
BOOL IJSVGIsLegalCommandCharacter(unichar aChar)
|
||||
{
|
||||
const char* validChars = "MmZzLlHhVvCcSsQqTtAa";
|
||||
return strchr(validChars, aChar) != NULL;
|
||||
if ((aChar | ('M' ^ 'm')) == 'm' || (aChar | ('Z' ^ 'z')) == 'z' || (aChar | ('C' ^ 'c')) == 'c' || (aChar | ('L' ^ 'l')) == 'l' || (aChar | ('S' ^ 's')) == 's' || (aChar | ('Q' ^ 'q')) == 'q' || (aChar | ('H' ^ 'h')) == 'h' || (aChar | ('V' ^ 'v')) == 'v' || (aChar | ('T' ^ 't')) == 't' || (aChar | ('A' ^ 'a')) == 'a') {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL IJSVGIsSVGLayer(CALayer* layer)
|
||||
@@ -354,9 +301,9 @@ CGFloat degrees_to_radians(CGFloat degrees)
|
||||
return ((degrees) / 180.0 * M_PI);
|
||||
}
|
||||
|
||||
+ (IJSVGCommandType)typeForCommandString:(NSString*)string
|
||||
+ (IJSVGCommandType)typeForCommandChar:(char)commandChar
|
||||
{
|
||||
return isupper([string characterAtIndex:0]) ? kIJSVGCommandTypeAbsolute : kIJSVGCommandTypeRelative;
|
||||
return isupper(commandChar) ? kIJSVGCommandTypeAbsolute : kIJSVGCommandTypeRelative;
|
||||
}
|
||||
|
||||
+ (NSRange)rangeOfParentheses:(NSString*)string
|
||||
@@ -365,7 +312,7 @@ CGFloat degrees_to_radians(CGFloat degrees)
|
||||
const char* characters = string.UTF8String;
|
||||
unsigned long length = strlen(characters);
|
||||
for (NSInteger i = 0; i < length; i++) {
|
||||
char c = characters[i];
|
||||
char c = *characters++;
|
||||
if (c == '(') {
|
||||
range.location = i + 1;
|
||||
} else if (c == ')') {
|
||||
@@ -375,7 +322,7 @@ CGFloat degrees_to_radians(CGFloat degrees)
|
||||
return range;
|
||||
}
|
||||
|
||||
+ (NSString*)defURL:(NSString*)string
|
||||
+ (NSString* _Nullable)defURL:(NSString*)string
|
||||
{
|
||||
// insta check for URL
|
||||
NSCharacterSet* set = NSCharacterSet.whitespaceCharacterSet;
|
||||
@@ -505,7 +452,7 @@ CGFloat degrees_to_radians(CGFloat degrees)
|
||||
return IJSVGBlendModeNormal;
|
||||
}
|
||||
|
||||
+ (NSString*)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode
|
||||
+ (NSString* _Nullable)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode
|
||||
{
|
||||
switch (blendMode) {
|
||||
case IJSVGBlendModeMultiply: {
|
||||
@@ -570,14 +517,21 @@ CGFloat degrees_to_radians(CGFloat degrees)
|
||||
+ (CGFloat*)scanFloatsFromString:(NSString*)string
|
||||
size:(NSInteger*)length
|
||||
{
|
||||
return IJSVGParsePathDataSequence(string, NULL, 1, length);
|
||||
IJSVGPathDataStream* stream = IJSVGPathDataStreamCreateDefault();
|
||||
CGFloat* floats = IJSVGParsePathDataStreamSequence(string.UTF8String, string.length,
|
||||
stream, NULL, 1, length);
|
||||
IJSVGPathDataStreamRelease(stream);
|
||||
return floats;
|
||||
}
|
||||
|
||||
+ (CGFloat*)parseViewBox:(NSString*)string
|
||||
{
|
||||
NSInteger size = 0;
|
||||
return [self.class scanFloatsFromString:string
|
||||
size:&size];
|
||||
IJSVGPathDataStream* stream = IJSVGPathDataStreamCreate(4,
|
||||
IJSVG_STREAM_CHAR_BLOCK_SIZE);
|
||||
CGFloat* floats = IJSVGParsePathDataStreamSequence(string.UTF8String,
|
||||
string.length, stream, NULL, 1, NULL);
|
||||
IJSVGPathDataStreamRelease(stream);
|
||||
return floats;
|
||||
}
|
||||
|
||||
+ (CGFloat)floatValue:(NSString*)string
|
||||
@@ -621,55 +575,4 @@ CGFloat degrees_to_radians(CGFloat degrees)
|
||||
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
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// IJSVGCache.h
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 02/09/2014.
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVG.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <sys/stat.h>
|
||||
|
||||
@interface IJSVGCache : NSObject {
|
||||
}
|
||||
|
||||
+ (IJSVG*)cachedSVGForFileURL:(NSURL*)aURL;
|
||||
+ (void)cacheSVG:(IJSVG*)svg fileURL:(NSURL*)aURL;
|
||||
+ (void)flushCache;
|
||||
+ (BOOL)enabled;
|
||||
+ (void)setEnabled:(BOOL)flag;
|
||||
+ (void)purgeCachedSVGForFileURL:(NSURL*)aURL;
|
||||
+ (void)setEvictItemsAfter:(NSInteger)count;
|
||||
|
||||
@end
|
||||
@@ -1,77 +0,0 @@
|
||||
//
|
||||
// IJSVGCache.m
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 02/09/2014.
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGCache.h"
|
||||
#import <malloc/malloc.h>
|
||||
|
||||
@implementation IJSVGCache
|
||||
|
||||
static NSInteger _maxCacheItems = 20;
|
||||
static NSCache* _cache = nil;
|
||||
static BOOL _enabled = YES;
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[self setEnabled:_enabled];
|
||||
}
|
||||
|
||||
+ (void)setEvictItemsAfter:(NSInteger)count
|
||||
{
|
||||
_maxCacheItems = count;
|
||||
[_cache setTotalCostLimit:_maxCacheItems];
|
||||
}
|
||||
|
||||
+ (IJSVG*)cachedSVGForFileURL:(NSURL*)aURL
|
||||
{
|
||||
if (![self.class enabled] || _cache == nil)
|
||||
return nil;
|
||||
IJSVG* svg = nil;
|
||||
if ((svg = [_cache objectForKey:aURL]) == nil)
|
||||
return nil;
|
||||
return svg;
|
||||
}
|
||||
|
||||
+ (void)purgeCachedSVGForFileURL:(NSURL*)aURL
|
||||
{
|
||||
[_cache removeObjectForKey:aURL];
|
||||
}
|
||||
|
||||
+ (void)cacheSVG:(IJSVG*)svg
|
||||
fileURL:(NSURL*)aURL
|
||||
{
|
||||
[_cache setObject:svg
|
||||
forKey:aURL
|
||||
cost:1];
|
||||
}
|
||||
|
||||
+ (void)setEnabled:(BOOL)flag
|
||||
{
|
||||
_enabled = flag;
|
||||
if (!flag) {
|
||||
[self.class flushCache];
|
||||
return;
|
||||
}
|
||||
|
||||
// create a new cache if allowed
|
||||
if (_cache == nil) {
|
||||
_cache = [[NSCache alloc] init];
|
||||
[_cache setTotalCostLimit:_maxCacheItems];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)enabled
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
+ (void)flushCache
|
||||
{
|
||||
[_cache removeAllObjects];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user