Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 050df84672 | |||
| ac61d3d6d6 | |||
| fdde1fd5f6 | |||
| fe179076cc | |||
| 01dd0d25d2 | |||
| 799593d7d8 | |||
| 0c7cfd776c | |||
| 757c4317d3 | |||
| 1727505968 | |||
| 775c28e91a | |||
| ec539a12b3 | |||
| 43210c018e | |||
| 3773e10f44 | |||
| 51fb9cc871 | |||
| be08ada5da | |||
| a3a6ee5a05 | |||
| cccfc0db68 | |||
| 19db898bdd | |||
| 8abbdf390a | |||
| 6e98e2cfed | |||
| 2c536a8962 | |||
| 65a8c0a691 | |||
| 2942cc0a58 | |||
| ba7a05553e | |||
| c9a7788d98 | |||
| 774ff48074 | |||
| 2eb629cd21 | |||
| 137e34623f | |||
| 39b0b5bbb4 | |||
| 820fca2679 | |||
| 2e5819183d | |||
| eff56d3c60 | |||
| 7a4fd35a64 | |||
| 964dc3005d | |||
| 1a8d44ec95 | |||
| 717198457b | |||
| e2991ab8b0 | |||
| dda3e5ed8c | |||
| c3a0fb5b91 | |||
| 7ce4520a56 | |||
| 368d19ea81 | |||
| d26c2f489f | |||
| 75b0d55b63 | |||
| 310308cd8a | |||
| 278f405a41 | |||
| 7addd97d0c | |||
| d01ca0f3bb | |||
| 6d7ad17e2a | |||
| deb09eaf04 | |||
| 1e7b8b38a5 | |||
| 58e1a8c45d | |||
| a525e4351a | |||
| c87716b311 | |||
| 583a930bf7 | |||
| ec2473d450 | |||
| 3cc477955a | |||
| 1f0ff52dff | |||
| e96bfa54b0 | |||
| cd3b540274 | |||
| 1cfbaf14e4 | |||
| 5a389f88d3 | |||
| 9f43832ff3 | |||
| 65623ec552 | |||
| 5192520b7c | |||
| 5123ee7308 | |||
| c886a6a80d | |||
| 4cd2895703 | |||
| a98d84f209 | |||
| 8faab28823 | |||
| cca5524a11 | |||
| c14e2367a0 | |||
| db4b0e9a18 | |||
| 93d6a868a9 | |||
| 60fa627d99 | |||
| ccaa350190 | |||
| 727f8a2dea | |||
| 972812b3f6 | |||
| ad8f440c72 |
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
@@ -7,15 +7,21 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
590EB7A427F637EF0047CECF /* IJSVGTransformLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 590EB7A227F637EF0047CECF /* IJSVGTransformLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
590EB7A527F637EF0047CECF /* IJSVGTransformLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 590EB7A327F637EF0047CECF /* IJSVGTransformLayer.m */; };
|
||||
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 */; };
|
||||
591A3E4D25CC91F800AD45B7 /* IJSVGParsing.h in Headers */ = {isa = PBXBuildFile; fileRef = 591A3E4B25CC91F800AD45B7 /* IJSVGParsing.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
591A3E4E25CC91F800AD45B7 /* IJSVGParsing.m in Sources */ = {isa = PBXBuildFile; fileRef = 591A3E4C25CC91F800AD45B7 /* IJSVGParsing.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 */; };
|
||||
5978C46A280A241200D25296 /* IJSVGRootLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 5978C468280A241200D25296 /* IJSVGRootLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
5978C46B280A241200D25296 /* IJSVGRootLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 5978C469280A241200D25296 /* IJSVGRootLayer.m */; };
|
||||
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 */; };
|
||||
@@ -30,7 +36,6 @@
|
||||
59EB75DC23905F7300F5AE63 /* IJSVGText.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756B23905F6B00F5AE63 /* IJSVGText.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75DD23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB756C23905F6B00F5AE63 /* IJSVGCommandQuadraticCurve.m */; };
|
||||
59EB75DE23905F7300F5AE63 /* IJSVGCommandVerticalLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756D23905F6C00F5AE63 /* IJSVGCommandVerticalLine.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75DF23905F7300F5AE63 /* IJSVGWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75E023905F7300F5AE63 /* IJSVGStyleSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75E123905F7300F5AE63 /* IJSVGCommandSmoothCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75E223905F7300F5AE63 /* IJSVGColorList.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757123905F6C00F5AE63 /* IJSVGColorList.m */; };
|
||||
@@ -57,12 +62,10 @@
|
||||
59EB75F723905F7300F5AE63 /* IJSVGDef.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758623905F6C00F5AE63 /* IJSVGDef.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75F823905F7300F5AE63 /* IJSVGCommandHorizontalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758723905F6C00F5AE63 /* IJSVGCommandHorizontalLine.m */; };
|
||||
59EB75F923905F7300F5AE63 /* IJSVGFontConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75FA23905F7300F5AE63 /* IJSVGWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758923905F6D00F5AE63 /* IJSVGWriter.m */; };
|
||||
59EB75FB23905F7300F5AE63 /* IJSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758A23905F6D00F5AE63 /* IJSVGPath.m */; };
|
||||
59EB75FC23905F7300F5AE63 /* IJSVGGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB75FD23905F7300F5AE63 /* IJSVGPatternLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */; };
|
||||
59EB75FE23905F7300F5AE63 /* IJSVGRenderingStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */; };
|
||||
59EB75FF23905F7300F5AE63 /* IJSVGBezierPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */; };
|
||||
59EB760023905F7300F5AE63 /* IJSVGGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758F23905F6D00F5AE63 /* IJSVGGradientLayer.m */; };
|
||||
59EB760123905F7300F5AE63 /* IJSVGLayerTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */; };
|
||||
59EB760223905F7300F5AE63 /* IJSVGCommandVerticalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759123905F6D00F5AE63 /* IJSVGCommandVerticalLine.m */; };
|
||||
@@ -113,7 +116,6 @@
|
||||
59EB763123905F7300F5AE63 /* IJSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C023905F7100F5AE63 /* IJSVGText.m */; };
|
||||
59EB763223905F7300F5AE63 /* IJSVGView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C123905F7100F5AE63 /* IJSVGView.m */; };
|
||||
59EB763323905F7300F5AE63 /* IJSVGLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */; };
|
||||
59EB763423905F7300F5AE63 /* IJSVGBezierPathAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB763523905F7300F5AE63 /* IJSVGStyleSheetSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C423905F7100F5AE63 /* IJSVGStyleSheetSelector.m */; };
|
||||
59EB763623905F7300F5AE63 /* IJSVGImageLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C523905F7100F5AE63 /* IJSVGImageLayer.m */; };
|
||||
59EB763723905F7300F5AE63 /* IJSVGCommandClose.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C623905F7100F5AE63 /* IJSVGCommandClose.m */; };
|
||||
@@ -132,13 +134,25 @@
|
||||
59EB764423905F7300F5AE63 /* IJSVGRendering.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75D323905F7300F5AE63 /* IJSVGRendering.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB764523905F7300F5AE63 /* IJSVGExporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75D423905F7300F5AE63 /* IJSVGExporter.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59EB764623905F7300F5AE63 /* IJSVGRendering.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75D523905F7300F5AE63 /* IJSVGRendering.m */; };
|
||||
59F36508262F1ABB00BCE3FD /* IJSVGColorType.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F36506262F1ABB00BCE3FD /* IJSVGColorType.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59F36509262F1ABB00BCE3FD /* IJSVGColorType.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F36507262F1ABB00BCE3FD /* IJSVGColorType.m */; };
|
||||
59F9EAF82808BB5F00188ACB /* IJSVGViewBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F9EAF62808BB5F00188ACB /* IJSVGViewBox.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59F9EAF92808BB5F00188ACB /* IJSVGViewBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F9EAF72808BB5F00188ACB /* IJSVGViewBox.m */; };
|
||||
59FCC09427F2394D00BB924E /* IJSVGRootNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FCC09227F2394D00BB924E /* IJSVGRootNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59FCC09527F2394D00BB924E /* IJSVGRootNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 59FCC09327F2394D00BB924E /* IJSVGRootNode.m */; };
|
||||
59FDBF0027F3454800AF7038 /* IJSVGColorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FDBEFE27F3454800AF7038 /* IJSVGColorNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
59FDBF0127F3454800AF7038 /* IJSVGColorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 59FDBEFF27F3454800AF7038 /* IJSVGColorNode.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
590EB7A227F637EF0047CECF /* IJSVGTransformLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGTransformLayer.h; sourceTree = "<group>"; };
|
||||
590EB7A327F637EF0047CECF /* IJSVGTransformLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGTransformLayer.m; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
591A3E4B25CC91F800AD45B7 /* IJSVGParsing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGParsing.h; sourceTree = "<group>"; };
|
||||
591A3E4C25CC91F800AD45B7 /* IJSVGParsing.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGParsing.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; };
|
||||
@@ -146,6 +160,8 @@
|
||||
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; };
|
||||
5978C468280A241200D25296 /* IJSVGRootLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGRootLayer.h; sourceTree = "<group>"; };
|
||||
5978C469280A241200D25296 /* IJSVGRootLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGRootLayer.m; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
@@ -160,7 +176,6 @@
|
||||
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; 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>"; };
|
||||
@@ -187,12 +202,10 @@
|
||||
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; 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>"; };
|
||||
59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRenderingStyle.m; sourceTree = "<group>"; };
|
||||
59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGBezierPathAdditions.m; sourceTree = "<group>"; };
|
||||
59EB758F23905F6D00F5AE63 /* IJSVGGradientLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGradientLayer.m; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
@@ -243,7 +256,6 @@
|
||||
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; 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>"; };
|
||||
59EB75C523905F7100F5AE63 /* IJSVGImageLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImageLayer.m; sourceTree = "<group>"; };
|
||||
59EB75C623905F7100F5AE63 /* IJSVGCommandClose.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandClose.m; sourceTree = "<group>"; };
|
||||
@@ -262,6 +274,14 @@
|
||||
59EB75D323905F7300F5AE63 /* IJSVGRendering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRendering.h; sourceTree = "<group>"; };
|
||||
59EB75D423905F7300F5AE63 /* IJSVGExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporter.h; sourceTree = "<group>"; };
|
||||
59EB75D523905F7300F5AE63 /* IJSVGRendering.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRendering.m; sourceTree = "<group>"; };
|
||||
59F36506262F1ABB00BCE3FD /* IJSVGColorType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGColorType.h; sourceTree = "<group>"; };
|
||||
59F36507262F1ABB00BCE3FD /* IJSVGColorType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorType.m; sourceTree = "<group>"; };
|
||||
59F9EAF62808BB5F00188ACB /* IJSVGViewBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGViewBox.h; sourceTree = "<group>"; };
|
||||
59F9EAF72808BB5F00188ACB /* IJSVGViewBox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGViewBox.m; sourceTree = "<group>"; };
|
||||
59FCC09227F2394D00BB924E /* IJSVGRootNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGRootNode.h; sourceTree = "<group>"; };
|
||||
59FCC09327F2394D00BB924E /* IJSVGRootNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGRootNode.m; sourceTree = "<group>"; };
|
||||
59FDBEFE27F3454800AF7038 /* IJSVGColorNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGColorNode.h; sourceTree = "<group>"; };
|
||||
59FDBEFF27F3454800AF7038 /* IJSVGColorNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorNode.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -332,6 +352,8 @@
|
||||
59EB758523905F6C00F5AE63 /* IJSVGColor.m */,
|
||||
59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */,
|
||||
59EB757123905F6C00F5AE63 /* IJSVGColorList.m */,
|
||||
59F36506262F1ABB00BCE3FD /* IJSVGColorType.h */,
|
||||
59F36507262F1ABB00BCE3FD /* IJSVGColorType.m */,
|
||||
);
|
||||
path = Colors;
|
||||
sourceTree = "<group>";
|
||||
@@ -349,12 +371,14 @@
|
||||
59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */,
|
||||
59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */,
|
||||
59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */,
|
||||
59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */,
|
||||
59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */,
|
||||
59EB759723905F6D00F5AE63 /* IJSVGShapeLayer.h */,
|
||||
59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */,
|
||||
59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */,
|
||||
59EB757423905F6C00F5AE63 /* IJSVGStrokeLayer.m */,
|
||||
590EB7A227F637EF0047CECF /* IJSVGTransformLayer.h */,
|
||||
590EB7A327F637EF0047CECF /* IJSVGTransformLayer.m */,
|
||||
5978C468280A241200D25296 /* IJSVGRootLayer.h */,
|
||||
5978C469280A241200D25296 /* IJSVGRootLayer.m */,
|
||||
);
|
||||
path = Layers;
|
||||
sourceTree = "<group>";
|
||||
@@ -379,6 +403,8 @@
|
||||
59EB756923905F6B00F5AE63 /* IJSVGDef.m */,
|
||||
59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */,
|
||||
59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */,
|
||||
59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */,
|
||||
59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */,
|
||||
59EB75AB23905F6F00F5AE63 /* IJSVGGradient.h */,
|
||||
59EB75D223905F7300F5AE63 /* IJSVGGradient.m */,
|
||||
59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */,
|
||||
@@ -393,6 +419,10 @@
|
||||
59EB75AA23905F6F00F5AE63 /* IJSVGPattern.m */,
|
||||
59EB756B23905F6B00F5AE63 /* IJSVGText.h */,
|
||||
59EB75C023905F7100F5AE63 /* IJSVGText.m */,
|
||||
59FCC09227F2394D00BB924E /* IJSVGRootNode.h */,
|
||||
59FCC09327F2394D00BB924E /* IJSVGRootNode.m */,
|
||||
59FDBEFE27F3454800AF7038 /* IJSVGColorNode.h */,
|
||||
59FDBEFF27F3454800AF7038 /* IJSVGColorNode.m */,
|
||||
);
|
||||
path = Nodes;
|
||||
sourceTree = "<group>";
|
||||
@@ -418,6 +448,10 @@
|
||||
5919E65A23F480330051873A /* IJSVGUnitPoint.m */,
|
||||
59A24EBA23F480EA0090C374 /* IJSVGUnitSize.h */,
|
||||
59A24EBB23F480EA0090C374 /* IJSVGUnitSize.m */,
|
||||
591A3E4B25CC91F800AD45B7 /* IJSVGParsing.h */,
|
||||
591A3E4C25CC91F800AD45B7 /* IJSVGParsing.m */,
|
||||
59F9EAF62808BB5F00188ACB /* IJSVGViewBox.h */,
|
||||
59F9EAF72808BB5F00188ACB /* IJSVGViewBox.m */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
@@ -449,8 +483,6 @@
|
||||
592ABBEB2397A11800F44380 /* Additions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */,
|
||||
59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */,
|
||||
59EB75B823905F7000F5AE63 /* IJSVGStringAdditions.h */,
|
||||
59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */,
|
||||
594A10D8248D7C90001A3181 /* NSImage+IJSVGAdditions.h */,
|
||||
@@ -508,8 +540,6 @@
|
||||
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */,
|
||||
59EB75CD23905F7200F5AE63 /* IJSVGView.h */,
|
||||
59EB75C123905F7100F5AE63 /* IJSVGView.m */,
|
||||
59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */,
|
||||
59EB758923905F6D00F5AE63 /* IJSVGWriter.m */,
|
||||
);
|
||||
path = Core;
|
||||
sourceTree = "<group>";
|
||||
@@ -541,7 +571,6 @@
|
||||
files = (
|
||||
59EB762623905F7300F5AE63 /* IJSVGImage.h in Headers */,
|
||||
59EB760823905F7300F5AE63 /* IJSVGShapeLayer.h in Headers */,
|
||||
59EB75DF23905F7300F5AE63 /* IJSVGWriter.h in Headers */,
|
||||
59EB760F23905F7300F5AE63 /* IJSVGCommandEllipticalArc.h in Headers */,
|
||||
59EB75F523905F7300F5AE63 /* IJSVGError.h in Headers */,
|
||||
59EB763E23905F7300F5AE63 /* IJSVGView.h in Headers */,
|
||||
@@ -586,19 +615,25 @@
|
||||
59EB75D623905F7300F5AE63 /* IJSVGLayer.h in Headers */,
|
||||
59EB763023905F7300F5AE63 /* IJSVGPatternLayer.h in Headers */,
|
||||
59EB75F023905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.h in Headers */,
|
||||
59EB763423905F7300F5AE63 /* IJSVGBezierPathAdditions.h in Headers */,
|
||||
59EB761823905F7300F5AE63 /* IJSVGParser.h in Headers */,
|
||||
59EB761E23905F7300F5AE63 /* IJSVGGroupLayer.h in Headers */,
|
||||
59EB761D23905F7300F5AE63 /* IJSVGStyle.h in Headers */,
|
||||
5919E65723F47FF60051873A /* IJSVGUnitRect.h in Headers */,
|
||||
5919E65B23F480330051873A /* IJSVGUnitPoint.h in Headers */,
|
||||
591A3E4D25CC91F800AD45B7 /* IJSVGParsing.h in Headers */,
|
||||
59A24EBC23F480EA0090C374 /* IJSVGUnitSize.h in Headers */,
|
||||
59EB764523905F7300F5AE63 /* IJSVGExporter.h in Headers */,
|
||||
59F36508262F1ABB00BCE3FD /* IJSVGColorType.h in Headers */,
|
||||
59E7CFAF23B148600077D599 /* IJSVGCommandParser.h in Headers */,
|
||||
59EB762823905F7300F5AE63 /* IJSVGCommandClose.h in Headers */,
|
||||
59EB75E423905F7300F5AE63 /* IJSVGGradientUnitLength.h in Headers */,
|
||||
59FCC09427F2394D00BB924E /* IJSVGRootNode.h in Headers */,
|
||||
594A10DA248D7C90001A3181 /* NSImage+IJSVGAdditions.h in Headers */,
|
||||
59EB762D23905F7300F5AE63 /* IJSVGLayerTree.h in Headers */,
|
||||
59FDBF0027F3454800AF7038 /* IJSVGColorNode.h in Headers */,
|
||||
590EB7A427F637EF0047CECF /* IJSVGTransformLayer.h in Headers */,
|
||||
5978C46A280A241200D25296 /* IJSVGRootLayer.h in Headers */,
|
||||
59F9EAF82808BB5F00188ACB /* IJSVGViewBox.h in Headers */,
|
||||
59EB760B23905F7300F5AE63 /* IJSVGStyleSheetSelector.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -678,6 +713,7 @@
|
||||
59EB763923905F7300F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m in Sources */,
|
||||
59EB75D823905F7300F5AE63 /* IJSVGStyleSheetRule.m in Sources */,
|
||||
59EB75FB23905F7300F5AE63 /* IJSVGPath.m in Sources */,
|
||||
59F36509262F1ABB00BCE3FD /* IJSVGColorType.m in Sources */,
|
||||
59EB760123905F7300F5AE63 /* IJSVGLayerTree.m in Sources */,
|
||||
59EB763A23905F7300F5AE63 /* IJSVGForeignObject.m in Sources */,
|
||||
59EB761123905F7300F5AE63 /* IJSVGCommand.m in Sources */,
|
||||
@@ -695,22 +731,23 @@
|
||||
59EB760723905F7300F5AE63 /* IJSVGNode.m in Sources */,
|
||||
5919E65C23F480330051873A /* IJSVGUnitPoint.m in Sources */,
|
||||
59EB75E923905F7300F5AE63 /* IJSVGStringAdditions.m in Sources */,
|
||||
59FDBF0127F3454800AF7038 /* IJSVGColorNode.m in Sources */,
|
||||
59EB761723905F7300F5AE63 /* IJSVGRadialGradient.m in Sources */,
|
||||
59EB75E223905F7300F5AE63 /* IJSVGColorList.m in Sources */,
|
||||
59EB75ED23905F7300F5AE63 /* IJSVGFontConverter.m in Sources */,
|
||||
59EB763C23905F7300F5AE63 /* IJSVGCommandEllipticalArc.m in Sources */,
|
||||
59EB75E723905F7300F5AE63 /* IJSVGImage.m in Sources */,
|
||||
59EB75FF23905F7300F5AE63 /* IJSVGBezierPathAdditions.m in Sources */,
|
||||
59EB75E623905F7300F5AE63 /* IJSVGStyle.m in Sources */,
|
||||
59EB75EB23905F7300F5AE63 /* IJSVGShapeLayer.m in Sources */,
|
||||
59EB75F623905F7300F5AE63 /* IJSVGColor.m in Sources */,
|
||||
59EB75F323905F7300F5AE63 /* IJSVGGroupLayer.m in Sources */,
|
||||
591A3E4E25CC91F800AD45B7 /* IJSVGParsing.m in Sources */,
|
||||
5919E65823F47FF60051873A /* IJSVGUnitRect.m in Sources */,
|
||||
5978C46B280A241200D25296 /* IJSVGRootLayer.m in Sources */,
|
||||
59EB762523905F7300F5AE63 /* IJSVGTransform.m in Sources */,
|
||||
59EB760023905F7300F5AE63 /* IJSVGGradientLayer.m in Sources */,
|
||||
59EB762B23905F7300F5AE63 /* IJSVGUnitLength.m in Sources */,
|
||||
59EB75F823905F7300F5AE63 /* IJSVGCommandHorizontalLine.m in Sources */,
|
||||
59EB75FA23905F7300F5AE63 /* IJSVGWriter.m in Sources */,
|
||||
59EB764623905F7300F5AE63 /* IJSVGRendering.m in Sources */,
|
||||
59EB762E23905F7300F5AE63 /* IJSVGExporter.m in Sources */,
|
||||
59EB761623905F7300F5AE63 /* IJSVGParser.m in Sources */,
|
||||
@@ -718,14 +755,17 @@
|
||||
59EB762423905F7300F5AE63 /* IJSVGTransaction.m in Sources */,
|
||||
59EB75DA23905F7300F5AE63 /* IJSVGDef.m in Sources */,
|
||||
59EB763723905F7300F5AE63 /* IJSVGCommandClose.m in Sources */,
|
||||
59F9EAF92808BB5F00188ACB /* IJSVGViewBox.m in Sources */,
|
||||
59EB764323905F7300F5AE63 /* IJSVGGradient.m in Sources */,
|
||||
59EB762A23905F7300F5AE63 /* IJSVGGradientUnitLength.m in Sources */,
|
||||
59EB764223905F7300F5AE63 /* IJSVGStyleSheet.m in Sources */,
|
||||
59EB764023905F7300F5AE63 /* IJSVGExporterPathInstruction.m in Sources */,
|
||||
59EB75FE23905F7300F5AE63 /* IJSVGRenderingStyle.m in Sources */,
|
||||
59EB75F223905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.m in Sources */,
|
||||
590EB7A527F637EF0047CECF /* IJSVGTransformLayer.m in Sources */,
|
||||
59EB75EE23905F7300F5AE63 /* IJSVGImageRep.m in Sources */,
|
||||
59EB762223905F7300F5AE63 /* IJSVGMath.m in Sources */,
|
||||
59FCC09527F2394D00BB924E /* IJSVGRootNode.m in Sources */,
|
||||
59EB763D23905F7300F5AE63 /* IJSVGGroup.m in Sources */,
|
||||
59EB761F23905F7300F5AE63 /* IJSVGCommandLineTo.m in Sources */,
|
||||
59EB75F123905F7300F5AE63 /* IJSVGUtils.m in Sources */,
|
||||
|
||||
BIN
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1220"
|
||||
LastUpgradeVersion = "1250"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// IJSVGBezierPathAdditions.h
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 30/08/2014.
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSBezierPath (IJSVGAdditions)
|
||||
|
||||
- (void)addQuadCurveToPoint:(NSPoint)aPoint
|
||||
controlPoint:(NSPoint)cp;
|
||||
|
||||
- (CGPathRef)newCGPathRef:(BOOL)autoClose;
|
||||
|
||||
@end
|
||||
@@ -1,87 +0,0 @@
|
||||
//
|
||||
// IJSVGBezierPathAdditions.m
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 30/08/2014.
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGBezierPathAdditions.h"
|
||||
|
||||
@implementation NSBezierPath (IJSVGAdditions)
|
||||
|
||||
- (void)addQuadCurveToPoint:(CGPoint)QP2
|
||||
controlPoint:(CGPoint)QP1
|
||||
{
|
||||
CGPoint QP0 = [self currentPoint];
|
||||
CGPoint CP3 = QP2;
|
||||
CGPoint CP1 = CGPointMake(QP0.x + ((2.0 / 3.0) * (QP1.x - QP0.x)), QP0.y + ((2.0 / 3.0) * (QP1.y - QP0.y)));
|
||||
CGPoint CP2 = CGPointMake(QP2.x + (2.0 / 3.0) * (QP1.x - QP2.x), QP2.y + (2.0 / 3.0) * (QP1.y - QP2.y));
|
||||
|
||||
[self curveToPoint:CP3
|
||||
controlPoint1:CP1
|
||||
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
|
||||
@@ -7,43 +7,30 @@
|
||||
//
|
||||
|
||||
#import "IJSVGStringAdditions.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@implementation NSString (IJSVGAdditions)
|
||||
|
||||
- (NSArray<NSString*>*)ijsvg_componentsSeparatedByChars:(const char*)aChar
|
||||
{
|
||||
NSMutableArray* comp = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSInteger length = self.length;
|
||||
unichar* chars = (unichar*)calloc(sizeof(unichar), self.length);
|
||||
|
||||
NSInteger ind = 0;
|
||||
BOOL startedString = NO;
|
||||
const char* buffer = self.UTF8String;
|
||||
|
||||
for (NSInteger i = 0; i < length; i++) {
|
||||
unichar theChar = buffer[i];
|
||||
|
||||
// start the buffer
|
||||
BOOL isEqualToChar = strchr(aChar, theChar) != NULL;
|
||||
if (isEqualToChar == NO) {
|
||||
startedString = YES;
|
||||
chars[ind++] = theChar;
|
||||
}
|
||||
|
||||
// has started and char is the search char, or its at end
|
||||
if ((startedString == YES && isEqualToChar) || (i == (length - 1) && startedString == YES)) {
|
||||
startedString = NO;
|
||||
|
||||
// append the comp
|
||||
[comp addObject:[NSString stringWithCharacters:chars length:ind]];
|
||||
|
||||
// restart and realloc the memory
|
||||
ind = 0;
|
||||
chars = memset(chars, '\0', sizeof(unichar) * ind);
|
||||
}
|
||||
char* chars = (char*)self.UTF8String;
|
||||
if(chars == NULL || strlen(chars) == 0) {
|
||||
return @[];
|
||||
}
|
||||
free(chars);
|
||||
return comp;
|
||||
NSMutableArray<NSString*>* strings = nil;
|
||||
strings = [[[NSMutableArray alloc] init] autorelease];
|
||||
char* copy = strdup(chars);
|
||||
char* spt = NULL;
|
||||
char* ptr = strtok_r(copy, aChar, &spt);
|
||||
while(ptr != NULL) {
|
||||
NSString* possibleString = nil;
|
||||
if((possibleString = [NSString stringWithUTF8String:ptr]) != nil) {
|
||||
[strings addObject:possibleString];
|
||||
}
|
||||
ptr = strtok_r(NULL, aChar, &spt);
|
||||
}
|
||||
(void)free(copy), copy = NULL;
|
||||
return strings;
|
||||
}
|
||||
|
||||
- (BOOL)ijsvg_containsAlpha
|
||||
@@ -78,17 +65,7 @@
|
||||
- (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;
|
||||
return IJSVGCharBufferIsHEX((char*)chars);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -167,6 +167,8 @@ typedef NS_ENUM(NSInteger, IJSVGPredefinedColor) {
|
||||
IJSVGColorYellowgreen
|
||||
};
|
||||
|
||||
extern NSString* const IJSVGColorCurrentColorName;
|
||||
|
||||
@interface IJSVGColor : NSObject
|
||||
|
||||
CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness);
|
||||
@@ -179,6 +181,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
|
||||
+ (NSString*)colorStringFromColor:(NSColor*)color;
|
||||
+ (NSColor*)colorFromHEXInteger:(NSInteger)hex;
|
||||
+ (NSColor*)computeColor:(id)colour;
|
||||
+ (BOOL)isNoneOrTransparent:(NSString*)string;
|
||||
+ (NSColor*)colorFromString:(NSString*)string;
|
||||
+ (NSColor*)colorFromHEXString:(NSString*)string;
|
||||
+ (NSColor*)colorFromHEXString:(NSString*)string
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
#import "IJSVGColor.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import "IJSVGStringAdditions.h"
|
||||
#import "IJSVGParsing.h"
|
||||
|
||||
NSString* const IJSVGColorCurrentColorName = @"currentColor";
|
||||
|
||||
@implementation IJSVGColor
|
||||
|
||||
static NSDictionary* _colorTree = nil;
|
||||
|
||||
|
||||
CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness)
|
||||
{
|
||||
hue *= (1.f / 360.f);
|
||||
@@ -240,39 +244,59 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
|
||||
alpha:a]];
|
||||
}
|
||||
|
||||
+ (BOOL)isNoneOrTransparent:(NSString*)string
|
||||
{
|
||||
const char* str = string.lowercaseString.UTF8String;
|
||||
return strcmp(str, "none") == 0 || strcmp(str, "transparent") == 0;
|
||||
}
|
||||
|
||||
+ (NSColor*)colorFromString:(NSString*)string
|
||||
{
|
||||
NSCharacterSet* set = NSCharacterSet.whitespaceAndNewlineCharacterSet;
|
||||
string = [string stringByTrimmingCharactersInSet:set];
|
||||
|
||||
if ([string length] < 3) {
|
||||
// swap over to C for performance
|
||||
if(string == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSColor* color = nil;
|
||||
string = [string lowercaseString];
|
||||
if ([self.class isHex:string] == NO) {
|
||||
color = [self.class colorFromPredefinedColorName:string];
|
||||
if (color != nil) {
|
||||
return color;
|
||||
}
|
||||
|
||||
const char* oString = string.UTF8String;
|
||||
if(strlen(oString) == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// is simply a clear color, dont fill
|
||||
if ([string.lowercaseString isEqualToString:@"none"] ||
|
||||
[string.lowercaseString isEqualToString:@"transparent"]) {
|
||||
return [self computeColorSpace:NSColor.clearColor];
|
||||
|
||||
char* str = IJSVGTimmedCharBufferCreate(oString);
|
||||
if (IJSVGCharBufferIsHEX(str) == YES) {
|
||||
(void)free(str), str = NULL;
|
||||
return [self.class colorFromHEXString:string];
|
||||
}
|
||||
|
||||
// is it RGB?
|
||||
if ([string hasPrefix:@"rgb"] == YES) {
|
||||
NSRange range = [IJSVGUtils rangeOfParentheses:string];
|
||||
NSString* rgbString = [string substringWithRange:range];
|
||||
NSArray* parts = [rgbString ijsvg_componentsSeparatedByChars:","];
|
||||
if (IJSVGCharBufferHasPrefix(str, "rgb") == YES) {
|
||||
NSUInteger count = 0;
|
||||
IJSVGParsingStringMethod** methods = NULL;
|
||||
methods = IJSVGParsingMethodParseString(str, &count);
|
||||
IJSVGParsingStringMethod* method = methods[0];
|
||||
|
||||
// memory clean for the string
|
||||
(void)free(str), str = NULL;
|
||||
|
||||
// nothing to return, just mem clean and get out of here
|
||||
if(count == 0 || methods == NULL) {
|
||||
if(methods != NULL) {
|
||||
IJSVGParsingStringMethodsRelease(methods, count);
|
||||
methods = NULL;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
// parse the parameters
|
||||
NSString* parameters = [NSString stringWithUTF8String:method->parameters];
|
||||
NSArray* parts = [parameters ijsvg_componentsSeparatedByChars:","];
|
||||
NSString* alpha = @"100%";
|
||||
if (parts.count == 4) {
|
||||
alpha = parts[3];
|
||||
}
|
||||
|
||||
IJSVGParsingStringMethodsRelease(methods, count);
|
||||
methods = NULL;
|
||||
return [self colorFromRString:parts[0]
|
||||
gString:parts[1]
|
||||
bString:parts[2]
|
||||
@@ -280,10 +304,10 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
|
||||
}
|
||||
|
||||
// is it HSL?
|
||||
if ([string hasPrefix:@"hsl"]) {
|
||||
if (IJSVGCharBufferHasPrefix(str, "hsl")) {
|
||||
NSInteger count = 0;
|
||||
CGFloat* params = [IJSVGUtils commandParameters:string
|
||||
count:&count];
|
||||
CGFloat* params = [IJSVGUtils scanFloatsFromCString:str
|
||||
size:&count];
|
||||
CGFloat alpha = 1;
|
||||
if (count == 4) {
|
||||
alpha = params[3];
|
||||
@@ -291,21 +315,30 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
|
||||
|
||||
// convert HSL to HSB
|
||||
CGFloat* hsb = IJSVGColorCSSHSLToHSB(params[0], params[1], params[2]);
|
||||
color = [NSColor colorWithDeviceHue:hsb[0]
|
||||
saturation:hsb[1]
|
||||
brightness:hsb[2]
|
||||
alpha:alpha];
|
||||
NSColor* color = [NSColor colorWithDeviceHue:hsb[0]
|
||||
saturation:hsb[1]
|
||||
brightness:hsb[2]
|
||||
alpha:alpha];
|
||||
|
||||
color = [self computeColorSpace:color];
|
||||
|
||||
// memory clean!
|
||||
free(hsb);
|
||||
free(params);
|
||||
(void)free(str), str = NULL;
|
||||
(void)free(hsb), hsb = NULL;
|
||||
(void)free(params), params = NULL;
|
||||
return color;
|
||||
}
|
||||
|
||||
color = [self.class colorFromHEXString:string];
|
||||
return color;
|
||||
|
||||
// is simply a clear color, dont fill
|
||||
if (strcmp(str, "none") == 0 ||
|
||||
strcmp(str, "transparent") == 0) {
|
||||
(void)free(str), str = NULL;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// could return nil
|
||||
(void)free(str), str = NULL;
|
||||
return [self.class colorFromPredefinedColorName:string];
|
||||
}
|
||||
|
||||
+ (NSColor*)colorFromPredefinedColorName:(NSString*)name
|
||||
@@ -754,28 +787,38 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
|
||||
containsAlphaComponent:(BOOL*)containsAlphaComponent
|
||||
{
|
||||
// absolutely no string
|
||||
if (string == nil || string.length == 0 || ![self.class isHex:string]) {
|
||||
if(string == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
char* str = (char*)string.UTF8String;
|
||||
size_t length = strlen(str);
|
||||
if (length == 0 || IJSVGCharBufferIsHEX(str) == NO) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([string hasPrefix:@"#"] == YES) {
|
||||
string = [string substringFromIndex:1];
|
||||
// remove the hash from the front of the string
|
||||
if(str[0] == '#') {
|
||||
length--;
|
||||
str++;
|
||||
}
|
||||
|
||||
// whats the length?
|
||||
NSUInteger length = string.length;
|
||||
unsigned long hex;
|
||||
// we need to work out if its shorthand
|
||||
// if it is, the length needs to be length*2
|
||||
if (length == 3 || length == 4) {
|
||||
// shorthand...
|
||||
NSMutableString* str = [[[NSMutableString alloc] init] autorelease];
|
||||
for (NSInteger i = 0; i < length; i++) {
|
||||
NSString* sub = [string substringWithRange:NSMakeRange(i, 1)];
|
||||
[str appendFormat:@"%@%@", sub, sub];
|
||||
char* chars = NULL;
|
||||
chars = (char*)calloc(sizeof(char),length*2+1);
|
||||
for(int i = 0; i < length; i++) {
|
||||
chars[i*2] = chars[i*2+1] = str[i];
|
||||
}
|
||||
string = str;
|
||||
hex = strtoul(chars, NULL, 16);
|
||||
(void)free(chars), chars = NULL;
|
||||
} else {
|
||||
hex = strtoul(str, NULL, 16);
|
||||
}
|
||||
|
||||
|
||||
// now convert rest to hex
|
||||
unsigned long hex = [self HEXFromArbitraryHexString:string];
|
||||
if (containsAlphaComponent != nil) {
|
||||
*containsAlphaComponent = [self HEXContainsAlphaComponent:hex];
|
||||
}
|
||||
|
||||
@@ -6,16 +6,19 @@
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColor.h"
|
||||
#import <IJSVG/IJSVGColor.h>
|
||||
#import <IJSVG/IJSVGColorType.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGColorList : NSObject <NSCopying> {
|
||||
|
||||
@private
|
||||
NSMutableDictionary<NSColor*, NSColor*>* _replacementColorTree;
|
||||
NSMutableSet<NSColor*>* _colors;
|
||||
NSMutableSet<IJSVGColorType*>* _colors;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign, readonly) NSUInteger count;
|
||||
|
||||
- (NSColor*)proposedColorForColor:(NSColor*)color;
|
||||
- (void)removeAllReplacementColors;
|
||||
- (void)removeReplacementColor:(NSColor*)color;
|
||||
@@ -25,7 +28,8 @@
|
||||
clearExistingColors:(BOOL)clearExistingColors;
|
||||
|
||||
- (void)addColorsFromList:(IJSVGColorList*)sheet;
|
||||
- (NSSet<NSColor*>*)colors;
|
||||
- (void)addColor:(NSColor*)color;
|
||||
- (NSSet<IJSVGColorType*>*)colors;
|
||||
- (void)addColor:(IJSVGColorType*)color;
|
||||
- (NSDictionary<NSColor*, NSColor*>*)replacementColors;
|
||||
|
||||
@end
|
||||
|
||||
@@ -89,24 +89,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSSet<NSColor*>*)colors
|
||||
- (NSSet<IJSVGColorType*>*)colors
|
||||
{
|
||||
return [NSSet setWithSet:_colors];
|
||||
}
|
||||
|
||||
- (void)addColorsFromList:(IJSVGColorList*)sheet
|
||||
{
|
||||
[_colors addObjectsFromArray:sheet.colors.allObjects];
|
||||
for(IJSVGColorType* color in sheet.colors) {
|
||||
[self addColor:color];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addColor:(NSColor*)color
|
||||
- (void)addColor:(IJSVGColorType*)color
|
||||
{
|
||||
[_colors addObject:[IJSVGColor computeColorSpace:color]];
|
||||
// we just need to update its bit mask
|
||||
if([_colors containsObject:color] == YES) {
|
||||
void (^handler)(IJSVGColorType * _Nonnull obj, BOOL * _Nonnull stop) =
|
||||
^(IJSVGColorType * _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
if([obj isEqual:color] == YES) {
|
||||
obj.flags |= color.flags;
|
||||
*stop = YES;
|
||||
}
|
||||
};
|
||||
[_colors enumerateObjectsUsingBlock:handler];
|
||||
return;
|
||||
}
|
||||
[_colors addObject:color];
|
||||
}
|
||||
|
||||
- (void)removeColor:(NSColor*)color
|
||||
- (NSDictionary<NSColor*,NSColor*>*)replacementColors
|
||||
{
|
||||
[_colors removeObject:[IJSVGColor computeColorSpace:color]];
|
||||
return _replacementColorTree;
|
||||
}
|
||||
|
||||
- (void)removeColor:(IJSVGColorType*)color
|
||||
{
|
||||
[_colors removeObject:color];
|
||||
}
|
||||
|
||||
- (NSUInteger)count
|
||||
{
|
||||
return _colors.count;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// IJSVGColorType.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 20/04/2021.
|
||||
// Copyright © 2021 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, IJSVGColorTypeFlags) {
|
||||
IJSVGColorTypeNone = 0,
|
||||
IJSVGColorTypeFlagUnknown = 1 << 0,
|
||||
IJSVGColorTypeFlagFill = 1 << 1,
|
||||
IJSVGColorTypeFlagStroke = 1 << 2,
|
||||
IJSVGColorTypeFlagStop = 1 << 3
|
||||
};
|
||||
|
||||
@interface IJSVGColorType : NSObject {
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSColor* color;
|
||||
@property (nonatomic, assign) IJSVGColorTypeFlags flags;
|
||||
|
||||
+ (IJSVGColorType*)typeWithColor:(NSColor*)color
|
||||
flags:(IJSVGColorTypeFlags)mask;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// IJSVGColorType.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 20/04/2021.
|
||||
// Copyright © 2021 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColorType.h"
|
||||
|
||||
@implementation IJSVGColorType
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_color release], _color = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (IJSVGColorType*)typeWithColor:(NSColor*)color
|
||||
flags:(IJSVGColorTypeFlags)mask
|
||||
{
|
||||
IJSVGColorType* type = [[[self alloc] init] autorelease];
|
||||
type.color = color;
|
||||
type.flags = mask;
|
||||
return type;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if([object isKindOfClass:IJSVGColorType.class] == NO) {
|
||||
return NO;
|
||||
}
|
||||
return [self.color isEqual:((IJSVGColorType*)object).color];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
return self.color.hash;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -6,8 +6,8 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGCommandParser.h"
|
||||
#import "IJSVGPath.h"
|
||||
#import <IJSVG/IJSVGCommandParser.h>
|
||||
#import <IJSVG/IJSVGPath.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
static const NSInteger IJSVGCustomVariableParameterCount = NSNotFound;
|
||||
@@ -17,20 +17,11 @@ typedef NS_ENUM(NSInteger, IJSVGCommandType) {
|
||||
kIJSVGCommandTypeRelative
|
||||
};
|
||||
|
||||
@interface IJSVGCommand : NSObject {
|
||||
NSString* commandString;
|
||||
char command;
|
||||
CGFloat* parameters;
|
||||
NSInteger parameterCount;
|
||||
NSArray<IJSVGCommand*>* subCommands;
|
||||
NSInteger requiredParameters;
|
||||
IJSVGCommandType type;
|
||||
IJSVGCommand* previousCommand;
|
||||
@interface IJSVGCommand : NSObject <NSCopying> {
|
||||
@private
|
||||
NSInteger _currentIndex;
|
||||
BOOL isSubCommand;
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) NSString* commandString;
|
||||
@property (nonatomic, assign) char command;
|
||||
@property (nonatomic, assign) CGFloat* parameters;
|
||||
@property (nonatomic, assign) NSInteger parameterCount;
|
||||
@@ -49,17 +40,30 @@ typedef NS_ENUM(NSInteger, IJSVGCommandType) {
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path;
|
||||
path:(CGMutablePathRef)path;
|
||||
+ (void)parseParams:(CGFloat*)params
|
||||
paramCount:(NSInteger)paramCount
|
||||
intoArray:(NSMutableArray<IJSVGCommand*>*)commands
|
||||
parentCommand:(IJSVGCommand*)parentCommand;
|
||||
|
||||
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer;
|
||||
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer
|
||||
dataStream:(IJSVGPathDataStream*)dataStream;
|
||||
+ (CGMutablePathRef)newPathForCommandsArray:(NSArray<IJSVGCommand*>*)commands;
|
||||
|
||||
+ (NSArray<IJSVGCommand*>*)convertCommands:(NSArray<IJSVGCommand*>*)commands
|
||||
toUnits:(IJSVGUnitType)unitType
|
||||
bounds:(CGRect)bounds;
|
||||
|
||||
- (id)initWithCommandStringBuffer:(const char*)str
|
||||
dataStream:(IJSVGPathDataStream*)dataStream;
|
||||
- (IJSVGCommand*)subcommandWithParameters:(CGFloat*)subParams
|
||||
paramCount:(NSInteger)paramCount
|
||||
previousCommand:(IJSVGCommand*)command;
|
||||
- (void)convertToUnits:(IJSVGUnitType)units
|
||||
boundingBox:(CGRect)boundingBox;
|
||||
- (IJSVGCommand*)commandByConvertingToUnits:(IJSVGUnitType)unitType
|
||||
boundingBox:(CGRect)boundingBox;
|
||||
|
||||
- (CGFloat)readFloat;
|
||||
- (NSPoint)readPoint;
|
||||
|
||||
@@ -22,15 +22,6 @@
|
||||
|
||||
@implementation IJSVGCommand
|
||||
|
||||
@synthesize commandString;
|
||||
@synthesize command;
|
||||
@synthesize parameterCount;
|
||||
@synthesize parameters;
|
||||
@synthesize subCommands;
|
||||
@synthesize type;
|
||||
@synthesize previousCommand;
|
||||
@synthesize isSubCommand;
|
||||
|
||||
+ (BOOL)requiresCustomParameterParsing
|
||||
{
|
||||
return NO;
|
||||
@@ -51,7 +42,7 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
}
|
||||
|
||||
@@ -101,12 +92,98 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (CGMutablePathRef)newPathForCommandsArray:(NSArray<IJSVGCommand*>*)commands
|
||||
{
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
IJSVGCommand* preCommand = nil;
|
||||
for(IJSVGCommand* command in commands) {
|
||||
for (IJSVGCommand* subCommand in command.subCommands) {
|
||||
[command.class runWithParams:subCommand.parameters
|
||||
paramCount:subCommand.parameterCount
|
||||
command:subCommand
|
||||
previousCommand:preCommand
|
||||
type:subCommand.type
|
||||
path:path];
|
||||
preCommand = subCommand;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer
|
||||
{
|
||||
IJSVGPathDataStream* stream = IJSVGPathDataStreamCreateDefault();
|
||||
NSArray<IJSVGCommand*>* commands = [self commandsForDataCharacters:buffer
|
||||
dataStream:stream];
|
||||
IJSVGPathDataStreamRelease(stream);
|
||||
return commands;
|
||||
}
|
||||
|
||||
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer
|
||||
dataStream:(IJSVGPathDataStream*)dataStream
|
||||
{
|
||||
NSMutableArray<IJSVGCommand*>* commands = [[[NSMutableArray alloc] init] autorelease];
|
||||
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;
|
||||
for (NSInteger i = 0; i < len; i++) {
|
||||
char nextChar = buffer[i + 1];
|
||||
BOOL atEnd = i == lastIndex;
|
||||
BOOL isStartCommand = IJSVGIsLegalCommandCharacter(nextChar);
|
||||
if (isStartCommand == YES || atEnd == YES) {
|
||||
|
||||
// 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
|
||||
Class commandClass = [IJSVGCommand commandClassForCommandChar:commandString[0]];
|
||||
IJSVGCommand* command = nil;
|
||||
command = (IJSVGCommand*)[[[commandClass alloc] initWithCommandStringBuffer:commandString
|
||||
dataStream:dataStream] autorelease];
|
||||
|
||||
[commands addObject:command];
|
||||
|
||||
// free the memory as at this point, we are done with it
|
||||
(void)free(commandString), commandString = NULL;
|
||||
}
|
||||
}
|
||||
(void)free(charBuffer), charBuffer = NULL;
|
||||
return commands;
|
||||
}
|
||||
|
||||
+ (NSArray<IJSVGCommand*>*)convertCommands:(NSArray<IJSVGCommand*>*)commands
|
||||
toUnits:(IJSVGUnitType)unitType
|
||||
bounds:(CGRect)bounds
|
||||
{
|
||||
NSMutableArray<IJSVGCommand*>* newCommands = nil;
|
||||
newCommands = [[[NSMutableArray alloc] initWithCapacity:commands.count] autorelease];
|
||||
for(IJSVGCommand* command in commands) {
|
||||
IJSVGCommand* nCommand = [command commandByConvertingToUnits:unitType
|
||||
boundingBox:bounds];
|
||||
[newCommands addObject:nCommand];
|
||||
}
|
||||
return newCommands;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([commandString release]), commandString = nil;
|
||||
(void)([subCommands release]), subCommands = nil;
|
||||
if (parameters) {
|
||||
(void)(free(parameters)), parameters = nil;
|
||||
(void)([_subCommands release]), _subCommands = nil;
|
||||
if (_parameters) {
|
||||
(void)(free(_parameters)), _parameters = nil;
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -117,20 +194,20 @@
|
||||
if ((self = [super init]) != nil) {
|
||||
// work out the basics
|
||||
_currentIndex = 0;
|
||||
command = str[0];
|
||||
type = [IJSVGUtils typeForCommandChar:command];
|
||||
_command = str[0];
|
||||
_type = [IJSVGUtils typeForCommandChar:_command];
|
||||
NSInteger sets = 0;
|
||||
NSInteger paramCount = [self.class requiredParameterCount];
|
||||
IJSVGPathDataSequence* sequence = [self.class pathDataSequence];
|
||||
parameters = IJSVGParsePathDataStreamSequence(str, strlen(str),
|
||||
dataStream, sequence, [self.class requiredParameterCount], &sets);
|
||||
_parameters = IJSVGParsePathDataStreamSequence(str, strlen(str),
|
||||
dataStream, sequence, paramCount, &sets);
|
||||
|
||||
if (sets <= 1) {
|
||||
CGFloat* subParams = [self parametersFromIndexOffset:0];
|
||||
IJSVGCommand* command = [self subcommandWithParameters:subParams
|
||||
paramCount:paramCount
|
||||
previousCommand:nil];
|
||||
subCommands = @[ command ].retain;
|
||||
_subCommands = @[ command ].retain;
|
||||
} else {
|
||||
NSMutableArray<IJSVGCommand*>* subCommandArray = nil;
|
||||
subCommandArray = [[NSMutableArray alloc] initWithCapacity:sets].autorelease;
|
||||
@@ -154,12 +231,43 @@
|
||||
}
|
||||
|
||||
// store the retained value
|
||||
subCommands = subCommandArray.copy;
|
||||
_subCommands = subCommandArray.copy;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setSubCommands:(NSArray<IJSVGCommand*>*)subCommands
|
||||
{
|
||||
(void)[_subCommands release], _subCommands = nil;
|
||||
_subCommands = subCommands.retain;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
IJSVGCommand* command = [[self.class alloc] init];
|
||||
command.type = self.type;
|
||||
command.command = self.command;
|
||||
command.isSubCommand = self.isSubCommand;
|
||||
command.parameterCount = self.parameterCount;
|
||||
size_t memsize = sizeof(CGFloat)*self.parameterCount;
|
||||
command.parameters = (CGFloat*)malloc(memsize);
|
||||
memcpy(command.parameters, self.parameters, memsize);
|
||||
|
||||
|
||||
IJSVGCommand* lastCommand = nil;
|
||||
NSMutableArray<IJSVGCommand*>* subcommands = nil;
|
||||
subcommands = [[[NSMutableArray alloc] initWithCapacity:self.subCommands.count] autorelease];
|
||||
for(IJSVGCommand* subcommand in self.subCommands) {
|
||||
IJSVGCommand* subCopy = [[subcommand copy] autorelease];
|
||||
subCopy.previousCommand = lastCommand;
|
||||
subCopy.isSubCommand = lastCommand != nil;
|
||||
[subcommands addObject:subCopy];
|
||||
}
|
||||
command.subCommands = subcommands;
|
||||
return command;
|
||||
}
|
||||
|
||||
- (CGFloat*)parametersFromIndexOffset:(NSInteger)index
|
||||
{
|
||||
CGFloat* subParams = 0;
|
||||
@@ -188,15 +296,15 @@
|
||||
|
||||
- (CGFloat)readFloat
|
||||
{
|
||||
CGFloat f = parameters[_currentIndex];
|
||||
CGFloat f = _parameters[_currentIndex];
|
||||
_currentIndex++;
|
||||
return f;
|
||||
}
|
||||
|
||||
- (NSPoint)readPoint
|
||||
{
|
||||
CGFloat x = parameters[_currentIndex];
|
||||
CGFloat y = parameters[_currentIndex + 1];
|
||||
CGFloat x = _parameters[_currentIndex];
|
||||
CGFloat y = _parameters[_currentIndex + 1];
|
||||
_currentIndex += 2;
|
||||
return NSMakePoint(x, y);
|
||||
}
|
||||
@@ -211,4 +319,34 @@
|
||||
_currentIndex = 0;
|
||||
}
|
||||
|
||||
- (void)convertToUnits:(IJSVGUnitType)units
|
||||
boundingBox:(CGRect)boundingBox
|
||||
{
|
||||
for(IJSVGCommand* command in _subCommands) {
|
||||
[command convertToUnits:units
|
||||
boundingBox:boundingBox];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
NSMutableString* str = [[[NSMutableString alloc] init] autorelease];
|
||||
[str appendFormat:@"%c ",_command];
|
||||
NSMutableArray* args = [[[NSMutableArray alloc] initWithCapacity:_parameterCount] autorelease];
|
||||
for(int i = 0; i < _parameterCount; i++) {
|
||||
[args addObject:[NSString stringWithFormat:@"%f",_parameters[i]]];
|
||||
}
|
||||
[str appendString:[args componentsJoinedByString:@", "]];
|
||||
return str;
|
||||
}
|
||||
|
||||
- (IJSVGCommand*)commandByConvertingToUnits:(IJSVGUnitType)unitType
|
||||
boundingBox:(CGRect)boundingBox
|
||||
{
|
||||
IJSVGCommand* copy = self.copy;
|
||||
[copy convertToUnits:unitType
|
||||
boundingBox:boundingBox];
|
||||
return [copy autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
[path close];
|
||||
CGPathCloseSubpath(path);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,17 +20,19 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[path.path curveToPoint:NSMakePoint(params[4], params[5])
|
||||
controlPoint1:NSMakePoint(params[0], params[1])
|
||||
controlPoint2:NSMakePoint(params[2], params[3])];
|
||||
CGPathAddCurveToPoint(path, NULL, params[0], params[1],
|
||||
params[2], params[3],
|
||||
params[4], params[5]);
|
||||
return;
|
||||
}
|
||||
[path.path relativeCurveToPoint:NSMakePoint(params[4], params[5])
|
||||
controlPoint1:NSMakePoint(params[0], params[1])
|
||||
controlPoint2:NSMakePoint(params[2], params[3])];
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPathAddCurveToPoint(path, NULL,
|
||||
currentPoint.x + params[0], currentPoint.y + params[1],
|
||||
currentPoint.x + params[2], currentPoint.y + params[3],
|
||||
currentPoint.x + params[4], currentPoint.y + params[5]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,7 +20,8 @@ static IJSVGPathDataSequence* _sequence;
|
||||
|
||||
+ (IJSVGPathDataSequence*)pathDataSequence
|
||||
{
|
||||
if(_sequence == NULL) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_sequence = (IJSVGPathDataSequence*)malloc(sizeof(IJSVGPathDataSequence) * 7);
|
||||
_sequence[0] = kIJSVGPathDataSequenceTypeFloat;
|
||||
_sequence[1] = kIJSVGPathDataSequenceTypeFloat;
|
||||
@@ -29,88 +30,110 @@ static IJSVGPathDataSequence* _sequence;
|
||||
_sequence[4] = kIJSVGPathDataSequenceTypeFlag;
|
||||
_sequence[5] = kIJSVGPathDataSequenceTypeFloat;
|
||||
_sequence[6] = kIJSVGPathDataSequenceTypeFloat;
|
||||
}
|
||||
});
|
||||
return _sequence;
|
||||
}
|
||||
|
||||
// modified from https://github.com/SVGKit/SVGKit/blob/880c94a5b77b6f22beb491a7a7e02ace220c32af/Source/Parsers/SVGKPointsAndPathsParser.m
|
||||
+ (void)runWithParams:(CGFloat*)params
|
||||
paramCount:(NSInteger)count
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
CGPoint radii = CGPointZero;
|
||||
CGPoint arcEndPoint = CGPointZero;
|
||||
CGPoint arcStartPoint = path.currentPoint;
|
||||
CGFloat xAxisRotation = 0;
|
||||
CGPoint pathCurrentPoint = CGPathGetCurrentPoint(path);
|
||||
CGFloat xAxisRotation = 0.f;
|
||||
BOOL largeArcFlag = NO;
|
||||
BOOL sweepFlag = NO;
|
||||
|
||||
|
||||
radii = [currentCommand readPoint];
|
||||
xAxisRotation = [currentCommand readFloat];
|
||||
largeArcFlag = [currentCommand readBOOL];
|
||||
sweepFlag = [currentCommand readBOOL];
|
||||
arcEndPoint = [currentCommand readPoint];
|
||||
|
||||
CGFloat rx = fabs(radii.x);
|
||||
CGFloat ry = fabs(radii.y);
|
||||
|
||||
xAxisRotation *= M_PI / 180.f;
|
||||
xAxisRotation = fmod(xAxisRotation, 2.f * M_PI);
|
||||
|
||||
if (type == kIJSVGCommandTypeRelative) {
|
||||
arcEndPoint.x += path.currentPoint.x;
|
||||
arcEndPoint.y += path.currentPoint.y;
|
||||
arcEndPoint.x += pathCurrentPoint.x;
|
||||
arcEndPoint.y += pathCurrentPoint.y;
|
||||
}
|
||||
|
||||
xAxisRotation *= M_PI / 180.f;
|
||||
CGPoint currentPoint = CGPointMake(cos(xAxisRotation) * (arcStartPoint.x - arcEndPoint.x) / 2.0 + sin(xAxisRotation) * (arcStartPoint.y - arcEndPoint.y) / 2.0, -sin(xAxisRotation) * (arcStartPoint.x - arcEndPoint.x) / 2.0 + cos(xAxisRotation) * (arcStartPoint.y - arcEndPoint.y) / 2.0);
|
||||
|
||||
CGFloat radiiAdjustment = pow(currentPoint.x, 2) / pow(radii.x, 2) + pow(currentPoint.y, 2) / pow(radii.y, 2);
|
||||
radii.x *= (radiiAdjustment > 1) ? sqrt(radiiAdjustment) : 1;
|
||||
radii.y *= (radiiAdjustment > 1) ? sqrt(radiiAdjustment) : 1;
|
||||
|
||||
CGFloat sweep = (largeArcFlag == sweepFlag ? -1 : 1) * sqrt(((pow(radii.x, 2) * pow(radii.y, 2)) - (pow(radii.x, 2) * pow(currentPoint.y, 2)) - (pow(radii.y, 2) * pow(currentPoint.x, 2))) / (pow(radii.x, 2) * pow(currentPoint.y, 2) + pow(radii.y, 2) * pow(currentPoint.x, 2)));
|
||||
sweep = (sweep != sweep) ? 0 : sweep;
|
||||
CGPoint preCenterPoint = CGPointMake(sweep * radii.x * currentPoint.y / radii.y, sweep * -radii.y * currentPoint.x / radii.x);
|
||||
|
||||
CGPoint centerPoint = CGPointMake((arcStartPoint.x + arcEndPoint.x) / 2.0 + cos(xAxisRotation) * preCenterPoint.x - sin(xAxisRotation) * preCenterPoint.y, (arcStartPoint.y + arcEndPoint.y) / 2.0 + sin(xAxisRotation) * preCenterPoint.x + cos(xAxisRotation) * preCenterPoint.y);
|
||||
|
||||
CGFloat startAngle = angle(CGPointMake(1, 0), CGPointMake((currentPoint.x - preCenterPoint.x) / radii.x, (currentPoint.y - preCenterPoint.y) / radii.y));
|
||||
|
||||
CGPoint deltaU = CGPointMake((currentPoint.x - preCenterPoint.x) / radii.x,
|
||||
(currentPoint.y - preCenterPoint.y) / radii.y);
|
||||
CGPoint deltaV = CGPointMake((-currentPoint.x - preCenterPoint.x) / radii.x,
|
||||
(-currentPoint.y - preCenterPoint.y) / radii.y);
|
||||
CGFloat angleDelta = (deltaU.x * deltaV.y < deltaU.y * deltaV.x ? -1 : 1) * acos(ratio(deltaU, deltaV));
|
||||
|
||||
angleDelta = (ratio(deltaU, deltaV) <= -1) ? M_PI : (ratio(deltaU, deltaV) >= 1) ? 0 : angleDelta;
|
||||
|
||||
// check for actually numbers, if this is not valid
|
||||
// kill it, blame WWDC 2017 SVG background for this...
|
||||
if (isnan(startAngle) || isnan(angleDelta)) {
|
||||
|
||||
CGFloat x1 = pathCurrentPoint.x;
|
||||
CGFloat y1 = pathCurrentPoint.y;
|
||||
|
||||
CGFloat x2 = arcEndPoint.x;
|
||||
CGFloat y2 = arcEndPoint.y;
|
||||
|
||||
if (rx == 0.f || ry == 0.f) {
|
||||
CGPathAddLineToPoint(path, NULL, x2, y2);
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat cosPhi = cos(xAxisRotation);
|
||||
CGFloat sinPhi = sin(xAxisRotation);
|
||||
|
||||
CGFloat x1p = cosPhi * (x1 - x2) / 2.f + sinPhi * (y1 - y2) / 2.f;
|
||||
CGFloat y1p = -sinPhi * (x1 - x2) / 2.f + cosPhi * (y1 - y2) / 2.f;
|
||||
|
||||
CGFloat rx_2 = rx * rx;
|
||||
CGFloat ry_2 = ry * ry;
|
||||
CGFloat xp_2 = x1p * x1p;
|
||||
CGFloat yp_2 = y1p * y1p;
|
||||
|
||||
CGFloat radius = MAX(radii.x, radii.y);
|
||||
CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) : CGPointMake(radii.x / radii.y, 1);
|
||||
CGFloat delta = xp_2 / rx_2 + yp_2 / ry_2;
|
||||
|
||||
if (delta > 1.f) {
|
||||
rx *= sqrt(delta);
|
||||
ry *= sqrt(delta);
|
||||
rx_2 = rx * rx;
|
||||
ry_2 = ry * ry;
|
||||
}
|
||||
|
||||
CGFloat sign = (largeArcFlag == sweepFlag) ? -1.f : 1.f;
|
||||
CGFloat numerator = MAX(0.f, rx_2 * ry_2 - rx_2 * yp_2 - ry_2 * xp_2);
|
||||
CGFloat denom = rx_2 * yp_2 + ry_2 * xp_2;
|
||||
CGFloat lhs = denom == 0.f ? 0.f : sign * sqrt(numerator / denom);
|
||||
|
||||
CGFloat cxp = lhs * (rx * y1p) / ry;
|
||||
CGFloat cyp = lhs * -((ry * x1p) / rx);
|
||||
|
||||
CGFloat cx = cosPhi * cxp + -sinPhi * cyp + (x1 + x2) / 2.f;
|
||||
CGFloat cy = cxp * sinPhi + cyp * cosPhi + (y1 + y2) / 2.f;
|
||||
|
||||
NSAffineTransform* trans = NSAffineTransform.transform;
|
||||
[trans translateXBy:-centerPoint.x
|
||||
yBy:-centerPoint.y];
|
||||
[trans rotateByRadians:-xAxisRotation];
|
||||
[trans scaleXBy:(1 / scale.x)
|
||||
yBy:(1 / scale.y)];
|
||||
[path.path transformUsingAffineTransform:trans];
|
||||
CGAffineTransform transform = CGAffineTransformMakeScale(1.f / rx, 1.f / ry);
|
||||
transform = CGAffineTransformRotate(transform, -xAxisRotation);
|
||||
transform = CGAffineTransformTranslate(transform, -cx, -cy);
|
||||
|
||||
CGPoint arcPt1 = CGPointApplyAffineTransform(CGPointMake(x1, y1), transform);
|
||||
CGPoint arcPt2 = CGPointApplyAffineTransform(CGPointMake(x2, y2), transform);
|
||||
|
||||
CGFloat startAngle = atan2(arcPt1.y, arcPt1.x);
|
||||
CGFloat endAngle = atan2(arcPt2.y, arcPt2.x);
|
||||
|
||||
CGFloat angleDelta = endAngle - startAngle;;
|
||||
|
||||
if (sweepFlag == YES) {
|
||||
if (angleDelta < 0.f) {
|
||||
angleDelta += 2.f * M_PI;
|
||||
}
|
||||
} else if (angleDelta > 0.f) {
|
||||
angleDelta = angleDelta - 2.f * M_PI;
|
||||
}
|
||||
|
||||
transform = CGAffineTransformMakeTranslation(cx, cy);
|
||||
transform = CGAffineTransformRotate(transform, xAxisRotation);
|
||||
transform = CGAffineTransformScale(transform, rx, ry);
|
||||
|
||||
[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];
|
||||
[trans translateXBy:centerPoint.x
|
||||
yBy:centerPoint.y];
|
||||
[path.path transformUsingAffineTransform:trans];
|
||||
CGPathAddRelativeArc(path, &transform, 0.f, 0.f, 1.f,
|
||||
startAngle, angleDelta);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,13 +20,15 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[path.path lineToPoint:NSMakePoint(params[0], path.currentPoint.y)];
|
||||
CGPathAddLineToPoint(path, NULL, params[0], CGPathGetCurrentPoint(path).y);
|
||||
return;
|
||||
}
|
||||
[path.path relativeLineToPoint:NSMakePoint(params[0], 0.f)];
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPathAddLineToPoint(path, NULL, currentPoint.x + params[0],
|
||||
currentPoint.y);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,15 +20,26 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[path.path lineToPoint:NSMakePoint(params[0], params[1])];
|
||||
CGPathAddLineToPoint(path, NULL, params[0], params[1]);
|
||||
return;
|
||||
}
|
||||
NSPoint point = NSMakePoint(path.currentPoint.x + params[0],
|
||||
path.currentPoint.y + params[1]);
|
||||
[path.path lineToPoint:point];
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPathAddLineToPoint(path, NULL, currentPoint.x + params[0],
|
||||
currentPoint.y + params[1]);
|
||||
}
|
||||
|
||||
- (void)convertToUnits:(IJSVGUnitType)units
|
||||
boundingBox:(CGRect)boundingBox
|
||||
{
|
||||
if(units == IJSVGUnitObjectBoundingBox) {
|
||||
self.parameters[0] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[0]] computeValue:boundingBox.size.width];
|
||||
self.parameters[1] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[1]] computeValue:boundingBox.size.height];
|
||||
}
|
||||
[super convertToUnits:units
|
||||
boundingBox:boundingBox];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
// move to's allow more then one move to, but if there are more then one,
|
||||
// we need to run the line to instead...who knew!
|
||||
@@ -41,10 +41,25 @@
|
||||
// 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])];
|
||||
CGPathMoveToPoint(path, NULL,
|
||||
params[0], params[1]);
|
||||
return;
|
||||
}
|
||||
[path.path relativeMoveToPoint:NSMakePoint(params[0], params[1])];
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPathMoveToPoint(path, NULL,
|
||||
currentPoint.x + params[0],
|
||||
currentPoint.y + params[1]);
|
||||
}
|
||||
|
||||
- (void)convertToUnits:(IJSVGUnitType)units
|
||||
boundingBox:(CGRect)boundingBox
|
||||
{
|
||||
if(units == IJSVGUnitObjectBoundingBox) {
|
||||
self.parameters[0] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[0]] computeValue:boundingBox.size.width];
|
||||
self.parameters[1] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[1]] computeValue:boundingBox.size.height];
|
||||
}
|
||||
[super convertToUnits:units
|
||||
boundingBox:boundingBox];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,15 +21,17 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[path.path addQuadCurveToPoint:NSMakePoint(params[2], params[3])
|
||||
controlPoint:NSMakePoint(params[0], params[1])];
|
||||
CGPathAddQuadCurveToPoint(path, NULL, params[0], params[1],
|
||||
params[2], params[3]);
|
||||
return;
|
||||
}
|
||||
[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])];
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPathAddQuadCurveToPoint(path, NULL,
|
||||
currentPoint.x + params[0], currentPoint.y + params[1],
|
||||
currentPoint.x + params[2], currentPoint.y + params[3]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,43 +22,43 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
NSPoint firstControl = NSMakePoint(path.currentPoint.x, path.currentPoint.y);
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPoint firstControl = CGPointMake(currentPoint.x, 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.currentPoint.x,
|
||||
-1 * command.parameters[3] + 2 * path.currentPoint.y);
|
||||
firstControl = CGPointMake(-1 * command.parameters[2] + 2 * currentPoint.x,
|
||||
-1 * command.parameters[3] + 2 * currentPoint.y);
|
||||
} else {
|
||||
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);
|
||||
NSPoint oldPoint = CGPointMake(currentPoint.x - command.parameters[4],
|
||||
currentPoint.y - command.parameters[5]);
|
||||
firstControl = CGPointMake(-1 * (command.parameters[2] + oldPoint.x) + 2 * currentPoint.x,
|
||||
-1 * (command.parameters[3] + oldPoint.y) + 2 * currentPoint.y);
|
||||
}
|
||||
} else {
|
||||
if (command.type == kIJSVGCommandTypeAbsolute) {
|
||||
firstControl = NSMakePoint(-1 * command.parameters[0] + 2 * path.currentPoint.x,
|
||||
-1 * command.parameters[1] + 2 * path.currentPoint.y);
|
||||
firstControl = CGPointMake(-1 * command.parameters[0] + 2 * currentPoint.x,
|
||||
-1 * command.parameters[1] + 2 * currentPoint.y);
|
||||
} else {
|
||||
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);
|
||||
NSPoint oldPoint = CGPointMake(currentPoint.x - command.parameters[2],
|
||||
currentPoint.y - command.parameters[3]);
|
||||
firstControl = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * currentPoint.x,
|
||||
-1 * (command.parameters[1] + oldPoint.y) + 2 * currentPoint.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[path.path curveToPoint:NSMakePoint(params[2], params[3])
|
||||
controlPoint1:NSMakePoint(firstControl.x, firstControl.y)
|
||||
controlPoint2:NSMakePoint(params[0], params[1])];
|
||||
CGPathAddCurveToPoint(path, NULL, firstControl.x, firstControl.y,
|
||||
params[0], params[1], params[2], params[3]);
|
||||
return;
|
||||
}
|
||||
[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])];
|
||||
CGPathAddCurveToPoint(path, NULL, firstControl.x, firstControl.y,
|
||||
currentPoint.x + params[0], currentPoint.y + params[1],
|
||||
currentPoint.x + params[2], currentPoint.y + params[3]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,35 +22,37 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
NSPoint commandPoint = NSMakePoint(path.currentPoint.x, path.currentPoint.y);
|
||||
CGPoint lastControlPoint = IJSVGPathGetLastQuadraticCommandPoint(path);
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPoint commandPoint = CGPointMake(currentPoint.x, currentPoint.y);
|
||||
if (command != nil) {
|
||||
if (command.class == IJSVGCommandQuadraticCurve.class) {
|
||||
// quadratic curve
|
||||
if (command.type == kIJSVGCommandTypeAbsolute) {
|
||||
commandPoint = NSMakePoint(-1 * command.parameters[0] + 2 * path.currentPoint.x,
|
||||
-1 * command.parameters[1] + 2 * path.currentPoint.y);
|
||||
commandPoint = NSMakePoint(-1 * command.parameters[0] + 2 * currentPoint.x,
|
||||
-1 * command.parameters[1] + 2 * currentPoint.y);
|
||||
} else {
|
||||
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);
|
||||
CGPoint oldPoint = CGPointMake(currentPoint.x - command.parameters[2],
|
||||
currentPoint.y - command.parameters[3]);
|
||||
commandPoint = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * (currentPoint.x),
|
||||
-1 * (command.parameters[1] + oldPoint.y) + 2 * currentPoint.y);
|
||||
}
|
||||
} else if (command.class == self.class) {
|
||||
// smooth quadratic curve
|
||||
commandPoint = CGPointMake(-1 * (path.lastControlPoint.x) + 2 * (path.currentPoint.x),
|
||||
-1 * (path.lastControlPoint.y) + 2 * path.currentPoint.y);
|
||||
commandPoint = CGPointMake(-1 * (lastControlPoint.x) + 2 * (currentPoint.x),
|
||||
-1 * (lastControlPoint.y) + 2 * currentPoint.y);
|
||||
}
|
||||
}
|
||||
path.lastControlPoint = commandPoint;
|
||||
// path.lastControlPoint = commandPoint;
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[path.path addQuadCurveToPoint:NSMakePoint(params[0], params[1])
|
||||
controlPoint:commandPoint];
|
||||
CGPathAddQuadCurveToPoint(path, NULL, commandPoint.x, commandPoint.y,
|
||||
params[0], params[1]);
|
||||
return;
|
||||
}
|
||||
[path.path addQuadCurveToPoint:NSMakePoint(path.currentPoint.x + params[0], path.currentPoint.y + params[1])
|
||||
controlPoint:commandPoint];
|
||||
CGPathAddQuadCurveToPoint(path, NULL, commandPoint.x, commandPoint.y,
|
||||
currentPoint.x + params[0], currentPoint.y + params[1]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
command:(IJSVGCommand*)currentCommand
|
||||
previousCommand:(IJSVGCommand*)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath*)path
|
||||
path:(CGMutablePathRef)path
|
||||
{
|
||||
if (type == kIJSVGCommandTypeAbsolute) {
|
||||
[path.path lineToPoint:NSMakePoint(path.currentPoint.x, params[0])];
|
||||
CGPathAddLineToPoint(path, NULL, CGPathGetCurrentPoint(path).x, params[0]);
|
||||
return;
|
||||
}
|
||||
[path.path relativeLineToPoint:NSMakePoint(0.f, params[0])];
|
||||
CGPoint currentPoint = CGPathGetCurrentPoint(path);
|
||||
CGPathAddLineToPoint(path, NULL, currentPoint.x, currentPoint.y + params[0]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,53 +6,50 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGBezierPathAdditions.h"
|
||||
#import "IJSVGColorList.h"
|
||||
#import "IJSVGExporter.h"
|
||||
#import "IJSVGGradientLayer.h"
|
||||
#import "IJSVGGroupLayer.h"
|
||||
#import "IJSVGImageLayer.h"
|
||||
#import "IJSVGLayerTree.h"
|
||||
#import "IJSVGParser.h"
|
||||
#import "IJSVGRendering.h"
|
||||
#import "IJSVGRenderingStyle.h"
|
||||
#import "IJSVGTransaction.h"
|
||||
#import <IJSVG/IJSVGColorList.h>
|
||||
#import <IJSVG/IJSVGRootNode.h>
|
||||
#import <IJSVG/IJSVGExporter.h>
|
||||
#import <IJSVG/IJSVGGradientLayer.h>
|
||||
#import <IJSVG/IJSVGGroupLayer.h>
|
||||
#import <IJSVG/IJSVGRootLayer.h>
|
||||
#import <IJSVG/IJSVGImageLayer.h>
|
||||
#import <IJSVG/IJSVGLayerTree.h>
|
||||
#import <IJSVG/IJSVGParser.h>
|
||||
#import <IJSVG/IJSVGRendering.h>
|
||||
#import <IJSVG/IJSVGRenderingStyle.h>
|
||||
#import <IJSVG/IJSVGTransaction.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVG;
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, IJSVGMatchPropertiesMask) {
|
||||
IJSVGMatchPropertyNone = 0,
|
||||
IJSVGMatchPropertyContainsMaskedElement = 1 << 0,
|
||||
IJSVGMatchPropertyContainsStrokedElement = 1 << 1
|
||||
};
|
||||
|
||||
@protocol IJSVGDelegate <NSObject, IJSVGParserDelegate>
|
||||
|
||||
@optional
|
||||
- (BOOL)svg:(IJSVG*)svg
|
||||
shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject;
|
||||
- (void)svg:(IJSVG*)svg
|
||||
handleForeignObject:(IJSVGForeignObject*)foreignObject
|
||||
document:(NSXMLDocument*)document;
|
||||
- (void)svg:(IJSVG*)svg
|
||||
foundSubSVG:(IJSVG*)subSVG
|
||||
withSVGString:(NSString*)subSVGString;
|
||||
foundSubSVG:(IJSVG*)subSVG
|
||||
withSVGString:(NSString*)subSVGString;
|
||||
|
||||
@end
|
||||
|
||||
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
|
||||
|
||||
@private
|
||||
IJSVGParser* _group;
|
||||
IJSVGRootNode* _rootNode;
|
||||
CGFloat _scale;
|
||||
CGFloat _clipScale;
|
||||
id<IJSVGDelegate> _delegate;
|
||||
IJSVGLayer* _layerTree;
|
||||
IJSVGLayerTree* _layerTree;
|
||||
CGRect _viewBox;
|
||||
CGFloat _backingScaleFactor;
|
||||
CGFloat _lastProposedBackingScale;
|
||||
IJSVGRenderQuality _lastProposedRenderQuality;
|
||||
CGFloat _backingScale;
|
||||
NSMutableDictionary* _replacementColors;
|
||||
|
||||
struct {
|
||||
unsigned int shouldHandleForeignObject : 1;
|
||||
unsigned int handleForeignObject : 1;
|
||||
unsigned int shouldHandleSubSVG : 1;
|
||||
} _respondsTo;
|
||||
}
|
||||
@@ -71,6 +68,8 @@
|
||||
@property (nonatomic, readonly) IJSVGUnitSize * intrinsicSize;
|
||||
@property (nonatomic, copy) NSString* title;
|
||||
@property (nonatomic, copy) NSString* desc;
|
||||
@property (nonatomic, retain) IJSVGLayerTree* layerTree;
|
||||
@property (nonatomic, retain) IJSVGRootLayer* rootLayer;
|
||||
|
||||
- (void)prepForDrawingInView:(NSView*)view;
|
||||
- (BOOL)isFont;
|
||||
@@ -78,16 +77,11 @@
|
||||
- (NSRect)viewBox;
|
||||
- (NSArray<IJSVGPath*>*)glyphs;
|
||||
- (NSString*)identifier;
|
||||
- (IJSVGLayer*)layer;
|
||||
- (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;
|
||||
|
||||
+ (id)svgNamed:(NSString*)string;
|
||||
+ (id)svgNamed:(NSString*)string
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
@@ -125,6 +119,13 @@
|
||||
- (id)initWithFilePathURL:(NSURL*)aURL
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGDelegate>)delegate;
|
||||
|
||||
- (id)initWithDataAssetNamed:(NSDataAssetName)name
|
||||
error:(NSError**)error;
|
||||
- (id)initWithDataAssetNamed:(NSDataAssetName)name
|
||||
bundle:(NSBundle*)bundle
|
||||
error:(NSError**)error;
|
||||
|
||||
- (NSImage*)imageWithSize:(NSSize)aSize;
|
||||
- (NSImage*)imageWithSize:(NSSize)aSize
|
||||
error:(NSError**)error;
|
||||
@@ -157,13 +158,13 @@
|
||||
- (NSData*)PDFDataWithRect:(NSRect)rect
|
||||
error:(NSError**)error;
|
||||
|
||||
- (void)beginVectorDraw;
|
||||
- (void)endVectorDraw;
|
||||
|
||||
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize;
|
||||
- (void)setNeedsDisplay;
|
||||
|
||||
// colors
|
||||
- (IJSVGColorList*)computedColorList:(BOOL*)hasPatternFills;
|
||||
- (IJSVGColorList*)colorList;
|
||||
- (void)performBlock:(dispatch_block_t)block;
|
||||
|
||||
// matching
|
||||
- (BOOL)matchesPropertiesWithMask:(IJSVGMatchPropertiesMask)mask;
|
||||
@end
|
||||
|
||||
@@ -12,26 +12,22 @@
|
||||
|
||||
@implementation IJSVG
|
||||
|
||||
// these are explicitly implemented
|
||||
@synthesize title = _title;
|
||||
@synthesize desc = _desc;
|
||||
@synthesize renderingBackingScaleHelper;
|
||||
@synthesize clipToViewport;
|
||||
@synthesize renderQuality;
|
||||
@synthesize renderingStyle = _renderingStyle;
|
||||
@synthesize intrinsicSize = _intrinsicSize;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// this can all be called on the background thread to be released
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
(void)([renderingBackingScaleHelper release]),
|
||||
renderingBackingScaleHelper = nil;
|
||||
(void)([_renderingBackingScaleHelper release]), _renderingBackingScaleHelper = nil;
|
||||
(void)([_replacementColors release]), _replacementColors = nil;
|
||||
(void)([_renderingStyle release]), _renderingStyle = nil;
|
||||
(void)([_group release]), _group = nil;
|
||||
(void)([_rootNode release]), _rootNode = nil;
|
||||
(void)([_intrinsicSize release]), _intrinsicSize = nil;
|
||||
(void)([_desc release]), _desc = nil;
|
||||
(void)([_title release]), _title = nil;
|
||||
(void)([_desc release]), _desc = nil;
|
||||
(void)([_rootLayer release]), _rootLayer = nil;
|
||||
|
||||
// kill any memory that has been around
|
||||
(void)([_layerTree release]), _layerTree = nil;
|
||||
@@ -74,12 +70,35 @@
|
||||
ext = @"svg";
|
||||
}
|
||||
if ((str = [bundle pathForResource:[string stringByDeletingPathExtension]
|
||||
ofType:ext])
|
||||
!= nil) {
|
||||
ofType:ext]) != nil) {
|
||||
return [[[self alloc] initWithFile:str
|
||||
error:error
|
||||
delegate:delegate] autorelease];
|
||||
}
|
||||
|
||||
// check the asset catalogues
|
||||
return [[[self alloc] initWithDataAssetNamed:string
|
||||
error:error] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithDataAssetNamed:(NSDataAssetName)name
|
||||
error:(NSError**)error
|
||||
{
|
||||
return [self initWithDataAssetNamed:name
|
||||
bundle:NSBundle.mainBundle
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (id)initWithDataAssetNamed:(NSDataAssetName)name
|
||||
bundle:(NSBundle*)bundle
|
||||
error:(NSError**)error
|
||||
{
|
||||
NSDataAsset* dataAsset = [[[NSDataAsset alloc] initWithName:name
|
||||
bundle:bundle] autorelease];
|
||||
if(dataAsset != nil) {
|
||||
return [[self initWithSVGData:dataAsset.data
|
||||
error:error] autorelease];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -89,10 +108,13 @@
|
||||
__block IJSVGImageLayer* imageLayer = nil;
|
||||
|
||||
// create the layers we require
|
||||
IJSVGImage* imageNode = [[[IJSVGImage alloc] init] autorelease];
|
||||
imageNode.image = image;
|
||||
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
layer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
imageLayer =
|
||||
[[[IJSVGImageLayer alloc] initWithImage:image] autorelease];
|
||||
[[[IJSVGImageLayer alloc] initWithImage:imageNode] autorelease];
|
||||
[layer addSublayer:imageLayer];
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
@@ -109,7 +131,6 @@
|
||||
// this completely bypasses passing of files
|
||||
if ((self = [super init]) != nil) {
|
||||
// keep the layer tree
|
||||
_layerTree = [group retain];
|
||||
_viewBox = viewBox;
|
||||
|
||||
// any setups
|
||||
@@ -187,15 +208,15 @@
|
||||
[self _checkDelegate];
|
||||
|
||||
// create the group
|
||||
_group = [[IJSVGParser groupForFileURL:aURL
|
||||
error:&anError
|
||||
delegate:self] retain];
|
||||
|
||||
IJSVGParser* parser = [IJSVGParser groupForFileURL:aURL
|
||||
error:&anError
|
||||
delegate:self];
|
||||
_rootNode = parser.rootNode.retain;
|
||||
[self _setupBasicInfoFromGroup];
|
||||
[self _setupBasicsFromAnyInitializer];
|
||||
|
||||
// something went wrong...
|
||||
if (_group == nil) {
|
||||
if (_rootNode == nil) {
|
||||
if (error != NULL) {
|
||||
*error = anError;
|
||||
}
|
||||
@@ -248,15 +269,16 @@
|
||||
[self _checkDelegate];
|
||||
|
||||
// setup the parser
|
||||
_group = [[IJSVGParser alloc] initWithSVGString:string
|
||||
error:&anError
|
||||
delegate:self];
|
||||
IJSVGParser* parser = [[[IJSVGParser alloc] initWithSVGString:string
|
||||
error:&anError
|
||||
delegate:self] autorelease];
|
||||
_rootNode = parser.rootNode.retain;
|
||||
|
||||
[self _setupBasicInfoFromGroup];
|
||||
[self _setupBasicsFromAnyInitializer];
|
||||
|
||||
// something went wrong :(
|
||||
if (_group == nil) {
|
||||
if (_rootNode == nil) {
|
||||
if (error != NULL) {
|
||||
*error = anError;
|
||||
}
|
||||
@@ -276,20 +298,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)discardDOM
|
||||
{
|
||||
// if we discard, we can no longer create a tree, so lets create tree
|
||||
// upfront before we kill anything
|
||||
[self layer];
|
||||
|
||||
// now clear memory
|
||||
(void)([_group release]), _group = nil;
|
||||
}
|
||||
|
||||
- (void)_setupBasicInfoFromGroup
|
||||
{
|
||||
_viewBox = _group.viewBox;
|
||||
_intrinsicSize = _group.intrinsicSize.retain;
|
||||
_viewBox = [_rootNode.viewBox computeValue:CGSizeZero];
|
||||
_intrinsicSize = _rootNode.intrinsicSize.retain;
|
||||
}
|
||||
|
||||
- (void)_setupBasicsFromAnyInitializer
|
||||
@@ -299,7 +311,6 @@
|
||||
self.renderQuality = kIJSVGRenderQualityFullResolution;
|
||||
|
||||
// setup low level backing scale
|
||||
_lastProposedBackingScale = 0.f;
|
||||
self.renderingBackingScaleHelper = ^CGFloat {
|
||||
return NSScreen.mainScreen.backingScaleFactor;
|
||||
};
|
||||
@@ -307,37 +318,32 @@
|
||||
|
||||
- (void)setTitle:(NSString*)title
|
||||
{
|
||||
_group.title = title;
|
||||
_rootNode.title = title;
|
||||
}
|
||||
|
||||
- (NSString*)title
|
||||
{
|
||||
return _group.title;
|
||||
return _rootNode.title;
|
||||
}
|
||||
|
||||
- (void)setDesc:(NSString*)description
|
||||
{
|
||||
_group.desc = description;
|
||||
_rootNode.desc = description;
|
||||
}
|
||||
|
||||
- (NSString*)desc
|
||||
{
|
||||
return _group.desc;
|
||||
return _rootNode.desc;
|
||||
}
|
||||
|
||||
- (NSString*)identifier
|
||||
{
|
||||
return _group.identifier;
|
||||
return _rootNode.identifier;
|
||||
}
|
||||
|
||||
- (void)_checkDelegate
|
||||
{
|
||||
_respondsTo.shouldHandleForeignObject =
|
||||
[_delegate respondsToSelector:@selector(svg:shouldHandleForeignObject:)];
|
||||
_respondsTo.handleForeignObject = [_delegate
|
||||
respondsToSelector:@selector(svg:handleForeignObject:document:)];
|
||||
_respondsTo.shouldHandleSubSVG =
|
||||
[_delegate respondsToSelector:@selector(svg:foundSubSVG:withSVGString:)];
|
||||
_respondsTo.shouldHandleSubSVG = [_delegate respondsToSelector:@selector(svg:foundSubSVG:withSVGString:)];
|
||||
}
|
||||
|
||||
- (NSRect)viewBox
|
||||
@@ -347,22 +353,22 @@
|
||||
|
||||
- (IJSVGGroup*)rootNode
|
||||
{
|
||||
return _group;
|
||||
return _rootNode;
|
||||
}
|
||||
|
||||
- (BOOL)isFont
|
||||
{
|
||||
return [_group isFont];
|
||||
return [_rootNode isFont];
|
||||
}
|
||||
|
||||
- (NSArray<IJSVGPath*>*)glyphs
|
||||
{
|
||||
return [_group glyphs];
|
||||
return [_rootNode glyphs];
|
||||
}
|
||||
|
||||
- (NSArray<IJSVG*>*)subSVGs:(BOOL)recursive
|
||||
{
|
||||
return [_group subSVGs:recursive];
|
||||
return [_rootNode subSVGs:recursive];
|
||||
}
|
||||
|
||||
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options
|
||||
@@ -436,7 +442,7 @@
|
||||
[self _beginDraw:rect];
|
||||
|
||||
// make sure we setup the scale based on the backing scale factor
|
||||
CGFloat scale = [self backingScaleFactor:NULL];
|
||||
CGFloat scale = [self backingScaleFactor];
|
||||
|
||||
// create the context and colorspace
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
@@ -526,10 +532,10 @@
|
||||
CGContextTranslateCTM(context, 0, -box.size.height);
|
||||
|
||||
// make sure we set the masks to path bits n bobs
|
||||
[self _beginVectorDraw];
|
||||
// [self _beginVectorDraw];
|
||||
// draw the icon
|
||||
[self _drawInRect:(NSRect)box context:context error:error];
|
||||
[self _endVectorDraw];
|
||||
// [self _endVectorDraw];
|
||||
|
||||
CGContextEndPage(context);
|
||||
|
||||
@@ -540,35 +546,39 @@
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)endVectorDraw
|
||||
{
|
||||
[self _endVectorDraw];
|
||||
}
|
||||
//- (void)endVectorDraw
|
||||
//{
|
||||
// [self _endVectorDraw];
|
||||
//}
|
||||
//
|
||||
//- (void)beginVectorDraw
|
||||
//{
|
||||
// [self _beginVectorDraw];
|
||||
//}
|
||||
|
||||
- (void)beginVectorDraw
|
||||
{
|
||||
[self _beginVectorDraw];
|
||||
}
|
||||
|
||||
- (void)_beginVectorDraw
|
||||
{
|
||||
// turn on converts masks to PDF's
|
||||
// as PDF context and layer masks dont work
|
||||
void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer, BOOL isMask) {
|
||||
((IJSVGLayer*)layer).convertMasksToPaths = YES;
|
||||
};
|
||||
[IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block];
|
||||
}
|
||||
|
||||
- (void)_endVectorDraw
|
||||
{
|
||||
// turn of convert masks to paths as not
|
||||
// needed for generic rendering
|
||||
void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer, BOOL isMask) {
|
||||
((IJSVGLayer*)layer).convertMasksToPaths = NO;
|
||||
};
|
||||
[IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block];
|
||||
}
|
||||
//- (void)_beginVectorDraw
|
||||
//{
|
||||
// // turn on converts masks to PDF's
|
||||
// // as PDF context and layer masks dont work
|
||||
// void (^block)(CALayer* layer, BOOL isMask, BOOL* stop) =
|
||||
// ^void(CALayer* layer, BOOL isMask, BOOL* stop) {
|
||||
// ((IJSVGLayer*)layer).convertMasksToPaths = YES;
|
||||
// };
|
||||
// [IJSVGLayer recursivelyWalkLayer:self.layer
|
||||
// withBlock:block];
|
||||
//}
|
||||
//
|
||||
//- (void)_endVectorDraw
|
||||
//{
|
||||
// // turn of convert masks to paths as not
|
||||
// // needed for generic rendering
|
||||
// void (^block)(CALayer* layer, BOOL isMask, BOOL* stop) =
|
||||
// ^void(CALayer* layer, BOOL isMask, BOOL* stop) {
|
||||
// ((IJSVGLayer*)layer).convertMasksToPaths = NO;
|
||||
// };
|
||||
// [IJSVGLayer recursivelyWalkLayer:self.layer
|
||||
// withBlock:block];
|
||||
//}
|
||||
|
||||
- (void)prepForDrawingInView:(NSView*)view
|
||||
{
|
||||
@@ -579,7 +589,7 @@
|
||||
}
|
||||
|
||||
// construct the layer before drawing
|
||||
[self layer];
|
||||
[self rootLayer];
|
||||
|
||||
// set the scale
|
||||
__block NSView* weakView = view;
|
||||
@@ -625,12 +635,6 @@
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (CGFloat)computeBackingScale:(CGFloat)actualScale
|
||||
{
|
||||
_backingScale = actualScale;
|
||||
return (CGFloat)(_scale + actualScale);
|
||||
}
|
||||
|
||||
- (NSRect)computeRectDrawingInRect:(NSRect)rect
|
||||
isValid:(BOOL*)valid
|
||||
{
|
||||
@@ -645,7 +649,14 @@
|
||||
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) {
|
||||
if (NSEqualRects(_viewBox, NSZeroRect) ||
|
||||
_viewBox.size.width <= 0 ||
|
||||
_viewBox.size.height <= 0 ||
|
||||
NSEqualRects(NSZeroRect, viewPort) ||
|
||||
CGRectIsEmpty(viewPort) ||
|
||||
CGRectIsNull(viewPort) ||
|
||||
viewPort.size.width <= 0 ||
|
||||
viewPort.size.height <= 0) {
|
||||
*valid = NO;
|
||||
return NSZeroRect;
|
||||
}
|
||||
@@ -660,151 +671,120 @@
|
||||
[self _drawInRect:rect context:context error:nil];
|
||||
}
|
||||
|
||||
//- (BOOL)_drawInRect:(NSRect)rect
|
||||
// context:(CGContextRef)ref
|
||||
// error:(NSError**)error
|
||||
//{
|
||||
// // prep for draw...
|
||||
// CGContextSaveGState(ref);
|
||||
// @try {
|
||||
// [self _beginDraw:rect];
|
||||
//
|
||||
// // we also need to calculate the viewport so we can clip
|
||||
// // the drawing if needed
|
||||
// BOOL canDraw = NO;
|
||||
// NSRect viewPort = [self computeRectDrawingInRect:rect isValid:&canDraw];
|
||||
// // check the viewport
|
||||
// if (canDraw == NO) {
|
||||
// if (error != NULL) {
|
||||
// *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
// code:IJSVGErrorDrawing
|
||||
// userInfo:nil] autorelease];
|
||||
// }
|
||||
// } else {
|
||||
// // clip to mask
|
||||
// if (self.clipToViewport == YES) {
|
||||
// CGContextClipToRect(ref, viewPort);
|
||||
// }
|
||||
//
|
||||
// // add the origin back onto the viewport
|
||||
// viewPort.origin.x -= (_viewBox.origin.x) * _scale;
|
||||
// viewPort.origin.y -= (_viewBox.origin.y) * _scale;
|
||||
//
|
||||
// // transforms
|
||||
// CGContextTranslateCTM(ref, viewPort.origin.x, viewPort.origin.y);
|
||||
// CGContextScaleCTM(ref, _scale, _scale);
|
||||
//
|
||||
// // do we need to update the backing scales on the
|
||||
// // layers?
|
||||
// [self backingScaleFactor:nil];
|
||||
//
|
||||
// CGInterpolationQuality quality;
|
||||
// switch (self.renderQuality) {
|
||||
// case kIJSVGRenderQualityLow: {
|
||||
// quality = kCGInterpolationLow;
|
||||
// break;
|
||||
// }
|
||||
// case kIJSVGRenderQualityOptimized: {
|
||||
// quality = kCGInterpolationMedium;
|
||||
// break;
|
||||
// }
|
||||
// default: {
|
||||
// quality = kCGInterpolationHigh;
|
||||
// }
|
||||
// }
|
||||
// CGContextSetInterpolationQuality(ref, quality);
|
||||
// BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
// [self.layer renderInContext:ref];
|
||||
// if (hasTransaction == YES) {
|
||||
// IJSVGEndTransaction();
|
||||
// }
|
||||
// }
|
||||
// } @catch (NSException* exception) {
|
||||
// // just catch and give back a drawing error to the caller
|
||||
// if (error != NULL) {
|
||||
// *error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
// code:IJSVGErrorDrawing
|
||||
// userInfo:nil] autorelease];
|
||||
// }
|
||||
// }
|
||||
// CGContextRestoreGState(ref);
|
||||
// return (error == nil);
|
||||
//}
|
||||
|
||||
- (BOOL)_drawInRect:(NSRect)rect
|
||||
context:(CGContextRef)ref
|
||||
error:(NSError**)error
|
||||
{
|
||||
// prep for draw...
|
||||
BOOL transaction = IJSVGBeginTransaction();
|
||||
CGContextSaveGState(ref);
|
||||
@try {
|
||||
[self _beginDraw:rect];
|
||||
|
||||
// we also need to calculate the viewport so we can clip
|
||||
// the drawing if needed
|
||||
BOOL canDraw = NO;
|
||||
NSRect viewPort = [self computeRectDrawingInRect:rect isValid:&canDraw];
|
||||
// check the viewport
|
||||
if (canDraw == NO) {
|
||||
if (error != NULL) {
|
||||
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
code:IJSVGErrorDrawing
|
||||
userInfo:nil] autorelease];
|
||||
}
|
||||
} else {
|
||||
// clip to mask
|
||||
if (self.clipToViewport == YES) {
|
||||
CGContextClipToRect(ref, viewPort);
|
||||
}
|
||||
|
||||
// add the origin back onto the viewport
|
||||
viewPort.origin.x -= (_viewBox.origin.x) * _scale;
|
||||
viewPort.origin.y -= (_viewBox.origin.y) * _scale;
|
||||
|
||||
// transforms
|
||||
CGContextTranslateCTM(ref, viewPort.origin.x, viewPort.origin.y);
|
||||
CGContextScaleCTM(ref, _scale, _scale);
|
||||
|
||||
// do we need to update the backing scales on the
|
||||
// layers?
|
||||
[self backingScaleFactor:nil];
|
||||
|
||||
CGInterpolationQuality quality;
|
||||
switch (self.renderQuality) {
|
||||
case kIJSVGRenderQualityLow: {
|
||||
quality = kCGInterpolationLow;
|
||||
break;
|
||||
}
|
||||
case kIJSVGRenderQualityOptimized: {
|
||||
quality = kCGInterpolationMedium;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
quality = kCGInterpolationHigh;
|
||||
}
|
||||
}
|
||||
CGContextSetInterpolationQuality(ref, quality);
|
||||
BOOL hasTransaction = IJSVGBeginTransaction();
|
||||
[self.layer renderInContext:ref];
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
}
|
||||
} @catch (NSException* exception) {
|
||||
// just catch and give back a drawing error to the caller
|
||||
if (error != NULL) {
|
||||
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
code:IJSVGErrorDrawing
|
||||
userInfo:nil] autorelease];
|
||||
}
|
||||
}
|
||||
// make sure we setup a transaction
|
||||
CGFloat backingScale = [self backingScaleFactor];
|
||||
[self.rootLayer renderInContext:ref
|
||||
viewPort:rect
|
||||
backingScale:backingScale
|
||||
quality:_renderQuality];
|
||||
CGContextRestoreGState(ref);
|
||||
return (error == nil);
|
||||
if(transaction) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGFloat)backingScaleFactor:(CGFloat* _Nullable)proposedBackingScale
|
||||
- (IJSVGLayerTree*)layerTree
|
||||
{
|
||||
if(_layerTree == nil) {
|
||||
_layerTree = [[IJSVGLayerTree alloc] init];
|
||||
}
|
||||
return _layerTree;
|
||||
}
|
||||
|
||||
- (IJSVGRootLayer*)rootLayer
|
||||
{
|
||||
if(_rootLayer == nil) {
|
||||
_rootLayer = [self.layerTree rootLayerForRootNode:_rootNode].retain;
|
||||
}
|
||||
return _rootLayer;
|
||||
}
|
||||
|
||||
- (CGFloat)backingScaleFactor
|
||||
{
|
||||
__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
|
||||
scale = (_scale * scale);
|
||||
|
||||
// dont do anything, nothing has changed, no point of iterating over
|
||||
// every layer for no reason!
|
||||
if (scale == _lastProposedBackingScale && renderQuality == _lastProposedRenderQuality) {
|
||||
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) {
|
||||
IJSVGLayer* propLayer = ((IJSVGLayer*)layer);
|
||||
propLayer.renderQuality = quality;
|
||||
if (propLayer.requiresBackingScaleHelp == YES) {
|
||||
propLayer.backingScaleFactor = scale;
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
_layerTree = [[tree layerForNode:_group] retain];
|
||||
if (hasTransaction == YES) {
|
||||
IJSVGEndTransaction();
|
||||
}
|
||||
return _layerTree;
|
||||
}
|
||||
|
||||
- (IJSVGLayer*)layer
|
||||
{
|
||||
if (_layerTree != nil) {
|
||||
return _layerTree;
|
||||
}
|
||||
|
||||
// create the renderer and assign default values
|
||||
// from this SVG object
|
||||
IJSVGLayerTree* renderer = [[[IJSVGLayerTree alloc] init] autorelease];
|
||||
renderer.viewBox = self.viewBox;
|
||||
renderer.style = self.renderingStyle;
|
||||
|
||||
// return the rendered layer
|
||||
return [self layerWithTree:renderer];
|
||||
return _backingScale = scale;
|
||||
}
|
||||
|
||||
- (void)setRenderingStyle:(IJSVGRenderingStyle*)style
|
||||
@@ -834,53 +814,72 @@
|
||||
(void)([_layerTree release]), _layerTree = nil;
|
||||
}
|
||||
|
||||
- (IJSVGColorList*)computedColorList:(BOOL*)hasPatternFills
|
||||
- (IJSVGColorList*)colorList
|
||||
{
|
||||
IJSVGColorList* sheet = [[[IJSVGColorList alloc] init] autorelease];
|
||||
void (^block)(CALayer* layer, BOOL isMask) = ^void(CALayer* layer,
|
||||
BOOL isMask) {
|
||||
if ([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO && layer.isHidden == NO) {
|
||||
IJSVGShapeLayer* sLayer = (IJSVGShapeLayer*)layer;
|
||||
NSColor* color = nil;
|
||||
if (sLayer.fillColor != nil) {
|
||||
color = [NSColor colorWithCGColor:sLayer.fillColor];
|
||||
if (color.alphaComponent != 0.f) {
|
||||
[sheet addColor:color];
|
||||
}
|
||||
}
|
||||
if (sLayer.strokeColor != nil) {
|
||||
color = [NSColor colorWithCGColor:sLayer.strokeColor];
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
if (color.alphaComponent != 0.f) {
|
||||
[sheet addColor:color];
|
||||
}
|
||||
}
|
||||
void (^block)(CALayer* layer, BOOL* stop) =
|
||||
^void(CALayer* layer, BOOL* stop) {
|
||||
|
||||
// dont do anything
|
||||
if(([layer isKindOfClass:IJSVGShapeLayer.class] &&
|
||||
layer.isHidden == NO) == NO) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// compute
|
||||
IJSVGShapeLayer* sLayer = (IJSVGShapeLayer*)layer;
|
||||
NSColor* color = nil;
|
||||
|
||||
// check for any patterns
|
||||
if (sLayer.patternFillLayer != nil || sLayer.gradientFillLayer != nil || sLayer.gradientStrokeLayer != nil || sLayer.patternStrokeLayer != nil) {
|
||||
if (hasPatternFills != nil && *hasPatternFills != YES) {
|
||||
*hasPatternFills = YES;
|
||||
}
|
||||
// fill color
|
||||
if (sLayer.fillColor != nil) {
|
||||
color = [NSColor colorWithCGColor:sLayer.fillColor];
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
if (color.alphaComponent != 0.f) {
|
||||
IJSVGColorType* type = nil;
|
||||
type = [IJSVGColorType typeWithColor:color
|
||||
flags:IJSVGColorTypeFlagFill];
|
||||
[sheet addColor:type];
|
||||
}
|
||||
}
|
||||
|
||||
// add any colors from gradients
|
||||
IJSVGGradientLayer* gradLayer = nil;
|
||||
IJSVGGradientLayer* gradStrokeLayer = nil;
|
||||
if ((gradLayer = sLayer.gradientFillLayer) != nil) {
|
||||
IJSVGColorList* gradSheet = gradLayer.gradient.computedColorList;
|
||||
[sheet addColorsFromList:gradSheet];
|
||||
}
|
||||
if ((gradStrokeLayer = sLayer.gradientStrokeLayer) != nil) {
|
||||
IJSVGColorList* gradSheet = gradStrokeLayer.gradient.computedColorList;
|
||||
[sheet addColorsFromList:gradSheet];
|
||||
}
|
||||
// stroke color
|
||||
if (sLayer.strokeColor != nil) {
|
||||
color = [NSColor colorWithCGColor:sLayer.strokeColor];
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
if (color.alphaComponent != 0.f) {
|
||||
IJSVGColorType* type = nil;
|
||||
type = [IJSVGColorType typeWithColor:color
|
||||
flags:IJSVGColorTypeFlagStroke];
|
||||
[sheet addColor:type];
|
||||
}
|
||||
}
|
||||
|
||||
// check for any patterns or strokes
|
||||
if (sLayer.patternFillLayer != nil || sLayer.gradientFillLayer != nil ||
|
||||
sLayer.gradientStrokeLayer != nil || sLayer.patternStrokeLayer != nil) {
|
||||
|
||||
// add any colors from gradients
|
||||
IJSVGGradientLayer* gradLayer = nil;
|
||||
IJSVGGradientLayer* gradStrokeLayer = nil;
|
||||
|
||||
// gradient fill
|
||||
if ((gradLayer = sLayer.gradientFillLayer) != nil) {
|
||||
IJSVGColorList* gradSheet = gradLayer.gradient.colorList;
|
||||
[sheet addColorsFromList:gradSheet];
|
||||
}
|
||||
|
||||
// gradient stroke layers
|
||||
if ((gradStrokeLayer = sLayer.gradientStrokeLayer) != nil) {
|
||||
IJSVGColorList* gradSheet = gradStrokeLayer.gradient.colorList;
|
||||
[sheet addColorsFromList:gradSheet];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// walk
|
||||
[IJSVGLayer recursivelyWalkLayer:self.layer withBlock:block];
|
||||
|
||||
// return the colours!
|
||||
|
||||
// gogogo!
|
||||
[IJSVGLayer recursivelyWalkLayer:self.rootLayer
|
||||
withBlock:block];
|
||||
return sheet;
|
||||
}
|
||||
|
||||
@@ -929,25 +928,43 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)svgParser:(IJSVGParser*)parser
|
||||
shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject
|
||||
{
|
||||
if (_delegate != nil && _respondsTo.shouldHandleForeignObject == 1) {
|
||||
return [_delegate svg:self
|
||||
shouldHandleForeignObject:foreignObject];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
#pragma mark matching
|
||||
|
||||
- (void)svgParser:(IJSVGParser*)parser
|
||||
handleForeignObject:(IJSVGForeignObject*)foreignObject
|
||||
document:(NSXMLDocument*)document
|
||||
- (BOOL)matchesPropertiesWithMask:(IJSVGMatchPropertiesMask)mask
|
||||
{
|
||||
if (_delegate != nil && _respondsTo.handleForeignObject == 1) {
|
||||
[_delegate svg:self
|
||||
handleForeignObject:foreignObject
|
||||
document:document];
|
||||
}
|
||||
__block IJSVGMatchPropertiesMask matchedMask = IJSVGMatchPropertyNone;
|
||||
IJSVGNodeWalkHandler handler = ^(IJSVGNode* node, BOOL* allowChildNodes,
|
||||
BOOL* stop) {
|
||||
// dont compute nodes that are not designed
|
||||
// to be rendered
|
||||
if(node.shouldRender == NO) {
|
||||
*allowChildNodes = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
// check for stroke
|
||||
IJSVGPath* path = (IJSVGPath*)node;
|
||||
if((mask & IJSVGMatchPropertyContainsStrokedElement) != 0 &&
|
||||
[node isKindOfClass:IJSVGPath.class] == YES &&
|
||||
[path matchesTraits:IJSVGNodeTraitStroked] == YES) {
|
||||
matchedMask |= IJSVGMatchPropertyContainsStrokedElement;
|
||||
}
|
||||
|
||||
// check for mask
|
||||
if((mask & IJSVGMatchPropertyContainsMaskedElement) != 0 &&
|
||||
node.mask != nil) {
|
||||
matchedMask |= IJSVGMatchPropertyContainsMaskedElement;
|
||||
}
|
||||
|
||||
// simply check if masks equal, if they are, stop this loop
|
||||
// and return the evaluation
|
||||
if(matchedMask == mask) {
|
||||
*stop = YES;
|
||||
}
|
||||
};
|
||||
[IJSVGNode walkNodeTree:_rootNode
|
||||
handler:handler];
|
||||
return matchedMask == mask;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2015 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVG.h"
|
||||
#import <IJSVG/IJSVG.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef void (^IJSVGFontConverterEnumerateBlock)(NSString* unicode, IJSVG* svg);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// Copyright (c) 2015 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGBezierPathAdditions.h"
|
||||
#import "IJSVGFontConverter.h"
|
||||
#import "IJSVGShapeLayer.h"
|
||||
|
||||
@@ -104,16 +103,15 @@
|
||||
|
||||
+ (IJSVG*)convertIJSVGPathToSVG:(IJSVGPath*)path
|
||||
{
|
||||
CGPathRef cgPath = [path.path newCGPathRef:NO];
|
||||
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:cgPath];
|
||||
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:path.path];
|
||||
IJSVG* svg = [self convertPathToSVG:flippedPath];
|
||||
CGPathRelease(flippedPath);
|
||||
CGPathRelease(cgPath);
|
||||
return svg;
|
||||
}
|
||||
|
||||
+ (IJSVG*)convertPathToSVG:(CGPathRef)path
|
||||
{
|
||||
IJSVGBeginTransaction();
|
||||
__block IJSVG* svg = nil;
|
||||
IJSVGGroupLayer* layer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
IJSVGShapeLayer* shape = [[[IJSVGShapeLayer alloc] init] autorelease];
|
||||
@@ -122,6 +120,7 @@
|
||||
CGRect box = CGPathGetPathBoundingBox(path);
|
||||
svg = [[IJSVG alloc] initWithSVGLayer:layer
|
||||
viewBox:box];
|
||||
IJSVGEndTransaction();
|
||||
return [svg autorelease];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVG.h"
|
||||
#import <IJSVG/IJSVG.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
IB_DESIGNABLE
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// IJSVGWriter.h
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 21/05/2015.
|
||||
// Copyright (c) 2015 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGPath.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGWriter : NSObject {
|
||||
}
|
||||
|
||||
+ (NSString*)SVGDocumentStringForSVGGlyph:(IJSVGPath*)node;
|
||||
+ (NSString*)SVGDocumentStringForBezierPath:(NSBezierPath*)path;
|
||||
+ (NSXMLDocument*)SVGDocumentForBezierPath:(NSBezierPath*)path;
|
||||
|
||||
@end
|
||||
@@ -1,115 +0,0 @@
|
||||
//
|
||||
// IJSVGWriter.m
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 21/05/2015.
|
||||
// Copyright (c) 2015 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGWriter.h"
|
||||
|
||||
@implementation IJSVGWriter
|
||||
|
||||
+ (NSString*)SVGDocumentStringForSVGGlyph:(IJSVGPath*)node
|
||||
{
|
||||
NSBezierPath* path = [node path];
|
||||
// we need to flip it
|
||||
NSAffineTransform* trans = NSAffineTransform.transform;
|
||||
[trans scaleXBy:1.f yBy:-1.f];
|
||||
[trans translateXBy:0.f yBy:path.controlPointBounds.size.height];
|
||||
path = [trans transformBezierPath:path];
|
||||
return [self.class SVGDocumentStringForBezierPath:path];
|
||||
}
|
||||
|
||||
+ (NSString*)SVGDocumentStringForBezierPath:(NSBezierPath*)path
|
||||
{
|
||||
return [self.class SVGDocumentForBezierPath:path].XMLString;
|
||||
}
|
||||
|
||||
+ (NSXMLDocument*)SVGDocumentForBezierPath:(NSBezierPath*)path
|
||||
{
|
||||
NSXMLElement* root = [self.class rootElementForPath:path];
|
||||
|
||||
// create the path data
|
||||
NSXMLElement* p = [[[NSXMLElement alloc] initWithName:@"path"] autorelease];
|
||||
|
||||
// add the drawing command
|
||||
NSXMLNode* n = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
|
||||
[n setName:@"d"];
|
||||
[n setStringValue:[self.class SVGPathStringForBezierPath:path]];
|
||||
[p addAttribute:n];
|
||||
|
||||
// add the drawing path to the root
|
||||
[root addChild:p];
|
||||
return [[[NSXMLDocument alloc] initWithRootElement:root] autorelease];
|
||||
}
|
||||
|
||||
+ (NSXMLElement*)rootElementForPath:(NSBezierPath*)path
|
||||
{
|
||||
NSXMLElement* element = [[[NSXMLElement alloc] initWithName:@"svg"] autorelease];
|
||||
NSRect bounds = path.controlPointBounds;
|
||||
|
||||
// width
|
||||
NSXMLNode* att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
|
||||
[att setName:@"width"];
|
||||
[att setStringValue:[NSString stringWithFormat:@"%f", bounds.size.width]];
|
||||
[element addAttribute:att];
|
||||
|
||||
// height
|
||||
att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
|
||||
[att setName:@"height"];
|
||||
[att setStringValue:[NSString stringWithFormat:@"%f", bounds.size.height]];
|
||||
[element addAttribute:att];
|
||||
|
||||
// viewbox
|
||||
att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
|
||||
[att setName:@"viewBox"];
|
||||
[att setStringValue:[NSString stringWithFormat:@"%f %f %f %f", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height]];
|
||||
[element addAttribute:att];
|
||||
|
||||
// namespace
|
||||
att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
|
||||
[att setName:@"xmlns"];
|
||||
[att setStringValue:@"http://www.w3.org/2000/svg"];
|
||||
[element addAttribute:att];
|
||||
return element;
|
||||
}
|
||||
|
||||
+ (NSString*)SVGPathStringForBezierPath:(NSBezierPath*)path
|
||||
{
|
||||
NSMutableString* str = [[[NSMutableString alloc] init] autorelease];
|
||||
for (NSInteger i = 0; i < path.elementCount; i++) {
|
||||
NSBezierPathElement element = [path elementAtIndex:i];
|
||||
switch (element) {
|
||||
// move
|
||||
case NSMoveToBezierPathElement: {
|
||||
NSPoint points[1];
|
||||
[path elementAtIndex:i associatedPoints:points];
|
||||
[str appendFormat:@"M%f %f", points[0].x, points[0].y];
|
||||
break;
|
||||
}
|
||||
// line
|
||||
case NSLineToBezierPathElement: {
|
||||
NSPoint points[1];
|
||||
[path elementAtIndex:i associatedPoints:points];
|
||||
[str appendFormat:@"L%f %f", points[0].x, points[0].y];
|
||||
break;
|
||||
}
|
||||
// curve
|
||||
case NSCurveToBezierPathElement: {
|
||||
NSPoint points[3];
|
||||
[path elementAtIndex:i associatedPoints:points];
|
||||
[str appendFormat:@"C%f %f %f %f %f %f", points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y];
|
||||
break;
|
||||
}
|
||||
// close
|
||||
case NSClosePathBezierPathElement: {
|
||||
[str appendFormat:@"Z"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,9 +7,15 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGUtils.h"
|
||||
#import <IJSVG/IJSVGUtils.h>
|
||||
#import <IJSVG/IJSVGColorType.h>
|
||||
|
||||
@class IJSVG;
|
||||
@class IJSVGExporter;
|
||||
@class IJSVGLayer;
|
||||
@class IJSVGNode;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^IJSVGCGPathHandler)(const CGPathElement* pathElement);
|
||||
typedef void (^IJSVGPathElementEnumerationBlock)(const CGPathElement* pathElement, CGPoint currentPoint);
|
||||
@@ -39,7 +45,16 @@ typedef NS_OPTIONS(NSInteger, IJSVGExporterOptions) {
|
||||
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
|
||||
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);
|
||||
@@ -47,6 +62,22 @@ void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlo
|
||||
const NSArray<NSString*>* IJSVGShortCharacterArray(void);
|
||||
const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes(void);
|
||||
|
||||
|
||||
@protocol IJSVGExporterDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
- (NSString* _Nullable)svgExporter:(IJSVGExporter*)exporter
|
||||
identifierForElement:(NSXMLElement* _Nullable)element
|
||||
type:(IJSVGNodeType)type
|
||||
defaultID:(NSString* (^)(void))defaultID;
|
||||
- (NSString* _Nullable)svgExporter:(IJSVGExporter*)exporter
|
||||
stringForColor:(NSColor*)color
|
||||
flags:(IJSVGColorTypeFlags)flag
|
||||
options:(IJSVGColorStringOptions)options;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface IJSVGExporter : NSObject {
|
||||
|
||||
@private
|
||||
@@ -58,22 +89,30 @@ const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes(void);
|
||||
NSInteger _idCount;
|
||||
NSInteger _shortIdCount;
|
||||
BOOL _appliedXLink;
|
||||
|
||||
struct {
|
||||
unsigned int identifierForElement: 1;
|
||||
unsigned int stringForColor: 1;
|
||||
} _respondsTo;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) id<IJSVGExporterDelegate> delegate;
|
||||
@property (nonatomic, assign) IJSVGFloatingPointOptions floatingPointOptions;
|
||||
@property (nonatomic, copy) NSString* title;
|
||||
@property (nonatomic, copy) NSString* description;
|
||||
@property (nonatomic, copy, nullable) NSString* title;
|
||||
@property (nonatomic, copy, nullable) NSString* desc;
|
||||
|
||||
- (id)initWithSVG:(IJSVG*)svg
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options;
|
||||
- (id)initWithSVG:(IJSVG*)svg
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
|
||||
|
||||
- (NSString*)SVGString;
|
||||
- (NSData*)SVGData;
|
||||
- (IJSVG*)SVG:(NSError**)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#import "IJSVGRadialGradient.h"
|
||||
#import "IJSVGShapeLayer.h"
|
||||
#import "IJSVGStrokeLayer.h"
|
||||
#import "IJSVGTransformLayer.h"
|
||||
|
||||
@implementation IJSVGExporter
|
||||
|
||||
@@ -28,9 +29,6 @@
|
||||
#define XML_DOC_CHARSET @"UTF-8"
|
||||
#define XML_DOC_GENERATOR @"Generated by IJSVG (https://github.com/iconjar/IJSVG)"
|
||||
|
||||
@synthesize title;
|
||||
@synthesize description;
|
||||
|
||||
BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option)
|
||||
{
|
||||
return (options & option) != 0;
|
||||
@@ -49,7 +47,7 @@ const NSArray<NSString*>* IJSVGShortCharacterArray(void)
|
||||
return _array;
|
||||
}
|
||||
|
||||
const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes()
|
||||
const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes(void)
|
||||
{
|
||||
static NSDictionary* _defaults;
|
||||
static dispatch_once_t onceToken;
|
||||
@@ -111,7 +109,7 @@ const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes()
|
||||
return _defaults;
|
||||
}
|
||||
|
||||
const NSArray* IJSVGInheritableAttributes()
|
||||
const NSArray* IJSVGInheritableAttributes(void)
|
||||
{
|
||||
static NSArray* _attributes;
|
||||
static dispatch_once_t onceToken;
|
||||
@@ -195,8 +193,8 @@ NSString* IJSVGHash(NSString* key)
|
||||
(void)([_svg release]), _svg = nil;
|
||||
(void)([_dom release]), _dom = nil;
|
||||
(void)([_defElement release]), _defElement = nil;
|
||||
(void)([title release]), title = nil;
|
||||
(void)([description release]), description = nil;
|
||||
(void)([_title release]), _title = nil;
|
||||
(void)([_desc release]), _desc = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -204,15 +202,16 @@ NSString* IJSVGHash(NSString* key)
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options
|
||||
{
|
||||
IJSVGFloatingPointOptions fpo = IJSVGFloatingPointOptionsDefault();
|
||||
return [self initWithSVG:svg
|
||||
size:size
|
||||
options:options
|
||||
floatingPointOptions:IJSVGFloatingPointOptionsDefault()];
|
||||
floatingPointOptions:fpo];
|
||||
}
|
||||
|
||||
- (id)initWithSVG:(IJSVG*)svg
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options
|
||||
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
@@ -222,15 +221,17 @@ NSString* IJSVGHash(NSString* key)
|
||||
|
||||
// defaults for floating point rounding, if any
|
||||
_floatingPointOptions = floatingPointOptions;
|
||||
|
||||
// clear memory as soon as possible
|
||||
@autoreleasepool {
|
||||
[self _prepare];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<IJSVGExporterDelegate>)delegate
|
||||
{
|
||||
_delegate = delegate;
|
||||
_respondsTo.identifierForElement = [delegate respondsToSelector:@selector(svgExporter:identifierForElement:type:defaultID:)];
|
||||
_respondsTo.stringForColor = [delegate respondsToSelector:@selector(svgExporter:stringForColor:flags:options:)];
|
||||
}
|
||||
|
||||
- (NSXMLElement*)defElement
|
||||
{
|
||||
if (_defElement != nil) {
|
||||
@@ -378,8 +379,15 @@ NSString* IJSVGHash(NSString* key)
|
||||
return [NSString stringWithFormat:@"%@%ld", chars[(_idCount++ % chars.count)], _shortIdCount];
|
||||
}
|
||||
|
||||
- (void)_prepare
|
||||
- (void)_generateDOMDocument
|
||||
{
|
||||
_idCount = 0;
|
||||
_shortIdCount = 0;
|
||||
_appliedXLink = NO;
|
||||
(void)[_dom release], _dom = nil;
|
||||
(void)[_defElement release], _defElement = nil;
|
||||
|
||||
|
||||
// create the stand alone DOM
|
||||
NSXMLElement* nestedRoot = nil;
|
||||
NSXMLElement* rootNode = [self rootNode:&nestedRoot];
|
||||
@@ -388,7 +396,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
_dom.characterEncoding = XML_DOC_CHARSET;
|
||||
|
||||
// sort out stuff, so here we go...
|
||||
[self _recursiveParseFromLayer:_svg.layer
|
||||
[self _recursiveParseFromLayer:_svg.rootLayer
|
||||
intoElement:nestedRoot];
|
||||
|
||||
// this needs to be added incase it needs to be cleaned
|
||||
@@ -592,7 +600,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
if ([self compareElementChildren:gradientA toElement:gradientB] == YES) {
|
||||
NSString* idString = [gradientB attributeForName:@"id"].stringValue;
|
||||
if (idString == nil || idString.length == 0) {
|
||||
idString = [self generateID];
|
||||
idString = [self identifierForElement:gradientA];
|
||||
IJSVGApplyAttributesToElement(@{ @"id" : idString }, gradientB);
|
||||
}
|
||||
NSDictionary* atts = @{ @"xlink:href" : IJSVGHash(idString) };
|
||||
@@ -923,7 +931,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
element.name = @"path";
|
||||
|
||||
NSDictionary* atts = @{ @"d" : data,
|
||||
@"id" : [self generateID] };
|
||||
@"id" : [self identifierForElement:element] };
|
||||
IJSVGApplyAttributesToElement(atts, element);
|
||||
|
||||
// store it against the def
|
||||
@@ -1043,10 +1051,12 @@ NSString* IJSVGHash(NSString* key)
|
||||
if (child != nil) {
|
||||
[element addChild:child];
|
||||
}
|
||||
} else if ([layer isKindOfClass:[IJSVGGroupLayer class]]) {
|
||||
} else if ([layer isKindOfClass:[IJSVGGroupLayer class]] ||
|
||||
[layer isKindOfClass:IJSVGTransformLayer.class]) {
|
||||
// assume its probably a group?
|
||||
NSXMLElement* child = [self elementForGroup:layer
|
||||
fromParent:element];
|
||||
|
||||
if (child != nil) {
|
||||
[element addChild:child];
|
||||
}
|
||||
@@ -1127,9 +1137,11 @@ NSString* IJSVGHash(NSString* key)
|
||||
patternElement.name = @"pattern";
|
||||
|
||||
NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
dict[@"id"] = [self generateID];
|
||||
dict[@"id"] = [self identifierForElement:patternElement];
|
||||
dict[@"width"] = IJSVGShortFloatStringWithOptions(layer.patternNode.width.value, _floatingPointOptions);
|
||||
dict[@"height"] = IJSVGShortFloatStringWithOptions(layer.patternNode.height.value, _floatingPointOptions);
|
||||
dict[@"patternUnits"] = layer.patternNode.units == IJSVGUnitObjectBoundingBox ? @"objectBoundingBox" : @"userSpaceOnUse";
|
||||
dict[@"patternContentUnits"] = layer.patternNode.contentUnits == IJSVGUnitObjectBoundingBox ? @"objectBoundingBox" : @"userSpaceOnUse";
|
||||
|
||||
// sort out x and y position
|
||||
IJSVGUnitLength* x = layer.patternNode.x;
|
||||
@@ -1175,7 +1187,6 @@ NSString* IJSVGHash(NSString* key)
|
||||
toElement:(NSXMLElement*)element
|
||||
{
|
||||
IJSVGGradient* gradient = layer.gradient;
|
||||
NSString* gradKey = [self generateID];
|
||||
NSXMLElement* gradientElement = [[[NSXMLElement alloc] init] autorelease];
|
||||
|
||||
// work out linear gradient
|
||||
@@ -1183,7 +1194,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
|
||||
IJSVGLinearGradient* lGradient = (IJSVGLinearGradient*)gradient;
|
||||
gradientElement.name = @"linearGradient";
|
||||
NSDictionary* dict = @{ @"id" : gradKey,
|
||||
NSDictionary* dict = @{
|
||||
@"x1" : [lGradient.x1 stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@"y1" : [lGradient.y1 stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@"x2" : [lGradient.x2 stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@@ -1196,16 +1207,21 @@ NSString* IJSVGHash(NSString* key)
|
||||
// assume radial
|
||||
IJSVGRadialGradient* rGradient = (IJSVGRadialGradient*)gradient;
|
||||
gradientElement.name = @"radialGradient";
|
||||
NSDictionary* dict = @{ @"id" : gradKey,
|
||||
NSDictionary* dict = @{
|
||||
@"cx" : [rGradient.cx stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@"cy" : [rGradient.cy stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@"fx" : [rGradient.fx stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@"fy" : [rGradient.fy stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@"r" : [rGradient.radius stringValueWithFloatingPointOptions:_floatingPointOptions] };
|
||||
@"r" : [rGradient.r stringValueWithFloatingPointOptions:_floatingPointOptions],
|
||||
@"fr" : [rGradient.fr stringValueWithFloatingPointOptions:_floatingPointOptions] };
|
||||
|
||||
// give it the attributes
|
||||
IJSVGApplyAttributesToElement(dict, gradientElement);
|
||||
}
|
||||
|
||||
// apply the identifier
|
||||
NSString* gradKey = [self identifierForElement:gradientElement];
|
||||
IJSVGApplyAttributesToElement(@{@"id": gradKey}, gradientElement);
|
||||
|
||||
// apply the units
|
||||
if (layer.gradient.units == IJSVGUnitUserSpaceOnUse) {
|
||||
@@ -1215,7 +1231,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
|
||||
// add the stops
|
||||
NSGradient* grad = layer.gradient.gradient;
|
||||
IJSVGColorList* sheet = layer.gradient.colorList;
|
||||
IJSVGColorList* sheet = layer.gradient.computedColorList;
|
||||
NSInteger noStops = grad.numberOfColorStops;
|
||||
for (NSInteger i = 0; i < noStops; i++) {
|
||||
|
||||
@@ -1239,9 +1255,9 @@ NSString* IJSVGHash(NSString* key)
|
||||
|
||||
// add the color
|
||||
IJSVGColorStringOptions options = IJSVGColorStringOptionForceHEX | IJSVGColorStringOptionAllowShortHand;
|
||||
NSString* stopColor = [IJSVGColor colorStringFromColor:aColor
|
||||
options:options];
|
||||
|
||||
NSString* stopColor = [self colorStringForColor:aColor
|
||||
flag:IJSVGColorTypeFlagStop
|
||||
options:options];
|
||||
// dont bother adding default
|
||||
if ([stopColor isEqualToString:@"#000"] == NO) {
|
||||
atts[@"stop-color"] = stopColor;
|
||||
@@ -1300,7 +1316,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
imageElement.name = @"image";
|
||||
|
||||
NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
dict[@"id"] = [self generateID];
|
||||
dict[@"id"] = [self identifierForElement:imageElement];
|
||||
dict[@"width"] = IJSVGShortFloatStringWithOptions(layer.frame.size.width, _floatingPointOptions);
|
||||
dict[@"height"] = IJSVGShortFloatStringWithOptions(layer.frame.size.height, _floatingPointOptions);
|
||||
dict[@"xlink:href"] = base64String;
|
||||
@@ -1357,15 +1373,15 @@ NSString* IJSVGHash(NSString* key)
|
||||
CGPathRef path = layer.path;
|
||||
|
||||
// copy the path as we want to translate
|
||||
CGAffineTransform trans = CGAffineTransformMakeTranslation(layer.originalPathOrigin.x,
|
||||
layer.originalPathOrigin.y);
|
||||
CGAffineTransform trans = CGAffineTransformMakeTranslation(layer.frame.origin.x,
|
||||
layer.frame.origin.y);
|
||||
CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &trans);
|
||||
|
||||
NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
BOOL cleanupPaths = IJSVGExporterHasOption(_options, IJSVGExporterOptionCleanupPaths);
|
||||
BOOL convertArcs = IJSVGExporterHasOption(_options, IJSVGExporterOptionConvertArcs);
|
||||
BOOL convertShapesToPaths = IJSVGExporterHasOption(_options, IJSVGExporterOptionConvertShapesToPaths);
|
||||
|
||||
|
||||
// path
|
||||
switch (layer.primitiveType) {
|
||||
case kIJSVGPrimitivePathTypeRect: {
|
||||
@@ -1516,7 +1532,10 @@ NSString* IJSVGHash(NSString* key)
|
||||
}
|
||||
});
|
||||
if (layer.primitiveType == kIJSVGPrimitivePathTypePolygon) {
|
||||
[instructions removeLastObject];
|
||||
// remove last one if it was M
|
||||
if(instructions.lastObject.instruction == 'M') {
|
||||
[instructions removeLastObject];
|
||||
}
|
||||
IJSVGExporterPathInstruction* instruction = nil;
|
||||
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z'
|
||||
dataCount:0] autorelease];
|
||||
@@ -1525,8 +1544,10 @@ NSString* IJSVGHash(NSString* key)
|
||||
dict[@"d"] = [self pathFromInstructions:instructions];
|
||||
} else {
|
||||
NSMutableArray<NSString*>* points = [[[NSMutableArray alloc] init] autorelease];
|
||||
__block CGPathElementType type;
|
||||
IJSVGEnumerateCGPathElements(transformPath, ^(const CGPathElement* pathElement, CGPoint currentPoint) {
|
||||
switch (pathElement->type) {
|
||||
type = pathElement->type;
|
||||
switch (type) {
|
||||
case kCGPathElementMoveToPoint: {
|
||||
pathElement->points[0].x = pathElement->points[0].x;
|
||||
pathElement->points[0].y = pathElement->points[0].y;
|
||||
@@ -1544,7 +1565,8 @@ NSString* IJSVGHash(NSString* key)
|
||||
}
|
||||
});
|
||||
// polygon does not need the move to command
|
||||
if (layer.primitiveType == kIJSVGPrimitivePathTypePolygon) {
|
||||
if (layer.primitiveType == kIJSVGPrimitivePathTypePolygon &&
|
||||
type == kCGPathElementMoveToPoint) {
|
||||
[points removeLastObject];
|
||||
}
|
||||
dict[@"points"] = [points componentsJoinedByString:@" "];
|
||||
@@ -1679,8 +1701,9 @@ NSString* IJSVGHash(NSString* key)
|
||||
// fill color
|
||||
if (layer.fillColor != nil) {
|
||||
NSColor* fillColor = [NSColor colorWithCGColor:layer.fillColor];
|
||||
NSString* colorString = [IJSVGColor colorStringFromColor:fillColor
|
||||
options:[self colorOptions]];
|
||||
NSString* colorString = [self colorStringForColor:fillColor
|
||||
flag:IJSVGColorTypeFlagFill
|
||||
options:[self colorOptions]];
|
||||
|
||||
// could be none
|
||||
if (colorString != nil) {
|
||||
@@ -1731,8 +1754,9 @@ NSString* IJSVGHash(NSString* key)
|
||||
|
||||
} else if (strokeLayer.strokeColor != nil) {
|
||||
NSColor* strokeColor = [NSColor colorWithCGColor:strokeLayer.strokeColor];
|
||||
NSString* strokeColorString = [IJSVGColor colorStringFromColor:strokeColor
|
||||
options:[self colorOptions]];
|
||||
NSString* strokeColorString = [self colorStringForColor:strokeColor
|
||||
flag:IJSVGColorTypeFlagStroke
|
||||
options:[self colorOptions]];
|
||||
|
||||
// could be none
|
||||
if (strokeColorString != nil) {
|
||||
@@ -1855,7 +1879,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
mask.name = @"mask";
|
||||
|
||||
// create the key
|
||||
NSString* maskKey = [self generateID];
|
||||
NSString* maskKey = [self identifierForElement:mask];
|
||||
NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
dict[@"id"] = maskKey;
|
||||
|
||||
@@ -1881,6 +1905,16 @@ NSString* IJSVGHash(NSString* key)
|
||||
[[self defElement] addChild:mask];
|
||||
}
|
||||
|
||||
- (NSXMLDocument*)_dom
|
||||
{
|
||||
if(_dom == nil) {
|
||||
@autoreleasepool {
|
||||
[self _generateDOMDocument];
|
||||
}
|
||||
}
|
||||
return _dom;
|
||||
}
|
||||
|
||||
- (NSString*)SVGString
|
||||
{
|
||||
NSXMLNodeOptions options = NSXMLNodePrettyPrint;
|
||||
@@ -1888,7 +1922,7 @@ NSString* IJSVGHash(NSString* key)
|
||||
options = NSXMLNodeOptionsNone;
|
||||
}
|
||||
options |= NSXMLNodeCompactEmptyElement;
|
||||
NSString* output = [_dom XMLStringWithOptions:options];
|
||||
NSString* output = [[self _dom] XMLStringWithOptions:options];
|
||||
if (IJSVGExporterHasOption(_options, IJSVGExporterOptionRemoveXMLDeclaration) == YES) {
|
||||
return [output substringFromIndex:38];
|
||||
}
|
||||
@@ -2036,4 +2070,46 @@ void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlo
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Delegate calling methods
|
||||
|
||||
- (NSString*)identifierForElement:(NSXMLElement* _Nullable)element
|
||||
{
|
||||
NSString* identifier = nil;
|
||||
if(_respondsTo.identifierForElement == 1) {
|
||||
__weak id weakSelf = self;
|
||||
NSString* (^block)(void) = ^NSString*(void) {
|
||||
return [weakSelf generateID];
|
||||
};
|
||||
IJSVGNodeType type = [IJSVGNode typeForString:element.localName
|
||||
kind:element.kind];
|
||||
identifier = [_delegate svgExporter:self
|
||||
identifierForElement:element
|
||||
type:type
|
||||
defaultID:block];
|
||||
if(identifier != nil) {
|
||||
return identifier;
|
||||
}
|
||||
}
|
||||
return [self generateID];
|
||||
}
|
||||
|
||||
- (NSString*)colorStringForColor:(NSColor*)color
|
||||
flag:(IJSVGColorTypeFlags)flag
|
||||
options:(IJSVGColorStringOptions)options
|
||||
{
|
||||
NSString* colorString = nil;
|
||||
if(_respondsTo.stringForColor == 1) {
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
colorString = [_delegate svgExporter:self
|
||||
stringForColor:color
|
||||
flags:flag
|
||||
options:options];
|
||||
if(colorString != nil) {
|
||||
return colorString;
|
||||
}
|
||||
}
|
||||
return [IJSVGColor colorStringFromColor:color
|
||||
options:options];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -364,16 +364,16 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
|
||||
IJSVGExporterPathInstruction* nInstruction = nil;
|
||||
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
|
||||
dataCount:2] autorelease];
|
||||
nInstruction.data[0] = instruction.data[3];
|
||||
nInstruction.data[1] = instruction.data[4];
|
||||
nInstruction.data[0] = instruction.data[2];
|
||||
nInstruction.data[1] = instruction.data[3];
|
||||
[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];
|
||||
nInstruction.data[0] = instruction.data[2];
|
||||
nInstruction.data[1] = instruction.data[3];
|
||||
[nInstructions addObject:nInstruction];
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6,18 +6,16 @@
|
||||
// Copyright © 2016 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGGradient.h"
|
||||
#import "IJSVGLayer.h"
|
||||
#import "IJSVGPath.h"
|
||||
#import <IJSVG/IJSVGGradient.h>
|
||||
#import <IJSVG/IJSVGLayer.h>
|
||||
#import <IJSVG/IJSVGPath.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface IJSVGGradientLayer : IJSVGLayer {
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) CGRect viewBox;
|
||||
@property (nonatomic, retain) IJSVGGradient* gradient;
|
||||
@property (nonatomic, assign) CGAffineTransform absoluteTransform;
|
||||
@property (nonatomic, assign) CGRect objectRect;
|
||||
@property (nonatomic, assign) CGRect viewBox;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -7,42 +7,34 @@
|
||||
//
|
||||
|
||||
#import "IJSVGGradientLayer.h"
|
||||
#import <IJSVG/IJSVGRootLayer.h>
|
||||
|
||||
@implementation IJSVGGradientLayer
|
||||
|
||||
@synthesize viewBox;
|
||||
@synthesize gradient;
|
||||
@synthesize absoluteTransform;
|
||||
@synthesize objectRect;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([gradient release]), gradient = nil;
|
||||
(void)([_gradient release]), _gradient = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
- (BOOL)requiresBackingScaleHelp
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
self.requiresBackingScaleHelp = YES;
|
||||
self.shouldRasterize = YES;
|
||||
}
|
||||
return self;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setGradient:(IJSVGGradient*)newGradient
|
||||
{
|
||||
if (gradient != nil) {
|
||||
(void)([gradient release]), gradient = nil;
|
||||
if (_gradient != nil) {
|
||||
(void)([_gradient release]), _gradient = nil;
|
||||
}
|
||||
gradient = [newGradient retain];
|
||||
_gradient = [newGradient retain];
|
||||
|
||||
// lets check its alpha properties on the colors
|
||||
BOOL hasAlphaChannel = NO;
|
||||
NSInteger stops = gradient.gradient.numberOfColorStops;
|
||||
NSInteger stops = _gradient.gradient.numberOfColorStops;
|
||||
for (NSInteger i = 0; i < stops; i++) {
|
||||
NSColor* color = nil;
|
||||
[gradient.gradient getColor:&color
|
||||
[_gradient.gradient getColor:&color
|
||||
location:NULL
|
||||
atIndex:i];
|
||||
if (color.alphaComponent != 1.f) {
|
||||
@@ -79,6 +71,11 @@
|
||||
[super setBackingScaleFactor:backingScaleFactor];
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
|
||||
{
|
||||
return [super referencingLayer] ?: self.superlayer;
|
||||
}
|
||||
|
||||
- (void)drawInContext:(CGContextRef)ctx
|
||||
{
|
||||
[super drawInContext:ctx];
|
||||
@@ -89,14 +86,22 @@
|
||||
}
|
||||
|
||||
// draw the gradient
|
||||
CGAffineTransform trans = CGAffineTransformMakeTranslation(-CGRectGetMinX(objectRect),
|
||||
-CGRectGetMinY(objectRect));
|
||||
CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform, trans);
|
||||
CALayer<IJSVGDrawableLayer>* layer = (CALayer<IJSVGDrawableLayer>*)self.referencingLayer;
|
||||
CGRect objectRect = layer.boundingBox;
|
||||
CGRect objectFrame = layer.frame;
|
||||
CGAffineTransform affine = [IJSVGLayer absoluteTransformForLayer:layer];
|
||||
affine = CGAffineTransformTranslate(affine,
|
||||
-CGRectGetMinX(objectFrame),
|
||||
-CGRectGetMinY(objectFrame));
|
||||
CGContextSaveGState(ctx);
|
||||
|
||||
IJSVGRootLayer* rootNode = (IJSVGRootLayer*)[IJSVGLayer rootLayerForLayer:self];
|
||||
CGRect bounds = [rootNode.viewBox computeValue:CGSizeZero];
|
||||
|
||||
[self.gradient drawInContextRef:ctx
|
||||
objectRect:objectRect
|
||||
absoluteTransform:transform
|
||||
viewPort:self.viewBox];
|
||||
absoluteTransform:affine
|
||||
viewPort:bounds];
|
||||
CGContextRestoreGState(ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,16 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGLayer.h"
|
||||
#import "IJSVGShapeLayer.h"
|
||||
#import <IJSVG/IJSVGLayer.h>
|
||||
#import <IJSVG/IJSVGShapeLayer.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface IJSVGGroupLayer : IJSVGLayer
|
||||
@interface IJSVGGroupLayer : IJSVGLayer {
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IJSVGUnitRect* viewBox;
|
||||
@property (nonatomic, assign) IJSVGViewBoxAlignment viewBoxAlignment;
|
||||
@property (nonatomic, assign) IJSVGViewBoxMeetOrSlice viewBoxMeetOrSlice;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,7 +7,16 @@
|
||||
//
|
||||
|
||||
#import "IJSVGGroupLayer.h"
|
||||
#import "IJSVGViewBox.h"
|
||||
#import "IJSVGUnitRect.h"
|
||||
#import "IJSVGLayer.h"
|
||||
|
||||
@implementation IJSVGGroupLayer
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_viewBox release], _viewBox = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,14 +6,20 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGLayer.h"
|
||||
#import <IJSVG/IJSVGLayer.h>
|
||||
#import <IJSVG/IJSVGImage.h>
|
||||
#import <IJSVG/IJSVGTransformLayer.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface IJSVGImageLayer : IJSVGLayer {
|
||||
|
||||
@private
|
||||
IJSVGLayer* _imageLayer;
|
||||
}
|
||||
|
||||
- (id)initWithImage:(NSImage*)image;
|
||||
- (id)initWithCGImage:(CGImageRef)imageRef;
|
||||
@property (nonatomic, retain) IJSVGImage* image;
|
||||
|
||||
- (id)initWithImage:(IJSVGImage*)image;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,46 +10,44 @@
|
||||
|
||||
@implementation IJSVGImageLayer
|
||||
|
||||
- (id)initWithImage:(NSImage*)image
|
||||
- (void)dealloc
|
||||
{
|
||||
NSRect rect = (NSRect){
|
||||
.origin = NSZeroPoint,
|
||||
.size = image.size
|
||||
};
|
||||
CGImageRef ref = [image CGImageForProposedRect:&rect
|
||||
context:nil
|
||||
hints:nil];
|
||||
return [self initWithCGImage:ref];
|
||||
(void)[_image release], _image = nil;
|
||||
(void)[_imageLayer release], _imageLayer = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithCGImage:(CGImageRef)imageRef
|
||||
- (id)initWithImage:(IJSVGImage*)image
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
// set the contents
|
||||
self.contents = (id)imageRef;
|
||||
|
||||
// make sure we say we need help
|
||||
self.requiresBackingScaleHelp = YES;
|
||||
self.shouldRasterize = YES;
|
||||
|
||||
// set the frame, simple stuff
|
||||
self.frame = (CGRect){
|
||||
.origin = CGPointZero,
|
||||
.size = CGSizeMake(CGImageGetWidth(imageRef),
|
||||
CGImageGetHeight(imageRef))
|
||||
};
|
||||
if((self = [super init]) != nil) {
|
||||
_image = image.retain;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplay
|
||||
- (BOOL)requiresBackingScaleHelp
|
||||
{
|
||||
// swap the content around on call
|
||||
// because set needs display discards previous
|
||||
// content - yolo!
|
||||
id oldContent = self.contents;
|
||||
[super setNeedsDisplay];
|
||||
self.contents = oldContent;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)layoutSublayers
|
||||
{
|
||||
[super layoutSublayers];
|
||||
[self reloadContent];
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)reloadContent
|
||||
{
|
||||
if(_imageLayer == nil) {
|
||||
_imageLayer = [IJSVGLayer layer].retain;
|
||||
_imageLayer.contentsGravity = kCAGravityResize;
|
||||
_imageLayer.affineTransform = CGAffineTransformMakeScale(1.f, -1.f);
|
||||
_imageLayer.contents = (id)_image.CGImage;
|
||||
[self addSublayer:_imageLayer];
|
||||
}
|
||||
|
||||
_imageLayer.frame = self.bounds;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGRendering.h"
|
||||
#import "IJSVGTransaction.h"
|
||||
#import <IJSVG/IJSVGRendering.h>
|
||||
#import <IJSVG/IJSVGTransaction.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@class IJSVGShapeLayer;
|
||||
@@ -15,8 +15,52 @@
|
||||
@class IJSVGPatternLayer;
|
||||
@class IJSVGStrokeLayer;
|
||||
@class IJSVGGroupLayer;
|
||||
@class IJSVGLayer;
|
||||
|
||||
@interface IJSVGLayer : CALayer {
|
||||
typedef NS_ENUM(NSUInteger, IJSVGLayerFillType) {
|
||||
IJSVGLayerFillTypeColor,
|
||||
IJSVGLayerFillTypePattern,
|
||||
IJSVGLayerFillTypeGradient,
|
||||
IJSVGLayerFillTypeUnknown
|
||||
};
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, IJSVGLayerTraits) {
|
||||
IJSVGLayerTraitGroup
|
||||
};
|
||||
|
||||
@protocol IJSVGPathableLayer <NSObject>
|
||||
|
||||
@required
|
||||
@property (nonatomic, assign) CGPathRef path;
|
||||
|
||||
@end
|
||||
|
||||
@protocol IJSVGDrawableLayer <NSObject>
|
||||
|
||||
@required
|
||||
@property (nonatomic, assign) CGBlendMode blendingMode;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* maskLayer;
|
||||
@property (nonatomic, copy) CAShapeLayerFillRule clipRule;
|
||||
@property (nonatomic, copy) CAShapeLayerFillRule fillRule;
|
||||
@property (nonatomic, readonly) CGPoint absoluteOrigin;
|
||||
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
|
||||
@property (nonatomic, assign) CGFloat backingScaleFactor;
|
||||
@property (nonatomic, readonly) BOOL requiresBackingScaleHelp;
|
||||
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* rootLayer;
|
||||
@property (nonatomic, readonly) CGRect absoluteFrame;
|
||||
@property (nonatomic, assign) CGRect boundingBox;
|
||||
@property (nonatomic, readonly) CGRect strokeBoundingBox;
|
||||
@property (nonatomic, readonly) CGRect boundingBoxBounds;
|
||||
@property (nonatomic, assign) CGRect outerBoundingBox;
|
||||
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
|
||||
@property (nonatomic, readonly) NSArray<CALayer<IJSVGDrawableLayer>*>* debugLayers;
|
||||
|
||||
- (void)performRenderInContext:(CGContextRef)ctx;
|
||||
|
||||
@end
|
||||
|
||||
@interface IJSVGLayer : CALayer <IJSVGDrawableLayer> {
|
||||
|
||||
@private
|
||||
IJSVGLayer* _maskingLayer;
|
||||
@@ -27,19 +71,65 @@
|
||||
@property (nonatomic, assign) IJSVGStrokeLayer* strokeLayer;
|
||||
@property (nonatomic, assign) IJSVGGradientLayer* gradientStrokeLayer;
|
||||
@property (nonatomic, assign) IJSVGPatternLayer* patternStrokeLayer;
|
||||
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
|
||||
@property (nonatomic, readonly) BOOL requiresBackingScaleHelp;
|
||||
@property (nonatomic, assign) CGFloat backingScaleFactor;
|
||||
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
|
||||
@property (nonatomic, assign) CGBlendMode blendingMode;
|
||||
@property (nonatomic, assign) CGPoint absoluteOrigin;
|
||||
@property (nonatomic, assign) BOOL convertMasksToPaths;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
|
||||
@property (nonatomic, copy) CAShapeLayerFillRule clipRule;
|
||||
@property (nonatomic, copy) CAShapeLayerFillRule fillRule;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* maskLayer;
|
||||
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* rootLayer;
|
||||
@property (nonatomic, readonly) CGRect absoluteFrame;
|
||||
@property (nonatomic, assign) CGRect boundingBox;
|
||||
@property (nonatomic, readonly) CGRect boundingBoxBounds;
|
||||
@property (nonatomic, readonly) CGRect strokeBoundingBox;
|
||||
@property (nonatomic, assign) CGRect outerBoundingBox;
|
||||
@property (nonatomic, readonly) CGRect outerBoundingBoxBounds;
|
||||
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
|
||||
|
||||
+ (IJSVGLayerFillType)fillTypeForFill:(id)fill;
|
||||
|
||||
+ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer;
|
||||
+ (void)recursivelyWalkLayer:(CALayer*)layer
|
||||
withBlock:(void (^)(CALayer* layer, BOOL isMask))block;
|
||||
+ (void)recursivelyWalkLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
withBlock:(void (^)(CALayer<IJSVGDrawableLayer>* layer, BOOL* stop))block;
|
||||
|
||||
- (void)applySublayerMaskToContext:(CGContextRef)context
|
||||
forSublayer:(IJSVGLayer*)sublayer
|
||||
withOffset:(CGPoint)offset;
|
||||
|
||||
+ (CGImageRef)newMaskImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
scale:(CGFloat)scale;
|
||||
|
||||
+ (CGImageRef)newImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
colorSpace:(CGColorSpaceRef)colorSpace
|
||||
bitmapInfo:(uint32_t)bitmapInfo
|
||||
scale:(CGFloat)scale;
|
||||
|
||||
+ (void)renderLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
inContext:(CGContextRef)ctx;
|
||||
|
||||
+ (void)applyBlendingMode:(CGBlendMode)blendMode
|
||||
toContext:(CGContextRef)ctx
|
||||
drawingBlock:(dispatch_block_t)drawingBlock;
|
||||
|
||||
+ (void)clipContextWithClip:(CALayer<IJSVGDrawableLayer>*)clipLayer
|
||||
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
inContext:(CGContextRef)ctx
|
||||
drawingBlock:(dispatch_block_t)drawingBlock;
|
||||
|
||||
+ (void)clipContextWithMask:(CALayer<IJSVGDrawableLayer>*)maskLayer
|
||||
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
inContext:(CGContextRef)context
|
||||
drawingBlock:(dispatch_block_t)drawingBlock;
|
||||
|
||||
+ (CALayer<IJSVGDrawableLayer>*)rootLayerForLayer:(CALayer<IJSVGDrawableLayer>*)layer;
|
||||
+ (CGAffineTransform)absoluteTransformForLayer:(CALayer*)layer;
|
||||
+ (CGRect)absoluteFrameForLayer:(CALayer<IJSVGDrawableLayer>*)layer;
|
||||
+ (CGRect)calculateFrameForSublayers:(NSArray<CALayer<IJSVGDrawableLayer>*>*)layers;
|
||||
|
||||
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,25 +10,255 @@
|
||||
#import "IJSVGGroupLayer.h"
|
||||
#import "IJSVGLayer.h"
|
||||
#import "IJSVGShapeLayer.h"
|
||||
#import "IJSVGTransformLayer.h"
|
||||
#import "IJSVGRootLayer.h"
|
||||
|
||||
@implementation IJSVGLayer
|
||||
|
||||
@synthesize gradientFillLayer;
|
||||
@synthesize patternFillLayer;
|
||||
@synthesize gradientStrokeLayer;
|
||||
@synthesize patternStrokeLayer;
|
||||
@synthesize strokeLayer;
|
||||
@synthesize requiresBackingScaleHelp;
|
||||
@synthesize backingScaleFactor;
|
||||
@synthesize blendingMode;
|
||||
@synthesize convertMasksToPaths;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([_clipLayer release]), _clipLayer = nil;
|
||||
(void)([_maskLayer release]), _maskLayer = nil;
|
||||
(void)([_clipRule release]), _clipRule = nil;
|
||||
(void)([_fillRule release]), _fillRule = nil;
|
||||
(void)([_maskingLayer release]), _maskingLayer = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
_boundingBox = CGRectNull;
|
||||
_outerBoundingBox = CGRectNull;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CAShapeLayerFillRule)fillRule
|
||||
{
|
||||
return kCAFillRuleNonZero;
|
||||
}
|
||||
|
||||
- (CAShapeLayerFillRule)clipRule
|
||||
{
|
||||
if(_clipRule == nil) {
|
||||
return self.fillRule;
|
||||
}
|
||||
return _clipRule;
|
||||
}
|
||||
|
||||
+ (IJSVGLayerFillType)fillTypeForFill:(id)fill
|
||||
{
|
||||
if([fill isKindOfClass:IJSVGColorNode.class]) {
|
||||
return IJSVGLayerFillTypeColor;
|
||||
}
|
||||
if([fill isKindOfClass:IJSVGGradient.class]) {
|
||||
return IJSVGLayerFillTypeGradient;
|
||||
}
|
||||
if([fill isKindOfClass:IJSVGPattern.class]) {
|
||||
return IJSVGLayerFillTypePattern;
|
||||
}
|
||||
return IJSVGLayerFillTypeUnknown;
|
||||
}
|
||||
|
||||
+ (CGAffineTransform)absoluteTransformForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
{
|
||||
CGAffineTransform identity = CGAffineTransformIdentity;
|
||||
CALayer<IJSVGDrawableLayer>* parentLayer = layer;
|
||||
while((parentLayer = parentLayer.referencingLayer) != nil) {
|
||||
identity = [self absoluteTransformForLayer:parentLayer];
|
||||
|
||||
// only go up until we find a root layer, at that point, we know
|
||||
// we can stop looking
|
||||
if([parentLayer isKindOfClass:IJSVGRootLayer.class] == YES) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return CGAffineTransformConcat(identity, layer.affineTransform);
|
||||
}
|
||||
|
||||
+ (CALayer<IJSVGDrawableLayer>*)rootLayerForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
{
|
||||
CALayer<IJSVGDrawableLayer>* parentLayer = (CALayer<IJSVGDrawableLayer>*)layer.referencingLayer;
|
||||
while([parentLayer isKindOfClass:IJSVGRootLayer.class] == NO &&
|
||||
parentLayer.referencingLayer != nil) {
|
||||
parentLayer = (CALayer<IJSVGDrawableLayer>*)parentLayer.referencingLayer;
|
||||
}
|
||||
return parentLayer;
|
||||
}
|
||||
|
||||
+ (void)renderLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
inContext:(CGContextRef)ctx
|
||||
{
|
||||
dispatch_block_t drawingBlock = ^{
|
||||
[layer performRenderInContext:ctx];
|
||||
};
|
||||
[self applyBlendingMode:layer.blendingMode
|
||||
toContext:ctx
|
||||
drawingBlock:^{
|
||||
// we need to clip first
|
||||
if(layer.clipLayer == nil) {
|
||||
drawingBlock();
|
||||
return;
|
||||
}
|
||||
[self clipContextWithClip:layer.clipLayer
|
||||
toLayer:layer
|
||||
inContext:ctx
|
||||
drawingBlock:drawingBlock];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)applyBlendingMode:(CGBlendMode)blendMode
|
||||
toContext:(CGContextRef)ctx
|
||||
drawingBlock:(dispatch_block_t)drawingBlock
|
||||
{
|
||||
if (blendMode != kCGBlendModeNormal) {
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextSetBlendMode(ctx, blendMode);
|
||||
drawingBlock();
|
||||
CGContextRestoreGState(ctx);
|
||||
return;
|
||||
}
|
||||
drawingBlock();
|
||||
}
|
||||
|
||||
/// Shape layers are the only thing we can clip, as they contain a path, however
|
||||
/// the layer passed to us from a clip could have groups contained with in it that
|
||||
/// have transforms on them, so simply recursively iterate over them and concat
|
||||
/// their transforms down to the path and clip at the end with the path.
|
||||
+ (void)recursivelyClip:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
transform:(CGAffineTransform)transform
|
||||
inContext:(CGContextRef)ctx
|
||||
{
|
||||
if([layer isKindOfClass:IJSVGShapeLayer.class]) {
|
||||
[self clipContextWithShapeLayer:(IJSVGShapeLayer*)layer
|
||||
transform:transform
|
||||
inContext:ctx];
|
||||
return;
|
||||
}
|
||||
|
||||
for(CALayer<IJSVGDrawableLayer>* drawableLayer in layer.sublayers) {
|
||||
CGAffineTransform drawTransform = CGAffineTransformConcat(transform,
|
||||
drawableLayer.affineTransform);
|
||||
|
||||
// If its not a shape layer, just go down the tree until we find one
|
||||
if([drawableLayer isKindOfClass:IJSVGShapeLayer.class] == NO) {
|
||||
[self recursivelyClip:drawableLayer
|
||||
transform:drawTransform
|
||||
inContext:ctx];
|
||||
continue;
|
||||
}
|
||||
IJSVGShapeLayer* shapeLayer = (IJSVGShapeLayer*)drawableLayer;
|
||||
[self clipContextWithShapeLayer:shapeLayer
|
||||
transform:transform
|
||||
inContext:ctx];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)clipContextWithShapeLayer:(IJSVGShapeLayer*)shapeLayer
|
||||
transform:(CGAffineTransform)transform
|
||||
inContext:(CGContextRef)ctx
|
||||
{
|
||||
CGAffineTransform drawTransform = CGAffineTransformConcat(transform,
|
||||
shapeLayer.affineTransform);
|
||||
// Shape layers paths are reset back to 0,0 origin, so in order to be
|
||||
// correct path, we need to shift it back to where it belongs.
|
||||
drawTransform = CGAffineTransformTranslate(transform,
|
||||
shapeLayer.frame.origin.x,
|
||||
shapeLayer.frame.origin.y);
|
||||
CGPathRef path = CGPathCreateCopyByTransformingPath(shapeLayer.path,
|
||||
&drawTransform);
|
||||
CGContextAddPath(ctx, path);
|
||||
CGPathRelease(path);
|
||||
}
|
||||
|
||||
+ (void)clipContextWithClip:(CALayer<IJSVGDrawableLayer>*)clipLayer
|
||||
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
inContext:(CGContextRef)ctx
|
||||
drawingBlock:(dispatch_block_t)drawingBlock
|
||||
{
|
||||
CGContextSaveGState(ctx);
|
||||
[self recursivelyClip:clipLayer
|
||||
transform:CGAffineTransformIdentity
|
||||
inContext:ctx];
|
||||
if([layer.clipRule isEqualToString:kCAFillRuleEvenOdd]) {
|
||||
CGContextEOClip(ctx);
|
||||
} else {
|
||||
CGContextClip(ctx);
|
||||
}
|
||||
drawingBlock();
|
||||
CGContextRestoreGState(ctx);
|
||||
}
|
||||
|
||||
+ (void)clipContextWithMask:(CALayer<IJSVGDrawableLayer>*)maskLayer
|
||||
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
inContext:(CGContextRef)ctx
|
||||
drawingBlock:(dispatch_block_t)drawingBlock
|
||||
{
|
||||
CGContextSaveGState(ctx);
|
||||
CGRect bounds = layer.outerBoundingBox;
|
||||
CGFloat scale = layer.backingScaleFactor;
|
||||
CGImageRef maskImage = [self newMaskImageForLayer:maskLayer
|
||||
scale:scale];
|
||||
CGContextClipToMask(ctx, bounds, maskImage);
|
||||
drawingBlock();
|
||||
CGImageRelease(maskImage);
|
||||
CGContextRestoreGState(ctx);
|
||||
}
|
||||
|
||||
+ (CGImageRef)newMaskImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
scale:(CGFloat)scale
|
||||
{
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
|
||||
CGImageRef ref = [self newImageForLayer:layer
|
||||
colorSpace:colorSpace
|
||||
bitmapInfo:kCGImageAlphaNone
|
||||
scale:scale];
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
return ref;
|
||||
}
|
||||
|
||||
+ (CGImageRef)newImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
colorSpace:(CGColorSpaceRef)colorSpace
|
||||
bitmapInfo:(uint32_t)bitmapInfo
|
||||
scale:(CGFloat)scale
|
||||
{
|
||||
CGRect frame = layer.outerBoundingBox;
|
||||
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
|
||||
ceilf(frame.size.width * scale),
|
||||
ceilf(frame.size.height * scale),
|
||||
8, 0, colorSpace, bitmapInfo);
|
||||
|
||||
CGContextSaveGState(offscreenContext);
|
||||
CGContextScaleCTM(offscreenContext, scale, scale);
|
||||
CGContextTranslateCTM(offscreenContext, -frame.origin.x, -frame.origin.y);
|
||||
[layer renderInContext:offscreenContext];
|
||||
CGImageRef image = CGBitmapContextCreateImage(offscreenContext);
|
||||
CGContextRelease(offscreenContext);
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (CGRect)absoluteFrameForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
{
|
||||
return (CGRect) {
|
||||
.origin = [self absoluteOriginForLayer:layer],
|
||||
.size = layer.frame.size
|
||||
};
|
||||
}
|
||||
|
||||
+ (CGPoint)absoluteOriginForLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
{
|
||||
CGPoint point = CGPointZero;
|
||||
CALayer<IJSVGDrawableLayer>* pLayer = layer;
|
||||
while (pLayer != nil) {
|
||||
point.x += pLayer.frame.origin.x;
|
||||
point.y += pLayer.frame.origin.y;
|
||||
pLayer = pLayer.referencingLayer;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
+ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer
|
||||
{
|
||||
NSMutableArray* arr = [[[NSMutableArray alloc] init] autorelease];
|
||||
@@ -43,44 +273,90 @@
|
||||
return arr;
|
||||
}
|
||||
|
||||
+ (void)recursivelyWalkLayer:(CALayer*)layer
|
||||
withBlock:(void (^)(CALayer* layer, BOOL isMask))block
|
||||
+ (void)recursivelyWalkLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
withBlock:(void (^)(CALayer<IJSVGDrawableLayer>* layer, BOOL* stop))block
|
||||
{
|
||||
// call for layer and mask if there is one
|
||||
block(layer, NO);
|
||||
|
||||
// do the mask too!
|
||||
if (layer.mask != nil) {
|
||||
block(layer.mask, YES);
|
||||
BOOL stop = NO;
|
||||
block(layer, &stop);
|
||||
if(stop == YES) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sublayers!!
|
||||
for (CALayer* aLayer in layer.sublayers) {
|
||||
for (CALayer<IJSVGDrawableLayer>* aLayer in layer.sublayers) {
|
||||
[self recursivelyWalkLayer:aLayer
|
||||
withBlock:block];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
{
|
||||
[self logLayer:layer
|
||||
depth:0];
|
||||
}
|
||||
|
||||
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer
|
||||
depth:(NSUInteger)depth
|
||||
{
|
||||
NSLog(@"%@ %@ frame: %@ transform: %@",[@"" stringByPaddingToLength:depth
|
||||
withString:@"- - "
|
||||
startingAtIndex:0], layer,
|
||||
NSStringFromRect(layer.frame),
|
||||
[IJSVGTransform affineTransformToSVGTransformComponentString:layer.affineTransform]);
|
||||
for(CALayer<IJSVGDrawableLayer>* sublayer in layer.debugLayers) {
|
||||
[self logLayer:sublayer
|
||||
depth:depth+1];
|
||||
}
|
||||
}
|
||||
|
||||
+ (CGRect)calculateFrameForSublayers:(NSArray<CALayer<IJSVGDrawableLayer>*>*)layers
|
||||
{
|
||||
CGRect rect = CGRectNull;
|
||||
for(CALayer<IJSVGDrawableLayer>* layer in layers) {
|
||||
CGRect layerFrame = layer.outerBoundingBox;
|
||||
// if we are a transform layer, we can just apply its transform
|
||||
// to its sublayers and keep going down the tree
|
||||
if([layer isKindOfClass:IJSVGTransformLayer.class] == YES) {
|
||||
CGRect frame = [self calculateFrameForSublayers:layer.sublayers];
|
||||
frame = CGRectApplyAffineTransform(frame, layer.affineTransform);
|
||||
layerFrame = frame;
|
||||
}
|
||||
if(CGRectIsNull(rect)) {
|
||||
rect = layerFrame;
|
||||
continue;
|
||||
}
|
||||
rect = CGRectUnion(rect, layerFrame);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (void)setBackingScaleFactor:(CGFloat)newFactor
|
||||
{
|
||||
if (self.backingScaleFactor == newFactor) {
|
||||
if (_backingScaleFactor == newFactor) {
|
||||
return;
|
||||
}
|
||||
backingScaleFactor = newFactor;
|
||||
|
||||
_backingScaleFactor = newFactor;
|
||||
self.contentsScale = newFactor;
|
||||
self.rasterizationScale = newFactor;
|
||||
|
||||
// make sure its applied to any mask or clipPath
|
||||
_maskLayer.backingScaleFactor = newFactor;
|
||||
_clipLayer.backingScaleFactor = newFactor;
|
||||
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)_customRenderInContext:(CGContextRef)ctx
|
||||
- (void)performRenderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if (self.convertMasksToPaths == YES && _maskingLayer != nil) {
|
||||
CGContextSaveGState(ctx);
|
||||
[self applySublayerMaskToContext:ctx
|
||||
forSublayer:(IJSVGLayer*)self
|
||||
withOffset:CGPointZero];
|
||||
[super renderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
if(_maskLayer != nil) {
|
||||
[self.class clipContextWithMask:_maskLayer
|
||||
toLayer:self
|
||||
inContext:ctx
|
||||
drawingBlock:^{
|
||||
[super renderInContext:ctx];
|
||||
}];
|
||||
return;
|
||||
}
|
||||
[super renderInContext:ctx];
|
||||
@@ -88,10 +364,10 @@
|
||||
|
||||
- (void)setConvertMasksToPaths:(BOOL)flag
|
||||
{
|
||||
if (convertMasksToPaths == flag) {
|
||||
if (_convertMasksToPaths == flag) {
|
||||
return;
|
||||
}
|
||||
convertMasksToPaths = flag;
|
||||
_convertMasksToPaths = flag;
|
||||
if (flag == YES) {
|
||||
if (_maskingLayer != nil) {
|
||||
(void)([_maskingLayer release]), _maskingLayer = nil;
|
||||
@@ -144,6 +420,21 @@
|
||||
CGContextConcatCTM(context, sublayerTransform);
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer>*)rootLayer
|
||||
{
|
||||
return [self.class rootLayerForLayer:self];
|
||||
}
|
||||
|
||||
- (CGAffineTransform)absoluteTransform
|
||||
{
|
||||
return [IJSVGLayer absoluteTransformForLayer:self];
|
||||
}
|
||||
|
||||
- (BOOL)requiresBackingScaleHelp
|
||||
{
|
||||
return _maskLayer != nil || _clipLayer != nil;
|
||||
}
|
||||
|
||||
- (IJSVGShapeLayer*)maskingLayer
|
||||
{
|
||||
return (IJSVGShapeLayer*)_maskingLayer ?: nil;
|
||||
@@ -151,14 +442,8 @@
|
||||
|
||||
- (void)renderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if (self.blendingMode != kCGBlendModeNormal) {
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextSetBlendMode(ctx, self.blendingMode);
|
||||
[self _customRenderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
return;
|
||||
}
|
||||
[self _customRenderInContext:ctx];
|
||||
[IJSVGLayer renderLayer:self
|
||||
inContext:ctx];
|
||||
}
|
||||
|
||||
- (id<CAAction>)actionForKey:(NSString*)event
|
||||
@@ -166,4 +451,50 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGRect)absoluteFrame
|
||||
{
|
||||
return [self.class absoluteFrameForLayer:self];
|
||||
}
|
||||
|
||||
- (CGRect)boundingBox
|
||||
{
|
||||
return CGRectIsNull(_boundingBox) == NO ? _boundingBox : self.frame;
|
||||
}
|
||||
|
||||
- (CGRect)outerBoundingBox
|
||||
{
|
||||
return CGRectIsNull(_outerBoundingBox) == NO ? _outerBoundingBox : self.frame;
|
||||
}
|
||||
|
||||
- (CGRect)outerBoundingBoxBounds
|
||||
{
|
||||
return (CGRect) {
|
||||
.origin = CGPointZero,
|
||||
.size = self.outerBoundingBox.size
|
||||
};
|
||||
}
|
||||
|
||||
- (CGRect)boundingBoxBounds
|
||||
{
|
||||
return (CGRect) {
|
||||
.origin = CGPointZero,
|
||||
.size = self.boundingBox.size
|
||||
};
|
||||
}
|
||||
|
||||
- (CGRect)strokeBoundingBox
|
||||
{
|
||||
return self.boundingBox;
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
|
||||
{
|
||||
return _referencingLayer ?: self.superlayer;
|
||||
}
|
||||
|
||||
-(NSArray<CALayer<IJSVGDrawableLayer>*>*)debugLayers
|
||||
{
|
||||
return self.sublayers;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
@interface IJSVGPatternLayer : IJSVGLayer
|
||||
|
||||
@property (nonatomic, retain) IJSVGLayer* pattern;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* pattern;
|
||||
@property (nonatomic, retain) IJSVGPattern* patternNode;
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,36 +6,61 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGPatternLayer.h"
|
||||
#import <IJSVG/IJSVGPatternLayer.h>
|
||||
#import <IJSVG/IJSVGTransform.h>
|
||||
#import <IJSVG/IJSVGUnitRect.h>
|
||||
#import <IJSVG/IJSVGViewBox.h>
|
||||
|
||||
@interface IJSVGPatternLayer ()
|
||||
|
||||
@property (nonatomic, assign, readonly) CGSize cellSize;
|
||||
@property (nonatomic, assign) CGRect viewBox;
|
||||
|
||||
@end
|
||||
|
||||
@implementation IJSVGPatternLayer
|
||||
|
||||
@synthesize pattern;
|
||||
@synthesize patternNode;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([pattern release]), pattern = nil;
|
||||
(void)([patternNode release]), patternNode = nil;
|
||||
(void)([_pattern release]), _pattern = nil;
|
||||
(void)([_patternNode release]), _patternNode = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
- (BOOL)requiresBackingScaleHelp
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
self.requiresBackingScaleHelp = YES;
|
||||
self.shouldRasterize = YES;
|
||||
}
|
||||
return self;
|
||||
return YES;
|
||||
}
|
||||
|
||||
void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
|
||||
{
|
||||
// reassign the layer
|
||||
IJSVGPatternLayer* layer = (IJSVGPatternLayer*)info;
|
||||
[layer.pattern renderInContext:ctx];
|
||||
CGSize size = layer.cellSize;
|
||||
CGContextSaveGState(ctx);
|
||||
CGRect rect = CGRectMake(0.f, 0.f, size.width, size.height);
|
||||
CGContextClipToRect(ctx, rect);
|
||||
|
||||
IJSVGViewBoxAlignment alignment = layer.patternNode.viewBoxAlignment;
|
||||
IJSVGViewBoxMeetOrSlice meetOrSlice = layer.patternNode.viewBoxMeetOrSlice;
|
||||
CGRect viewBox = layer.viewBox;
|
||||
|
||||
[IJSVGViewBox drawViewBox:viewBox
|
||||
inRect:rect
|
||||
alignment:alignment
|
||||
meetOrSlice:meetOrSlice
|
||||
inContext:ctx
|
||||
drawingBlock:^(CGSize size) {
|
||||
[layer.pattern renderInContext:ctx];
|
||||
}];
|
||||
CGContextSaveGState(ctx);
|
||||
};
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer>*)referencingLayer
|
||||
{
|
||||
return [super referencingLayer] ?: self.superlayer;
|
||||
}
|
||||
|
||||
- (void)drawInContext:(CGContextRef)ctx
|
||||
{
|
||||
// holder for callback
|
||||
@@ -45,13 +70,54 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
|
||||
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
|
||||
CGContextSetFillColorSpace(ctx, patternSpace);
|
||||
CGColorSpaceRelease(patternSpace);
|
||||
|
||||
CGRect rect = self.referencingLayer.boundingBoxBounds;
|
||||
|
||||
IJSVGUnitLength* wLength = _patternNode.width;
|
||||
IJSVGUnitLength* hLength = _patternNode.height;
|
||||
|
||||
if(self.patternNode.units == IJSVGUnitObjectBoundingBox ||
|
||||
self.patternNode.contentUnits == IJSVGUnitObjectBoundingBox) {
|
||||
wLength = wLength.lengthByMatchingPercentage;
|
||||
hLength = hLength.lengthByMatchingPercentage;
|
||||
}
|
||||
|
||||
CGFloat width = [wLength computeValue:rect.size.width];
|
||||
CGFloat height = [hLength computeValue:rect.size.height];
|
||||
_cellSize = CGSizeMake(width, height);
|
||||
|
||||
CALayer<IJSVGDrawableLayer>* layer = (CALayer<IJSVGDrawableLayer>*)self.referencingLayer;
|
||||
|
||||
// transform us back into the correct space
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
if (self.patternNode.units == IJSVGUnitUserSpaceOnUse) {
|
||||
CGRect frame = layer.boundingBox;
|
||||
transform = [IJSVGLayer absoluteTransformForLayer:layer];
|
||||
transform = CGAffineTransformTranslate(transform,
|
||||
-CGRectGetMinX(frame),
|
||||
-CGRectGetMinY(frame));
|
||||
}
|
||||
|
||||
transform = CGAffineTransformConcat(transform, IJSVGConcatTransforms(self.patternNode.transforms));
|
||||
// transform the X and Y shift
|
||||
transform = CGAffineTransformTranslate(transform,
|
||||
[_patternNode.x computeValue:rect.size.width],
|
||||
[_patternNode.y computeValue:rect.size.height]);
|
||||
|
||||
// who knew that patterns have viewBoxes? Not me, but here is an implementation
|
||||
// of it anyway
|
||||
if(_patternNode.viewBox != nil && _patternNode.viewBox.isZeroRect == NO) {
|
||||
if(_patternNode.units == IJSVGUnitObjectBoundingBox) {
|
||||
IJSVGUnitRect* viewBox = nil;
|
||||
viewBox = [[_patternNode.viewBox copyByConvertingToUnitsLengthType:IJSVGUnitLengthTypePercentage] autorelease];
|
||||
_viewBox = [viewBox computeValue:rect.size];
|
||||
}
|
||||
}
|
||||
|
||||
// create the pattern
|
||||
CGRect rect = self.bounds;
|
||||
CGPatternRef ref = CGPatternCreate((void*)self, self.bounds,
|
||||
CGAffineTransformIdentity,
|
||||
roundf(rect.size.width * self.patternNode.width.value),
|
||||
roundf(rect.size.height * self.patternNode.height.value),
|
||||
CGRect selfBounds = self.boundingBoxBounds;
|
||||
CGPatternRef ref = CGPatternCreate((void*)self, selfBounds,
|
||||
transform, width, height,
|
||||
kCGPatternTilingConstantSpacing,
|
||||
true, &callbacks);
|
||||
|
||||
@@ -61,7 +127,12 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
|
||||
CGPatternRelease(ref);
|
||||
|
||||
// fill it
|
||||
CGContextFillRect(ctx, rect);
|
||||
CGContextFillRect(ctx, selfBounds);
|
||||
}
|
||||
|
||||
- (NSArray<CALayer<IJSVGDrawableLayer>*>*)debugLayers
|
||||
{
|
||||
return @[self.pattern];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
//
|
||||
// IJSVGRadialGradient.m
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 03/09/2014.
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGRadialGradient.h"
|
||||
|
||||
@implementation IJSVGRadialGradient
|
||||
|
||||
@synthesize cx;
|
||||
@synthesize cy;
|
||||
@synthesize fx;
|
||||
@synthesize fy;
|
||||
@synthesize radius;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([cx release]), cx = nil;
|
||||
(void)([cy release]), cy = nil;
|
||||
(void)([fx release]), fx = nil;
|
||||
(void)([fy release]), fy = nil;
|
||||
(void)([radius release]), radius = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
IJSVGRadialGradient* grad = [super copyWithZone:zone];
|
||||
grad.fx = self.fx;
|
||||
grad.fy = self.fy;
|
||||
grad.cx = self.cx;
|
||||
grad.cy = self.cy;
|
||||
grad.radius = self.radius;
|
||||
return grad;
|
||||
}
|
||||
|
||||
+ (NSGradient*)parseGradient:(NSXMLElement*)element
|
||||
gradient:(IJSVGRadialGradient*)gradient
|
||||
{
|
||||
// cx defaults to 50% if not specified
|
||||
NSDictionary* kv = @{ @"cx" : @"cx",
|
||||
@"cy" : @"cy",
|
||||
@"r" : @"radius" };
|
||||
|
||||
for (NSString* key in kv.allKeys) {
|
||||
NSString* str = [element attributeForName:key].stringValue;
|
||||
IJSVGUnitLength* unit = nil;
|
||||
if (str != nil) {
|
||||
unit = [IJSVGUnitLength unitWithString:str
|
||||
fromUnitType:gradient.units];
|
||||
} else {
|
||||
// spec says to say 50% for missing property default
|
||||
unit = [IJSVGUnitLength unitWithPercentageFloat:.5f];
|
||||
}
|
||||
[gradient setValue:unit
|
||||
forKey:kv[key]];
|
||||
}
|
||||
|
||||
// fx and fy are the same unless specified otherwise
|
||||
gradient.fx = gradient.cx;
|
||||
gradient.fy = gradient.cy;
|
||||
|
||||
// needs fixing
|
||||
NSString* fx = [element attributeForName:@"fx"].stringValue;
|
||||
if (fx != nil) {
|
||||
gradient.fx = [IJSVGUnitLength unitWithString:fx
|
||||
fromUnitType:gradient.units];
|
||||
}
|
||||
|
||||
NSString* fy = [element attributeForName:@"fy"].stringValue;
|
||||
if (fx != nil) {
|
||||
gradient.fy = [IJSVGUnitLength unitWithString:fy
|
||||
fromUnitType:gradient.units];
|
||||
}
|
||||
|
||||
if (gradient.gradient != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray* colors = nil;
|
||||
CGFloat* colorStops = [self.class computeColorStopsFromString:element colors:&colors];
|
||||
NSGradient* ret = [[[NSGradient alloc] initWithColors:colors
|
||||
atLocations:colorStops
|
||||
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
|
||||
free(colorStops);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox
|
||||
{
|
||||
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
|
||||
CGFloat radius = 0.f;
|
||||
CGPoint startPoint = CGPointZero;
|
||||
CGPoint gradientStartPoint = CGPointZero;
|
||||
CGPoint gradientEndPoint = CGPointZero;
|
||||
|
||||
// transforms
|
||||
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
|
||||
|
||||
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
|
||||
|
||||
// make sure we apply the absolute position to
|
||||
// transform us back into the correct space
|
||||
if (inUserSpace == YES) {
|
||||
CGContextConcatCTM(ctx, absoluteTransform);
|
||||
}
|
||||
|
||||
// compute size based on percentages
|
||||
CGFloat x = [self.cx computeValue:CGRectGetWidth(boundingBox)];
|
||||
CGFloat y = [self.cy computeValue:CGRectGetHeight(boundingBox)];
|
||||
startPoint = CGPointMake(x, y);
|
||||
CGFloat val = MIN(CGRectGetWidth(boundingBox),
|
||||
CGRectGetHeight(boundingBox));
|
||||
radius = [self.radius computeValue:val];
|
||||
|
||||
CGFloat ex = [self.fx computeValue:CGRectGetWidth(boundingBox)];
|
||||
CGFloat ey = [self.fy computeValue:CGRectGetHeight(boundingBox)];
|
||||
|
||||
gradientEndPoint = CGPointMake(ex, ey);
|
||||
gradientStartPoint = startPoint;
|
||||
|
||||
// transform if width or height is not equal - this can only
|
||||
// be done if we are using objectBoundingBox
|
||||
if (inUserSpace == NO && CGRectGetWidth(boundingBox) != CGRectGetHeight(boundingBox)) {
|
||||
CGAffineTransform tr = CGAffineTransformMakeTranslation(gradientStartPoint.x,
|
||||
gradientStartPoint.y);
|
||||
if (CGRectGetWidth(boundingBox) > CGRectGetHeight(boundingBox)) {
|
||||
tr = CGAffineTransformScale(tr, CGRectGetWidth(boundingBox) / CGRectGetHeight(boundingBox), 1);
|
||||
} else {
|
||||
tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(boundingBox) / CGRectGetWidth(boundingBox));
|
||||
}
|
||||
tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y);
|
||||
selfTransform = CGAffineTransformConcat(tr, selfTransform);
|
||||
}
|
||||
|
||||
// transform the context
|
||||
CGContextConcatCTM(ctx, selfTransform);
|
||||
|
||||
// draw the gradient
|
||||
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
||||
CGContextDrawRadialGradient(ctx, self.CGGradient,
|
||||
gradientEndPoint, 0,
|
||||
gradientStartPoint,
|
||||
radius, options);
|
||||
|
||||
#ifdef IJSVG_DEBUG_GRADIENTS
|
||||
[self _debugStart:gradientStartPoint
|
||||
end:gradientEndPoint
|
||||
context:ctx];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// IJSVGRootLayer.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 15/04/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <IJSVG/IJSVG.h>
|
||||
|
||||
@interface IJSVGRootLayer : IJSVGGroupLayer {
|
||||
|
||||
@private
|
||||
BOOL _disableBackingScalePropagation;
|
||||
|
||||
}
|
||||
|
||||
- (void)renderInContext:(CGContextRef)ctx
|
||||
viewPort:(CGRect)viewPort
|
||||
backingScale:(CGFloat)backingScale
|
||||
quality:(IJSVGRenderQuality)quality;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// IJSVGRootLayer.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 15/04/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGRootLayer.h"
|
||||
|
||||
@implementation IJSVGRootLayer
|
||||
|
||||
- (void)performRenderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if(self.viewBox != nil) {
|
||||
CGRect viewBox = [self.viewBox computeValue:CGSizeZero];
|
||||
__block IJSVGRootLayer* weakSelf = self;
|
||||
IJSVGViewBoxDrawingBlock drawingBlock = ^(CGSize size) {
|
||||
// we have to make sure we set the backing scale factor once
|
||||
// we know how scale this will be drawn at
|
||||
weakSelf.backingScaleFactor *= MAX(size.width, size.height);
|
||||
[super performRenderInContext:ctx];
|
||||
};
|
||||
[IJSVGViewBox drawViewBox:viewBox
|
||||
inRect:self.boundingBoxBounds
|
||||
alignment:self.viewBoxAlignment
|
||||
meetOrSlice:self.viewBoxMeetOrSlice
|
||||
inContext:ctx
|
||||
drawingBlock:drawingBlock];
|
||||
return;
|
||||
}
|
||||
[super performRenderInContext:ctx];
|
||||
}
|
||||
|
||||
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
|
||||
{
|
||||
[super setBackingScaleFactor:backingScaleFactor];
|
||||
if(_disableBackingScalePropagation == YES) {
|
||||
return;
|
||||
}
|
||||
[self propagateBackingScalePropertiesToSublayers];
|
||||
}
|
||||
|
||||
- (void)propagateBackingScalePropertiesToSublayers
|
||||
{
|
||||
__block IJSVGRootLayer* weakSelf = self;
|
||||
for(CALayer<IJSVGDrawableLayer>* layer in self.sublayers) {
|
||||
[IJSVGLayer recursivelyWalkLayer:layer
|
||||
withBlock:^(CALayer<IJSVGDrawableLayer>* propLayer, BOOL *stop) {
|
||||
propLayer.renderQuality = weakSelf.renderQuality;
|
||||
propLayer.backingScaleFactor = weakSelf.backingScaleFactor;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)renderInContext:(CGContextRef)ctx
|
||||
viewPort:(CGRect)viewPort
|
||||
backingScale:(CGFloat)backingScale
|
||||
quality:(IJSVGRenderQuality)quality
|
||||
{
|
||||
CGRect frame = viewPort;
|
||||
self.frame = frame;
|
||||
_disableBackingScalePropagation = YES;
|
||||
self.backingScaleFactor = backingScale;
|
||||
self.renderQuality = quality;
|
||||
_disableBackingScalePropagation = NO;
|
||||
[self propagateBackingScalePropertiesToSublayers];
|
||||
[self renderInContext:ctx];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -6,11 +6,11 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGLayer.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import <IJSVG/IJSVGLayer.h>
|
||||
#import <IJSVG/IJSVGUtils.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface IJSVGShapeLayer : CAShapeLayer {
|
||||
@interface IJSVGShapeLayer : CAShapeLayer <IJSVGDrawableLayer, IJSVGPathableLayer> {
|
||||
|
||||
@private
|
||||
IJSVGLayer* _maskingLayer;
|
||||
@@ -21,14 +21,25 @@
|
||||
@property (nonatomic, assign) IJSVGStrokeLayer* strokeLayer;
|
||||
@property (nonatomic, assign) IJSVGGradientLayer* gradientStrokeLayer;
|
||||
@property (nonatomic, assign) IJSVGPatternLayer* patternStrokeLayer;
|
||||
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
|
||||
@property (nonatomic, assign) CGFloat backingScaleFactor;
|
||||
@property (nonatomic, readonly) BOOL requiresBackingScaleHelp;
|
||||
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
|
||||
@property (nonatomic, assign) CGBlendMode blendingMode;
|
||||
@property (nonatomic, assign) CGPoint absoluteOrigin;
|
||||
@property (nonatomic, assign) CGPoint originalPathOrigin;
|
||||
@property (nonatomic, assign) BOOL convertMasksToPaths;
|
||||
@property (nonatomic, assign) IJSVGPrimitivePathType primitiveType;
|
||||
@property (nonatomic, readonly) CGRect computedFrame;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* maskLayer;
|
||||
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* rootLayer;
|
||||
@property (nonatomic, readonly) CGRect absoluteFrame;
|
||||
@property (nonatomic, assign) CGRect boundingBox;
|
||||
@property (nonatomic, assign) CGRect outerBoundingBox;
|
||||
@property (nonatomic, readonly) CGRect boundingBoxBounds;
|
||||
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
|
||||
@property (nonatomic, assign) CGRect strokeBoundingBox;
|
||||
@property (nonatomic, copy) CAShapeLayerFillRule clipRule;
|
||||
|
||||
- (void)applySublayerMaskToContext:(CGContextRef)context
|
||||
forSublayer:(IJSVGLayer*)sublayer
|
||||
|
||||
@@ -11,45 +11,74 @@
|
||||
|
||||
@implementation IJSVGShapeLayer
|
||||
|
||||
@synthesize gradientFillLayer;
|
||||
@synthesize patternFillLayer;
|
||||
@synthesize gradientStrokeLayer;
|
||||
@synthesize patternStrokeLayer;
|
||||
@synthesize strokeLayer;
|
||||
@synthesize requiresBackingScaleHelp;
|
||||
@synthesize backingScaleFactor;
|
||||
@synthesize blendingMode;
|
||||
@synthesize convertMasksToPaths;
|
||||
@synthesize originalPathOrigin;
|
||||
@synthesize renderQuality;
|
||||
@synthesize primitiveType;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([_clipLayer release]), _clipLayer = nil;
|
||||
(void)([_maskLayer release]), _maskLayer = nil;
|
||||
(void)([_maskingLayer release]), _maskingLayer = nil;
|
||||
(void)([_clipRule release]), _clipRule = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer> *)rootLayer
|
||||
{
|
||||
return [IJSVGLayer rootLayerForLayer:self];
|
||||
}
|
||||
|
||||
- (CGRect)absoluteFrame
|
||||
{
|
||||
return [IJSVGLayer absoluteFrameForLayer:self];
|
||||
}
|
||||
|
||||
- (CGAffineTransform)absoluteTransform
|
||||
{
|
||||
return [IJSVGLayer absoluteTransformForLayer:self];
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
|
||||
{
|
||||
return _referencingLayer ?: self.superlayer;
|
||||
}
|
||||
|
||||
- (CGRect)boundingBoxBounds
|
||||
{
|
||||
return (CGRect) {
|
||||
.origin = CGPointZero,
|
||||
.size = self.boundingBox.size
|
||||
};
|
||||
}
|
||||
|
||||
- (BOOL)requiresBackingScaleHelp
|
||||
{
|
||||
return _maskLayer != nil || _clipLayer != nil;
|
||||
}
|
||||
|
||||
- (void)setBackingScaleFactor:(CGFloat)newFactor
|
||||
{
|
||||
if (self.backingScaleFactor == newFactor) {
|
||||
if (_backingScaleFactor == newFactor) {
|
||||
return;
|
||||
}
|
||||
backingScaleFactor = newFactor;
|
||||
|
||||
_backingScaleFactor = newFactor;
|
||||
self.contentsScale = newFactor;
|
||||
self.rasterizationScale = newFactor;
|
||||
|
||||
// make sure its applied to any mask or clipPath
|
||||
_maskLayer.backingScaleFactor = newFactor;
|
||||
_clipLayer.backingScaleFactor = newFactor;
|
||||
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)_customRenderInContext:(CGContextRef)ctx
|
||||
- (void)performRenderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if (self.convertMasksToPaths == YES && _maskingLayer != nil) {
|
||||
CGContextSaveGState(ctx);
|
||||
[self applySublayerMaskToContext:ctx
|
||||
forSublayer:(IJSVGLayer*)self
|
||||
withOffset:CGPointZero];
|
||||
[super renderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
if(_maskLayer != nil) {
|
||||
[IJSVGLayer clipContextWithMask:_maskLayer
|
||||
toLayer:self
|
||||
inContext:ctx
|
||||
drawingBlock:^{
|
||||
[super renderInContext:ctx];
|
||||
}];
|
||||
return;
|
||||
}
|
||||
[super renderInContext:ctx];
|
||||
@@ -57,10 +86,10 @@
|
||||
|
||||
- (void)setConvertMasksToPaths:(BOOL)flag
|
||||
{
|
||||
if (convertMasksToPaths == flag) {
|
||||
if (_convertMasksToPaths == flag) {
|
||||
return;
|
||||
}
|
||||
convertMasksToPaths = flag;
|
||||
_convertMasksToPaths = flag;
|
||||
if (flag == YES) {
|
||||
if (_maskingLayer != nil) {
|
||||
(void)([_maskingLayer release]), _maskingLayer = nil;
|
||||
@@ -120,26 +149,8 @@
|
||||
|
||||
- (void)renderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if (self.blendingMode != kCGBlendModeNormal) {
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextSetBlendMode(ctx, self.blendingMode);
|
||||
[self _customRenderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
return;
|
||||
}
|
||||
[self _customRenderInContext:ctx];
|
||||
}
|
||||
|
||||
- (CGPoint)absoluteOrigin
|
||||
{
|
||||
CGPoint point = CGPointZero;
|
||||
CALayer* pLayer = self;
|
||||
while (pLayer != nil) {
|
||||
point.x += pLayer.frame.origin.x;
|
||||
point.y += pLayer.frame.origin.y;
|
||||
pLayer = pLayer.superlayer;
|
||||
}
|
||||
return point;
|
||||
[IJSVGLayer renderLayer:(IJSVGLayer*)self
|
||||
inContext:ctx];
|
||||
}
|
||||
|
||||
- (id<CAAction>)actionForKey:(NSString*)event
|
||||
@@ -147,4 +158,9 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(NSArray<CALayer<IJSVGDrawableLayer>*>*)debugLayers
|
||||
{
|
||||
return self.sublayers;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,4 +10,11 @@
|
||||
|
||||
@implementation IJSVGStrokeLayer
|
||||
|
||||
- (CGRect)outerBoundingBox
|
||||
{
|
||||
return CGRectMake(-self.lineWidth / 2.f, -self.lineWidth / 2.f,
|
||||
self.boundingBox.size.width + self.lineWidth,
|
||||
self.boundingBox.size.height + self.lineWidth);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// IJSVGTransformLayer.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 31/03/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <IJSVG/IJSVGLayer.h>
|
||||
|
||||
@interface IJSVGTransformLayer : CATransformLayer <IJSVGDrawableLayer>
|
||||
|
||||
@property (nonatomic, assign) CGBlendMode blendingMode;
|
||||
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
|
||||
@property (nonatomic, readonly) CGPoint absoluteOrigin;
|
||||
@property (nonatomic, readonly) CGRect computedFrame;
|
||||
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* referencedLayer;
|
||||
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// IJSVGTransformLayer.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 31/03/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGTransformLayer.h"
|
||||
|
||||
@implementation IJSVGTransformLayer
|
||||
|
||||
@synthesize backingScaleFactor;
|
||||
@synthesize renderQuality;
|
||||
@synthesize requiresBackingScaleHelp;
|
||||
@synthesize maskLayer = _maskLayer;
|
||||
@synthesize fillRule = _fillRule;
|
||||
@synthesize clipRule = _clipRule;
|
||||
@synthesize absoluteFrame;
|
||||
@synthesize boundingBox;
|
||||
@synthesize boundingBoxBounds;
|
||||
@synthesize strokeBoundingBox;
|
||||
@synthesize outerBoundingBox;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_maskLayer release], _maskLayer = nil;
|
||||
(void)[_fillRule release], _fillRule = nil;
|
||||
(void)[_clipRule release], _clipRule = nil;
|
||||
(void)[_clipLayer release], _clipLayer = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer> *)referencedLayer
|
||||
{
|
||||
return self.sublayers.firstObject;
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer> *)referencingLayer {
|
||||
return _referencingLayer ?: self.superlayer;
|
||||
}
|
||||
|
||||
- (CALayer<IJSVGDrawableLayer>*)rootLayer
|
||||
{
|
||||
return [IJSVGLayer rootLayerForLayer:self];
|
||||
}
|
||||
|
||||
- (BOOL)requiresBackingScaleHelp
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)renderInContext:(CGContextRef)ctx
|
||||
{
|
||||
[IJSVGLayer renderLayer:self
|
||||
inContext:ctx];
|
||||
}
|
||||
|
||||
- (void)performRenderInContext:(CGContextRef)ctx
|
||||
{
|
||||
[super renderInContext:ctx];
|
||||
}
|
||||
|
||||
- (NSArray<CALayer<IJSVGDrawableLayer>*>*)debugLayers
|
||||
{
|
||||
return self.sublayers;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// IJSVGColorNode.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 29/03/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
|
||||
@interface IJSVGColorNode : IJSVGNode {
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSColor* color;
|
||||
|
||||
+ (IJSVGNode*)colorNodeWithColor:(NSColor*)color;
|
||||
|
||||
- (id)initWithColor:(NSColor*)color;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// IJSVGColorNode.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 29/03/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColorNode.h"
|
||||
|
||||
@implementation IJSVGColorNode
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_color release], _color = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (IJSVGNode*)colorNodeWithColor:(NSColor *)color
|
||||
{
|
||||
return [[[self alloc] initWithColor:color] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithColor:(NSColor*)color {
|
||||
if((self = [super init]) != nil) {
|
||||
[self addTraits:IJSVGNodeTraitPaintable];
|
||||
self.color = color;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)applyPropertiesFromNode:(IJSVGNode*)node
|
||||
{
|
||||
if([node isKindOfClass:self.class]) {
|
||||
self.color = ((IJSVGColorNode*)node).color;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGNode.h"
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGDef : NSObject {
|
||||
|
||||
@@ -7,14 +7,11 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGNode.h"
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
|
||||
@interface IJSVGForeignObject : IJSVGNode {
|
||||
|
||||
NSString * requiredExtension;
|
||||
|
||||
}
|
||||
|
||||
@property ( nonatomic, copy ) NSString * requiredExtension;
|
||||
@property (nonatomic, copy) NSString* requiredExtension;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
|
||||
@implementation IJSVGForeignObject
|
||||
|
||||
@synthesize requiredExtension;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([requiredExtension release]), requiredExtension = nil;
|
||||
(void)([_requiredExtension release]), _requiredExtension = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColorList.h"
|
||||
#import "IJSVGDef.h"
|
||||
#import "IJSVGTransform.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <IJSVG/IJSVGColorList.h>
|
||||
#import <IJSVG/IJSVGDef.h>
|
||||
#import <IJSVG/IJSVGTransform.h>
|
||||
#import <IJSVG/IJSVGGroup.h>
|
||||
|
||||
@interface IJSVGGradient : IJSVGNode
|
||||
@interface IJSVGGradient : IJSVGGroup
|
||||
|
||||
@property (nonatomic, retain) NSGradient* gradient;
|
||||
@property (nonatomic, assign) CGGradientRef CGGradient;
|
||||
@@ -21,8 +22,9 @@
|
||||
@property (nonatomic, retain) IJSVGUnitLength* y2;
|
||||
@property (nonatomic, retain) IJSVGColorList* colorList;
|
||||
|
||||
+ (CGFloat*)computeColorStopsFromString:(NSXMLElement*)element
|
||||
colors:(NSArray**)someColors;
|
||||
+ (CGFloat*)computeColorStops:(IJSVGGradient*)gradient
|
||||
colors:(NSArray**)someColors;
|
||||
|
||||
- (CGGradientRef)CGGradient;
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
objectRect:(NSRect)objectRect
|
||||
@@ -33,6 +35,7 @@
|
||||
end:(CGPoint)endPoint
|
||||
context:(CGContextRef)ctx;
|
||||
|
||||
- (IJSVGColorList*)colorList;
|
||||
- (IJSVGColorList*)computedColorList;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,23 +7,22 @@
|
||||
//
|
||||
|
||||
#import "IJSVGGradient.h"
|
||||
#import "IJSVGParser.h"
|
||||
|
||||
@implementation IJSVGGradient
|
||||
|
||||
@synthesize gradient, CGGradient;
|
||||
@synthesize x1, x2, y1, y2;
|
||||
@synthesize colorList = _colorList;
|
||||
@synthesize colorList = _privateColorList;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([x1 release]), x1 = nil;
|
||||
(void)([x2 release]), x2 = nil;
|
||||
(void)([y1 release]), y1 = nil;
|
||||
(void)([y2 release]), y2 = nil;
|
||||
(void)([gradient release]), gradient = nil;
|
||||
(void)([_colorList release]), _colorList = nil;
|
||||
if (CGGradient != nil) {
|
||||
CGGradientRelease(CGGradient);
|
||||
(void)([_x1 release]), _x1 = nil;
|
||||
(void)([_x2 release]), _x2 = nil;
|
||||
(void)([_y1 release]), _y1 = nil;
|
||||
(void)([_y2 release]), _y2 = nil;
|
||||
(void)([_gradient release]), _gradient = nil;
|
||||
(void)([_privateColorList release]), _privateColorList = nil;
|
||||
if (_CGGradient != nil) {
|
||||
CGGradientRelease(_CGGradient);
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -37,84 +36,41 @@
|
||||
|
||||
- (void)setColorList:(IJSVGColorList*)list
|
||||
{
|
||||
(void)([_colorList release]), _colorList = nil;
|
||||
_colorList = list.retain;
|
||||
if (CGGradient != nil) {
|
||||
CGGradientRelease(CGGradient);
|
||||
(void)([_privateColorList release]), _privateColorList = nil;
|
||||
_privateColorList = list.retain;
|
||||
if (_CGGradient != nil) {
|
||||
CGGradientRelease(_CGGradient);
|
||||
_CGGradient = nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (CGFloat*)computeColorStopsFromString:(NSXMLElement*)element
|
||||
colors:(NSArray**)someColors
|
||||
+ (CGFloat *)computeColorStops:(IJSVGGradient*)gradient
|
||||
colors:(NSArray**)someColors
|
||||
{
|
||||
// find each stop element
|
||||
NSArray* stops = [element children];
|
||||
NSArray<IJSVGNode*>* stops = gradient.children;
|
||||
NSMutableArray* colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease];
|
||||
CGFloat* stopsParams = (CGFloat*)malloc(stops.count * sizeof(CGFloat));
|
||||
|
||||
NSInteger i = 0;
|
||||
for (NSXMLElement* stop in stops) {
|
||||
// find the offset
|
||||
CGFloat offset = [stop attributeForName:@"offset"].stringValue.floatValue;
|
||||
if (offset > 1.f) {
|
||||
offset /= 100.f;
|
||||
}
|
||||
|
||||
for(IJSVGNode* stopNode in stops) {
|
||||
NSColor* color = ((IJSVGColorNode*)(stopNode.fill)).color;
|
||||
CGFloat opacity = stopNode.fillOpacity.value;
|
||||
CGFloat offset = stopNode.offset.value;
|
||||
stopsParams[i++] = offset;
|
||||
|
||||
// find the stop opacity
|
||||
CGFloat stopOpacity = 1.f;
|
||||
NSXMLNode* stopOpacityAttribute = [stop attributeForName:@"stop-opacity"];
|
||||
if (stopOpacityAttribute != nil) {
|
||||
stopOpacity = stopOpacityAttribute.stringValue.floatValue;
|
||||
}
|
||||
|
||||
// find the stop color
|
||||
NSString* scs = [stop attributeForName:@"stop-color"].stringValue;
|
||||
NSColor* stopColor = [IJSVGColor colorFromString:scs];
|
||||
if (stopColor != nil && stopOpacity != 1.f) {
|
||||
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
|
||||
to:stopOpacity];
|
||||
}
|
||||
|
||||
// compute any style that there was...
|
||||
NSXMLNode* styleAttribute = [stop attributeForName:@"style"];
|
||||
if (styleAttribute != nil) {
|
||||
|
||||
IJSVGStyle* style = [IJSVGStyle parseStyleString:styleAttribute.stringValue];
|
||||
NSColor* color = [IJSVGColor colorFromString:[style property:@"stop-color"]];
|
||||
|
||||
// we have a color!
|
||||
if (color != nil) {
|
||||
// is there a stop opacity?
|
||||
NSString* numberString = nil;
|
||||
if ((numberString = [style property:@"stop-opacity"]) != nil) {
|
||||
color = [IJSVGColor changeAlphaOnColor:color
|
||||
to:numberString.floatValue];
|
||||
} else {
|
||||
color = [IJSVGColor changeAlphaOnColor:color
|
||||
to:stopOpacity];
|
||||
}
|
||||
stopColor = color;
|
||||
if(color == nil) {
|
||||
color = [IJSVGColor colorFromHEXInteger:0x000000];
|
||||
if(opacity != 1.f) {
|
||||
color = [IJSVGColor changeAlphaOnColor:color
|
||||
to:opacity];
|
||||
}
|
||||
}
|
||||
|
||||
// default is black
|
||||
if (stopColor == nil) {
|
||||
stopColor = [IJSVGColor colorFromString:@"black"];
|
||||
if (stopOpacity != 1.f) {
|
||||
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
|
||||
to:stopOpacity];
|
||||
}
|
||||
}
|
||||
|
||||
// add the stop color
|
||||
[(NSMutableArray*)colors addObject:stopColor];
|
||||
[colors addObject:color];
|
||||
}
|
||||
*someColors = colors;
|
||||
*someColors = (NSArray*)colors;
|
||||
return stopsParams;
|
||||
}
|
||||
|
||||
- (IJSVGColorList*)computedColorList
|
||||
- (IJSVGColorList*)colorList
|
||||
{
|
||||
IJSVGColorList* sheet = [[[IJSVGColorList alloc] init] autorelease];
|
||||
NSInteger num = self.gradient.numberOfColorStops;
|
||||
@@ -123,21 +79,28 @@
|
||||
[self.gradient getColor:&color
|
||||
location:nil
|
||||
atIndex:i];
|
||||
[sheet addColor:color];
|
||||
IJSVGColorType* type = [IJSVGColorType typeWithColor:color
|
||||
flags:IJSVGColorTypeFlagStop];
|
||||
[sheet addColor:type];
|
||||
}
|
||||
return sheet;
|
||||
}
|
||||
|
||||
- (IJSVGColorList*)computedColorList
|
||||
{
|
||||
return _privateColorList;
|
||||
}
|
||||
|
||||
- (CGGradientRef)CGGradient
|
||||
{
|
||||
// store it in the cache
|
||||
if (CGGradient != nil) {
|
||||
return CGGradient;
|
||||
if (_CGGradient != nil) {
|
||||
return _CGGradient;
|
||||
}
|
||||
|
||||
// actually create the gradient
|
||||
NSInteger num = self.gradient.numberOfColorStops;
|
||||
CGFloat* locations = malloc(sizeof(CGFloat) * num);
|
||||
CGFloat* locations = (CGFloat*)malloc(sizeof(CGFloat) * num);
|
||||
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num,
|
||||
&kCFTypeArrayCallBacks);
|
||||
for (NSInteger i = 0; i < num; i++) {
|
||||
@@ -145,16 +108,16 @@
|
||||
[self.gradient getColor:&color
|
||||
location:&locations[i]
|
||||
atIndex:i];
|
||||
if (_colorList != nil) {
|
||||
color = [_colorList proposedColorForColor:color];
|
||||
if (_privateColorList != nil) {
|
||||
color = [_privateColorList proposedColorForColor:color];
|
||||
}
|
||||
CFArrayAppendValue(colors, color.CGColor);
|
||||
}
|
||||
CGGradientRef result = CGGradientCreateWithColors(self.gradient.colorSpace.CGColorSpace,
|
||||
CGGradientRef result = CGGradientCreateWithColors(_gradient.colorSpace.CGColorSpace,
|
||||
colors, locations);
|
||||
CFRelease(colors);
|
||||
free(locations);
|
||||
return CGGradient = result;
|
||||
return _CGGradient = result;
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
|
||||
@@ -6,17 +6,18 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGPath.h"
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
#import <IJSVG/IJSVGPath.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGGroup : IJSVGNode {
|
||||
|
||||
NSMutableArray* children;
|
||||
@private
|
||||
NSMutableArray<IJSVGNode*>* _children;
|
||||
}
|
||||
|
||||
- (void)addChild:(id)child;
|
||||
- (NSArray*)children;
|
||||
- (void)purgeChildren;
|
||||
@property (nonatomic, readonly) NSArray<IJSVGNode*>* children;
|
||||
|
||||
- (void)addChild:(IJSVGNode*)child;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,21 +12,24 @@
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([children release]), children = nil;
|
||||
(void)([_children release]), _children = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
children = [[NSMutableArray alloc] init];
|
||||
_children = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)prepareFromCopy
|
||||
{
|
||||
children = [[NSMutableArray alloc] init];
|
||||
if(_children != nil) {
|
||||
(void)[_children release], _children = nil;
|
||||
}
|
||||
_children = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
@@ -34,7 +37,7 @@
|
||||
IJSVGGroup* node = [super copyWithZone:zone];
|
||||
[node prepareFromCopy];
|
||||
|
||||
for (IJSVGNode* childNode in self.children) {
|
||||
for (IJSVGNode* childNode in _children) {
|
||||
childNode = [[childNode copy] autorelease];
|
||||
childNode.parentNode = node;
|
||||
[node addChild:childNode];
|
||||
@@ -42,25 +45,41 @@
|
||||
return node;
|
||||
}
|
||||
|
||||
- (void)purgeChildren
|
||||
- (void)addChild:(IJSVGNode*)child
|
||||
{
|
||||
[children removeAllObjects];
|
||||
if(child == nil || (child.parentNode == self && [_children containsObject:child])) {
|
||||
return;
|
||||
}
|
||||
child.parentNode = self;
|
||||
[_children addObject:child];
|
||||
}
|
||||
|
||||
- (void)addChild:(id)child
|
||||
- (void)removeChild:(IJSVGNode*)child
|
||||
{
|
||||
if (child != nil)
|
||||
[children addObject:child];
|
||||
if(child.parentNode == self) {
|
||||
[child detach];
|
||||
}
|
||||
[_children removeObject:child];
|
||||
}
|
||||
|
||||
- (NSArray*)children
|
||||
- (CGRect)bounds
|
||||
{
|
||||
return children;
|
||||
CGRect rect = CGRectZero;
|
||||
for(IJSVGNode* node in self.children) {
|
||||
rect = CGRectUnion(rect, node.bounds);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (NSArray<IJSVGNode*>*)children
|
||||
{
|
||||
return _children;
|
||||
}
|
||||
|
||||
- (NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ - %@", [super description], self.children];
|
||||
return [NSString stringWithFormat:@"%@ - %@",
|
||||
[super description], self.children];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,21 +6,22 @@
|
||||
// Copyright © 2016 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGNode.h"
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGPath;
|
||||
|
||||
@interface IJSVGImage : IJSVGNode {
|
||||
|
||||
NSImage* image;
|
||||
CGImageRef CGImage;
|
||||
IJSVGPath* imagePath;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) CGSize intrinsicSize;
|
||||
@property (nonatomic, readonly) CGRect intrinsicBounds;
|
||||
@property (nonatomic, readonly) CGAffineTransform intrinsicTransform;
|
||||
@property (nonatomic, retain) NSImage* image;
|
||||
|
||||
- (CGImageRef)CGImage;
|
||||
- (void)drawInContextRef:(CGContextRef)context
|
||||
path:(IJSVGPath*)path;
|
||||
- (void)loadFromBase64EncodedString:(NSString*)encodedString;
|
||||
- (void)loadFromString:(NSString*)encodedString;
|
||||
- (void)loadFromURL:(NSURL*)aURL;
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,12 +15,11 @@
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)(CGImageRelease(CGImage)), CGImage = nil;
|
||||
(void)([imagePath release]), imagePath = nil;
|
||||
(void)([image release]), image = nil;
|
||||
(void)([_image release]), _image = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)loadFromBase64EncodedString:(NSString*)encodedString
|
||||
- (void)loadFromString:(NSString*)encodedString
|
||||
{
|
||||
if ([encodedString hasPrefix:@"data:"]) {
|
||||
encodedString = [encodedString stringByReplacingOccurrencesOfString:@"\\s+"
|
||||
@@ -28,8 +27,15 @@
|
||||
options:NSRegularExpressionSearch
|
||||
range:NSMakeRange(0, encodedString.length)];
|
||||
}
|
||||
NSURL* URL = [NSURL URLWithString:encodedString];
|
||||
NSData* data = [NSData dataWithContentsOfURL:URL];
|
||||
NSURL* url = [NSURL URLWithString:encodedString];
|
||||
if(url != nil) {
|
||||
[self loadFromURL:url];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadFromURL:(NSURL*)aURL
|
||||
{
|
||||
NSData* data = [NSData dataWithContentsOfURL:aURL];
|
||||
|
||||
// no data, just ignore...invalid probably
|
||||
if (data == nil) {
|
||||
@@ -41,35 +47,24 @@
|
||||
[self setImage:anImage];
|
||||
}
|
||||
|
||||
- (IJSVGPath*)path
|
||||
{
|
||||
if (imagePath == nil) {
|
||||
// lazy load the path as it might not be needed
|
||||
imagePath = [[IJSVGPath alloc] init];
|
||||
[imagePath.path appendBezierPathWithRect:NSMakeRect(0.f, 0.f, self.width.value, self.height.value)];
|
||||
[imagePath close];
|
||||
}
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
- (void)setImage:(NSImage*)anImage
|
||||
{
|
||||
if (image != nil) {
|
||||
(void)([image release]), image = nil;
|
||||
if (_image != nil) {
|
||||
(void)([_image release]), _image = nil;
|
||||
}
|
||||
image = [anImage retain];
|
||||
_image = [anImage retain];
|
||||
_intrinsicSize = (CGSize)_image.size;
|
||||
|
||||
if (CGImage != nil) {
|
||||
CGImageRelease(CGImage);
|
||||
CGImage = nil;
|
||||
}
|
||||
|
||||
NSRect rect = NSMakeRect(0.f, 0.f, self.width.value, self.height.value);
|
||||
CGImage = [image CGImageForProposedRect:&rect
|
||||
context:nil
|
||||
hints:nil];
|
||||
NSRect rect = NSMakeRect(0.f, 0.f, _intrinsicSize.width, _intrinsicSize.height);
|
||||
CGImage = [_image CGImageForProposedRect:&rect
|
||||
context:nil
|
||||
hints:nil];
|
||||
|
||||
// be sure to retain (some reason this is required in Xcode 8 beta 5?)
|
||||
CGImageRetain(CGImage);
|
||||
}
|
||||
|
||||
@@ -78,32 +73,26 @@
|
||||
return CGImage;
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)context
|
||||
path:(IJSVGPath*)path
|
||||
- (CGRect)intrinsicBounds
|
||||
{
|
||||
// run the transforms
|
||||
// draw the image
|
||||
if (self.width.value == 0.f || self.height.value == 0.f) {
|
||||
return;
|
||||
}
|
||||
CGRect rect = CGRectZero;
|
||||
rect.size.width = _intrinsicSize.width;
|
||||
rect.size.height = _intrinsicSize.height;
|
||||
return rect;
|
||||
}
|
||||
|
||||
// make sure path is set
|
||||
if (path == nil) {
|
||||
path = [self path];
|
||||
}
|
||||
- (CGAffineTransform)intrinsicTransform
|
||||
{
|
||||
CGFloat widthRatio = self.width.value / _intrinsicSize.width;
|
||||
CGFloat heightRatio = self.height.value / _intrinsicSize.height;
|
||||
return CGAffineTransformMakeScale(widthRatio, heightRatio);
|
||||
}
|
||||
|
||||
CGRect rect = path.path.bounds;
|
||||
CGRect bounds = CGRectMake(0.f, 0.f, rect.size.width, rect.size.height);
|
||||
|
||||
// save the state of the context
|
||||
CGContextSaveGState(context);
|
||||
{
|
||||
// flip the coordinates
|
||||
CGContextTranslateCTM(context, rect.origin.x, (rect.origin.y) + rect.size.height);
|
||||
CGContextScaleCTM(context, 1.f, -1.f);
|
||||
CGContextDrawImage(context, bounds, CGImage);
|
||||
}
|
||||
CGContextRestoreGState(context);
|
||||
- (CGRect)bounds
|
||||
{
|
||||
return CGRectMake(0.f, 0.f,
|
||||
self.width.value,
|
||||
self.height.value);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGGradient.h"
|
||||
#import <IJSVG/IJSVGGradient.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGLinearGradient : IJSVGGradient
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "IJSVGLinearGradient.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import "IJSVGParser.h"
|
||||
|
||||
@implementation IJSVGLinearGradient
|
||||
|
||||
@@ -15,20 +16,20 @@
|
||||
gradient:(IJSVGLinearGradient*)aGradient
|
||||
{
|
||||
// just ask unit for the value
|
||||
NSString* x1 = ([element attributeForName:@"x1"].stringValue ?: @"0");
|
||||
NSString* x2 = ([element attributeForName:@"x2"].stringValue ?: @"100%");
|
||||
NSString* y1 = ([element attributeForName:@"y1"].stringValue ?: @"0");
|
||||
NSString* y2 = ([element attributeForName:@"y2"].stringValue ?: @"0");
|
||||
NSString* x1 = ([element attributeForName:IJSVGAttributeX1].stringValue ?: @"0");
|
||||
NSString* x2 = ([element attributeForName:IJSVGAttributeX2].stringValue ?: @"100%");
|
||||
NSString* y1 = ([element attributeForName:IJSVGAttributeY1].stringValue ?: @"0");
|
||||
NSString* y2 = ([element attributeForName:IJSVGAttributeY2].stringValue ?: @"0");
|
||||
aGradient.x1 = [IJSVGGradientUnitLength unitWithString:x1 fromUnitType:aGradient.units];
|
||||
aGradient.x2 = [IJSVGGradientUnitLength unitWithString:x2 fromUnitType:aGradient.units];
|
||||
aGradient.y1 = [IJSVGGradientUnitLength unitWithString:y1 fromUnitType:aGradient.units];
|
||||
aGradient.y2 = [IJSVGGradientUnitLength unitWithString:y2 fromUnitType:aGradient.units];
|
||||
|
||||
|
||||
// compute the color stops and colours
|
||||
NSArray* colors = nil;
|
||||
CGFloat* stopsParams = [self.class computeColorStopsFromString:element
|
||||
colors:&colors];
|
||||
|
||||
CGFloat* stopsParams = [self.class computeColorStops:aGradient
|
||||
colors:&colors];
|
||||
|
||||
// create the gradient with the colours
|
||||
NSGradient* grad = [[NSGradient alloc] initWithColors:colors
|
||||
atLocations:stopsParams
|
||||
@@ -50,7 +51,7 @@
|
||||
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
|
||||
|
||||
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
|
||||
|
||||
|
||||
// make sure we apply the absolute position to
|
||||
// transform us back into the correct space
|
||||
if (inUserSpace == YES) {
|
||||
@@ -64,7 +65,7 @@
|
||||
|
||||
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
|
||||
[self.y2 computeValue:height]);
|
||||
|
||||
|
||||
// transform the context
|
||||
CGContextConcatCTM(ctx, selfTransform);
|
||||
|
||||
|
||||
@@ -6,18 +6,29 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGStyle.h"
|
||||
#import "IJSVGUnitLength.h"
|
||||
#import <IJSVG/IJSVGStyle.h>
|
||||
#import <IJSVG/IJSVGUnitLength.h>
|
||||
#import <IJSVG/IJSVGViewBox.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGNode;
|
||||
@class IJSVG;
|
||||
@class IJSVGGroup;
|
||||
@class IJSVGDef;
|
||||
@class IJSVGGradient;
|
||||
@class IJSVGGroup;
|
||||
@class IJSVGPattern;
|
||||
@class IJSVGTransform;
|
||||
@class IJSVGRootNode;
|
||||
@class IJSVGUnitRect;
|
||||
|
||||
typedef void (^IJSVGNodeWalkHandler)(IJSVGNode* node, BOOL* allowChildNodes, BOOL* stop);
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, IJSVGNodeTraits) {
|
||||
IJSVGNodeTraitNone = 0,
|
||||
IJSVGNodeTraitStroked = 1 << 0,
|
||||
IJSVGNodeTraitPaintable = 1 << 1
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, IJSVGNodeType) {
|
||||
IJSVGNodeTypeGroup,
|
||||
@@ -45,7 +56,9 @@ typedef NS_ENUM(NSInteger, IJSVGNodeType) {
|
||||
IJSVGNodeTypeSwitch,
|
||||
IJSVGNodeTypeTitle,
|
||||
IJSVGNodeTypeDesc,
|
||||
IJSVGNodeTypeStop,
|
||||
IJSVGNodeTypeNotFound,
|
||||
IJSVGNodeTypeUnknown,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, IJSVGWindingRule) {
|
||||
@@ -95,10 +108,22 @@ typedef NS_ENUM(NSInteger, IJSVGBlendMode) {
|
||||
IJSVGBlendModeLuminosity = kCGBlendModeLuminosity
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, IJSVGOverflowVisibility) {
|
||||
IJSVGOverflowVisibilityHidden,
|
||||
IJSVGOverflowVisibilityVisible
|
||||
};
|
||||
|
||||
static CGFloat IJSVGInheritedFloatValue = -99.9999991;
|
||||
|
||||
@interface IJSVGNode : NSObject <NSCopying>
|
||||
|
||||
void IJSVGAssertPaintableObject(id object);
|
||||
|
||||
@property (nonatomic, assign) IJSVGNodeTraits traits;
|
||||
@property (nonatomic, assign, readonly) CGRect bounds;
|
||||
@property (nonatomic, retain) IJSVGUnitRect* viewBox;
|
||||
@property (nonatomic, assign) IJSVGViewBoxAlignment viewBoxAlignment;
|
||||
@property (nonatomic, assign) IJSVGViewBoxMeetOrSlice viewBoxMeetOrSlice;
|
||||
@property (nonatomic, copy) NSString* title;
|
||||
@property (nonatomic, copy) NSString* desc;
|
||||
@property (nonatomic, assign) IJSVGNodeType type;
|
||||
@@ -107,7 +132,6 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991;
|
||||
@property (nonatomic, retain) NSArray* classNameList;
|
||||
@property (nonatomic, copy) NSString* unicode;
|
||||
@property (nonatomic, assign) BOOL shouldRender;
|
||||
@property (nonatomic, assign) BOOL usesDefaultFillColor;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* x;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* y;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* width;
|
||||
@@ -116,36 +140,43 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* fillOpacity;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* strokeOpacity;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* strokeWidth;
|
||||
@property (nonatomic, retain) NSColor* fillColor;
|
||||
@property (nonatomic, retain) NSColor* strokeColor;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* offset;
|
||||
@property (nonatomic, retain) IJSVGNode* fill;
|
||||
@property (nonatomic, retain) IJSVGNode* stroke;
|
||||
@property (nonatomic, copy) NSString* identifier;
|
||||
@property (nonatomic, assign) IJSVGNode* parentNode;
|
||||
@property (nonatomic, assign) IJSVGNode* intermediateParentNode;
|
||||
@property (nonatomic, retain) IJSVGGroup* clipPath;
|
||||
@property (nonatomic, retain) IJSVGGroup* mask;
|
||||
@property (nonatomic, assign) IJSVGWindingRule windingRule;
|
||||
@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle;
|
||||
@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle;
|
||||
@property (nonatomic, retain) NSArray<IJSVGTransform*>* transforms;
|
||||
@property (nonatomic, retain) IJSVGDef* def;
|
||||
@property (nonatomic, retain) IJSVGGradient* fillGradient;
|
||||
@property (nonatomic, retain) IJSVGPattern* fillPattern;
|
||||
@property (nonatomic, retain) IJSVGGradient* strokeGradient;
|
||||
@property (nonatomic, retain) IJSVGPattern* strokePattern;
|
||||
@property (nonatomic, assign) CGFloat* strokeDashArray;
|
||||
@property (nonatomic, assign) NSInteger strokeDashArrayCount;
|
||||
@property (nonatomic, readonly) NSArray<NSNumber*>* lineDashPattern;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* strokeDashOffset;
|
||||
@property (nonatomic, retain) IJSVG* svg;
|
||||
@property (nonatomic, assign) IJSVGUnitType contentUnits;
|
||||
@property (nonatomic, assign) IJSVGUnitType units;
|
||||
@property (nonatomic, assign) IJSVGBlendMode blendMode;
|
||||
@property (nonatomic, assign) IJSVGOverflowVisibility overflowVisibility;
|
||||
|
||||
+ (void)walkNodeTree:(IJSVGNode*)node
|
||||
handler:(IJSVGNodeWalkHandler)handler;
|
||||
|
||||
+ (IJSVGNodeType)typeForString:(NSString*)string
|
||||
kind:(NSXMLNodeKind)kind;
|
||||
|
||||
- (void)applyPropertiesFromNode:(IJSVGNode*)node;
|
||||
- (id)initWithDef:(BOOL)flag;
|
||||
- (void)addDef:(IJSVGNode*)aDef;
|
||||
- (IJSVGDef*)defForID:(NSString*)anID;
|
||||
|
||||
- (IJSVGUnitType)contentUnitsWithReferencingNodeBounds:(CGRect*)bounds;
|
||||
- (IJSVGUnitType)contentUnitsWithReferencingNode:(IJSVGNode**)referencingNode;
|
||||
|
||||
- (instancetype)detach;
|
||||
|
||||
- (void)addTraits:(IJSVGNodeTraits)traits;
|
||||
- (void)removeTraits:(IJSVGNodeTraits)traits;
|
||||
- (BOOL)matchesTraits:(IJSVGNodeTraits)traits;
|
||||
- (void)computeTraits;
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,225 +6,187 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGDef.h"
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import <IJSVG/IJSVGDef.h>
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
#import <IJSVG/IJSVGGroup.h>
|
||||
#import <IJSVG/IJSVGUtils.h>
|
||||
|
||||
@implementation IJSVGNode
|
||||
|
||||
@synthesize title;
|
||||
@synthesize desc;
|
||||
@synthesize shouldRender;
|
||||
@synthesize type;
|
||||
@synthesize name;
|
||||
@synthesize classNameList;
|
||||
@synthesize className;
|
||||
@synthesize unicode;
|
||||
@synthesize x;
|
||||
@synthesize y;
|
||||
@synthesize width;
|
||||
@synthesize height;
|
||||
@synthesize fillColor;
|
||||
@synthesize fillOpacity;
|
||||
@synthesize strokeColor;
|
||||
@synthesize strokeOpacity;
|
||||
@synthesize strokeWidth;
|
||||
@synthesize opacity;
|
||||
@synthesize identifier;
|
||||
@synthesize parentNode;
|
||||
@synthesize intermediateParentNode;
|
||||
@synthesize transforms;
|
||||
@synthesize windingRule;
|
||||
@synthesize def;
|
||||
@synthesize fillGradient;
|
||||
@synthesize fillPattern;
|
||||
@synthesize strokeGradient;
|
||||
@synthesize strokePattern;
|
||||
@synthesize clipPath;
|
||||
@synthesize lineCapStyle;
|
||||
@synthesize lineJoinStyle;
|
||||
@synthesize strokeDashArrayCount;
|
||||
@synthesize strokeDashArray;
|
||||
@synthesize strokeDashOffset;
|
||||
@synthesize usesDefaultFillColor;
|
||||
@synthesize svg;
|
||||
@synthesize mask;
|
||||
@synthesize units;
|
||||
@synthesize contentUnits;
|
||||
@synthesize blendMode;
|
||||
@synthesize fill = _fill;
|
||||
@synthesize stroke = _stroke;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(strokeDashArray);
|
||||
(void)([x release]), x = nil;
|
||||
(void)([y release]), y = nil;
|
||||
(void)([width release]), width = nil;
|
||||
(void)([height release]), height = nil;
|
||||
(void)([opacity release]), opacity = nil;
|
||||
(void)([fillOpacity release]), fillOpacity = nil;
|
||||
(void)([strokeOpacity release]), strokeOpacity = nil;
|
||||
(void)([strokeWidth release]), strokeWidth = nil;
|
||||
(void)([strokeDashOffset release]), strokeDashOffset = nil;
|
||||
(void)([unicode release]), unicode = nil;
|
||||
(void)([fillGradient release]), fillGradient = nil;
|
||||
(void)([strokeGradient release]), strokeGradient = nil;
|
||||
(void)([strokePattern release]), strokePattern = nil;
|
||||
(void)([transforms release]), transforms = nil;
|
||||
(void)([fillColor release]), fillColor = nil;
|
||||
(void)([strokeColor release]), strokeColor = nil;
|
||||
(void)([identifier release]), identifier = nil;
|
||||
(void)([def release]), def = nil;
|
||||
(void)([name release]), name = nil;
|
||||
(void)([title release]), title = nil;
|
||||
(void)([desc release]), desc = nil;
|
||||
(void)([className release]), className = nil;
|
||||
(void)([classNameList release]), classNameList = nil;
|
||||
(void)([fillPattern release]), fillPattern = nil;
|
||||
(void)([clipPath release]), clipPath = nil;
|
||||
(void)([svg release]), svg = nil;
|
||||
(void)([mask release]), mask = nil;
|
||||
(void)free(_strokeDashArray), _strokeDashArray = NULL;
|
||||
(void)([_x release]), _x = nil;
|
||||
(void)([_y release]), _y = nil;
|
||||
(void)([_width release]), _width = nil;
|
||||
(void)([_height release]), _height = nil;
|
||||
(void)([_opacity release]), _opacity = nil;
|
||||
(void)([_offset release]), _offset = nil;
|
||||
(void)([_fillOpacity release]), _fillOpacity = nil;
|
||||
(void)([_strokeOpacity release]), _strokeOpacity = nil;
|
||||
(void)([_strokeWidth release]), _strokeWidth = nil;
|
||||
(void)([_strokeDashOffset release]), _strokeDashOffset = nil;
|
||||
(void)([_unicode release]), _unicode = nil;
|
||||
(void)([_fill release]), _fill = nil;
|
||||
(void)([_stroke release]), _stroke = nil;
|
||||
(void)([_transforms release]), _transforms = nil;
|
||||
(void)([_identifier release]), _identifier = 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)([_clipPath release]), _clipPath = nil;
|
||||
(void)([_svg release]), _svg = nil;
|
||||
(void)([_mask release]), _mask = nil;
|
||||
(void)([_viewBox release]), _viewBox = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (IJSVGNodeType)typeForString:(NSString*)string
|
||||
kind:(NSXMLNodeKind)kind
|
||||
{
|
||||
string = [string lowercaseString];
|
||||
if ([string isEqualToString:@"style"])
|
||||
// possible fix for older os's that complain
|
||||
if(string == nil || kind == NSXMLCommentKind) {
|
||||
return IJSVGNodeTypeNotFound;
|
||||
}
|
||||
|
||||
const char* name = string.lowercaseString.UTF8String;
|
||||
if(name == NULL) {
|
||||
return IJSVGNodeTypeNotFound;
|
||||
}
|
||||
if (strcmp(name, "style") == 0) {
|
||||
return IJSVGNodeTypeStyle;
|
||||
if ([string isEqualToString:@"switch"])
|
||||
}
|
||||
if (strcmp(name, "switch") == 0) {
|
||||
return IJSVGNodeTypeSwitch;
|
||||
if ([string isEqualToString:@"defs"])
|
||||
}
|
||||
if (strcmp(name, "defs") == 0) {
|
||||
return IJSVGNodeTypeDef;
|
||||
if ([string isEqualToString:@"g"])
|
||||
}
|
||||
if (strcmp(name, "g") == 0) {
|
||||
return IJSVGNodeTypeGroup;
|
||||
if ([string isEqualToString:@"path"])
|
||||
}
|
||||
if (strcmp(name, "path") == 0) {
|
||||
return IJSVGNodeTypePath;
|
||||
if ([string isEqualToString:@"polygon"])
|
||||
}
|
||||
if (strcmp(name, "polygon") == 0) {
|
||||
return IJSVGNodeTypePolygon;
|
||||
if ([string isEqualToString:@"polyline"])
|
||||
}
|
||||
if (strcmp(name, "polyline") == 0) {
|
||||
return IJSVGNodeTypePolyline;
|
||||
if ([string isEqualToString:@"rect"])
|
||||
}
|
||||
if (strcmp(name, "rect") == 0) {
|
||||
return IJSVGNodeTypeRect;
|
||||
if ([string isEqualToString:@"line"])
|
||||
}
|
||||
if (strcmp(name, "line") == 0) {
|
||||
return IJSVGNodeTypeLine;
|
||||
if ([string isEqualToString:@"circle"])
|
||||
}
|
||||
if (strcmp(name, "circle") == 0) {
|
||||
return IJSVGNodeTypeCircle;
|
||||
if ([string isEqualToString:@"ellipse"])
|
||||
}
|
||||
if (strcmp(name, "ellipse") == 0) {
|
||||
return IJSVGNodeTypeEllipse;
|
||||
if ([string isEqualToString:@"use"])
|
||||
}
|
||||
if (strcmp(name, "use") == 0) {
|
||||
return IJSVGNodeTypeUse;
|
||||
if ([string isEqualToString:@"lineargradient"])
|
||||
}
|
||||
if (strcmp(name, "lineargradient") == 0) {
|
||||
return IJSVGNodeTypeLinearGradient;
|
||||
if ([string isEqualToString:@"radialgradient"])
|
||||
}
|
||||
if (strcmp(name, "radialgradient") == 0) {
|
||||
return IJSVGNodeTypeRadialGradient;
|
||||
if ([string isEqualToString:@"glyph"])
|
||||
}
|
||||
if(strcmp(name, "stop") == 0) {
|
||||
return IJSVGNodeTypeStop;
|
||||
}
|
||||
if (strcmp(name, "glyph") == 0) {
|
||||
return IJSVGNodeTypeGlyph;
|
||||
if ([string isEqualToString:@"font"])
|
||||
}
|
||||
if (strcmp(name, "font") == 0) {
|
||||
return IJSVGNodeTypeFont;
|
||||
if ([string isEqualToString:@"clippath"])
|
||||
}
|
||||
if (strcmp(name, "clippath") == 0) {
|
||||
return IJSVGNodeTypeClipPath;
|
||||
if ([string isEqualToString:@"mask"])
|
||||
}
|
||||
if (strcmp(name, "mask") == 0) {
|
||||
return IJSVGNodeTypeMask;
|
||||
if ([string isEqualToString:@"image"])
|
||||
}
|
||||
if (strcmp(name, "image") == 0) {
|
||||
return IJSVGNodeTypeImage;
|
||||
if ([string isEqualToString:@"pattern"])
|
||||
}
|
||||
if (strcmp(name, "pattern") == 0) {
|
||||
return IJSVGNodeTypePattern;
|
||||
if ([string isEqualToString:@"svg"])
|
||||
}
|
||||
if (strcmp(name, "svg") == 0) {
|
||||
return IJSVGNodeTypeSVG;
|
||||
if ([string isEqualToString:@"text"])
|
||||
}
|
||||
if (strcmp(name, "text") == 0) {
|
||||
return IJSVGNodeTypeText;
|
||||
if ([string isEqualToString:@"tspan"] || kind == NSXMLTextKind) {
|
||||
}
|
||||
if (strcmp(name, "tspan") == 0 || kind == NSXMLTextKind) {
|
||||
return IJSVGNodeTypeTextSpan;
|
||||
}
|
||||
if([string isEqualToString:@"title"]) {
|
||||
if(strcmp(name, "title") == 0) {
|
||||
return IJSVGNodeTypeTitle;
|
||||
}
|
||||
if([string isEqualToString:@"desc"]) {
|
||||
if(strcmp(name, "desc") == 0) {
|
||||
return IJSVGNodeTypeDesc;
|
||||
}
|
||||
return IJSVGNodeTypeUnknown;
|
||||
}
|
||||
|
||||
// are we commong HTML? - if so just treat as a group
|
||||
if (IJSVGIsCommonHTMLElementName(string) == YES) {
|
||||
return IJSVGNodeTypeGroup;
|
||||
+ (void)walkNodeTree:(IJSVGNode*)node
|
||||
handler:(IJSVGNodeWalkHandler)handler
|
||||
{
|
||||
BOOL allowChildNodes = YES;
|
||||
BOOL stop = NO;
|
||||
[self _walkNodeTree:node
|
||||
handler:handler
|
||||
allowChildNodes:&allowChildNodes
|
||||
stop:&stop];
|
||||
}
|
||||
|
||||
+ (void)_walkNodeTree:(IJSVGNode*)node
|
||||
handler:(IJSVGNodeWalkHandler)handler
|
||||
allowChildNodes:(BOOL*)allowChildNodes
|
||||
stop:(BOOL*)stop
|
||||
{
|
||||
// run the handler and instantly stop
|
||||
// if stop is set
|
||||
handler(node, allowChildNodes, stop);
|
||||
if(*stop == YES) {
|
||||
return;
|
||||
}
|
||||
|
||||
// child nodes only work for nodes
|
||||
// that are type group
|
||||
if(*allowChildNodes == NO ||
|
||||
[node isKindOfClass:IJSVGGroup.class] == NO) {
|
||||
*allowChildNodes = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
// iterate over the childnodes
|
||||
IJSVGGroup* group = (IJSVGGroup*)node;
|
||||
for(IJSVGNode* childNode in group.children) {
|
||||
[self _walkNodeTree:childNode
|
||||
handler:handler
|
||||
allowChildNodes:allowChildNodes
|
||||
stop:stop];
|
||||
if(*stop == YES) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return IJSVGNodeTypeNotFound;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [self initWithDef:YES]) != nil) {
|
||||
self.opacity = [IJSVGUnitLength unitWithFloat:1];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)applyPropertiesFromNode:(IJSVGNode*)node
|
||||
{
|
||||
self.title = node.title;
|
||||
self.desc = node.desc;
|
||||
|
||||
self.name = node.name;
|
||||
self.type = node.type;
|
||||
self.unicode = node.unicode;
|
||||
self.className = node.className;
|
||||
self.classNameList = node.classNameList;
|
||||
|
||||
self.x = node.x;
|
||||
self.y = node.y;
|
||||
self.width = node.width;
|
||||
self.height = node.height;
|
||||
|
||||
self.fillGradient = node.fillGradient;
|
||||
self.fillPattern = node.fillPattern;
|
||||
self.strokeGradient = node.strokeGradient;
|
||||
self.strokePattern = node.strokePattern;
|
||||
|
||||
self.fillColor = node.fillColor;
|
||||
self.strokeColor = node.strokeColor;
|
||||
self.clipPath = node.clipPath;
|
||||
|
||||
self.units = node.units;
|
||||
self.contentUnits = node.contentUnits;
|
||||
|
||||
self.opacity = node.opacity;
|
||||
self.strokeWidth = node.strokeWidth;
|
||||
self.fillOpacity = node.fillOpacity;
|
||||
self.strokeOpacity = node.strokeOpacity;
|
||||
|
||||
self.identifier = node.identifier;
|
||||
self.usesDefaultFillColor = node.usesDefaultFillColor;
|
||||
|
||||
self.transforms = node.transforms;
|
||||
self.def = node.def;
|
||||
self.windingRule = node.windingRule;
|
||||
self.lineCapStyle = node.lineCapStyle;
|
||||
self.lineJoinStyle = node.lineJoinStyle;
|
||||
self.parentNode = node.parentNode;
|
||||
|
||||
self.shouldRender = node.shouldRender;
|
||||
self.blendMode = node.blendMode;
|
||||
|
||||
// dash array needs physical memory copied
|
||||
CGFloat* nStrokeDashArray = (CGFloat*)malloc(node.strokeDashArrayCount * sizeof(CGFloat));
|
||||
memcpy(self.strokeDashArray, nStrokeDashArray, node.strokeDashArrayCount * sizeof(CGFloat));
|
||||
self.strokeDashArray = nStrokeDashArray;
|
||||
self.strokeDashArrayCount = node.strokeDashArrayCount;
|
||||
self.strokeDashOffset = node.strokeDashOffset;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
IJSVGNode* node = [self.class allocWithZone:zone];
|
||||
[node applyPropertiesFromNode:self];
|
||||
return node;
|
||||
}
|
||||
|
||||
- (id)initWithDef:(BOOL)flag
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
self.opacity = [IJSVGUnitLength unitWithFloat:0.f];
|
||||
self.opacity = [IJSVGUnitLength unitWithFloat:1.f];
|
||||
self.fillOpacity = [IJSVGUnitLength unitWithFloat:1.f];
|
||||
self.fillOpacity.inherit = YES;
|
||||
|
||||
@@ -241,159 +203,246 @@
|
||||
self.lineCapStyle = IJSVGLineCapStyleInherit;
|
||||
self.lineJoinStyle = IJSVGLineJoinStyleInherit;
|
||||
self.units = IJSVGUnitInherit;
|
||||
self.contentUnits = IJSVGUnitInherit;
|
||||
|
||||
self.blendMode = IJSVGBlendModeNormal;
|
||||
|
||||
if (flag) {
|
||||
def = [[IJSVGDef alloc] init];
|
||||
}
|
||||
self.overflowVisibility = IJSVGOverflowVisibilityVisible;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (IJSVGDef*)defForID:(NSString*)anID
|
||||
|
||||
- (void)applyPropertiesFromNode:(IJSVGNode*)node
|
||||
{
|
||||
IJSVGDef* aDef = nil;
|
||||
if ((aDef = [def defForID:anID]) != nil) {
|
||||
return aDef;
|
||||
}
|
||||
if (parentNode != nil) {
|
||||
return [parentNode defForID:anID];
|
||||
}
|
||||
return nil;
|
||||
self.title = node.title;
|
||||
self.desc = node.desc;
|
||||
|
||||
self.name = node.name;
|
||||
self.type = node.type;
|
||||
self.unicode = node.unicode;
|
||||
self.className = node.className;
|
||||
self.classNameList = node.classNameList;
|
||||
|
||||
self.viewBox = node.viewBox;
|
||||
self.viewBoxAlignment = node.viewBoxAlignment;
|
||||
self.viewBoxMeetOrSlice = node.viewBoxMeetOrSlice;
|
||||
|
||||
self.x = node.x;
|
||||
self.y = node.y;
|
||||
self.width = node.width;
|
||||
self.height = node.height;
|
||||
|
||||
self.fill = node.fill;
|
||||
self.stroke = node.stroke;
|
||||
self.clipPath = node.clipPath;
|
||||
|
||||
self.units = node.units;
|
||||
self.contentUnits = node.contentUnits;
|
||||
|
||||
self.opacity = node.opacity;
|
||||
self.strokeWidth = node.strokeWidth;
|
||||
self.fillOpacity = node.fillOpacity;
|
||||
self.strokeOpacity = node.strokeOpacity;
|
||||
|
||||
self.identifier = node.identifier;
|
||||
|
||||
self.transforms = node.transforms;
|
||||
self.windingRule = node.windingRule;
|
||||
self.lineCapStyle = node.lineCapStyle;
|
||||
self.lineJoinStyle = node.lineJoinStyle;
|
||||
self.parentNode = node.parentNode;
|
||||
|
||||
self.shouldRender = node.shouldRender;
|
||||
self.blendMode = node.blendMode;
|
||||
self.overflowVisibility = node.overflowVisibility;
|
||||
|
||||
// dash array needs physical memory copied
|
||||
CGFloat* nStrokeDashArray = (CGFloat*)malloc(node.strokeDashArrayCount * sizeof(CGFloat));
|
||||
memcpy(self.strokeDashArray, nStrokeDashArray, node.strokeDashArrayCount * sizeof(CGFloat));
|
||||
self.strokeDashArray = nStrokeDashArray;
|
||||
self.strokeDashArrayCount = node.strokeDashArrayCount;
|
||||
self.strokeDashOffset = node.strokeDashOffset;
|
||||
}
|
||||
|
||||
- (void)addDef:(IJSVGNode*)aDef
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
[def addDef:aDef];
|
||||
IJSVGNode* node = [self.class allocWithZone:zone];
|
||||
[node applyPropertiesFromNode:self];
|
||||
return node;
|
||||
}
|
||||
|
||||
- (void)setFill:(IJSVGNode*)fill
|
||||
{
|
||||
NSAssert([fill matchesTraits:IJSVGNodeTraitPaintable] || fill == nil, @"Fill must a paintable node.");
|
||||
(void)[_fill release], _fill = nil;
|
||||
_fill = [fill retain];
|
||||
}
|
||||
|
||||
- (void)setStroke:(IJSVGNode*)stroke
|
||||
{
|
||||
NSAssert([stroke matchesTraits:IJSVGNodeTraitPaintable]|| stroke == nil, @"Stroke must be a paintable node.");
|
||||
(void)[_stroke release], _stroke = nil;
|
||||
_stroke = [stroke retain];
|
||||
}
|
||||
|
||||
// winding rule can inherit..
|
||||
- (IJSVGWindingRule)windingRule
|
||||
{
|
||||
if (windingRule == IJSVGWindingRuleInherit && parentNode != nil) {
|
||||
return parentNode.windingRule;
|
||||
if (_windingRule == IJSVGWindingRuleInherit && _parentNode != nil) {
|
||||
return _parentNode.windingRule;
|
||||
}
|
||||
return windingRule;
|
||||
return _windingRule;
|
||||
}
|
||||
|
||||
- (IJSVGLineCapStyle)lineCapStyle
|
||||
{
|
||||
if (lineCapStyle == IJSVGLineCapStyleInherit) {
|
||||
if (parentNode != nil) {
|
||||
return parentNode.lineCapStyle;
|
||||
if (_lineCapStyle == IJSVGLineCapStyleInherit) {
|
||||
if (_parentNode != nil) {
|
||||
return _parentNode.lineCapStyle;
|
||||
}
|
||||
}
|
||||
return lineCapStyle;
|
||||
return _lineCapStyle;
|
||||
}
|
||||
|
||||
- (IJSVGLineJoinStyle)lineJoinStyle
|
||||
{
|
||||
if (lineJoinStyle == IJSVGLineJoinStyleInherit) {
|
||||
if (parentNode != nil) {
|
||||
return parentNode.lineJoinStyle;
|
||||
if (_lineJoinStyle == IJSVGLineJoinStyleInherit) {
|
||||
if (_parentNode != nil) {
|
||||
return _parentNode.lineJoinStyle;
|
||||
}
|
||||
}
|
||||
return lineJoinStyle;
|
||||
return _lineJoinStyle;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGUnitLength*)opacity
|
||||
{
|
||||
if (opacity.inherit && parentNode != nil) {
|
||||
return parentNode.opacity;
|
||||
if (_opacity.inherit && _parentNode != nil) {
|
||||
return _parentNode.opacity;
|
||||
}
|
||||
return opacity;
|
||||
return _opacity;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGUnitLength*)fillOpacity
|
||||
{
|
||||
if (fillOpacity.inherit && parentNode != nil) {
|
||||
return parentNode.fillOpacity;
|
||||
if (_fillOpacity.inherit && _parentNode != nil) {
|
||||
return _parentNode.fillOpacity;
|
||||
}
|
||||
return fillOpacity;
|
||||
return _fillOpacity;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGUnitLength*)strokeWidth
|
||||
{
|
||||
if (strokeWidth.inherit && parentNode != nil) {
|
||||
return parentNode.strokeWidth;
|
||||
if (_strokeWidth.inherit && _parentNode != nil) {
|
||||
return _parentNode.strokeWidth;
|
||||
}
|
||||
return strokeWidth;
|
||||
return _strokeWidth;
|
||||
}
|
||||
|
||||
- (NSArray<NSNumber*>*)lineDashPattern
|
||||
{
|
||||
NSMutableArray* arr = [[[NSMutableArray alloc] initWithCapacity:self.strokeDashArrayCount] autorelease];
|
||||
for (NSInteger i = 0; i < self.strokeDashArrayCount; i++) {
|
||||
[arr addObject:@((CGFloat)self.strokeDashArray[i])];
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (NSColor*)strokeColor
|
||||
- (IJSVGNode*)stroke
|
||||
{
|
||||
if (strokeColor != nil)
|
||||
return strokeColor;
|
||||
if (strokeColor == nil && parentNode != nil)
|
||||
return parentNode.strokeColor;
|
||||
return nil;
|
||||
if (_stroke == nil && _parentNode != nil) {
|
||||
return _parentNode.stroke;
|
||||
}
|
||||
return _stroke;
|
||||
}
|
||||
|
||||
- (IJSVGUnitLength*)strokeOpacity
|
||||
{
|
||||
if (strokeOpacity.inherit && parentNode != nil) {
|
||||
return parentNode.strokeOpacity;
|
||||
if (_strokeOpacity.inherit && _parentNode != nil) {
|
||||
return _parentNode.strokeOpacity;
|
||||
}
|
||||
return strokeOpacity;
|
||||
return _strokeOpacity;
|
||||
}
|
||||
|
||||
// even though the spec explicity states fill color
|
||||
// must be on the path, it can also be on the
|
||||
- (NSColor*)fillColor
|
||||
- (IJSVGNode*)fill
|
||||
{
|
||||
if (fillColor == nil && parentNode != nil) {
|
||||
return parentNode.fillColor;
|
||||
if (_fill == nil && _parentNode != nil) {
|
||||
return _parentNode.fill;
|
||||
}
|
||||
return fillColor;
|
||||
return _fill;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGGradient*)fillGradient
|
||||
- (IJSVGUnitType)units
|
||||
{
|
||||
if (fillGradient == nil && parentNode != nil) {
|
||||
return parentNode.fillGradient;
|
||||
if(_units == IJSVGUnitInherit && _parentNode != nil) {
|
||||
return _parentNode.units;
|
||||
}
|
||||
return fillGradient;
|
||||
return _units;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGPattern*)fillPattern
|
||||
- (IJSVGUnitType)contentUnits
|
||||
{
|
||||
if (fillPattern == nil && parentNode != nil) {
|
||||
return parentNode.fillPattern;
|
||||
if(_contentUnits == IJSVGUnitInherit && _parentNode != nil) {
|
||||
return _parentNode.contentUnits;
|
||||
}
|
||||
return fillPattern;
|
||||
return _contentUnits;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGGradient*)strokeGradient
|
||||
- (IJSVGUnitType)contentUnitsWithReferencingNodeBounds:(CGRect*)bounds
|
||||
{
|
||||
if (strokeGradient == nil && parentNode != nil) {
|
||||
return parentNode.strokeGradient;
|
||||
}
|
||||
return strokeGradient;
|
||||
IJSVGNode* node = nil;
|
||||
IJSVGUnitType type = [self contentUnitsWithReferencingNode:&node];
|
||||
*bounds = node.parentNode.bounds;
|
||||
return type;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGPattern*)strokePattern
|
||||
- (IJSVGUnitType)contentUnitsWithReferencingNode:(IJSVGNode**)referencingNode
|
||||
{
|
||||
if (strokePattern == nil && parentNode != nil) {
|
||||
return parentNode.strokePattern;
|
||||
if(_contentUnits == IJSVGUnitInherit && _parentNode != nil) {
|
||||
return [_parentNode contentUnitsWithReferencingNode:referencingNode];
|
||||
}
|
||||
return strokePattern;
|
||||
*referencingNode = self;
|
||||
return _contentUnits;
|
||||
}
|
||||
|
||||
- (void)addTraits:(IJSVGNodeTraits)traits
|
||||
{
|
||||
_traits |= traits;
|
||||
}
|
||||
|
||||
- (void)removeTraits:(IJSVGNodeTraits)traits
|
||||
{
|
||||
_traits = _traits & ~traits;
|
||||
}
|
||||
|
||||
- (BOOL)matchesTraits:(IJSVGNodeTraits)traits
|
||||
{
|
||||
return (_traits & traits) == traits;
|
||||
}
|
||||
|
||||
- (void)computeTraits
|
||||
{
|
||||
// by default this does nothing
|
||||
}
|
||||
|
||||
- (instancetype)detach
|
||||
{
|
||||
self.parentNode = nil;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ %@ %@",self.name,self.classNameList,self.identifier];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGBezierPathAdditions.h"
|
||||
#import "IJSVGNode.h"
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
#import <IJSVG/IJSVGColorNode.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGGroup;
|
||||
@@ -23,15 +23,13 @@ typedef NS_ENUM(NSInteger, IJSVGPrimitivePathType) {
|
||||
};
|
||||
|
||||
@interface IJSVGPath : IJSVGNode {
|
||||
|
||||
NSBezierPath* path;
|
||||
CGPoint lastControlPoint;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) IJSVGPrimitivePathType primitiveType;
|
||||
@property (nonatomic, retain) NSBezierPath* path;
|
||||
@property (nonatomic, assign) CGMutablePathRef path;
|
||||
@property (nonatomic, assign) CGPoint lastControlPoint;
|
||||
@property (nonatomic, readonly) CGPathRef CGPath;
|
||||
@property (nonatomic, readonly) CGRect controlPointBoundingBox;
|
||||
@property (nonatomic, readonly) CGRect pathBoundingBox;
|
||||
|
||||
- (void)close;
|
||||
- (NSPoint)currentPoint;
|
||||
|
||||
@@ -6,23 +6,15 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGGroup.h"
|
||||
#import "IJSVGPath.h"
|
||||
#import <IJSVG/IJSVGPath.h>
|
||||
|
||||
@implementation IJSVGPath
|
||||
|
||||
@synthesize path = _path;
|
||||
@synthesize lastControlPoint;
|
||||
@synthesize CGPath = _CGPath;
|
||||
@synthesize primitiveType = _primitiveType;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_CGPath != nil) {
|
||||
CGPathRelease(_CGPath);
|
||||
_CGPath = nil;
|
||||
if(_path != NULL) {
|
||||
(void)CGPathRelease(_path), _path = NULL;
|
||||
}
|
||||
((void)[_path release]), _path = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -30,42 +22,70 @@
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
_primitiveType = kIJSVGPrimitivePathTypePath;
|
||||
_path = NSBezierPath.bezierPath.retain;
|
||||
_path = CGPathCreateMutable();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)bounds
|
||||
{
|
||||
return self.pathBoundingBox;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
IJSVGPath* node = [super copyWithZone:zone];
|
||||
node.path = [self.path.copy autorelease];
|
||||
node.path = _path;
|
||||
return node;
|
||||
}
|
||||
|
||||
- (void)setPath:(CGMutablePathRef)path
|
||||
{
|
||||
// this will automatically copy any path into a mutable path
|
||||
// regardless of if it was a mutable path to begin with
|
||||
if(_path != NULL) {
|
||||
(void)CGPathRelease(_path), _path = NULL;
|
||||
}
|
||||
_path = CGPathCreateMutableCopy(path);
|
||||
}
|
||||
|
||||
- (CGRect)pathBoundingBox
|
||||
{
|
||||
return CGPathGetPathBoundingBox(_path);
|
||||
}
|
||||
|
||||
- (CGRect)controlPointBoundingBox
|
||||
{
|
||||
return CGPathGetBoundingBox(_path);
|
||||
}
|
||||
|
||||
- (NSPoint)currentPoint
|
||||
{
|
||||
return _path.currentPoint;
|
||||
return CGPathGetCurrentPoint(_path);
|
||||
}
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[_path closePath];
|
||||
CGPathCloseSubpath(_path);
|
||||
}
|
||||
|
||||
- (void)invlidateCGPath
|
||||
{
|
||||
if (_CGPath != nil) {
|
||||
CGPathRelease(_CGPath);
|
||||
}
|
||||
_CGPath = nil;
|
||||
}
|
||||
#pragma mark Traits
|
||||
|
||||
- (CGPathRef)CGPath
|
||||
- (void)computeTraits
|
||||
{
|
||||
if (_CGPath == nil) {
|
||||
_CGPath = [_path newCGPathRef:NO];
|
||||
if(self.stroke != nil) {
|
||||
// by default we can just add this on
|
||||
[self addTraits:IJSVGNodeTraitStroked];
|
||||
|
||||
// if we detect the stroke was a color, we need to check its alpha
|
||||
// component to then remove the trait if its 0.f
|
||||
if([self.stroke isKindOfClass:IJSVGColorNode.class] == YES) {
|
||||
IJSVGColorNode* strokeColor = (IJSVGColorNode*)self.stroke;
|
||||
if(strokeColor.color.alphaComponent == 0.f) {
|
||||
[self removeTraits:IJSVGNodeTraitStroked];
|
||||
}
|
||||
}
|
||||
}
|
||||
return _CGPath;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
// Copyright © 2016 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGGroup.h"
|
||||
#import "IJSVGImage.h"
|
||||
#import <IJSVG/IJSVGImage.h>
|
||||
#import <IJSVG/IJSVGGroup.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGPattern : IJSVGGroup {
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,7 +7,19 @@
|
||||
//
|
||||
|
||||
#import "IJSVGPattern.h"
|
||||
#import "IJSVGUnitRect.h"
|
||||
|
||||
@implementation IJSVGPattern
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
self.viewBox = nil;
|
||||
self.viewBoxAlignment = IJSVGViewBoxAlignmentXMidYMid;
|
||||
self.viewBoxMeetOrSlice = IJSVGViewBoxMeetOrSliceMeet;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
+3
-2
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGGradient.h"
|
||||
#import <IJSVG/IJSVGGradient.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGRadialGradient : IJSVGGradient
|
||||
@@ -15,7 +15,8 @@
|
||||
@property (nonatomic, retain) IJSVGUnitLength* cy;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* fx;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* fy;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* radius;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* fr;
|
||||
@property (nonatomic, retain) IJSVGUnitLength* r;
|
||||
|
||||
+ (NSGradient*)parseGradient:(NSXMLElement*)element
|
||||
gradient:(IJSVGRadialGradient*)gradient;
|
||||
@@ -0,0 +1,185 @@
|
||||
//
|
||||
// IJSVGRadialGradient.m
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 03/09/2014.
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <IJSVG/IJSVGRadialGradient.h>
|
||||
#import <IJSVG/IJSVGParser.h>
|
||||
|
||||
@implementation IJSVGRadialGradient
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([_cx release]), _cx = nil;
|
||||
(void)([_cy release]), _cy = nil;
|
||||
(void)([_fx release]), _fx = nil;
|
||||
(void)([_fy release]), _fy = nil;
|
||||
(void)([_fr release]), _fr = nil;
|
||||
(void)([_r release]), _r = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
IJSVGRadialGradient* grad = [super copyWithZone:zone];
|
||||
grad.fx = _fx;
|
||||
grad.fy = _fy;
|
||||
grad.fr = _fr;
|
||||
grad.cx = _cx;
|
||||
grad.cy = _cy;
|
||||
grad.r = _r;
|
||||
return grad;
|
||||
}
|
||||
|
||||
+ (NSGradient*)parseGradient:(NSXMLElement*)element
|
||||
gradient:(IJSVGRadialGradient*)gradient
|
||||
{
|
||||
// cx defaults to 50% if not specified
|
||||
NSDictionary* kv = @{
|
||||
IJSVGAttributeCX : @"cx",
|
||||
IJSVGAttributeCY : @"cy",
|
||||
IJSVGAttributeR : @"r" };
|
||||
|
||||
for (NSString* key in kv.allKeys) {
|
||||
NSString* str = [element attributeForName:key].stringValue;
|
||||
IJSVGUnitLength* unit = nil;
|
||||
if (str != nil) {
|
||||
unit = [IJSVGUnitLength unitWithString:str
|
||||
fromUnitType:gradient.units];
|
||||
} else {
|
||||
// spec says to say 50% for missing property default
|
||||
unit = [IJSVGUnitLength unitWithPercentageFloat:.5f];
|
||||
}
|
||||
[gradient setValue:unit
|
||||
forKey:kv[key]];
|
||||
}
|
||||
|
||||
// fr
|
||||
NSString* fr = [element attributeForName:IJSVGAttributeFR].stringValue;
|
||||
if(fr != nil) {
|
||||
gradient.fr = [IJSVGUnitLength unitWithString:fr
|
||||
fromUnitType:gradient.units];
|
||||
} else {
|
||||
gradient.fr = [IJSVGUnitLength unitWithPercentageFloat:0.f];
|
||||
}
|
||||
|
||||
// fx and fy are the same unless specified otherwise
|
||||
gradient.fx = gradient.cx;
|
||||
gradient.fy = gradient.cy;
|
||||
|
||||
// needs fixing
|
||||
NSString* fx = [element attributeForName:IJSVGAttributeFX].stringValue;
|
||||
if (fx != nil) {
|
||||
gradient.fx = [IJSVGUnitLength unitWithString:fx
|
||||
fromUnitType:gradient.units];
|
||||
}
|
||||
|
||||
NSString* fy = [element attributeForName:IJSVGAttributeFY].stringValue;
|
||||
if (fy != nil) {
|
||||
gradient.fy = [IJSVGUnitLength unitWithString:fy
|
||||
fromUnitType:gradient.units];
|
||||
}
|
||||
|
||||
if (gradient.gradient != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray* colors = nil;
|
||||
CGFloat* colorStops = [self.class computeColorStops:gradient
|
||||
colors:&colors];
|
||||
|
||||
NSGradient* ret = [[[NSGradient alloc] initWithColors:colors
|
||||
atLocations:colorStops
|
||||
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
|
||||
free(colorStops);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox
|
||||
{
|
||||
CGContextSaveGState(ctx);
|
||||
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
|
||||
CGFloat radius = 0.f;
|
||||
CGPoint startPoint = CGPointZero;
|
||||
CGPoint gradientStartPoint = CGPointZero;
|
||||
CGPoint gradientEndPoint = CGPointZero;
|
||||
|
||||
// transforms
|
||||
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
|
||||
|
||||
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
|
||||
|
||||
// compute size based on percentages
|
||||
CGFloat width = CGRectGetWidth(boundingBox);
|
||||
CGFloat height = CGRectGetHeight(boundingBox);
|
||||
CGFloat cx = [_cx computeValue:width];
|
||||
CGFloat cy = [_cy computeValue:height];
|
||||
startPoint = CGPointMake(cx, cy);
|
||||
CGFloat val = MIN(width, height);
|
||||
radius = [_r computeValue:val];
|
||||
CGFloat focalRadius = [_fr computeValue:val];
|
||||
|
||||
CGFloat fx = [_fx computeValue:width];
|
||||
CGFloat fy = [_fy computeValue:height];
|
||||
|
||||
gradientEndPoint = CGPointMake(fx, fy);
|
||||
gradientStartPoint = startPoint;
|
||||
|
||||
// transform if width or height is not equal - this can only
|
||||
// be done if we are using objectBoundingBox
|
||||
if(inUserSpace == YES) {
|
||||
CGFloat rad = 2.f * radius;
|
||||
CGRect rect = CGRectMake(startPoint.x, startPoint.y, rad, rad);
|
||||
rect = CGRectApplyAffineTransform(rect, selfTransform);
|
||||
rect = CGRectApplyAffineTransform(rect, absoluteTransform);
|
||||
radius = CGRectGetHeight(rect) / 2.f;
|
||||
CGContextConcatCTM(ctx, absoluteTransform);
|
||||
} else if(width != height) {
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
CGAffineTransform invert = CGAffineTransformIdentity;
|
||||
CGPoint invPoint = CGPointZero;
|
||||
CGFloat* radiusScale;
|
||||
if(width > height) {
|
||||
transform = CGAffineTransformMakeScale(1.f, height / width);
|
||||
radiusScale = &invPoint.y;
|
||||
} else {
|
||||
transform = CGAffineTransformMakeScale(width / height, 1.f);
|
||||
radiusScale = &invPoint.x;
|
||||
}
|
||||
invert = CGAffineTransformInvert(transform);
|
||||
invPoint.x = invert.a;
|
||||
invPoint.y = invert.d;
|
||||
gradientStartPoint.x *= invPoint.x;
|
||||
gradientStartPoint.y *= invPoint.y;
|
||||
gradientEndPoint.x *= invPoint.x;
|
||||
gradientEndPoint.y *= invPoint.y;
|
||||
radius *= *radiusScale;
|
||||
focalRadius *= *radiusScale;
|
||||
selfTransform = CGAffineTransformConcat(transform, selfTransform);
|
||||
}
|
||||
|
||||
// transform the context
|
||||
CGContextConcatCTM(ctx, selfTransform);
|
||||
|
||||
// draw the gradient
|
||||
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
||||
CGContextDrawRadialGradient(ctx, self.CGGradient,
|
||||
gradientEndPoint, focalRadius,
|
||||
gradientStartPoint,
|
||||
radius, options);
|
||||
CGContextRestoreGState(ctx);
|
||||
|
||||
//#ifdef IJSVG_DEBUG_GRADIENTS
|
||||
// [self _debugStart:gradientStartPoint
|
||||
// end:gradientEndPoint
|
||||
// context:ctx];
|
||||
//#endif
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// IJSVGRootNode.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 28/03/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <IJSVG/IJSVG.h>
|
||||
#import <IJSVG/IJSVGGroup.h>
|
||||
#import <IJSVG/IJSVGUnitSize.h>
|
||||
|
||||
@interface IJSVGRootNode : IJSVGGroup
|
||||
|
||||
@property (nonatomic, retain) IJSVGUnitSize* intrinsicSize;
|
||||
@property (nonatomic, readonly) CGRect bounds;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// IJSVGRootNode.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 28/03/2022.
|
||||
// Copyright © 2022 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGRootNode.h"
|
||||
|
||||
@implementation IJSVGRootNode
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)[_intrinsicSize release], _intrinsicSize = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
self.viewBoxAlignment = IJSVGViewBoxAlignmentXMidYMid;
|
||||
self.viewBoxMeetOrSlice = IJSVGViewBoxMeetOrSliceMeet;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)bounds
|
||||
{
|
||||
return [self.viewBox computeValue:CGSizeZero];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -6,11 +6,9 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGGroup.h"
|
||||
#import <IJSVG/IJSVGGroup.h>
|
||||
|
||||
@interface IJSVGText : IJSVGGroup {
|
||||
|
||||
NSString* text;
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) NSString* text;
|
||||
|
||||
@@ -10,18 +10,16 @@
|
||||
|
||||
@implementation IJSVGText
|
||||
|
||||
@synthesize text;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([text release]), text = nil;
|
||||
(void)([_text release]), _text = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (IJSVGText*)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
IJSVGText* node = [super copyWithZone:zone];
|
||||
node.text = self.text;
|
||||
node.text = _text;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,108 +6,106 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColor.h"
|
||||
#import "IJSVGCommand.h"
|
||||
#import "IJSVGDef.h"
|
||||
#import "IJSVGError.h"
|
||||
#import "IJSVGForeignObject.h"
|
||||
#import "IJSVGGroup.h"
|
||||
#import "IJSVGImage.h"
|
||||
#import "IJSVGLinearGradient.h"
|
||||
#import "IJSVGPath.h"
|
||||
#import "IJSVGPattern.h"
|
||||
#import "IJSVGRadialGradient.h"
|
||||
#import "IJSVGStyleSheet.h"
|
||||
#import "IJSVGText.h"
|
||||
#import "IJSVGTransform.h"
|
||||
#import "IJSVGUnitRect.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import <IJSVG/IJSVGColor.h>
|
||||
#import <IJSVG/IJSVGCommand.h>
|
||||
#import <IJSVG/IJSVGDef.h>
|
||||
#import <IJSVG/IJSVGError.h>
|
||||
#import <IJSVG/IJSVGForeignObject.h>
|
||||
#import <IJSVG/IJSVGGroup.h>
|
||||
#import <IJSVG/IJSVGColorNode.h>
|
||||
#import <IJSVG/IJSVGImage.h>
|
||||
#import <IJSVG/IJSVGLinearGradient.h>
|
||||
#import <IJSVG/IJSVGPath.h>
|
||||
#import <IJSVG/IJSVGPattern.h>
|
||||
#import <IJSVG/IJSVGRadialGradient.h>
|
||||
#import <IJSVG/IJSVGStyleSheet.h>
|
||||
#import <IJSVG/IJSVGText.h>
|
||||
#import <IJSVG/IJSVGTransform.h>
|
||||
#import <IJSVG/IJSVGUnitRect.h>
|
||||
#import <IJSVG/IJSVGUtils.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
static NSString const* IJSVGAttributeViewBox = @"viewBox";
|
||||
static NSString const* IJSVGAttributeID = @"id";
|
||||
static NSString const* IJSVGAttributeClass = @"class";
|
||||
static NSString const* IJSVGAttributeX = @"x";
|
||||
static NSString const* IJSVGAttributeY = @"y";
|
||||
static NSString const* IJSVGAttributeWidth = @"width";
|
||||
static NSString const* IJSVGAttributeHeight = @"height";
|
||||
static NSString const* IJSVGAttributeOpacity = @"opacity";
|
||||
static NSString const* IJSVGAttributeStrokeOpacity = @"stroke-opacity";
|
||||
static NSString const* IJSVGAttributeStrokeWidth = @"stroke-width";
|
||||
static NSString const* IJSVGAttributeStrokeDashOffset = @"stroke-dashoffset";
|
||||
static NSString const* IJSVGAttributeFillOpacity = @"fill-opacity";
|
||||
static NSString const* IJSVGAttributeClipPath = @"clip-path";
|
||||
static NSString const* IJSVGAttributeMask = @"mask";
|
||||
static NSString const* IJSVGAttributeGradientUnits = @"gradientUnits";
|
||||
static NSString const* IJSVGAttributeMaskUnits = @"maskUnits";
|
||||
static NSString const* IJSVGAttributeMaskContentUnits = @"maskContentUnits";
|
||||
static NSString const* IJSVGAttributeTransform = @"transform";
|
||||
static NSString const* IJSVGAttributeGradientTransform = @"gradientTransform";
|
||||
static NSString const* IJSVGAttributeUnicode = @"unicode";
|
||||
static NSString const* IJSVGAttributeStrokeLineCap = @"stroke-linecap";
|
||||
static NSString const* IJSVGAttributeLineJoin = @"stroke-linejoin";
|
||||
static NSString const* IJSVGAttributeStroke = @"stroke";
|
||||
static NSString const* IJSVGAttributeStrokeDashArray = @"stroke-dasharray";
|
||||
static NSString const* IJSVGAttributeFill = @"fill";
|
||||
static NSString const* IJSVGAttributeFillRule = @"fill-rule";
|
||||
static NSString const* IJSVGAttributeBlendMode = @"mix-blend-mode";
|
||||
static NSString const* IJSVGAttributeDisplay = @"display";
|
||||
static NSString const* IJSVGAttributeStyle = @"style";
|
||||
static NSString const* IJSVGAttributeD = @"d";
|
||||
static NSString const* IJSVGAttributeXLink = @"xlink:href";
|
||||
static NSString const* IJSVGAttributeX1 = @"x1";
|
||||
static NSString const* IJSVGAttributeX2 = @"x2";
|
||||
static NSString const* IJSVGAttributeY1 = @"y1";
|
||||
static NSString const* IJSVGAttributeY2 = @"y2";
|
||||
static NSString const* IJSVGAttributeRX = @"rx";
|
||||
static NSString const* IJSVGAttributeRY = @"ry";
|
||||
static NSString const* IJSVGAttributeCX = @"cx";
|
||||
static NSString const* IJSVGAttributeCY = @"cy";
|
||||
static NSString const* IJSVGAttributeR = @"r";
|
||||
static NSString const* IJSVGAttributePoints = @"points";
|
||||
extern NSString* const IJSVGAttributeViewBox;
|
||||
extern NSString* const IJSVGAttributePreserveAspectRatio;
|
||||
extern NSString* const IJSVGAttributeID;
|
||||
extern NSString* const IJSVGAttributeClass;
|
||||
extern NSString* const IJSVGAttributeX;
|
||||
extern NSString* const IJSVGAttributeY;
|
||||
extern NSString* const IJSVGAttributeWidth;
|
||||
extern NSString* const IJSVGAttributeHeight;
|
||||
extern NSString* const IJSVGAttributeOpacity;
|
||||
extern NSString* const IJSVGAttributeStrokeOpacity;
|
||||
extern NSString* const IJSVGAttributeStrokeWidth;
|
||||
extern NSString* const IJSVGAttributeStrokeDashOffset;
|
||||
extern NSString* const IJSVGAttributeFillOpacity;
|
||||
extern NSString* const IJSVGAttributeClipPath;
|
||||
extern NSString* const IJSVGAttributeMask;
|
||||
extern NSString* const IJSVGAttributeGradientUnits;
|
||||
extern NSString* const IJSVGAttributePatternContentUnits;
|
||||
extern NSString* const IJSVGAttributeMaskUnits;
|
||||
extern NSString* const IJSVGAttributeMaskContentUnits;
|
||||
extern NSString* const IJSVGAttributeTransform;
|
||||
extern NSString* const IJSVGAttributeGradientTransform;
|
||||
extern NSString* const IJSVGAttributeUnicode;
|
||||
extern NSString* const IJSVGAttributeStrokeLineCap;
|
||||
extern NSString* const IJSVGAttributeLineJoin;
|
||||
extern NSString* const IJSVGAttributeStroke;
|
||||
extern NSString* const IJSVGAttributeStrokeDashArray;
|
||||
extern NSString* const IJSVGAttributeFill;
|
||||
extern NSString* const IJSVGAttributeFillRule;
|
||||
extern NSString* const IJSVGAttributeBlendMode;
|
||||
extern NSString* const IJSVGAttributeDisplay;
|
||||
extern NSString* const IJSVGAttributeStyle;
|
||||
extern NSString* const IJSVGAttributeD;
|
||||
extern NSString* const IJSVGAttributeXLink;
|
||||
extern NSString* const IJSVGAttributeX1;
|
||||
extern NSString* const IJSVGAttributeX2;
|
||||
extern NSString* const IJSVGAttributeY1;
|
||||
extern NSString* const IJSVGAttributeY2;
|
||||
extern NSString* const IJSVGAttributeRX;
|
||||
extern NSString* const IJSVGAttributeRY;
|
||||
extern NSString* const IJSVGAttributeCX;
|
||||
extern NSString* const IJSVGAttributeCY;
|
||||
extern NSString* const IJSVGAttributeR;
|
||||
extern NSString* const IJSVGAttributeFR;
|
||||
extern NSString* const IJSVGAttributeFX;
|
||||
extern NSString* const IJSVGAttributeFY;
|
||||
extern NSString* const IJSVGAttributePoints;
|
||||
extern NSString* const IJSVGAttributeOffset;
|
||||
extern NSString* const IJSVGAttributeStopColor;
|
||||
extern NSString* const IJSVGAttributeStopOpacity;
|
||||
extern NSString* const IJSVGAttributeHref;
|
||||
extern NSString* const IJSVGAttributeOverflow;
|
||||
|
||||
|
||||
@class IJSVGParser;
|
||||
|
||||
@protocol IJSVGParserDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)svgParser:(IJSVGParser*)svg
|
||||
shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject;
|
||||
- (void)svgParser:(IJSVGParser*)svg
|
||||
handleForeignObject:(IJSVGForeignObject*)foreignObject
|
||||
document:(NSXMLDocument*)document;
|
||||
- (void)svgParser:(IJSVGParser*)svg
|
||||
foundSubSVG:(IJSVG*)subSVG
|
||||
withSVGString:(NSString*)string;
|
||||
|
||||
@end
|
||||
|
||||
@interface IJSVGParser : IJSVGGroup {
|
||||
|
||||
NSRect viewBox;
|
||||
IJSVGUnitSize* intrinsicSize;
|
||||
@interface IJSVGParser : NSObject {
|
||||
|
||||
@private
|
||||
id<IJSVGParserDelegate> _delegate;
|
||||
NSXMLDocument* _document;
|
||||
NSMutableArray<IJSVGNode*>* _glyphs;
|
||||
IJSVGStyleSheet* _styleSheet;
|
||||
NSMutableDictionary<NSString*, NSXMLElement*>* _defNodes;
|
||||
NSMutableDictionary<NSString*, NSXMLElement*>* _baseDefNodes;
|
||||
NSMutableArray<IJSVG*>* _svgs;
|
||||
|
||||
struct {
|
||||
unsigned int shouldHandleForeignObject : 1;
|
||||
unsigned int handleForeignObject : 1;
|
||||
unsigned int handleSubSVG : 1;
|
||||
} _respondsTo;
|
||||
|
||||
IJSVGPathDataStream* _commandDataStream;
|
||||
IJSVGStyleSheet* _styleSheet;
|
||||
NSMapTable<IJSVGNode*, NSMutableDictionary<NSString*, NSXMLElement*>*>* _detachedElements;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) NSRect viewBox;
|
||||
@property (nonatomic, readonly) IJSVGUnitSize* intrinsicSize;
|
||||
@property (nonatomic, retain, readonly) IJSVGRootNode* rootNode;
|
||||
|
||||
+ (BOOL)isDataSVG:(NSData*)data;
|
||||
|
||||
@@ -124,9 +122,5 @@ static NSString const* IJSVGAttributePoints = @"points";
|
||||
+ (IJSVGParser*)groupForFileURL:(NSURL*)aURL
|
||||
error:(NSError**)error
|
||||
delegate:(id<IJSVGParserDelegate>)delegate;
|
||||
- (NSSize)size;
|
||||
- (BOOL)isFont;
|
||||
- (NSArray*)glyphs;
|
||||
- (NSArray<IJSVG*>*)subSVGs:(BOOL)recursive;
|
||||
|
||||
@end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,18 +6,25 @@
|
||||
// Copyright © 2016 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGRenderingStyle.h"
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
#import <IJSVG/IJSVGRenderingStyle.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@class IJSVGLayer;
|
||||
@class IJSVGRootLayer;
|
||||
@class IJSVGRootNode;
|
||||
|
||||
@interface IJSVGLayerTree : NSObject {
|
||||
@private
|
||||
NSMutableArray<NSValue*>* _viewPortStack;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) CGRect viewBox;
|
||||
@property (nonatomic, assign) CGFloat backingScale;
|
||||
@property (nonatomic, retain) IJSVGRenderingStyle* style;
|
||||
|
||||
- (IJSVGLayer*)layerForNode:(IJSVGNode*)node;
|
||||
- (id)initWithViewPortRect:(CGRect)viewPort
|
||||
backingScale:(CGFloat)scale;
|
||||
- (IJSVGRootLayer*)rootLayerForRootNode:(IJSVGRootNode*)rootNode;
|
||||
|
||||
@end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColorList.h"
|
||||
#import "IJSVGNode.h"
|
||||
#import <IJSVG/IJSVGColorList.h>
|
||||
#import <IJSVG/IJSVGNode.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@@ -10,13 +10,6 @@
|
||||
|
||||
@implementation IJSVGRenderingStyle
|
||||
|
||||
@synthesize colorList = _colorList;
|
||||
@synthesize lineCapStyle = _lineCapStyle;
|
||||
@synthesize lineJoinStyle = _lineJoinStyle;
|
||||
@synthesize lineWidth = _lineWidth;
|
||||
@synthesize fillColor = _fillColor;
|
||||
@synthesize strokeColor = _strokeColor;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([_fillColor release]), _fillColor = nil;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColor.h"
|
||||
#import <IJSVG/IJSVGColor.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface IJSVGStyle : NSObject {
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
+ (NSArray*)allowedColourKeys
|
||||
{
|
||||
return @[ @"fill", @"stroke-colour", @"stop-color", @"stroke" ];
|
||||
return @[ @"fill", @"stroke-color", @"stop-color", @"stroke" ];
|
||||
}
|
||||
|
||||
- (void)setProperties:(NSDictionary*)properties
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
// Copyright © 2016 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGStyleSheetRule.h"
|
||||
#import "IJSVGStyleSheetSelector.h"
|
||||
#import <IJSVG/IJSVGStyleSheetRule.h>
|
||||
#import <IJSVG/IJSVGStyleSheetSelector.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGNode;
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
#import "IJSVGStyleSheet.h"
|
||||
|
||||
@interface IJSVGStyleSheetSelectorListItem : NSObject {
|
||||
|
||||
IJSVGStyleSheetSelector* selector;
|
||||
IJSVGStyleSheetRule* rule;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IJSVGStyleSheetRule* rule;
|
||||
@@ -23,12 +20,11 @@
|
||||
|
||||
@implementation IJSVGStyleSheetSelectorListItem
|
||||
|
||||
@synthesize rule, selector;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([rule release]), rule = nil;
|
||||
(void)([selector release]), selector = nil;
|
||||
(void)([_rule release]), _rule = nil;
|
||||
(void)([_selector release]), _selector = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,13 @@
|
||||
// Copyright © 2016 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGStyle.h"
|
||||
#import "IJSVGStyleSheetSelector.h"
|
||||
#import <IJSVG/IJSVGStyle.h>
|
||||
#import <IJSVG/IJSVGStyleSheetSelector.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGNode;
|
||||
|
||||
@interface IJSVGStyleSheetRule : NSObject {
|
||||
|
||||
NSArray* selectors;
|
||||
IJSVGStyle* style;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSArray* selectors;
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
|
||||
@implementation IJSVGStyleSheetRule
|
||||
|
||||
@synthesize selectors, style;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([selectors release]), selectors = nil;
|
||||
(void)([style release]), style = nil;
|
||||
(void)([_selectors release]), _selectors = nil;
|
||||
(void)([_style release]), _style = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -24,7 +22,7 @@
|
||||
{
|
||||
// interate over each select and work out if
|
||||
// it allows us to be applied
|
||||
for (IJSVGStyleSheetSelector* selector in selectors) {
|
||||
for (IJSVGStyleSheetSelector* selector in _selectors) {
|
||||
if ([selector matchesNode:node]) {
|
||||
*matchedSelector = selector;
|
||||
return YES;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2016 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGStyleSheetSelectorRaw.h"
|
||||
#import <IJSVG/IJSVGStyleSheetSelectorRaw.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGNode;
|
||||
@@ -14,7 +14,7 @@
|
||||
@interface IJSVGStyleSheetSelector : NSObject {
|
||||
|
||||
NSString* selector;
|
||||
NSUInteger specificity;
|
||||
|
||||
@private
|
||||
NSMutableArray* _rawSelectors;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#define SPECIFICITY_CLASS 10
|
||||
#define SPECIFICITY_IDENTIFIER 100
|
||||
|
||||
@synthesize specificity;
|
||||
|
||||
BOOL IJSVGStyleSheetIsSiblingCombinator(IJSVGStyleSheetSelectorCombinator combinator)
|
||||
{
|
||||
return combinator == IJSVGStyleSheetSelectorCombinatorNextSibling ||
|
||||
@@ -276,15 +274,16 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
|
||||
|
||||
// 1 for a tag
|
||||
if(rawSelector.tag != nil) {
|
||||
self.specificity += SPECIFICITY_TAG;
|
||||
_specificity += SPECIFICITY_TAG;
|
||||
}
|
||||
|
||||
// 100 for a id
|
||||
if(rawSelector.identifier != nil)
|
||||
self.specificity += SPECIFICITY_IDENTIFIER;
|
||||
if(rawSelector.identifier != nil) {
|
||||
_specificity += SPECIFICITY_IDENTIFIER;
|
||||
}
|
||||
|
||||
// 10 for a class
|
||||
self.specificity += (rawSelector.classes.count*SPECIFICITY_CLASS);
|
||||
_specificity += (rawSelector.classes.count*SPECIFICITY_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,9 @@ typedef NS_ENUM(NSUInteger, IJSVGStyleSheetSelectorCombinator) {
|
||||
};
|
||||
|
||||
@interface IJSVGStyleSheetSelectorRaw : NSObject {
|
||||
|
||||
NSString* tag;
|
||||
NSString* identifier;
|
||||
|
||||
|
||||
@private
|
||||
NSMutableArray* classes;
|
||||
|
||||
IJSVGStyleSheetSelectorCombinator combinator;
|
||||
NSString* combinatorString;
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) NSString* tag;
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
|
||||
@implementation IJSVGStyleSheetSelectorRaw
|
||||
|
||||
@synthesize classes, identifier, tag, combinator, combinatorString;
|
||||
@synthesize classes;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)([classes release]), classes = nil;
|
||||
(void)([identifier release]), identifier = nil;
|
||||
(void)([tag release]), tag = nil;
|
||||
(void)([combinatorString release]), combinatorString = nil;
|
||||
(void)([_identifier release]), _identifier = nil;
|
||||
(void)([_tag release]), _tag = nil;
|
||||
(void)([_combinatorString release]), _combinatorString = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
classes = [[NSMutableArray alloc] init];
|
||||
combinator = IJSVGStyleSheetSelectorCombinatorDescendant;
|
||||
combinatorString = @" ";
|
||||
_combinator = IJSVGStyleSheetSelectorCombinatorDescendant;
|
||||
_combinatorString = @" ";
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -38,7 +38,8 @@
|
||||
|
||||
- (NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"Combinator: %@, Tag: %@, Classes: %@, Identifier: %@", combinatorString, tag, classes, identifier];
|
||||
return [NSString stringWithFormat:@"Combinator: %@, Tag: %@, Classes: %@, Identifier: %@",
|
||||
_combinatorString, _tag, classes, _identifier];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitLength.h"
|
||||
#import <IJSVG/IJSVGUnitLength.h>
|
||||
|
||||
@interface IJSVGGradientUnitLength : IJSVGUnitLength
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// IJSVGParsing.h
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 04/02/2021.
|
||||
// Copyright © 2021 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
char* parameters;
|
||||
} IJSVGParsingStringMethod;
|
||||
|
||||
IJSVGParsingStringMethod* IJSVGParsingStringMethodCreate(void);
|
||||
void IJSVGParsingStringMethodRelease(IJSVGParsingStringMethod* stringMethod);
|
||||
IJSVGParsingStringMethod** IJSVGParsingMethodParseString(const char* string,
|
||||
NSUInteger* count);
|
||||
void IJSVGParsingStringMethodsRelease(IJSVGParsingStringMethod** methods,
|
||||
NSUInteger count);
|
||||
|
||||
@interface IJSVGParsing : NSObject
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// IJSVGParsing.m
|
||||
// IJSVG
|
||||
//
|
||||
// Created by Curtis Hard on 04/02/2021.
|
||||
// Copyright © 2021 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGParsing.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
IJSVGParsingStringMethod* IJSVGParsingStringMethodCreate(void)
|
||||
{
|
||||
IJSVGParsingStringMethod* method = (IJSVGParsingStringMethod*)malloc(sizeof(IJSVGParsingStringMethod));
|
||||
method->name = NULL;
|
||||
method->parameters = NULL;
|
||||
return method;
|
||||
}
|
||||
|
||||
void IJSVGParsingStringMethodRelease(IJSVGParsingStringMethod* stringMethod)
|
||||
{
|
||||
if(stringMethod->name != NULL) {
|
||||
(void)free(stringMethod->name), stringMethod->name = NULL;
|
||||
}
|
||||
if(stringMethod->parameters != NULL) {
|
||||
(void)free(stringMethod->parameters), stringMethod->parameters = NULL;
|
||||
}
|
||||
if(stringMethod != NULL) {
|
||||
(void)free(stringMethod), stringMethod = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void IJSVGParsingStringMethodsRelease(IJSVGParsingStringMethod** methods,
|
||||
NSUInteger count)
|
||||
{
|
||||
for(int i = 0; i < count; i++) {
|
||||
IJSVGParsingStringMethodRelease(methods[i]);
|
||||
}
|
||||
(void)free(methods), methods = NULL;
|
||||
}
|
||||
|
||||
IJSVGParsingStringMethod** IJSVGParsingMethodParseString(const char* string,
|
||||
NSUInteger* count)
|
||||
{
|
||||
const char* charString = string;
|
||||
unsigned long length = strlen(string);
|
||||
char* buffer = (char*)calloc(sizeof(char), length);
|
||||
char* originBuffer = buffer;
|
||||
int bufferIndex = 0;
|
||||
|
||||
const size_t defBufferSize = 5;
|
||||
size_t currentBufferSize = defBufferSize;
|
||||
NSUInteger methodCount = 0;
|
||||
|
||||
IJSVGParsingStringMethod* method = NULL;
|
||||
IJSVGParsingStringMethod** methods = NULL;
|
||||
methods = (IJSVGParsingStringMethod**)malloc(sizeof(IJSVGParsingStringMethod*)*currentBufferSize);
|
||||
|
||||
// each command requires a name and parameters, store for later use
|
||||
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;
|
||||
|
||||
//write here
|
||||
if(method == NULL) {
|
||||
method = IJSVGParsingStringMethodCreate();
|
||||
method->name = (char*)calloc(sizeof(char),bufferIndex+1);
|
||||
memcpy(method->name, buffer, sizeof(char)*bufferIndex);
|
||||
IJSVGTrimCharBuffer(method->name);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// there has to be a method at this point, if not, something is wrong
|
||||
// in the syntax
|
||||
if(method != NULL) {
|
||||
method->parameters = (char*)calloc(sizeof(char),bufferIndex+1);
|
||||
memcpy(method->parameters, buffer, sizeof(char)*bufferIndex);
|
||||
IJSVGTrimCharBuffer(method->parameters);
|
||||
|
||||
// now we can add
|
||||
if(methodCount + 1 > currentBufferSize) {
|
||||
currentBufferSize += defBufferSize;
|
||||
*methods = *(IJSVGParsingStringMethod**)realloc(methods, sizeof(IJSVGParsingStringMethod*)*currentBufferSize);
|
||||
}
|
||||
methods[methodCount++] = method;
|
||||
method = NULL;
|
||||
}
|
||||
|
||||
// write null up until the limit we reached
|
||||
memset(buffer, '\0', bufferIndex);
|
||||
bufferIndex = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// increment the buffer count
|
||||
*buffer++ = currentChar;
|
||||
bufferIndex++;
|
||||
}
|
||||
|
||||
// left over
|
||||
if(method != NULL) {
|
||||
(void)IJSVGParsingStringMethodRelease(method), method = NULL;
|
||||
}
|
||||
|
||||
buffer = originBuffer;
|
||||
*count = methodCount;
|
||||
(void)free(buffer), buffer = NULL;
|
||||
return methods;
|
||||
}
|
||||
|
||||
@implementation IJSVGParsing
|
||||
|
||||
@end
|
||||
@@ -20,10 +20,12 @@ BOOL IJSVGBeginTransaction(void)
|
||||
// of the catransaction for background composites
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
[CATransaction lock];
|
||||
return YES;
|
||||
};
|
||||
|
||||
void IJSVGEndTransaction(void)
|
||||
{
|
||||
[CATransaction unlock];
|
||||
[CATransaction commit];
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUtils.h"
|
||||
#import <IJSVG/IJSVGUtils.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class IJSVGTransform;
|
||||
@@ -14,7 +14,7 @@
|
||||
typedef CGFloat (^IJSVGTransformParameterModifier)(NSInteger index, CGFloat value);
|
||||
typedef void (^IJSVGTransformApplyBlock)(IJSVGTransform* transform);
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, IJSVGTransformCommand) {
|
||||
typedef NS_ENUM(NSInteger, IJSVGTransformCommand) {
|
||||
IJSVGTransformCommandMatrix,
|
||||
IJSVGTransformCommandTranslate,
|
||||
IJSVGTransformCommandTranslateX,
|
||||
@@ -27,11 +27,6 @@ typedef NS_OPTIONS(NSInteger, IJSVGTransformCommand) {
|
||||
};
|
||||
|
||||
@interface IJSVGTransform : NSObject {
|
||||
|
||||
IJSVGTransformCommand command;
|
||||
CGFloat* parameters;
|
||||
NSInteger parameterCount;
|
||||
NSInteger sort;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) IJSVGTransformCommand command;
|
||||
@@ -40,6 +35,7 @@ typedef NS_OPTIONS(NSInteger, IJSVGTransformCommand) {
|
||||
@property (nonatomic, assign) NSInteger sort;
|
||||
|
||||
void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApplyBlock block);
|
||||
BOOL IJSVGAffineTransformScalesAndTranslates(CGAffineTransform affineTransform);
|
||||
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform*>* transforms);
|
||||
NSString* IJSVGTransformAttributeString(CGAffineTransform transform);
|
||||
|
||||
@@ -49,10 +45,11 @@ NSString* IJSVGTransformAttributeString(CGAffineTransform transform);
|
||||
+ (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;
|
||||
- (void)applyBounds:(CGRect)bounds
|
||||
withContentUnits:(IJSVGUnitType)contentUnits;
|
||||
- (CGAffineTransform)CGAffineTransform;
|
||||
- (CGAffineTransform)CGAffineTransformWithModifier:(IJSVGTransformParameterModifier)modifier;
|
||||
- (CGAffineTransform)stackIdentity:(CGAffineTransform)identity;
|
||||
|
||||
@@ -8,28 +8,24 @@
|
||||
|
||||
#import "IJSVGMath.h"
|
||||
#import "IJSVGTransform.h"
|
||||
#import "IJSVGParsing.h"
|
||||
|
||||
@implementation IJSVGTransform
|
||||
|
||||
@synthesize command;
|
||||
@synthesize parameters;
|
||||
@synthesize parameterCount;
|
||||
@synthesize sort;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
(void)free(parameters);
|
||||
(void)free(_parameters);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
IJSVGTransform* trans = [[self.class alloc] init];
|
||||
trans.command = self.command;
|
||||
trans.parameters = (CGFloat*)malloc(sizeof(CGFloat) * self.parameterCount);
|
||||
trans.sort = sort;
|
||||
trans.parameterCount = self.parameterCount;
|
||||
memcpy(trans.parameters, self.parameters, sizeof(CGFloat) * self.parameterCount);
|
||||
trans.command = _command;
|
||||
trans.parameters = (CGFloat*)malloc(sizeof(CGFloat) * _parameterCount);
|
||||
trans.sort = _sort;
|
||||
trans.parameterCount = _parameterCount;
|
||||
memcpy(trans.parameters, _parameters, sizeof(CGFloat) * _parameterCount);
|
||||
return trans;
|
||||
}
|
||||
|
||||
@@ -54,6 +50,16 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
}
|
||||
};
|
||||
|
||||
BOOL IJSVGAffineTransformScalesAndTranslates(CGAffineTransform transform)
|
||||
{
|
||||
if(transform.tx != 0.f || transform.ty != 0.f) {
|
||||
CGFloat scaleX = sqrt(pow(transform.a, 2.f) + pow(transform.c, 2.f));
|
||||
CGFloat scaleY = sqrt(pow(transform.b, 2.f) + pow(transform.d, 2.f));
|
||||
return scaleX != 1.f || scaleY != 1.f;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (IJSVGTransform*)transformByTranslatingX:(CGFloat)x
|
||||
y:(CGFloat)y
|
||||
{
|
||||
@@ -83,19 +89,49 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
- (void)recalculateWithBounds:(CGRect)bounds
|
||||
{
|
||||
CGFloat max = bounds.size.width > bounds.size.height ? bounds.size.width : bounds.size.height;
|
||||
switch (self.command) {
|
||||
switch (_command) {
|
||||
case IJSVGTransformCommandRotate: {
|
||||
if (self.parameterCount == 1) {
|
||||
if (_parameterCount == 1) {
|
||||
return;
|
||||
}
|
||||
self.parameters[1] = self.parameters[1] * max;
|
||||
self.parameters[2] = self.parameters[2] * max;
|
||||
_parameters[1] = _parameters[1] * max;
|
||||
_parameters[2] = _parameters[2] * max;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+ (IJSVGTransformCommand)commandForCommandCString:(char*)str
|
||||
{
|
||||
IJSVGCharBufferToLower(str);
|
||||
if (strcmp(str, "matrix") == 0) {
|
||||
return IJSVGTransformCommandMatrix;
|
||||
}
|
||||
if (strcmp(str, "translate") == 0) {
|
||||
return IJSVGTransformCommandTranslate;
|
||||
}
|
||||
if (strcmp(str, "translatex") == 0) {
|
||||
return IJSVGTransformCommandTranslateX;
|
||||
}
|
||||
if (strcmp(str, "translatey") == 0) {
|
||||
return IJSVGTransformCommandTranslateY;
|
||||
}
|
||||
if (strcmp(str, "scale") == 0) {
|
||||
return IJSVGTransformCommandScale;
|
||||
}
|
||||
if (strcmp(str, "skewx") == 0) {
|
||||
return IJSVGTransformCommandSkewX;
|
||||
}
|
||||
if (strcmp(str, "skewy") == 0) {
|
||||
return IJSVGTransformCommandSkewY;
|
||||
}
|
||||
if (strcmp(str, "rotate") == 0) {
|
||||
return IJSVGTransformCommandRotate;
|
||||
}
|
||||
return IJSVGTransformCommandNotImplemented;
|
||||
}
|
||||
|
||||
+ (IJSVGTransformCommand)commandForCommandString:(NSString*)str
|
||||
{
|
||||
str = str.lowercaseString;
|
||||
@@ -139,222 +175,94 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
+ (NSArray<IJSVGTransform*>*)transformsForString:(NSString*)string
|
||||
{
|
||||
NSMutableArray<IJSVGTransform*>* array = nil;
|
||||
array = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSMutableArray<IJSVGTransform*>* transforms = nil;
|
||||
transforms = [[[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;
|
||||
IJSVGParsingStringMethod** methods = NULL;
|
||||
NSUInteger count = 0;
|
||||
methods = IJSVGParsingMethodParseString(charString, &count);
|
||||
for(int i = 0; i < count; i++) {
|
||||
IJSVGParsingStringMethod* method = methods[i];
|
||||
IJSVGTransformCommand commandType;
|
||||
commandType = [self.class commandForCommandCString:method->name];
|
||||
if(commandType == IJSVGTransformCommandNotImplemented) {
|
||||
(void)IJSVGParsingStringMethodRelease(method), method = NULL;
|
||||
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++;
|
||||
// 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 scanFloatsFromCString:method->parameters
|
||||
size:&count];
|
||||
transform.parameterCount = count;
|
||||
|
||||
// add to the list of transforms to return
|
||||
[transforms addObject:transform];
|
||||
(void)IJSVGParsingStringMethodRelease(method), method = NULL;
|
||||
}
|
||||
buffer = originBuffer;
|
||||
(void)free(buffer), buffer = NULL;
|
||||
return array;
|
||||
(void)free(methods), methods = NULL;
|
||||
return transforms;
|
||||
}
|
||||
|
||||
+ (NSBezierPath*)transformedPath:(IJSVGPath*)path
|
||||
- (void)applyBounds:(CGRect)bounds
|
||||
withContentUnits:(IJSVGUnitType)contentUnits
|
||||
{
|
||||
if (path.transforms.count == 0) {
|
||||
return path.path;
|
||||
if(contentUnits != IJSVGUnitObjectBoundingBox) {
|
||||
return;
|
||||
}
|
||||
NSBezierPath* cop = [[path.path copy] autorelease];
|
||||
for (IJSVGTransform* transform in path.transforms) {
|
||||
NSAffineTransform* at = NSAffineTransform.transform;
|
||||
switch (transform.command) {
|
||||
// matrix
|
||||
case IJSVGTransformCommandMatrix: {
|
||||
at.transformStruct = (NSAffineTransformStruct) {
|
||||
.m11 = transform.parameters[0],
|
||||
.m12 = transform.parameters[1],
|
||||
.m21 = transform.parameters[2],
|
||||
.m22 = transform.parameters[3],
|
||||
.tX = transform.parameters[4],
|
||||
.tY = transform.parameters[5],
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
// skewX
|
||||
case IJSVGTransformCommandSkewX: {
|
||||
CGFloat degrees = transform.parameters[0];
|
||||
CGFloat radians = degrees * M_PI / 180.f;
|
||||
at.transformStruct = (NSAffineTransformStruct) {
|
||||
.m11 = 1.f,
|
||||
.m12 = 0.f,
|
||||
.m21 = tan(radians),
|
||||
.m22 = 1.f,
|
||||
.tX = 0.f,
|
||||
.tY = 0.f
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
// skewX
|
||||
case IJSVGTransformCommandSkewY: {
|
||||
CGFloat degrees = transform.parameters[0];
|
||||
CGFloat radians = degrees * M_PI / 180.f;
|
||||
at.transformStruct = (NSAffineTransformStruct) {
|
||||
.m11 = 1.f,
|
||||
.m12 = tan(radians),
|
||||
.m21 = 0.f,
|
||||
.m22 = 1.f,
|
||||
.tX = 0.f,
|
||||
.tY = 0.f
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
// translate
|
||||
|
||||
switch(self.command) {
|
||||
case IJSVGTransformCommandTranslate: {
|
||||
if (transform.parameterCount == 1)
|
||||
[at translateXBy:transform.parameters[0]
|
||||
yBy:0];
|
||||
else
|
||||
[at translateXBy:transform.parameters[0]
|
||||
yBy:transform.parameters[1]];
|
||||
break;
|
||||
}
|
||||
|
||||
// translateX
|
||||
case IJSVGTransformCommandTranslateX: {
|
||||
[at translateXBy:transform.parameters[0] yBy:0.f];
|
||||
break;
|
||||
}
|
||||
|
||||
// translateY
|
||||
case IJSVGTransformCommandTranslateY: {
|
||||
[at translateXBy:0.f yBy:transform.parameters[0]];
|
||||
break;
|
||||
}
|
||||
|
||||
// scale
|
||||
case IJSVGTransformCommandScale: {
|
||||
if (transform.parameterCount == 1)
|
||||
[at scaleBy:transform.parameters[0]];
|
||||
else
|
||||
[at scaleXBy:transform.parameters[0]
|
||||
yBy:transform.parameters[1]];
|
||||
break;
|
||||
}
|
||||
|
||||
// rotate
|
||||
case IJSVGTransformCommandRotate: {
|
||||
if (transform.parameterCount == 1)
|
||||
[at rotateByDegrees:transform.parameters[0]];
|
||||
else {
|
||||
CGFloat centerX = transform.parameters[1];
|
||||
CGFloat centerY = transform.parameters[2];
|
||||
CGFloat angle = transform.parameters[0] * (M_PI / 180.f);
|
||||
[at translateXBy:centerX
|
||||
yBy:centerY];
|
||||
[at rotateByRadians:angle];
|
||||
[at translateXBy:-1.f * centerX
|
||||
yBy:-1.f * centerY];
|
||||
self.parameters[0] *= bounds.size.width;
|
||||
if(self.parameterCount == 2) {
|
||||
self.parameters[1] *= bounds.size.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// do nothing
|
||||
case IJSVGTransformCommandNotImplemented: {
|
||||
}
|
||||
}
|
||||
[cop transformUsingAffineTransform:at];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return cop;
|
||||
}
|
||||
|
||||
- (CGAffineTransform)CGAffineTransform
|
||||
{
|
||||
return [self CGAffineTransformWithModifier:nil];
|
||||
return [self stackIdentity:CGAffineTransformIdentity];
|
||||
}
|
||||
|
||||
- (CGAffineTransform)stackIdentity:(CGAffineTransform)identity
|
||||
{
|
||||
switch (self.command) {
|
||||
switch (_command) {
|
||||
|
||||
// translate
|
||||
case IJSVGTransformCommandTranslate: {
|
||||
if (self.parameterCount == 1) {
|
||||
return CGAffineTransformTranslate(identity, self.parameters[0], 0.f);
|
||||
if (_parameterCount == 1) {
|
||||
return CGAffineTransformTranslate(identity, _parameters[0], 0.f);
|
||||
}
|
||||
return CGAffineTransformTranslate(identity, self.parameters[0], self.parameters[1]);
|
||||
return CGAffineTransformTranslate(identity, _parameters[0], _parameters[1]);
|
||||
}
|
||||
|
||||
// translateX
|
||||
case IJSVGTransformCommandTranslateX: {
|
||||
return CGAffineTransformTranslate(identity, self.parameters[0], 0.f);
|
||||
return CGAffineTransformTranslate(identity, _parameters[0], 0.f);
|
||||
}
|
||||
|
||||
// translateY
|
||||
case IJSVGTransformCommandTranslateY: {
|
||||
return CGAffineTransformTranslate(identity, 0.f, self.parameters[0]);
|
||||
return CGAffineTransformTranslate(identity, 0.f, _parameters[0]);
|
||||
}
|
||||
|
||||
// rotate
|
||||
case IJSVGTransformCommandRotate: {
|
||||
if (self.parameterCount == 1) {
|
||||
return CGAffineTransformRotate(identity, (self.parameters[0] / 180) * M_PI);
|
||||
if (_parameterCount == 1) {
|
||||
return CGAffineTransformRotate(identity, (_parameters[0] / 180) * M_PI);
|
||||
}
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p2 = self.parameters[2];
|
||||
CGFloat p0 = _parameters[0];
|
||||
CGFloat p1 = _parameters[1];
|
||||
CGFloat p2 = _parameters[2];
|
||||
CGFloat angle = p0 * (M_PI / 180.f);
|
||||
|
||||
identity = CGAffineTransformTranslate(identity, p1, p2);
|
||||
@@ -364,35 +272,35 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// scale
|
||||
case IJSVGTransformCommandScale: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
if (self.parameterCount == 1) {
|
||||
CGFloat p0 = _parameters[0];
|
||||
if (_parameterCount == 1) {
|
||||
return CGAffineTransformScale(identity, p0, p0);
|
||||
}
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p1 = _parameters[1];
|
||||
return CGAffineTransformScale(identity, p0, p1);
|
||||
}
|
||||
|
||||
// matrix
|
||||
case IJSVGTransformCommandMatrix: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p2 = self.parameters[2];
|
||||
CGFloat p3 = self.parameters[3];
|
||||
CGFloat p4 = self.parameters[4];
|
||||
CGFloat p5 = self.parameters[5];
|
||||
CGFloat p0 = _parameters[0];
|
||||
CGFloat p1 = _parameters[1];
|
||||
CGFloat p2 = _parameters[2];
|
||||
CGFloat p3 = _parameters[3];
|
||||
CGFloat p4 = _parameters[4];
|
||||
CGFloat p5 = _parameters[5];
|
||||
return CGAffineTransformMake(p0, p1, p2, p3, p4, p5);
|
||||
}
|
||||
|
||||
// skewX
|
||||
case IJSVGTransformCommandSkewX: {
|
||||
CGFloat degrees = self.parameters[0];
|
||||
CGFloat degrees = _parameters[0];
|
||||
CGFloat radians = degrees * M_PI / 180.f;
|
||||
return CGAffineTransformMake(1.f, 0.f, tan(radians), 1.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
// skewY
|
||||
case IJSVGTransformCommandSkewY: {
|
||||
CGFloat degrees = self.parameters[0];
|
||||
CGFloat degrees = _parameters[0];
|
||||
CGFloat radians = degrees * M_PI / 180.f;
|
||||
return CGAffineTransformMake(1.f, tan(radians), 0.f, 1.f, 0.f, 0.f);
|
||||
}
|
||||
@@ -406,15 +314,15 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
- (CGAffineTransform)CGAffineTransformWithModifier:(IJSVGTransformParameterModifier)modifier
|
||||
{
|
||||
switch (self.command) {
|
||||
switch (_command) {
|
||||
// matrix
|
||||
case IJSVGTransformCommandMatrix: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p2 = self.parameters[2];
|
||||
CGFloat p3 = self.parameters[3];
|
||||
CGFloat p4 = self.parameters[4];
|
||||
CGFloat p5 = self.parameters[5];
|
||||
CGFloat p0 = _parameters[0];
|
||||
CGFloat p1 = _parameters[1];
|
||||
CGFloat p2 = _parameters[2];
|
||||
CGFloat p3 = _parameters[3];
|
||||
CGFloat p4 = _parameters[4];
|
||||
CGFloat p5 = _parameters[5];
|
||||
if (modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
p1 = modifier(1, p1);
|
||||
@@ -428,11 +336,11 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// translate
|
||||
case IJSVGTransformCommandTranslate: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
if (self.parameterCount == 1) {
|
||||
CGFloat p0 = _parameters[0];
|
||||
if (_parameterCount == 1) {
|
||||
return CGAffineTransformMakeTranslation(p0, 0);
|
||||
}
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p1 = _parameters[1];
|
||||
if (modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
p1 = modifier(1, p1);
|
||||
@@ -442,7 +350,7 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// translateX
|
||||
case IJSVGTransformCommandTranslateX: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p0 = _parameters[0];
|
||||
if (modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
}
|
||||
@@ -451,7 +359,7 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// translateY
|
||||
case IJSVGTransformCommandTranslateY: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p0 = _parameters[0];
|
||||
if (modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
}
|
||||
@@ -460,11 +368,11 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// scale
|
||||
case IJSVGTransformCommandScale: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
if (self.parameterCount == 1) {
|
||||
CGFloat p0 = _parameters[0];
|
||||
if (_parameterCount == 1) {
|
||||
return CGAffineTransformMakeScale(p0, p0);
|
||||
}
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p1 = _parameters[1];
|
||||
if (modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
p1 = modifier(1, p1);
|
||||
@@ -474,7 +382,7 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// skewX
|
||||
case IJSVGTransformCommandSkewX: {
|
||||
CGFloat degrees = self.parameters[0];
|
||||
CGFloat degrees = _parameters[0];
|
||||
if (modifier != nil) {
|
||||
degrees = modifier(0, degrees);
|
||||
}
|
||||
@@ -484,7 +392,7 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// skewY
|
||||
case IJSVGTransformCommandSkewY: {
|
||||
CGFloat degrees = self.parameters[0];
|
||||
CGFloat degrees = _parameters[0];
|
||||
if (modifier != nil) {
|
||||
degrees = modifier(0, degrees);
|
||||
}
|
||||
@@ -494,12 +402,12 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
|
||||
// rotate
|
||||
case IJSVGTransformCommandRotate: {
|
||||
if (self.parameterCount == 1) {
|
||||
return CGAffineTransformMakeRotation((self.parameters[0] / 180) * M_PI);
|
||||
if (_parameterCount == 1) {
|
||||
return CGAffineTransformMakeRotation((_parameters[0] / 180) * M_PI);
|
||||
} else {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
CGFloat p1 = self.parameters[1];
|
||||
CGFloat p2 = self.parameters[2];
|
||||
CGFloat p0 = _parameters[0];
|
||||
CGFloat p1 = _parameters[1];
|
||||
CGFloat p2 = _parameters[2];
|
||||
if (modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
p1 = modifier(1, p1);
|
||||
@@ -727,7 +635,7 @@ void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApp
|
||||
- (NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ %@", [super description],
|
||||
[self.class affineTransformToSVGMatrixString:self.CGAffineTransform]];
|
||||
[self.class affineTransformToSVGTransformComponentString:self.CGAffineTransform]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user