Compare commits
141 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 63586f1181 | |||
| dc94d9761b | |||
| 8deef07f7f | |||
| 2c962db6cc | |||
| 9dda7915fa | |||
| 1fbb56b443 | |||
| 4bbf2277bc | |||
| 7eeeea5167 | |||
| 8f84aa9070 | |||
| 200fd6893d | |||
| 01ad4eaeb2 | |||
| 6b1c988d89 | |||
| c91ac95bc2 | |||
| cf14f27560 | |||
| cef1de35d7 | |||
| c1a98ef5a6 | |||
| 690e1c8619 | |||
| eda2b73eb2 | |||
| f00ede11f0 | |||
| 169da55131 | |||
| acfec29765 | |||
| a44cc7c098 | |||
| 171e97451b | |||
| 27e096350e | |||
| 04646fe4ec | |||
| a092b612a8 | |||
| d176fe6396 | |||
| c94de1d241 | |||
| 1294372daa | |||
| 60e5c6b68a | |||
| 06c8191732 | |||
| 2f0bead7a4 | |||
| ee46609165 | |||
| 9e58ae6e19 | |||
| 199d1a5707 | |||
| f72ae8b401 | |||
| c126f511d6 | |||
| 399e9271b4 | |||
| f9107094a4 | |||
| 7a64c122cf | |||
| 8ee96c4a5b | |||
| 7cace854bd | |||
| 91cf59bd32 | |||
| b5e15445a5 | |||
| e7577a3e76 | |||
| 25b38fa128 | |||
| 8ef14224dd | |||
| ebfc31cdb1 | |||
| ccfcfbf228 | |||
| 4fe1d594b0 | |||
| 61d5bb99d5 | |||
| faccec3e01 | |||
| 66e9c9000e | |||
| 2006e68c2a | |||
| 01aea1129d | |||
| 388982d37b | |||
| 941130d1f2 | |||
| b9e964dc50 | |||
| 8532819b6a | |||
| e576803bb7 | |||
| a6a802a36b | |||
| b50963292c | |||
| c40c63c48d | |||
| 6d21b56416 | |||
| dbdd8a6971 | |||
| b7ba91aa82 | |||
| 98efacf93c | |||
| 1b3cf5a1a0 | |||
| 35f8663631 | |||
| 6d4eb76803 | |||
| 36dae3ad1b | |||
| 8149293b7b | |||
| 1993c55cb8 | |||
| 1f13134ccd | |||
| 435489f65f | |||
| 4bcbcc374b | |||
| cb544d7a6b | |||
| a4cd0bcc4e | |||
| 02b03d8862 | |||
| 94ae7c2757 | |||
| 27371a9d78 | |||
| 3c1422a65f | |||
| 8ed817aa43 | |||
| ca754ff61c | |||
| 53da0fca4b | |||
| 1259ce1e63 | |||
| 70cd111b1c | |||
| 15b0805bf9 | |||
| e11e28c54f | |||
| f320bd4684 | |||
| 2faeda560f | |||
| c56a5ecca1 | |||
| e85f67358e | |||
| 0fb27d4e94 | |||
| 9bce41afff | |||
| 09b0cc6d96 | |||
| 58fbb01ff2 | |||
| 5a5b144ab1 | |||
| 359cff7569 | |||
| 57bfe633e7 | |||
| c757fb4b33 | |||
| 4d1141a889 | |||
| 481359ec58 | |||
| fb14d7be65 | |||
| 0e4a5528f7 | |||
| 36216a51ed | |||
| 9e1ffd5d46 | |||
| 05d0b6e173 | |||
| 9cecea923c | |||
| 8ff1fc860e | |||
| edef84274d | |||
| 484675f666 | |||
| 2f574e3cbb | |||
| b64b0f3735 | |||
| c0cdb41ddc | |||
| 258a617564 | |||
| bf40002fe0 | |||
| 2ef0bd88ef | |||
| 0aca44ef76 | |||
| a3e512d7b8 | |||
| 0ffd20e87c | |||
| 0f0943816c | |||
| ddb5b2f746 | |||
| 80bc3ed1d8 | |||
| 1a7a7b4d7b | |||
| 0876a1e976 | |||
| 6747160504 | |||
| d2059e4d2f | |||
| 71c47a313e | |||
| 70f9c29fe5 | |||
| 5f8f3d8be5 | |||
| e26ebe300f | |||
| c0c46ad2b7 | |||
| abade39e2a | |||
| 2f7a6aa213 | |||
| 2598046369 | |||
| 5424e32a63 | |||
| a8a7f8d356 | |||
| a3bde2f710 | |||
| 0cc22cad44 | |||
| 448d46e8ec |
@@ -7,6 +7,15 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
343A19181FB2212C000652A2 /* IJSVGGradientUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */; };
|
||||
59069A2922D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59069A2822D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg */; };
|
||||
59069A2B22D0EE0E004DDEA5 /* test (1).svg in Resources */ = {isa = PBXBuildFile; fileRef = 59069A2A22D0EE0E004DDEA5 /* test (1).svg */; };
|
||||
590C87EB201F9888004A1554 /* json.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87EA201F9888004A1554 /* json.svg */; };
|
||||
590C87ED201FA08C004A1554 /* intertwingly.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87EC201FA08C004A1554 /* intertwingly.svg */; };
|
||||
590C87EF201FA093004A1554 /* NewTux.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87EE201FA092004A1554 /* NewTux.svg */; };
|
||||
590C87F1201FBF27004A1554 /* AJ_Digital_Camera.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */; };
|
||||
590C87F4201FC9E4004A1554 /* radialgradient2.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87F3201FC9E3004A1554 /* radialgradient2.svg */; };
|
||||
590C87F6201FD0D4004A1554 /* car.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87F5201FD0D4004A1554 /* car.svg */; };
|
||||
591704CC1E2016E400012644 /* IJSVGExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 591704CB1E2016E400012644 /* IJSVGExporter.m */; };
|
||||
591A13E11E19838F001D1629 /* IJSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 591A13E01E19838F001D1629 /* IJSVGText.m */; };
|
||||
59265CE81C4F840400F333F0 /* css.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59265CE71C4F840400F333F0 /* css.svg */; };
|
||||
@@ -28,10 +37,13 @@
|
||||
595665DE19B6309C00D805FF /* test.svg in Resources */ = {isa = PBXBuildFile; fileRef = 595665DD19B6309C00D805FF /* test.svg */; };
|
||||
595665E119B630B600D805FF /* SVGView.m in Sources */ = {isa = PBXBuildFile; fileRef = 595665E019B630B600D805FF /* SVGView.m */; };
|
||||
597046A21E24352700A60138 /* IJSVGStrokeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 597046A11E24352700A60138 /* IJSVGStrokeLayer.m */; };
|
||||
597AC83322CFD0FC007C0E42 /* home.svg in Resources */ = {isa = PBXBuildFile; fileRef = 597AC83222CFD0FC007C0E42 /* home.svg */; };
|
||||
5986308719BA104800CF15EA /* linecap.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5986308619BA104800CF15EA /* linecap.svg */; };
|
||||
5986308A19BA106D00CF15EA /* SVGExampleView5.m in Sources */ = {isa = PBXBuildFile; fileRef = 5986308919BA106D00CF15EA /* SVGExampleView5.m */; };
|
||||
5986308C19BA180E00CF15EA /* dashed.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5986308B19BA180E00CF15EA /* dashed.svg */; };
|
||||
598759F61E242C850024CC3F /* IJSVGExporterPathInstruction.m in Sources */ = {isa = PBXBuildFile; fileRef = 598759F51E242C850024CC3F /* IJSVGExporterPathInstruction.m */; };
|
||||
5991A2A9201E30E600913E3B /* gradients.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5991A2A8201E30E600913E3B /* gradients.svg */; };
|
||||
5991A2AB201E310200913E3B /* heart.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5991A2AA201E310200913E3B /* heart.svg */; };
|
||||
599465DC1C4AA87200A2EEF3 /* IJSVGStyleSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 599465D51C4AA87200A2EEF3 /* IJSVGStyleSheet.m */; };
|
||||
599465DD1C4AA87200A2EEF3 /* IJSVGStyleSheetRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 599465D71C4AA87200A2EEF3 /* IJSVGStyleSheetRule.m */; };
|
||||
599465DE1C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 599465D91C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m */; };
|
||||
@@ -42,6 +54,7 @@
|
||||
59A3DA6D1E283022003E59A9 /* IJSVGTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A3DA6C1E283022003E59A9 /* IJSVGTransaction.m */; };
|
||||
59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59B93C6C19B7D1840063E823 /* paperplane.svg */; };
|
||||
59B93C6F19B7D32C0063E823 /* products.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59B93C6E19B7D32C0063E823 /* products.svg */; };
|
||||
59D1E3A0202279CA00C54672 /* Group.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D1E39F202279CA00C54672 /* Group.svg */; };
|
||||
59E0F5ED1E29964700F757F7 /* IJSVGUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E0F5EC1E29964700F757F7 /* IJSVGUnitLength.m */; };
|
||||
59E2645119BA240D008A6FDB /* IJSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E2641C19BA240D008A6FDB /* IJSVG.m */; };
|
||||
59E2645219BA240D008A6FDB /* IJSVGBezierPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E2641E19BA240D008A6FDB /* IJSVGBezierPathAdditions.m */; };
|
||||
@@ -76,6 +89,10 @@
|
||||
59E8ABF31E2167D90032A80C /* IJSVGImageLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E8ABF21E2167D90032A80C /* IJSVGImageLayer.m */; };
|
||||
59E8ABF61E2176340032A80C /* IJSVGGroupLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E8ABF51E2176340032A80C /* IJSVGGroupLayer.m */; };
|
||||
59E8ABF91E219C860032A80C /* IJSVGMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E8ABF81E219C860032A80C /* IJSVGMath.m */; };
|
||||
59EA311622CF395400DAB3B7 /* IJSVGStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA310F22CF395400DAB3B7 /* IJSVGStringAdditions.m */; };
|
||||
59EA311722CF395400DAB3B7 /* IJSVGRendering.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA311022CF395400DAB3B7 /* IJSVGRendering.m */; };
|
||||
59EA311822CF395400DAB3B7 /* IJSVGImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA311322CF395400DAB3B7 /* IJSVGImageRep.m */; };
|
||||
59EA311922CF395400DAB3B7 /* IJSVGView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA311422CF395400DAB3B7 /* IJSVGView.m */; };
|
||||
59F799E219B880CE00096CB7 /* htc_one.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59F799E119B880CE00096CB7 /* htc_one.svg */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -90,6 +107,16 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
343A19161FB2212C000652A2 /* IJSVGGradientUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradientUnitLength.h; sourceTree = "<group>"; };
|
||||
343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGradientUnitLength.m; sourceTree = "<group>"; };
|
||||
59069A2822D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = compuserver_msn_Ford_Focus.svg; sourceTree = "<group>"; };
|
||||
59069A2A22D0EE0E004DDEA5 /* test (1).svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "test (1).svg"; sourceTree = "<group>"; };
|
||||
590C87EA201F9888004A1554 /* json.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = json.svg; sourceTree = "<group>"; };
|
||||
590C87EC201FA08C004A1554 /* intertwingly.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = intertwingly.svg; sourceTree = "<group>"; };
|
||||
590C87EE201FA092004A1554 /* NewTux.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = NewTux.svg; sourceTree = "<group>"; };
|
||||
590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = AJ_Digital_Camera.svg; sourceTree = "<group>"; };
|
||||
590C87F3201FC9E3004A1554 /* radialgradient2.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = radialgradient2.svg; sourceTree = "<group>"; };
|
||||
590C87F5201FD0D4004A1554 /* car.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = car.svg; sourceTree = "<group>"; };
|
||||
591704CA1E2016E400012644 /* IJSVGExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporter.h; sourceTree = "<group>"; };
|
||||
591704CB1E2016E400012644 /* IJSVGExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporter.m; sourceTree = "<group>"; };
|
||||
591A13DF1E19838F001D1629 /* IJSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGText.h; sourceTree = "<group>"; };
|
||||
@@ -130,12 +157,15 @@
|
||||
595665E019B630B600D805FF /* SVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVGView.m; sourceTree = "<group>"; };
|
||||
597046A01E24352700A60138 /* IJSVGStrokeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStrokeLayer.h; sourceTree = "<group>"; };
|
||||
597046A11E24352700A60138 /* IJSVGStrokeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStrokeLayer.m; sourceTree = "<group>"; };
|
||||
597AC83222CFD0FC007C0E42 /* home.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = home.svg; sourceTree = "<group>"; };
|
||||
5986308619BA104800CF15EA /* linecap.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = linecap.svg; sourceTree = "<group>"; };
|
||||
5986308819BA106D00CF15EA /* SVGExampleView5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGExampleView5.h; sourceTree = "<group>"; };
|
||||
5986308919BA106D00CF15EA /* SVGExampleView5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVGExampleView5.m; sourceTree = "<group>"; };
|
||||
5986308B19BA180E00CF15EA /* dashed.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dashed.svg; sourceTree = "<group>"; };
|
||||
598759F41E242C850024CC3F /* IJSVGExporterPathInstruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporterPathInstruction.h; sourceTree = "<group>"; };
|
||||
598759F51E242C850024CC3F /* IJSVGExporterPathInstruction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporterPathInstruction.m; sourceTree = "<group>"; };
|
||||
5991A2A8201E30E600913E3B /* gradients.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = gradients.svg; sourceTree = "<group>"; };
|
||||
5991A2AA201E310200913E3B /* heart.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = heart.svg; sourceTree = "<group>"; };
|
||||
599465D41C4AA87200A2EEF3 /* IJSVGStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheet.h; sourceTree = "<group>"; };
|
||||
599465D51C4AA87200A2EEF3 /* IJSVGStyleSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheet.m; sourceTree = "<group>"; };
|
||||
599465D61C4AA87200A2EEF3 /* IJSVGStyleSheetRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetRule.h; sourceTree = "<group>"; };
|
||||
@@ -154,6 +184,7 @@
|
||||
59A3DA6C1E283022003E59A9 /* IJSVGTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGTransaction.m; sourceTree = "<group>"; };
|
||||
59B93C6C19B7D1840063E823 /* paperplane.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = paperplane.svg; sourceTree = "<group>"; };
|
||||
59B93C6E19B7D32C0063E823 /* products.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = products.svg; sourceTree = "<group>"; };
|
||||
59D1E39F202279CA00C54672 /* Group.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Group.svg; sourceTree = "<group>"; };
|
||||
59E0F5EB1E29964700F757F7 /* IJSVGUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitLength.h; sourceTree = "<group>"; };
|
||||
59E0F5EC1E29964700F757F7 /* IJSVGUnitLength.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitLength.m; sourceTree = "<group>"; };
|
||||
59E2641B19BA240D008A6FDB /* IJSVG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVG.h; sourceTree = "<group>"; };
|
||||
@@ -222,6 +253,14 @@
|
||||
59E8ABF51E2176340032A80C /* IJSVGGroupLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroupLayer.m; sourceTree = "<group>"; };
|
||||
59E8ABF71E219C860032A80C /* IJSVGMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGMath.h; sourceTree = "<group>"; };
|
||||
59E8ABF81E219C860032A80C /* IJSVGMath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGMath.m; sourceTree = "<group>"; };
|
||||
59EA310E22CF395300DAB3B7 /* IJSVGImageRep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImageRep.h; sourceTree = "<group>"; };
|
||||
59EA310F22CF395400DAB3B7 /* IJSVGStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStringAdditions.m; sourceTree = "<group>"; };
|
||||
59EA311022CF395400DAB3B7 /* IJSVGRendering.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRendering.m; sourceTree = "<group>"; };
|
||||
59EA311122CF395400DAB3B7 /* IJSVGRendering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRendering.h; sourceTree = "<group>"; };
|
||||
59EA311222CF395400DAB3B7 /* IJSVGView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGView.h; sourceTree = "<group>"; };
|
||||
59EA311322CF395400DAB3B7 /* IJSVGImageRep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImageRep.m; sourceTree = "<group>"; };
|
||||
59EA311422CF395400DAB3B7 /* IJSVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGView.m; sourceTree = "<group>"; };
|
||||
59EA311522CF395400DAB3B7 /* IJSVGStringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStringAdditions.h; sourceTree = "<group>"; };
|
||||
59F799E119B880CE00096CB7 /* htc_one.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = htc_one.svg; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -291,6 +330,18 @@
|
||||
5956657A19B62F4600D805FF /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59069A2A22D0EE0E004DDEA5 /* test (1).svg */,
|
||||
59069A2822D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg */,
|
||||
597AC83222CFD0FC007C0E42 /* home.svg */,
|
||||
59D1E39F202279CA00C54672 /* Group.svg */,
|
||||
590C87F5201FD0D4004A1554 /* car.svg */,
|
||||
590C87F3201FC9E3004A1554 /* radialgradient2.svg */,
|
||||
590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */,
|
||||
590C87EC201FA08C004A1554 /* intertwingly.svg */,
|
||||
590C87EE201FA092004A1554 /* NewTux.svg */,
|
||||
590C87EA201F9888004A1554 /* json.svg */,
|
||||
5991A2AA201E310200913E3B /* heart.svg */,
|
||||
5991A2A8201E30E600913E3B /* gradients.svg */,
|
||||
59265CE71C4F840400F333F0 /* css.svg */,
|
||||
59459CEB19B906FE00CE493B /* clipped.svg */,
|
||||
59F799E119B880CE00096CB7 /* htc_one.svg */,
|
||||
@@ -335,6 +386,14 @@
|
||||
59E2641A19BA240D008A6FDB /* source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59EA310E22CF395300DAB3B7 /* IJSVGImageRep.h */,
|
||||
59EA311322CF395400DAB3B7 /* IJSVGImageRep.m */,
|
||||
59EA311122CF395400DAB3B7 /* IJSVGRendering.h */,
|
||||
59EA311022CF395400DAB3B7 /* IJSVGRendering.m */,
|
||||
59EA311522CF395400DAB3B7 /* IJSVGStringAdditions.h */,
|
||||
59EA310F22CF395400DAB3B7 /* IJSVGStringAdditions.m */,
|
||||
59EA311222CF395400DAB3B7 /* IJSVGView.h */,
|
||||
59EA311422CF395400DAB3B7 /* IJSVGView.m */,
|
||||
59A3DA6B1E283022003E59A9 /* IJSVGTransaction.h */,
|
||||
59A3DA6C1E283022003E59A9 /* IJSVGTransaction.m */,
|
||||
598759F41E242C850024CC3F /* IJSVGExporterPathInstruction.h */,
|
||||
@@ -392,6 +451,8 @@
|
||||
59E2643C19BA240D008A6FDB /* IJSVGForeignObject.m */,
|
||||
59E2643D19BA240D008A6FDB /* IJSVGGradient.h */,
|
||||
59E2643E19BA240D008A6FDB /* IJSVGGradient.m */,
|
||||
343A19161FB2212C000652A2 /* IJSVGGradientUnitLength.h */,
|
||||
343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */,
|
||||
59E2643F19BA240D008A6FDB /* IJSVGGroup.h */,
|
||||
59E2644019BA240D008A6FDB /* IJSVGGroup.m */,
|
||||
59E2644119BA240D008A6FDB /* IJSVGLinearGradient.h */,
|
||||
@@ -483,7 +544,7 @@
|
||||
5956656F19B62F4600D805FF /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0600;
|
||||
LastUpgradeCheck = 0920;
|
||||
ORGANIZATIONNAME = "Curtis Hard";
|
||||
TargetAttributes = {
|
||||
5956657619B62F4600D805FF = {
|
||||
@@ -500,6 +561,7 @@
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
@@ -521,13 +583,25 @@
|
||||
files = (
|
||||
59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */,
|
||||
5956658219B62F4600D805FF /* Images.xcassets in Resources */,
|
||||
590C87ED201FA08C004A1554 /* intertwingly.svg in Resources */,
|
||||
590C87F1201FBF27004A1554 /* AJ_Digital_Camera.svg in Resources */,
|
||||
59069A2B22D0EE0E004DDEA5 /* test (1).svg in Resources */,
|
||||
590C87EF201FA093004A1554 /* NewTux.svg in Resources */,
|
||||
59265CE81C4F840400F333F0 /* css.svg in Resources */,
|
||||
595665DE19B6309C00D805FF /* test.svg in Resources */,
|
||||
597AC83322CFD0FC007C0E42 /* home.svg in Resources */,
|
||||
590C87EB201F9888004A1554 /* json.svg in Resources */,
|
||||
59D1E3A0202279CA00C54672 /* Group.svg in Resources */,
|
||||
59F799E219B880CE00096CB7 /* htc_one.svg in Resources */,
|
||||
59B93C6F19B7D32C0063E823 /* products.svg in Resources */,
|
||||
5991A2A9201E30E600913E3B /* gradients.svg in Resources */,
|
||||
59069A2922D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg in Resources */,
|
||||
5986308719BA104800CF15EA /* linecap.svg in Resources */,
|
||||
5956658519B62F4600D805FF /* MainMenu.xib in Resources */,
|
||||
590C87F4201FC9E4004A1554 /* radialgradient2.svg in Resources */,
|
||||
59459CEC19B906FE00CE493B /* clipped.svg in Resources */,
|
||||
590C87F6201FD0D4004A1554 /* car.svg in Resources */,
|
||||
5991A2AB201E310200913E3B /* heart.svg in Resources */,
|
||||
5986308C19BA180E00CF15EA /* dashed.svg in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -550,6 +624,7 @@
|
||||
59E2646919BA240D008A6FDB /* IJSVGStyle.m in Sources */,
|
||||
59E2646419BA240D008A6FDB /* IJSVGLinearGradient.m in Sources */,
|
||||
595665DC19B6302600D805FF /* README.md in Sources */,
|
||||
59EA311922CF395400DAB3B7 /* IJSVGView.m in Sources */,
|
||||
5941DAFD1CF9BC9B00B3A911 /* IJSVGImage.m in Sources */,
|
||||
599465DE1C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m in Sources */,
|
||||
5948DED61BB2BFE5004156FF /* IJSVGWriter.m in Sources */,
|
||||
@@ -557,6 +632,7 @@
|
||||
5986308A19BA106D00CF15EA /* SVGExampleView5.m in Sources */,
|
||||
59E2645619BA240D008A6FDB /* IJSVGCommandArc.m in Sources */,
|
||||
59E8ABF91E219C860032A80C /* IJSVGMath.m in Sources */,
|
||||
343A19181FB2212C000652A2 /* IJSVGGradientUnitLength.m in Sources */,
|
||||
59265CEB1C4F843E00F333F0 /* SVGExampleView6.m in Sources */,
|
||||
5941DAFE1CF9BC9B00B3A911 /* IJSVGPattern.m in Sources */,
|
||||
59E8ABF01E211EDB0032A80C /* IJSVGShapeLayer.m in Sources */,
|
||||
@@ -577,6 +653,7 @@
|
||||
5956658019B62F4600D805FF /* AppDelegate.m in Sources */,
|
||||
59E2646519BA240D008A6FDB /* IJSVGNode.m in Sources */,
|
||||
591A13E11E19838F001D1629 /* IJSVGText.m in Sources */,
|
||||
59EA311822CF395400DAB3B7 /* IJSVGImageRep.m in Sources */,
|
||||
59A11E6C19B89CEA00E44498 /* SVGExampleView1.m in Sources */,
|
||||
59A3DA6D1E283022003E59A9 /* IJSVGTransaction.m in Sources */,
|
||||
59E2646A19BA240D008A6FDB /* IJSVGTransform.m in Sources */,
|
||||
@@ -588,6 +665,7 @@
|
||||
598759F61E242C850024CC3F /* IJSVGExporterPathInstruction.m in Sources */,
|
||||
59E2645E19BA240D008A6FDB /* IJSVGCommandSmoothCurve.m in Sources */,
|
||||
59E2645819BA240D008A6FDB /* IJSVGCommandCommandSmoothQuadraticCurve.m in Sources */,
|
||||
59EA311622CF395400DAB3B7 /* IJSVGStringAdditions.m in Sources */,
|
||||
59E2645D19BA240D008A6FDB /* IJSVGCommandQuadraticCurve.m in Sources */,
|
||||
59E2646719BA240D008A6FDB /* IJSVGPath.m in Sources */,
|
||||
59E8ABED1E211EBE0032A80C /* IJSVGLayer.m in Sources */,
|
||||
@@ -596,6 +674,7 @@
|
||||
59A11E7219B89D6600E44498 /* SVGExampleView3.m in Sources */,
|
||||
59E0F5ED1E29964700F757F7 /* IJSVGUnitLength.m in Sources */,
|
||||
5956657D19B62F4600D805FF /* main.m in Sources */,
|
||||
59EA311722CF395400DAB3B7 /* IJSVGRendering.m in Sources */,
|
||||
59A11E6F19B89D2000E44498 /* SVGExampleView2.m in Sources */,
|
||||
5948DED51BB2BFE5004156FF /* IJSVGFontConverter.m in Sources */,
|
||||
59E2646319BA240D008A6FDB /* IJSVGGroup.m in Sources */,
|
||||
@@ -676,7 +755,7 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx10.12;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -712,7 +791,7 @@
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx10.12;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
|
||||
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
|
||||
"D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596" : 0,
|
||||
"91965C60FB9217304DAC6A57C88233440365843F" : 9223372036854775807
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "83EE8FFF-CAF0-4D33-92A0-4CA5D3A6A33C",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
||||
"D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596" : "IJSVG\/",
|
||||
"91965C60FB9217304DAC6A57C88233440365843F" : "..\/..\/.."
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "IJSVGExample",
|
||||
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
|
||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "IJSVGExample\/IJSVGExample.xcodeproj",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/daveyheuser\/Iconjar-mac.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "91965C60FB9217304DAC6A57C88233440365843F"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/curthard89\/IJSVG.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
uuid = "21141E92-29FD-4CF6-AB04-0D4E4FD9A4AC"
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
</Bucket>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0600"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -37,10 +37,11 @@
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -62,17 +63,22 @@
|
||||
ReferencedContainer = "container:IJSVGExample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "5956657619B62F4600D805FF"
|
||||
@@ -85,12 +91,13 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "5956657619B62F4600D805FF"
|
||||
|
||||
|
After Width: | Height: | Size: 515 KiB |
@@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14835.7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14835.7"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@@ -666,23 +667,24 @@
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
<point key="canvasLocation" x="139" y="154"/>
|
||||
</menu>
|
||||
<window title="IJSVGExample" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
|
||||
<window title="IJSVGExample" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" appearanceType="aqua" animationBehavior="default" id="QvC-M9-y7g">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="335" y="390" width="556" height="679"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
|
||||
<rect key="contentRect" x="335" y="390" width="600" height="479"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3008" height="1669"/>
|
||||
<view key="contentView" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="556" height="679"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="479"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView misplaced="YES" id="hhC-1S-CCX" customClass="SVGView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="556" height="679"/>
|
||||
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hhC-1S-CCX" customClass="SVGView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="479"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
</view>
|
||||
<point key="canvasLocation" x="550" y="495.5"/>
|
||||
<point key="canvasLocation" x="98" y="496.5"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="193px" height="172px" viewBox="0 0 193 172" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group">
|
||||
<rect id="Rectangle-Copy" fill="#E80000" x="53" y="41" width="140" height="131"></rect>
|
||||
<rect id="Rectangle" fill="#1813DF" x="0" y="0" width="140" height="131"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 679 B |
@@ -0,0 +1,72 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500pt" height="800">
|
||||
<defs>
|
||||
<linearGradient id="a">
|
||||
<stop offset="0" stop-color="#3f2600" stop-opacity=".6"/>
|
||||
<stop offset="1" stop-color="#3f2600" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="d">
|
||||
<stop offset="0" stop-color="#fff" stop-opacity=".65"/>
|
||||
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="e">
|
||||
<stop offset="0" stop-color="#ffa63f"/>
|
||||
<stop offset="1" stop-color="#ff0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="b">
|
||||
<stop offset="0" stop-color="#ffeed7"/>
|
||||
<stop offset="1" stop-color="#bdbfc2"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="c">
|
||||
<stop offset="0" stop-color="#fff" stop-opacity=".8"/>
|
||||
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="f" cx="446.77762" cy="1219.4125" r="195.07191" fx="446.77762" fy="1219.4125" gradientTransform="scale(1.04523 .95673)" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="g" x1="400.57785" x2="400.84448" y1="369.53015" y2="304.07886" gradientTransform="scale(.57526 1.73834)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
|
||||
<linearGradient id="h" x1="303.01761" x2="297.0856" y1="237.93179" y2="330.09561" gradientTransform="scale(1.11607 .896)" gradientUnits="userSpaceOnUse" xlink:href="#c"/>
|
||||
<linearGradient id="i" x1="378.93771" x2="380.27319" y1="278.60202" y2="243.91606" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
|
||||
<linearGradient id="j" x1="381.38742" x2="380.5517" y1="277.495" y2="245.68338" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
|
||||
<linearGradient id="k" x1="379.09573" x2="376.79556" y1="240.92712" y2="281.01636" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="l" x1="389.63535" x2="387.06866" y1="242.28218" y2="281.32513" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="m" x1="437.57941" x2="437.57941" y1="528.87177" y2="394.10361" gradientTransform="scale(.81285 1.23023)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" xlink:href="#b"/>
|
||||
<linearGradient id="n" x1="375.17325" x2="377.48541" y1="419.78485" y2="324.03815" gradientTransform="scale(.64978 1.53897)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
|
||||
<linearGradient id="o" x1="320.75104" x2="321.32224" y1="498.17776" y2="614.50439" gradientTransform="scale(1.0748 .9304)" gradientUnits="userSpaceOnUse" xlink:href="#c"/>
|
||||
<linearGradient id="p" x1="322.48257" x2="323.2514" y1="435.26761" y2="488.48251" gradientTransform="scale(1.077 .9285)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="q" x1="411.2215" x2="411.2215" y1="242.94365" y2="331.44858" gradientTransform="scale(.5717 1.74915)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="r" x1="867.34546" x2="867.33453" y1="234.73897" y2="314.83911" gradientTransform="scale(.57267 1.74621)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="s" x1="236.25362" x2="212.5099" y1="657.11133" y2="737.41229" gradientTransform="scale(1.01151 .98862)" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
|
||||
<linearGradient id="t" x1="381.56607" x2="279.64313" y1="655.73102" y2="386.66583" gradientTransform="scale(1.0655 .93853)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
|
||||
<linearGradient id="u" x1="218.11714" x2="203.12654" y1="630.30475" y2="737.8537" gradientTransform="scale(1.00985 .99025)" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
|
||||
<linearGradient id="v" x1="117.88966" x2="182.24524" y1="587.23602" y2="704.73077" gradientTransform="scale(1.00772 .99233)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="w" x1="223.10072" x2="230.53499" y1="570.41809" y2="710.97723" gradientTransform="scale(.9995 1.0005)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="x" x1="316.93988" x2="371.60889" y1="474.01779" y2="582.63507" gradientTransform="scale(1.0655 .93853)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
<linearGradient id="y" x1="284.68652" x2="285.45923" y1="410.46326" y2="485.69934" gradientTransform="scale(1.21868 .82056)" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
|
||||
<linearGradient id="z" x1="288.82358" x2="288.37628" y1="398.85422" y2="482.55939" gradientTransform="scale(1.22194 .81837)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
|
||||
</defs>
|
||||
<path fill="url(#f)" d="M670.88202 1166.6423a203.89551 186.63016 0 1 1-407.79102 0 203.89551 186.63016 0 1 1 407.79102 0z" transform="matrix(1.4177 0 0 .41474 -349.5468 157.94132)"/>
|
||||
<path d="M154.23535 558.54232c-27.985-40.27875-33.4425-171.23 31.85875-251.7875 32.3575-38.6475 40.6125-65.58125 43.16375-101.74125 1.73625-41.22375-29.15625-164.3025 87.35375-173.68 118.0075-9.415 111.67 107.075 110.99125 168.71875-.56375 52.05 38.2175 81.55125 64.745 122.11875 49.09875 74.5375 44.94625 202.875-9.24875 272.34-68.64625 86.96-127.44125 49.2475-166.4875 52.4125-73.11625 4.0025-75.53375 42.98875-162.37625-88.38125z"/>
|
||||
<path fill="url(#g)" d="M246.571 470.864c-12.239 12.496-44.396 69.092 4.869 105.36 17.369 12.633-16.377 59.495-32.005 36.308-27.57-41.618-8.831-106.941 8.315-130.188 11.652-16.487 29.23-22.676 18.821-11.48z" transform="matrix(-1.67739 -.02245 -.02112 1.4709 862.8276 -357.26968)"/>
|
||||
<path stroke="#000" stroke-width=".97729802" d="M256.513 459.837c-19.915 17.717-56.176 80.091-3.288 120.606 17.37 12.632-15.393 52.463-33.79 32.089-63.963-70.82 1.669-152.254 24.262-180.25 20.192-24.347 38.078 5.752 12.816 27.555z" transform="matrix(-1.67755 0 0 1.52374 863.8676 -382.33468)"/>
|
||||
<path fill="url(#h)" d="M399.56879 258.15753a58.37323 46.863022 0 1 1-116.74646 0 58.37323 46.863022 0 1 1 116.74646 0z" transform="matrix(1.26626 -.07137 -.04598 1.19574 -108.6094 -190.01368)"/>
|
||||
<path fill="url(#i)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(1.30445 -.07553 .07713 1.34257 -165.9954 -241.86968)"/>
|
||||
<path fill="url(#j)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(-1.81082 .04951 .03173 1.55333 896.7076 -349.02968)"/>
|
||||
<path d="M326.35672821 170.5767474a14.88487384 23.14205282 2.00317994 1 0 29.77908237.06371242 14.88487384 23.14205282 2.00317994 1 0-29.77908237-.06371242zm-52.12561644.13467082a10.82556484 19.2435689-4.93566296 1 1-21.50167273 2.6153013 10.82556484 19.2435689-4.93566296 1 1 21.50167273-2.6153013z"/>
|
||||
<path fill="url(#k)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(-.48032 -.03645 -.0468 .4756 502.7436 22.75972)"/>
|
||||
<path fill="url(#l)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(.35691 -.04082 .04132 .39854 138.5816 50.73832)"/>
|
||||
<path fill="url(#m)" d="M258.702 495.425c12.836-29.103 40.114-80.226 40.695-119.758 0-31.442 94.179-38.951 101.737-7.558 7.558 31.393 26.741 78.483 38.95 101.156 12.208 22.672 47.809 94.695 9.884 157.546-34.157 55.644-137.725 99.666-193.01-7.557-18.603-37.207-15.285-83.315 1.744-123.829z" transform="matrix(1.25 0 0 1.25 -125.2984 -232.48268)"/>
|
||||
<path fill="url(#n)" d="M242.905 473.815c-11.263 18.967-35.5 69.309 12.137 102.047 51.311 34.82 46.473 97.062-15.607 61.955-56.777-31.789-22.845-137.778-4.51-162.266 12.107-17.214 29.897-38.031 7.98-1.736z" transform="matrix(1.38936 -.11107 .10221 1.30214 -202.3394 -230.19068)"/>
|
||||
<path stroke="#000" stroke-width="1.5625" d="M195.34285 330.39232c-21.83125 35.635-74.22125 119.76625-4.11 163.40375 94.46125 57.94375 67.71625 115.88875-18.49875 63.7175-121.38625-72.83-14.78125-219.52 33.91375-275.4225 55.555-62.75 10.6925 11.35875-11.305 48.30125z"/>
|
||||
<path fill="url(#o)" d="M421.481 504.727c0 32.412-29.272 74.516-79.528 74.138-51.828.455-73.949-41.726-73.949-74.138 0-32.412 34.379-58.717 76.739-58.717 42.359 0 76.738 26.305 76.738 58.717z" font-size="12" transform="matrix(1.30209 0 0 1.22525 -140.7104 -217.80968)"/>
|
||||
<path fill="url(#p)" d="M398.227 412.292c-.612 38.572-23.18 47.671-51.74 47.671-28.561 0-49.292-5.694-51.741-47.671 0-26.314 23.18-41.542 51.741-41.542 28.56 0 51.74 15.228 51.74 41.542z" font-size="12" transform="matrix(1.1868 0 0 1.06708 -100.1294 -164.33068)"/>
|
||||
<path fill="url(#q)" d="M234.285 456.475c17.716-26.996 55.015-68.364 6.977 5.813-38.951 61.043-14.403 100.273-1.744 111.039 36.527 32.562 34.966 54.349 6.395 37.206-61.625-36.626-48.835-98.248-11.628-154.058z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
|
||||
<path fill="url(#r)" d="M490.662 467.52c-15.319-31.701-64.134-111.902 2.326-18.603 60.461 84.297 18.022 143.013 10.464 148.827-7.557 5.813-33.137 17.44-25.579-2.907 7.557-20.347 45.234-58.973 12.789-127.317z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
|
||||
<path fill="url(#s)" stroke="#e68c3f" stroke-width="6.25" d="M220.915 716.921c-40.442-21.416-99.252 4.124-77.902-54.066 4.276-13.238-6.375-33.008.581-45.926 8.139-15.698 25.58-12.209 36.045-22.674 10.318-10.891 16.859-29.649 36.044-26.742 19.184 2.907 31.945 26.461 45.344 55.229 9.883 20.638 44.941 49.664 42.65 72.758-2.696 35.5-43.027 42.19-82.762 21.421z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
|
||||
<path fill="url(#t)" d="M415.072 495.764c-3.007 24.906-35.813 76.627-69.518 81.534-34.26 5.336-66.432-34.06-74.147-71.114-9.889-41.206 22.587-57.6 71.938-56.627 53.301 1.654 74.121 13.891 71.727 46.207z" font-size="12" transform="matrix(.5982 .26858 -.23962 .61721 389.8156 76.21132)"/>
|
||||
<path fill="url(#u)" stroke="#e68c3f" stroke-width="6.25067997" d="M220.274 718.402c-41.327-23.59-99.894 5.605-77.261-55.547 4.736-13.068-6.596-33.552.36-46.47 8.139-15.698 25.801-11.665 36.266-22.13 10.318-10.891 18.827-27.868 38.012-24.961 19.184 2.907 29.977 24.68 43.376 53.448 9.883 20.638 43.415 48.971 41.124 72.065-2.696 35.5-42.724 45.471-81.877 23.595z" transform="matrix(-1.1685 .42314 .47528 1.16478 417.5906 -278.07368)"/>
|
||||
<path fill="url(#v)" d="M216.482 675.68c-86.531-57.503-47.308-70.96-36.843-81.425 10.318-10.891 18.827-27.868 38.012-24.961 19.184 2.907 29.977 24.68 43.376 53.448 9.883 20.638 43.06 48.918 41.124 72.065-2.616 27.11-48.19 5.487-85.669-19.127z" transform="matrix(-.9451 .34375 .42408 .95606 403.5756 -128.59468)"/>
|
||||
<path fill="url(#w)" d="M216.506 677.071c-86.531-57.503-46.797-73.57-33.946-81.28 15.399-9.942 15.158-30.831 34.343-27.924 19.184 2.907 30.725 26.107 44.124 54.875 9.883 20.638 43.06 48.918 41.124 72.065-2.616 27.11-48.166 6.878-85.645-17.736z" transform="matrix(1.00431 -.05229 -.0174 1.04575 -66.5614 -92.71798)"/>
|
||||
<path d="M514.16392618 492.89388153c-6.69409764 11.6729672-34.29007759 30.19600752-52.6812594 25.36804862-18.76593057-4.73521422-27.21700072-31.1485461-23.54211688-51.13877146 3.41150018-22.51206827 23.54139341-23.63093696 48.7850296-12.52637614 27.13954878 12.29170413 35.346749 22.8266733 27.43834668 38.29709898z" font-size="12"/>
|
||||
<path fill="url(#x)" d="M415.072 495.764c-3.007 24.906-35.813 76.627-69.518 81.534-34.26 5.336-66.432-34.06-74.147-71.114-9.889-41.206 22.587-57.6 71.938-56.627 53.301 1.654 74.121 13.891 71.727 46.207z" font-size="12" transform="matrix(.35123 .14946 -.12886 .34347 413.7696 254.03832)"/>
|
||||
<path fill="url(#y)" stroke="#e68c3f" stroke-width="3.75" d="M309.954 338.729c7.147-6.77 24.811-27.066 57.961-5.755 6.162 4.01 11.162 4.377 23.021 9.455 23.726 9.749 12.382 33.259-12.744 41.108-10.758 3.489-20.536 16.556-40.129 15.439-16.734-.977-21.119-11.874-31.398-17.906-18.269-10.311-20.965-24.254-11.1-31.653 9.866-7.399 13.725-10.059 14.389-10.688z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
|
||||
<path fill="none" stroke="#e68c3f" stroke-width="3.125" d="M363.76535 215.29857c-12.35375.72625-39.24125 27.61375-67.5825 27.61375-28.34125 0-45.055-26.16125-49.415-26.16125"/>
|
||||
<path fill="url(#z)" d="M309.954 338.729c7.147-6.77 29.691-25.348 59.588-6.328 6.299 3.766 12.804 7.865 22.478 13.464 19.162 11.748 9.671 28.678-13.286 39.39-10.418 4.495-27.593 14.415-40.671 13.721-14.533-1.408-23.935-11.399-33.567-17.906-17.67-12.303-16.597-22.237-8.389-30.508 6.205-5.679 13.183-11.204 13.847-11.833z" transform="matrix(.62789 0 0 .59567 81.6136 -12.43538)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="447px" height="336px" viewBox="0 0 447 336" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Rectangle</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
|
||||
<stop stop-color="#1E54F6" offset="0%"></stop>
|
||||
<stop stop-color="#EE2323" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<rect id="path-2" x="0" y="0" width="447" height="336"></rect>
|
||||
</defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Rectangle">
|
||||
<use fill="#D8D8D8" fill-rule="evenodd" xlink:href="#path-2"></use>
|
||||
<rect stroke="url(#linearGradient-1)" stroke-width="10" x="5" y="5" width="437" height="326"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 992 B |
@@ -12,7 +12,7 @@
|
||||
|
||||
- (IJSVG *)svg
|
||||
{
|
||||
return [[IJSVG svgNamed:@"paperplane"] retain];
|
||||
return [[IJSVG svgNamed:@"heart"] retain];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
|
||||
@interface SVGView : NSView {
|
||||
|
||||
@private
|
||||
IJSVG * svg;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
if( ( self = [super initWithFrame:frameRect] ) != nil )
|
||||
{
|
||||
svg = [self svg];
|
||||
svg.renderQuality = IJSVGRenderQualityFullResolution;
|
||||
svg.renderingBackingScaleHelper = ^{
|
||||
return [svg computeBackingScale:self.window.backingScaleFactor];
|
||||
return self.window.backingScaleFactor;
|
||||
};
|
||||
}
|
||||
return self;
|
||||
@@ -31,7 +32,7 @@
|
||||
|
||||
- (IJSVG *)svg
|
||||
{
|
||||
return [[IJSVG svgNamed:@"test"] retain];
|
||||
return [IJSVG svgNamed:@"test (1)"];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
|
||||
|
After Width: | Height: | Size: 515 KiB |
|
After Width: | Height: | Size: 318 KiB |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="595.279px" height="841.89px" viewBox="0 0 595.279 841.89" enable-background="new 0 0 595.279 841.89"
|
||||
xml:space="preserve">
|
||||
<radialGradient id="SVGID_1_" cx="229.116" cy="650.3413" r="160.6544" gradientTransform="matrix(0.1736 0.9848 0.4924 -0.0868 -59.0956 137.9539)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.0573" style="stop-color:#CECECE"/>
|
||||
<stop offset="0.1221" style="stop-color:#9E9E1F"/>
|
||||
<stop offset="0.1907" style="stop-color:#74D974"/>
|
||||
<stop offset="0.2638" style="stop-color:#5050D1"/>
|
||||
<stop offset="0.5767" style="stop-color:#D44033"/>
|
||||
<stop offset="0.6687" style="stop-color:#D000FF"/>
|
||||
<stop offset="0.773" style="stop-color:#0C0CE3"/>
|
||||
<stop offset="0.8528" style="stop-color:#030303"/>
|
||||
<stop offset="0.9632" style="stop-color:#000000"/>
|
||||
</radialGradient>
|
||||
<ellipse fill="url(#SVGID_1_)" stroke="#000000" stroke-miterlimit="10" cx="251.667" cy="315.818" rx="185.064" ry="131.819"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf8" standalone="no"?>
|
||||
<svg viewBox="0 0 372.77139 350.83377" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<clipPath id="clipPath4110">
|
||||
<path d="m1349.1479-106.15129v-302.89728c-47.8699-80.88268-146.0391-44.39418-170.2081,0-74.5507,130.56653 130.5076,196.53622 170.2081,302.89728z"/>
|
||||
<path d="m1349.1479-106.15129v-302.89728c47.8699-80.88268 146.0391-44.39418 170.2081,0 74.5507,130.56653-130.5076,196.53622-170.2081,302.89728z"/>
|
||||
</clipPath>
|
||||
<filter height="1.35511" id="filter4031" width="1.33422" x="-.16711" y="-.17756">
|
||||
<feGaussianBlur stdDeviation="25.9554"/>
|
||||
</filter>
|
||||
<linearGradient id="linearGradient4159">
|
||||
<stop offset="0" stop-color="#fff"/>
|
||||
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient4169" x2="0" xlink:href="#linearGradient4159" y1="386.94983" y2="490.03617"/>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient4165" x2="0" xlink:href="#linearGradient4159" y1="387.32314" y2="490.40948"/>
|
||||
</defs>
|
||||
<g transform="translate(-202.18571,-396.94529)">
|
||||
<g clip-path="url(#clipPath4110)" transform="translate(-960.57649,853.93036)">
|
||||
<path d="m1349.1479-106.15129v-302.89728c-47.8699-80.88268-146.0391-44.39418-170.2081,0-74.5507,130.56653 130.5076,196.53622 170.2081,302.89728z"/>
|
||||
<path d="m1349.1479-106.15129v-302.89728c47.8699-80.88268 146.0391-44.39418 170.2081,0 74.5507,130.56653-130.5076,196.53622-170.2081,302.89728z"/>
|
||||
</g>
|
||||
<g clip-path="url(#clipPath4110)" fill="#f00" filter="url(#filter4031)" transform="translate(-960.57649,853.93036)">
|
||||
<path d="m1349.1479-106.15129v-302.89728c-47.8699-80.88268-146.0391-44.39418-170.2081,0-74.5507,130.56653 130.5076,196.53622 170.2081,302.89728z" fill="#f00"/>
|
||||
<path d="m1349.1479-106.15129v-302.89728c47.8699-80.88268 146.0391-44.39418 170.2081,0 74.5507,130.56653-130.5076,196.53622-170.2081,302.89728z" fill="#f00"/>
|
||||
</g>
|
||||
<path d="m370.99493,455.63757c0,30.71925-28.70788,20.90496-64.58143,20.90496s-65.328,9.81429-65.328-20.90496 29.08123-55.62213 64.95466-55.62213 64.95477,24.90287 64.95477,55.62213z" fill="url(#linearGradient4165)"/>
|
||||
<path d="m535.62152,455.26427c0,30.71925-28.7079,20.90496-64.5815,20.90496s-65.328,9.81429-65.328-20.90496 29.0813-55.62213 64.9547-55.62213 64.9548,24.90287 64.9548,55.62213z" fill="url(#linearGradient4169)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="508" height="508" version="1.1" viewBox="0 0 508 508" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!--Generated by IJSVG (https://github.com/iconjar/IJSVG)-->
|
||||
<defs>
|
||||
<linearGradient id="a" x1="0.145454" x2="0.599999" y1="0.257812" y2="0.570312" gradientTransform="matrix(1,0,0,1,-7.61378e-09,-1.86769e-08)">
|
||||
<stop offset="0%" stop-color="#FBDDB2" stop-opacity="0.99"></stop>
|
||||
<stop offset="100%" stop-color="#EFA81A" stop-opacity="0.95"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient id="b" x1="-0.0270271" x2="0.783784" y1="0.46875" y2="0.476562" gradientTransform="matrix(1,0,0,1,3.52391e-08,-2.90476e-08)">
|
||||
<stop offset="0%" stop-color="#787878" stop-opacity="0.99"></stop>
|
||||
<stop offset="100%" stop-color="#FFF" stop-opacity="0.99"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient id="c" x1="0.235289" x2="0.672269" y1="0.265619" y2="0.59375" gradientTransform="matrix(1,0,0,1,1.18803e-07,-1.01189e-08)" xlink:href="#b"></linearGradient>
|
||||
<linearGradient id="d" x1="0.981639" x2="0.146789" y1="0.0312495" y2="0.601562" gradientTransform="matrix(1,0,0,1,-5.18186e-08,1.7497e-08)" xlink:href="#b"></linearGradient>
|
||||
<linearGradient id="e" x1="1.20507" x2="0.102482" y1="0.523438" y2="0.515617" gradientTransform="matrix(1,0,0,1,8.20491e-05,8.70101e-06)" xlink:href="#b"></linearGradient>
|
||||
<radialGradient id="f" fx="-0.0123102%" fy="-0.0135221%" cx="-0.000123102" cy="-0.000135221" r="0.981982" gradientTransform="matrix(0.897766,0,0,1.11388,0.194914,0.125151)" xlink:href="#a"></radialGradient>
|
||||
<linearGradient id="g" x1="0.242009" x2="0.497717" y1="0.382812" y2="0.507812" gradientTransform="matrix(1,0,0,1,5.50934e-10,1.51001e-09)">
|
||||
<stop offset="0%" stop-color="#CA536D" stop-opacity="0.99"></stop>
|
||||
<stop offset="100%" stop-color="#A81837" stop-opacity="0.95"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="scale(1.00011)">
|
||||
<path fill="url(#a)" fill-rule="evenodd" stroke="#580400" stroke-width="11.905" d="M126.604,52.0403h51.3235v120.598h-51.3235Z"></path>
|
||||
<path fill="none" fill-rule="evenodd" stroke="#154850" stroke-linejoin="round" stroke-width="11.905" d="M111.364,481.507c270.797,-1.602 272.4,0 272.4,0l-1.603,-227.534l-134.597,-132.995l-134.598,136.2c-1.603,1.602 1.42109e-14,222.727 -1.602,224.329Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
|
||||
<path fill="url(#b)" fill-rule="evenodd" d="M117.773,475.097c59.287,0 59.287,-1.602 59.287,-1.602c0,0 0,-171.451 0,-171.451c0,0 -57.685,-43.264 -57.685,-43.264c-3.205,1.602 -1.602,217.92 -1.602,216.317Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
|
||||
<path fill="url(#c)" fill-rule="evenodd" d="M117.773,258.78l124.983,-126.586l28.844,84.924l-94.54,84.926l-59.287,-43.264Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
|
||||
<path fill="url(#d)" fill-rule="evenodd" d="M229.938,205.902l22.433,-75.31l123.381,124.983l-59.288,51.275l-86.526,-100.948Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
|
||||
<path fill="url(#e)" fill-rule="evenodd" d="M314.862,475.098l-1.602,-173.054l64.094,-48.071l1.603,221.125h-64.095Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
|
||||
<path fill="url(#f)" fill-rule="evenodd" stroke="#580400" stroke-linejoin="round" stroke-width="11.9213" d="M177.06,486.314l-1.602,-153.826c0,-36.854 20.029,-62.491 62.491,-62.491c44.065,0 65.697,30.444 65.697,62.491v153.826c0,0 -126.586,-1.602 -126.586,0Z" transform="matrix(1.07519,0,0,1.07519,-5.19257,-47.0224)"></path>
|
||||
<path fill="url(#g)" fill-rule="evenodd" stroke="#580400" stroke-width="11.905" d="M63.293,303.646c150.621,-144.212 150.621,-144.212 150.621,-144.212c0,0 68.901,-1.602 70.503,-1.602c1.603,0 139.405,137.802 139.405,137.802c0,0 32.048,-33.649 32.048,-33.649c0,0 -206.704,-206.704 -206.704,-206.704c0,-1.42109e-14 -216.318,214.716 -216.318,214.716c7.10543e-15,0 30.4448,33.649 30.4448,33.649Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<defs xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<radialGradient id="s1" fx=".4" fy=".2">
|
||||
<stop stop-color="#FE8"/><stop stop-color="#D70" offset="1"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="s2" fx=".8" fy=".5" xlink:href="#s1"/>
|
||||
<radialGradient id="s3" fx=".5" fy=".9" xlink:href="#s1"/>
|
||||
<radialGradient id="s4" fx=".1" fy=".5" xlink:href="#s1"/>
|
||||
</defs>
|
||||
<g stroke="#940">
|
||||
<path d="M73,29c-37-40-62-24-52,4l6-7c-8-16,7-26,42,9z" fill="url(#s1)"/>
|
||||
<path d="M47,8c33-16,48,21,9,47l-6-5c38-27,20-44,5-37z" fill="url(#s2)"/>
|
||||
<path d="M77,32c22,30,10,57-39,51l-1-8c3,3,67,5,36-36z" fill="url(#s3)"/>
|
||||
<path d="M58,84c-4,20-38-4-8-24l-6-5c-36,43,15,56,23,27z" fill="url(#s4)"/>
|
||||
<path d="M40,14c-40,37-37,52-9,68l1-8c-16-13-29-21,16-56z" fill="url(#s1)"/>
|
||||
<path d="M31,33c19,23,20,7,35,41l-9,1.7c-4-19-8-14-31-37z" fill="url(#s2)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 962 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 102">
|
||||
<radialGradient id="jsongrad" cx="65" cy="90" r="100" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#EEF"/><stop offset="1"/></radialGradient>
|
||||
<path d="M61,02 A 49,49 0,0,0 39,98 C 9,79 10,24 45,25 C 72,24 65,75 50,75 C 93,79 91,21 62,02" id="jsonswirl" fill="url(#jsongrad)"/>
|
||||
<use xlink:href="#jsonswirl" transform="rotate(180 50,50)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 472 B |
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="800" height="800" version="1.1" viewBox="0 0 800 800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!--Generated by IJSVG (https://github.com/iconjar/IJSVG)-->
|
||||
<defs>
|
||||
<linearGradient id="b" x1="0" x2="1" gradientUnits="userSpaceOnUse" y1="0" y2="0" gradientTransform="matrix(0,1,1,0,0,200)">
|
||||
<stop offset="0%" stop-color="#D83352"></stop>
|
||||
<stop offset="50%" stop-color="#F6DC7B"></stop>
|
||||
<stop offset="100%" stop-color="#F6DC7B"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="100" y="100" width="600" height="600" fill="url(#b)"></rect>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 691 B |
@@ -1,20 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="120" height="120"
|
||||
viewPort="0 0 120 120" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="-3" y="-3" width="6" height="6" />
|
||||
|
||||
<line stroke-linecap="butt"
|
||||
x1="30" y1="30" x2="30" y2="90"
|
||||
stroke="black" stroke-width="20"/>
|
||||
|
||||
<line stroke-linecap="round"
|
||||
x1="60" y1="30" x2="60" y2="90"
|
||||
stroke="black" stroke-width="20"/>
|
||||
|
||||
<line stroke-linecap="square"
|
||||
x1="90" y1="30" x2="90" y2="90"
|
||||
stroke="black" stroke-width="20"/>
|
||||
|
||||
<path d="M30,30 L30,90 M60,30 L60,90 M90,30 L90,90"
|
||||
stroke="white" />
|
||||
</svg>
|
||||
<rect x="-3" y="-3" width="6" height="6" fill="red"
|
||||
transform="skewY(30)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 593 B After Width: | Height: | Size: 203 B |
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="drawing.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs id="defs4">
|
||||
<linearGradient id="linearGradient3193">
|
||||
<stop style="stop-color:#0000ff;stop-opacity:1;" offset="0" id="stop3195" />
|
||||
<stop style="stop-color:#ff0000;stop-opacity:1;" offset="1" id="stop3197" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3193"
|
||||
id="linearGradient3199"
|
||||
x1="128.57143"
|
||||
y1="289.50504"
|
||||
x2="425.71428"
|
||||
y2="289.50504"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="scale(1.1,1.1) translate(20,20) rotate(10) scale(.9,.9)">
|
||||
</linearGradient>
|
||||
<radialGradient id="radialGradient3193">
|
||||
<stop style="stop-color:#0000ff;stop-opacity:1;" offset="0" />
|
||||
<stop style="stop-color:#ff0000;stop-opacity:1;" offset="1" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
xlink:href="#radialGradient3193"
|
||||
id="radialGradient3199"
|
||||
cx="300.57143"
|
||||
cy="529.50504"
|
||||
fx="400.57143"
|
||||
fy="529.50504"
|
||||
r="100.71428"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="scale(1.1,1.1) translate(20,20) rotate(10) scale(.9,.9)">
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g>
|
||||
<rect
|
||||
style="fill:url(#linearGradient3199);fill-opacity:1"
|
||||
id="rect3191"
|
||||
width="397.14285"
|
||||
height="157.14285"
|
||||
x="128.57143"
|
||||
y="160.93361" />
|
||||
<rect
|
||||
style="fill:url(#radialGradient3199);fill-opacity:1"
|
||||
id="rect3192"
|
||||
width="397.14285"
|
||||
height="157.14285"
|
||||
x="128.57143"
|
||||
y="400.93361" />
|
||||
|
||||
<rect id='myrect' x="400" y="20" width="60" height="60" rx="3" ry="3"
|
||||
style="opacity:0.5;fill:#0000FF;stroke:rgb(0, 255, 0);stroke-width:10px;stroke-opacity:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:15;stroke-dasharray:5,3,2;stroke-dashoffset:3"/>
|
||||
|
||||
|
||||
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="269" height="269" version="1.1" viewBox="0 0 269 269" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!--Generated by IJSVG (https://github.com/iconjar/IJSVG)-->
|
||||
<defs>
|
||||
<mask id="a" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox">
|
||||
<use fill="#FFF" xlink:href="#d"></use>
|
||||
</mask>
|
||||
<linearGradient id="b" x1="0" x2="1" gradientUnits="userSpaceOnUse" y1="0" y2="0" gradientTransform="matrix(0,-197.994,-197.994,0,101.4,199.62)">
|
||||
<stop offset="0%" stop-color="#D83352"></stop>
|
||||
<stop offset="41.2669%" stop-color="#F6DC7B"></stop>
|
||||
<stop offset="100%" stop-color="#F6DC7B"></stop>
|
||||
</linearGradient>
|
||||
<mask id="c" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox">
|
||||
<path fill="#FFF" d="M0,202h202v-202h-202Z"></path>
|
||||
</mask>
|
||||
<path id="d" d="M2.404,100.624c0,-54.674 44.321,-98.998 98.995,-98.998v-4.88498e-15c54.675,0 98.997,44.324 98.997,98.998v0c0,54.674 -44.322,98.996 -98.997,98.996v0c-54.674,0 -98.995,-44.322 -98.995,-98.996"></path>
|
||||
</defs>
|
||||
<g transform="scale(0.998762)">
|
||||
<g transform="matrix(1.33333,0,0,-1.33333,0,269.333)">
|
||||
<use mask="url(#a)" fill="url(#b)" stroke="none" xlink:href="#d"></use>
|
||||
<g mask="url(#c)">
|
||||
<path fill="#231F20" stroke="none" d="M0,0c0,-6.725 -5.451,-12.175 -12.177,-12.175c-6.725,0 -12.176,5.45 -12.176,12.175c0,6.725 5.451,12.178 12.176,12.178c6.726,0 12.177,-5.453 12.177,-12.178" transform="matrix(1,0,0,1,75.0225,94.2754)"></path>
|
||||
<path fill="none" stroke="#231F20" stroke-linecap="round" stroke-width="9" d="M0,0c14.428,-16.873 42.352,-15.393 42.352,-15.393" transform="matrix(1,0,0,1,41.2588,117.041)"></path>
|
||||
<path fill="#231F20" stroke="none" d="M0,0c0,-6.725 -5.453,-12.176 -12.178,-12.176c-6.724,0 -12.176,5.451 -12.176,12.176c0,6.725 5.452,12.178 12.176,12.178c6.725,0 12.178,-5.453 12.178,-12.178" transform="matrix(1,0,0,1,146.952,94.3281)"></path>
|
||||
<path fill="none" stroke="#231F20" stroke-linecap="round" stroke-width="9" d="M0,0c-14.428,-16.873 -42.352,-15.393 -42.352,-15.393" transform="matrix(1,0,0,1,161.54,117.094)"></path>
|
||||
<path fill="none" stroke="#231F20" stroke-linecap="round" stroke-width="10" d="M0,0c29.782,24.805 58.656,-1.05 58.656,-1.05" transform="matrix(1,0,0,1,72.0713,41.6172)"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 590 KiB After Width: | Height: | Size: 522 KiB |
@@ -6,18 +6,6 @@ Orignaly written for IconJar (in development)
|
||||
|
||||
It also supports the NSPasteboards writing protocol, an IJSVG object can be put onto the pasteboard and application like Sketch and Photoshop can paste them into the document as vector objects (generated PDF's on the fly).
|
||||
|
||||
Example app
|
||||
====
|
||||
There is an example application provided, it will generate this test bed for SVG's
|
||||
|
||||
The example screen contains six SVG's rendered in individual views, from left to right.
|
||||
* First example shows transforms and colours
|
||||
* Second example shows linear gradients
|
||||
* Third example shows defined paths being reused
|
||||
* Forth example shows transforms such as translate being used and stroke colours
|
||||
* Fith example shows clip paths being used
|
||||
* Sixth example shows dashed stroke array's being used
|
||||
|
||||
Quick Start
|
||||
====
|
||||
Add all the IJSVG library files into your project, import the IJSVG.h into the files you wish to use the SVG's. The easiest way to
|
||||
@@ -39,12 +27,49 @@ IJSVG does allow you to directly draw the SVG into any focused drawing context f
|
||||
[svg drawInRect:self.bounds];
|
||||
}
|
||||
|
||||
#### Helpers
|
||||
|
||||
IJSVG provides a very simple way of helping out the backing scale factor of the drawing context when the SVG is drawn. Due to CALayers defaulting to 1.0 when custom drawing methods are implemented, they do not know about your backing scale factor. Luckily you can simply do this:
|
||||
|
||||
__block IJSVG * svg ....
|
||||
svg.renderingBackingScaleHelper = ^{
|
||||
return [svg computeBackingScale:someView.window.backingScaleFactor];
|
||||
};
|
||||
|
||||
# Exporting
|
||||
#### Yes, thats right... CALayers -> SVG (whos idea was this?!)
|
||||
|
||||
IJSVG provides a way of exporting the rendered layer tree back to an SVG file. This isnt 100% perfect but it does a good job of generating what IJSVG renders (have yet to find an issue).
|
||||
|
||||
Its a simple as doing this:
|
||||
|
||||
IJSVG * svg ...
|
||||
IJSVGExporter * exporter = [[IJSVGExporter alloc] initWithSVG:svg options:IJSVGExporterOptionAll];
|
||||
NSString * svgString = [exporter SVGString];
|
||||
|
||||
Which will give you back the SVG code to put into a file, there are various options you can give it for more XML manipulation such s collpasing groups and converting transform's from matrix's back to their human readable counter parts.
|
||||
|
||||
The fun part is you can actually create an SVG object from a IJSVGLayer and work with them without needing to load a file, for example:
|
||||
|
||||
// create group layer and a shape layer (subclass of CAShapeLayer)
|
||||
IJSVGGroupLayer * baseSVGGroup = ....
|
||||
IJSVGShapeLayer * shapeLayer = ....
|
||||
[baseSVGGroup addSublayer:shapeLayer];
|
||||
|
||||
// create the SVG - note the viewbox!
|
||||
IJSVG * svg = [[IJSVG alloc] initWithSVGLayer:baseSVGGroup viewBox:NSMakeRect(0.f, 0.f, 50.f, 50.f)];
|
||||
.... do what you want
|
||||
|
||||
and now you would have a usuable SVG to render where ever you would like and more importantly you can now export that back to an SVG file.
|
||||
|
||||
All layers must be of generic type IJSVGLayer or IJSVGShapeLayer, it will throw an exception if you do not use these. Also if you go out the scope of what those layers can do, it wont render nor will it export (get malformed results).
|
||||
|
||||
# What it supports
|
||||
* Elements: def, use, g, path, clipPath, circle, elipse, rect, polyline, polygon and line (supports groups heirachy and inheritance, clip-paths etc)
|
||||
* Commands: A, M, L, H, V, C, S, T, Q and Z and full support for multiple parameters of each type
|
||||
* Transformations: matrix, rotate (not around a point - currently), translate, scale transformations
|
||||
* Transformations: matrix, rotate, translate, scale and skew transformations
|
||||
* Stroking: stroking, stroke color, stroke opacity, dashed, dashed offset and phase, stroke line cap style
|
||||
* Filling: fill color, fill mode (winding rules), fill opacity, linear gradients, radial gradients
|
||||
* Filling: fill color, fill mode (winding rules), fill opacity, linear gradients, radial gradients and patterns
|
||||
* Color: supports all predefined colors from the SVG spec and hex values
|
||||
* Caching: has basic caching implemenation
|
||||
* CSS: Basic embedded style sheets are support with very basic selectors
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-cayman
|
||||
@@ -12,8 +12,14 @@
|
||||
#import "IJSVGLayerTree.h"
|
||||
#import "IJSVGGroupLayer.h"
|
||||
#import "IJSVGImageLayer.h"
|
||||
#import "IJSVGExporter.h"
|
||||
#import "IJSVGRendering.h"
|
||||
#import "IJSVGColorList.h"
|
||||
#import "IJSVGGradientLayer.h"
|
||||
#import "IJSVGRenderingStyle.h"
|
||||
|
||||
@class IJSVG;
|
||||
@class IJSVGQuartzRenderer;
|
||||
|
||||
void IJSVGBeginTransactionLock();
|
||||
void IJSVGEndTransactionLock();
|
||||
@@ -33,8 +39,6 @@ withSVGString:(NSString *)subSVGString;
|
||||
|
||||
@end
|
||||
|
||||
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
|
||||
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
|
||||
|
||||
@private
|
||||
@@ -46,6 +50,10 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
CGRect _viewBox;
|
||||
CGSize _proposedViewSize;
|
||||
CGFloat _lastProposedBackingScale;
|
||||
IJSVGRenderQuality _lastProposedRenderQuality;
|
||||
CGFloat _backingScale;
|
||||
NSMutableDictionary * _replacementColors;
|
||||
IJSVGQuartzRenderer * _quartzRenderer;
|
||||
|
||||
struct {
|
||||
unsigned int shouldHandleForeignObject: 1;
|
||||
@@ -63,16 +71,20 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
|
||||
// global overwriting rules for when rendering an SVG, this will overide any
|
||||
// fillColor, strokeColor, pattern and gradient fill
|
||||
@property (nonatomic, retain) NSColor * fillColor;
|
||||
@property (nonatomic, retain) NSColor * strokeColor;
|
||||
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
|
||||
@property (nonatomic, assign) BOOL clipToViewport;
|
||||
@property (nonatomic, retain) IJSVGRenderingStyle * style;
|
||||
|
||||
- (void)prepForDrawingInView:(NSView *)view;
|
||||
- (BOOL)isFont;
|
||||
- (IJSVGGroup *)rootNode;
|
||||
- (NSRect)viewBox;
|
||||
- (NSArray *)glyphs;
|
||||
- (NSArray<IJSVGPath *> *)glyphs;
|
||||
- (NSString *)identifier;
|
||||
- (IJSVGLayer *)layer;
|
||||
- (IJSVGLayer *)layerWithTree:(IJSVGLayerTree *)tree;
|
||||
- (NSArray<IJSVG *> *)subSVGs:(BOOL)recursive;
|
||||
- (NSString *)SVGStringWithOptions:(IJSVGExporterOptions)options;
|
||||
|
||||
- (CGFloat)computeBackingScale:(CGFloat)scale;
|
||||
- (void)discardDOM;
|
||||
@@ -127,6 +139,9 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
error:(NSError **)error;
|
||||
- (NSImage *)imageWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped;
|
||||
- (NSImage *)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError **)error;
|
||||
- (BOOL)drawAtPoint:(NSPoint)point
|
||||
size:(NSSize)size;
|
||||
- (BOOL)drawAtPoint:(NSPoint)point
|
||||
@@ -135,6 +150,8 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
- (BOOL)drawInRect:(NSRect)rect;
|
||||
- (BOOL)drawInRect:(NSRect)rect
|
||||
error:(NSError **)error;
|
||||
- (void)drawInRect:(NSRect)rect
|
||||
context:(CGContextRef)context;
|
||||
|
||||
- (NSData *)PDFData;
|
||||
- (NSData *)PDFData:(NSError **)error;
|
||||
@@ -142,4 +159,12 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
- (NSData *)PDFDataWithRect:(NSRect)rect
|
||||
error:(NSError **)error;
|
||||
|
||||
- (void)beginVectorDraw;
|
||||
- (void)endVectorDraw;
|
||||
|
||||
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize;
|
||||
- (void)setNeedsDisplay;
|
||||
|
||||
// colors
|
||||
- (IJSVGColorList *)computedColorList:(BOOL *)hasPatternFills;
|
||||
@end
|
||||
|
||||
@@ -9,34 +9,39 @@
|
||||
#import "IJSVG.h"
|
||||
#import "IJSVGCache.h"
|
||||
#import "IJSVGTransaction.h"
|
||||
#import "IJSVGExporter.h"
|
||||
|
||||
@implementation IJSVG
|
||||
|
||||
@synthesize fillColor;
|
||||
@synthesize strokeColor;
|
||||
@synthesize renderingBackingScaleHelper;
|
||||
@synthesize clipToViewport;
|
||||
@synthesize renderQuality;
|
||||
@synthesize style = _style;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
IJSVGBeginTransactionLock();
|
||||
[renderingBackingScaleHelper release], renderingBackingScaleHelper = nil;
|
||||
[fillColor release], fillColor = nil;
|
||||
[strokeColor release], strokeColor = nil;
|
||||
[_group release], _group = nil;
|
||||
[_layerTree release], _layerTree = nil;
|
||||
[_replacementColors release], _replacementColors = nil;
|
||||
[_quartzRenderer release], _quartzRenderer = nil;
|
||||
[_style release], _style = nil;
|
||||
[super dealloc];
|
||||
IJSVGEndTransactionLock();
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString *)string
|
||||
error:(NSError **)error
|
||||
{
|
||||
return [[self class] svgNamed:string
|
||||
return [self.class svgNamed:string
|
||||
error:error
|
||||
delegate:nil];
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString *)string
|
||||
{
|
||||
return [[self class] svgNamed:string
|
||||
return [self.class svgNamed:string
|
||||
error:nil];
|
||||
}
|
||||
|
||||
@@ -44,7 +49,7 @@
|
||||
useCache:(BOOL)useCache
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [[self class] svgNamed:string
|
||||
return [self.class svgNamed:string
|
||||
useCache:useCache
|
||||
error:nil
|
||||
delegate:delegate];
|
||||
@@ -53,7 +58,7 @@
|
||||
+ (id)svgNamed:(NSString *)string
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
return [[self class] svgNamed:string
|
||||
return [self.class svgNamed:string
|
||||
error:nil
|
||||
delegate:delegate];
|
||||
}
|
||||
@@ -73,7 +78,7 @@
|
||||
error:(NSError **)error
|
||||
delegate:(id<IJSVGDelegate>)delegate
|
||||
{
|
||||
NSBundle * bundle = [NSBundle mainBundle];
|
||||
NSBundle * bundle = NSBundle.mainBundle;
|
||||
NSString * str = nil;
|
||||
NSString * ext = [string pathExtension];
|
||||
if( ext == nil || ext.length == 0 ) {
|
||||
@@ -257,6 +262,7 @@
|
||||
[IJSVGCache cacheSVG:self
|
||||
fileURL:aURL];
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
return self;
|
||||
@@ -327,7 +333,15 @@
|
||||
|
||||
- (void)_setupBasicsFromAnyInitializer
|
||||
{
|
||||
_lastProposedBackingScale = 1.f;
|
||||
self.style = [[[IJSVGRenderingStyle alloc] init] autorelease];
|
||||
self.clipToViewport = YES;
|
||||
self.renderQuality = IJSVGRenderQualityFullResolution;
|
||||
|
||||
// setup low level backing scale
|
||||
_lastProposedBackingScale = 0.f;
|
||||
self.renderingBackingScaleHelper = ^CGFloat{
|
||||
return 1.f;
|
||||
};
|
||||
}
|
||||
|
||||
- (NSString *)identifier
|
||||
@@ -347,12 +361,17 @@
|
||||
return _viewBox;
|
||||
}
|
||||
|
||||
- (IJSVGGroup *)rootNode
|
||||
{
|
||||
return _group;
|
||||
}
|
||||
|
||||
- (BOOL)isFont
|
||||
{
|
||||
return [_group isFont];
|
||||
}
|
||||
|
||||
- (NSArray *)glyphs
|
||||
- (NSArray<IJSVGPath *> *)glyphs
|
||||
{
|
||||
return [_group glyphs];
|
||||
}
|
||||
@@ -362,6 +381,14 @@
|
||||
return [_group subSVGs:recursive];
|
||||
}
|
||||
|
||||
- (NSString *)SVGStringWithOptions:(IJSVGExporterOptions)options
|
||||
{
|
||||
IJSVGExporter * exporter = [[[IJSVGExporter alloc] initWithSVG:self
|
||||
size:self.viewBox.size
|
||||
options:options] autorelease];
|
||||
return [exporter SVGString];
|
||||
}
|
||||
|
||||
- (NSImage *)imageWithSize:(NSSize)aSize
|
||||
{
|
||||
return [self imageWithSize:aSize
|
||||
@@ -385,13 +412,23 @@
|
||||
error:nil];
|
||||
}
|
||||
|
||||
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize
|
||||
{
|
||||
[self _beginDraw:(NSRect) {
|
||||
.origin = CGPointZero,
|
||||
.size = aSize
|
||||
}];
|
||||
return NSMakeRect(0.f, 0.f, _proposedViewSize.width * _clipScale,
|
||||
_proposedViewSize.height * _clipScale);
|
||||
}
|
||||
|
||||
- (NSImage *)imageWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError **)error
|
||||
{
|
||||
NSImage * im = [[[NSImage alloc] initWithSize:aSize] autorelease];
|
||||
[im lockFocus];
|
||||
CGContextRef ref = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
CGContextRef ref = [[NSGraphicsContext currentContext] CGContext];
|
||||
CGContextSaveGState(ref);
|
||||
if(flipped) {
|
||||
CGContextTranslateCTM(ref, 0.f, aSize.height);
|
||||
@@ -405,6 +442,16 @@
|
||||
return im;
|
||||
}
|
||||
|
||||
- (NSImage *)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
|
||||
flipped:(BOOL)flipped
|
||||
error:(NSError **)error
|
||||
{
|
||||
NSRect rect = [self computeOriginalDrawingFrameWithSize:aSize];
|
||||
return [self imageWithSize:rect.size
|
||||
flipped:flipped
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (NSData *)PDFData
|
||||
{
|
||||
return [self PDFData:nil];
|
||||
@@ -444,10 +491,13 @@
|
||||
CGContextScaleCTM( context, 1, -1 );
|
||||
CGContextTranslateCTM( context, 0, -box.size.height);
|
||||
|
||||
// draw the icon
|
||||
[self _drawInRect:(NSRect)box
|
||||
context:context
|
||||
error:error];
|
||||
// make sure we set the masks to path bits n bobs
|
||||
[self _beginVectorDraw]; {
|
||||
// draw the icon
|
||||
[self _drawInRect:(NSRect)box
|
||||
context:context
|
||||
error:error];
|
||||
} [self _endVectorDraw];
|
||||
|
||||
CGContextEndPage(context);
|
||||
|
||||
@@ -458,6 +508,56 @@
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)endVectorDraw
|
||||
{
|
||||
[self _endVectorDraw];
|
||||
}
|
||||
|
||||
- (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)prepForDrawingInView:(NSView *)view
|
||||
{
|
||||
// kill the render
|
||||
if(view == nil) {
|
||||
self.renderingBackingScaleHelper = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
// construct the layer before drawing
|
||||
[self layer];
|
||||
|
||||
// set the scale
|
||||
__block NSView * weakView = view;
|
||||
self.renderingBackingScaleHelper = ^CGFloat{
|
||||
return weakView.window.screen.backingScaleFactor;
|
||||
};
|
||||
}
|
||||
|
||||
- (BOOL)drawAtPoint:(NSPoint)point
|
||||
size:(NSSize)aSize
|
||||
{
|
||||
@@ -484,12 +584,13 @@
|
||||
error:(NSError **)error
|
||||
{
|
||||
return [self _drawInRect:rect
|
||||
context:[[NSGraphicsContext currentContext] graphicsPort]
|
||||
context:[[NSGraphicsContext currentContext] CGContext]
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (CGFloat)computeBackingScale:(CGFloat)actualScale
|
||||
{
|
||||
_backingScale = actualScale;
|
||||
return (CGFloat)(_scale + actualScale);
|
||||
}
|
||||
|
||||
@@ -499,8 +600,8 @@
|
||||
// we also need to calculate the viewport so we can clip
|
||||
// the drawing if needed
|
||||
NSRect viewPort = NSZeroRect;
|
||||
viewPort.origin.x = round(rect.size.width/2-(_proposedViewSize.width/2)*_clipScale);
|
||||
viewPort.origin.y = round(rect.size.height/2-(_proposedViewSize.height/2)*_clipScale);;
|
||||
viewPort.origin.x = round((rect.size.width/2-(_proposedViewSize.width/2)*_clipScale) + rect.origin.x);
|
||||
viewPort.origin.y = round((rect.size.height/2-(_proposedViewSize.height/2)*_clipScale) + rect.origin.y);
|
||||
viewPort.size.width = _proposedViewSize.width*_clipScale;
|
||||
viewPort.size.height = _proposedViewSize.height*_clipScale;
|
||||
|
||||
@@ -522,6 +623,14 @@
|
||||
return viewPort;
|
||||
}
|
||||
|
||||
- (void)drawInRect:(NSRect)rect
|
||||
context:(CGContextRef)context
|
||||
{
|
||||
[self _drawInRect:rect
|
||||
context:context
|
||||
error:nil];
|
||||
}
|
||||
|
||||
- (BOOL)_drawInRect:(NSRect)rect
|
||||
context:(CGContextRef)ref
|
||||
error:(NSError **)error
|
||||
@@ -530,63 +639,70 @@
|
||||
@synchronized (self) {
|
||||
CGContextSaveGState(ref);
|
||||
@try {
|
||||
|
||||
[self _beginDraw:rect];
|
||||
|
||||
// scale the whole drawing context, but first, we need
|
||||
// to translate the context so its centered
|
||||
CGFloat tX = round(rect.size.width/2-(_viewBox.size.width/2)*_scale);
|
||||
CGFloat tY = round(rect.size.height/2-(_viewBox.size.height/2)*_scale);
|
||||
|
||||
// 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];
|
||||
NSRect viewPort = [self computeRectDrawingInRect:rect isValid:&canDraw];
|
||||
// check the viewport
|
||||
if( !canDraw ) {
|
||||
if( canDraw == NO ) {
|
||||
if( error != NULL ) {
|
||||
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
code:IJSVGErrorDrawing
|
||||
userInfo:nil] autorelease];
|
||||
}
|
||||
CGContextRestoreGState(ref);
|
||||
return NO;
|
||||
} else {
|
||||
// clip to mask
|
||||
if(self.clipToViewport == YES) {
|
||||
CGContextClipToRect( ref, viewPort);
|
||||
}
|
||||
|
||||
// add the origin back onto the viewport
|
||||
viewPort.origin.x -= (_viewBox.origin.x)*_scale;
|
||||
viewPort.origin.y -= (_viewBox.origin.y)*_scale;
|
||||
|
||||
// transforms
|
||||
CGContextTranslateCTM( ref, viewPort.origin.x, viewPort.origin.y);
|
||||
CGContextScaleCTM( ref, _scale, _scale );
|
||||
|
||||
// render the layer, its really important we lock
|
||||
// the transaction when drawing
|
||||
IJSVGBeginTransactionLock();
|
||||
// do we need to update the backing scales on the
|
||||
// layers?
|
||||
if(self.renderingBackingScaleHelper != nil) {
|
||||
[self _askHelperForBackingScale];
|
||||
}
|
||||
|
||||
CGInterpolationQuality quality;
|
||||
switch(self.renderQuality) {
|
||||
case IJSVGRenderQualityLow: {
|
||||
quality = kCGInterpolationLow;
|
||||
break;
|
||||
}
|
||||
case IJSVGRenderQualityOptimized: {
|
||||
quality = kCGInterpolationMedium;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
quality = kCGInterpolationHigh;
|
||||
}
|
||||
}
|
||||
CGContextSetInterpolationQuality(ref, quality);
|
||||
[self.layer renderInContext:ref];
|
||||
IJSVGEndTransactionLock();
|
||||
}
|
||||
|
||||
// clip to mask
|
||||
CGContextClipToRect( ref, viewPort);
|
||||
|
||||
tX -= (_viewBox.origin.x*_scale);
|
||||
tY -= (_viewBox.origin.y*_scale);
|
||||
|
||||
CGContextTranslateCTM( ref, tX, tY );
|
||||
CGContextScaleCTM( ref, _scale, _scale );
|
||||
|
||||
// render the layer, its really important we lock
|
||||
// the transaction when drawing
|
||||
__block IJSVG * weakSelf = self;
|
||||
IJSVGBeginTransactionLock();
|
||||
// do we need to update the backing scales on the
|
||||
// layers?
|
||||
if(weakSelf.renderingBackingScaleHelper != nil) {
|
||||
[weakSelf _askHelperForBackingScale];
|
||||
}
|
||||
|
||||
// render the layers
|
||||
[weakSelf.layer renderInContext:ref];
|
||||
IJSVGEndTransactionLock();
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
// just catch and give back a drawing error to the caller
|
||||
if( error != NULL )
|
||||
if( error != NULL ) {
|
||||
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
code:IJSVGErrorDrawing
|
||||
userInfo:nil] autorelease];
|
||||
}
|
||||
}
|
||||
@finally {
|
||||
CGContextRestoreGState(ref);
|
||||
}
|
||||
CGContextRestoreGState(ref);
|
||||
}
|
||||
return (error == nil);
|
||||
}
|
||||
@@ -598,47 +714,33 @@
|
||||
scale = 1.f;
|
||||
}
|
||||
|
||||
// make sure we multiple the scale by the scale of the rendered clip
|
||||
// or it will be blurry for gradients and other bitmap drawing
|
||||
scale = (_scale * scale);
|
||||
|
||||
// dont do anything, nothing has changed, no point of iterating over
|
||||
// every layer for no reason!
|
||||
if(scale == _lastProposedBackingScale) {
|
||||
if(scale == _lastProposedBackingScale && renderQuality == _lastProposedRenderQuality) {
|
||||
return;
|
||||
}
|
||||
_lastProposedBackingScale = scale;
|
||||
[self _recursivelySetScale:scale
|
||||
forLayer:self.layer];
|
||||
}
|
||||
|
||||
- (void)_recursivelySetScale:(CGFloat)scale
|
||||
forLayer:(IJSVGLayer *)layer
|
||||
{
|
||||
// update the backing layer scale
|
||||
if(layer.requiresBackingScaleHelp == YES) {
|
||||
layer.backingScaleFactor = scale;
|
||||
}
|
||||
|
||||
// find the next!
|
||||
for(IJSVGLayer * aLayer in layer.sublayers) {
|
||||
[self _recursivelySetScale:scale
|
||||
forLayer:aLayer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFillColor:(NSColor *)aColor
|
||||
{
|
||||
if(fillColor != nil) {
|
||||
[fillColor release], fillColor = nil;
|
||||
}
|
||||
fillColor = [aColor retain];
|
||||
[_layerTree release], _layerTree = nil;
|
||||
}
|
||||
|
||||
- (void)setStrokeColor:(NSColor *)aColor
|
||||
{
|
||||
if(strokeColor != nil) {
|
||||
[strokeColor release], strokeColor = nil;
|
||||
}
|
||||
strokeColor = [aColor retain];
|
||||
[_layerTree release], _layerTree = nil;
|
||||
IJSVGRenderQuality quality = self.renderQuality;
|
||||
_lastProposedBackingScale = scale;
|
||||
_lastProposedRenderQuality = quality;
|
||||
|
||||
// walk the tree
|
||||
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
|
||||
IJSVGLayer * propLayer = ((IJSVGLayer *)layer);
|
||||
propLayer.renderQuality = quality;
|
||||
if(propLayer.requiresBackingScaleHelp == YES) {
|
||||
propLayer.backingScaleFactor = scale;
|
||||
}
|
||||
};
|
||||
|
||||
// gogogo
|
||||
[IJSVGLayer recursivelyWalkLayer:self.layer
|
||||
withBlock:block];
|
||||
|
||||
}
|
||||
|
||||
- (IJSVGLayer *)layerWithTree:(IJSVGLayerTree *)tree
|
||||
@@ -664,13 +766,116 @@
|
||||
// create the renderer and assign default values
|
||||
// from this SVG object
|
||||
IJSVGLayerTree * renderer = [[[IJSVGLayerTree alloc] init] autorelease];
|
||||
renderer.fillColor = self.fillColor;
|
||||
renderer.strokeColor = self.strokeColor;
|
||||
renderer.viewBox = self.viewBox;
|
||||
renderer.style = self.style;
|
||||
|
||||
// return the rendered layer
|
||||
return [self layerWithTree:renderer];
|
||||
}
|
||||
|
||||
- (void)setStyle:(IJSVGRenderingStyle *)style
|
||||
{
|
||||
[self removeStyleObservers];
|
||||
[_style release], _style = nil;
|
||||
_style = style.retain;
|
||||
[self addStyleObservers];
|
||||
}
|
||||
|
||||
- (void)removeStyleObservers
|
||||
{
|
||||
for(NSString * propertyName in IJSVGRenderingStyle.observableProperties) {
|
||||
@try {
|
||||
[_style removeObserver:self
|
||||
forKeyPath:propertyName];
|
||||
} @catch(NSException * e) {}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addStyleObservers
|
||||
{
|
||||
for(NSString * propertyName in IJSVGRenderingStyle.observableProperties) {
|
||||
[_style addObserver:self
|
||||
forKeyPath:propertyName
|
||||
options:0
|
||||
context:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
|
||||
context:(void *)context
|
||||
{
|
||||
// invalidate the tree if a style is set
|
||||
if(object == _style) {
|
||||
[self invalidateLayerTree];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplay
|
||||
{
|
||||
[self invalidateLayerTree];
|
||||
}
|
||||
|
||||
- (void)invalidateLayerTree
|
||||
{
|
||||
[_layerTree release], _layerTree = nil;
|
||||
}
|
||||
|
||||
- (IJSVGColorList *)computedColorList:(BOOL *)hasPatternFills
|
||||
{
|
||||
IJSVGColorList * sheet = [[[IJSVGColorList alloc] init] autorelease];
|
||||
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
|
||||
if([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO && layer.isHidden == NO) {
|
||||
IJSVGShapeLayer * sLayer = (IJSVGShapeLayer *)layer;
|
||||
NSColor * color = nil;
|
||||
if(sLayer.fillColor != nil) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// check for any patterns
|
||||
if(sLayer.patternFillLayer != nil ||
|
||||
sLayer.gradientFillLayer != nil ||
|
||||
sLayer.gradientStrokeLayer != nil ||
|
||||
sLayer.patternStrokeLayer != nil) {
|
||||
if(hasPatternFills != nil && *hasPatternFills != YES) {
|
||||
*hasPatternFills = YES;
|
||||
}
|
||||
|
||||
// add any colors from gradients
|
||||
IJSVGGradientLayer * gradLayer = nil;
|
||||
IJSVGGradientLayer * gradStrokeLayer = nil;
|
||||
if((gradLayer = sLayer.gradientFillLayer) != nil) {
|
||||
IJSVGColorList * gradSheet = gradLayer.gradient.computedColorList;
|
||||
[sheet addColorsFromList:gradSheet];
|
||||
}
|
||||
if((gradStrokeLayer = sLayer.gradientStrokeLayer) != nil) {
|
||||
IJSVGColorList * gradSheet = gradStrokeLayer.gradient.computedColorList;
|
||||
[sheet addColorsFromList:gradSheet];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// walk
|
||||
[IJSVGLayer recursivelyWalkLayer:self.layer
|
||||
withBlock:block];
|
||||
|
||||
// return the colours!
|
||||
return sheet;
|
||||
}
|
||||
|
||||
- (void)_beginDraw:(NSRect)rect
|
||||
{
|
||||
// in order to correctly fit the the SVG into the
|
||||
@@ -696,8 +901,9 @@
|
||||
|
||||
- (id)pasteboardPropertyListForType:(NSString *)type
|
||||
{
|
||||
if( [type isEqualToString:NSPasteboardTypePDF] )
|
||||
if( [type isEqualToString:NSPasteboardTypePDF] ) {
|
||||
return [self PDFData];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ static BOOL _enabled = YES;
|
||||
|
||||
+ (IJSVG *)cachedSVGForFileURL:(NSURL *)aURL
|
||||
{
|
||||
if( ![[self class] enabled] || _cache == nil )
|
||||
if( ![self.class enabled] || _cache == nil )
|
||||
return nil;
|
||||
IJSVG * svg = nil;
|
||||
if( ( svg = [_cache objectForKey:aURL] ) == nil )
|
||||
@@ -53,7 +53,7 @@ static BOOL _enabled = YES;
|
||||
{
|
||||
_enabled = flag;
|
||||
if( !flag ) {
|
||||
[[self class] flushCache];
|
||||
[self.class flushCache];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, IJSVGColorStringOptions) {
|
||||
IJSVGColorStringOptionNone = 1 << 0,
|
||||
IJSVGColorStringOptionForceHEX = 1 << 1,
|
||||
IJSVGColorStringOptionAllowShortHand = 1 << 2,
|
||||
IJSVGColorStringOptionAllowRRGGBBAA = 1 << 3,
|
||||
IJSVGColorStringOptionDefault = IJSVGColorStringOptionAllowShortHand
|
||||
};
|
||||
|
||||
typedef NS_ENUM( NSInteger, IJSVGPredefinedColor ) {
|
||||
IJSVGColorAliceblue,
|
||||
IJSVGColorAntiquewhite,
|
||||
@@ -160,14 +168,26 @@ typedef NS_ENUM( NSInteger, IJSVGPredefinedColor ) {
|
||||
|
||||
@interface IJSVGColor : NSObject
|
||||
|
||||
CGFloat * IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness);
|
||||
|
||||
+ (NSColor *)computeColorSpace:(NSColor *)color;
|
||||
+ (NSColorSpace *)defaultColorSpace;
|
||||
+ (BOOL)isColor:(NSString *)string;
|
||||
+ (NSString *)colorStringFromColor:(NSColor *)color
|
||||
forceHex:(BOOL)forceHex;
|
||||
options:(IJSVGColorStringOptions)options;
|
||||
+ (NSString *)colorStringFromColor:(NSColor *)color;
|
||||
+ (NSColor *)colorFromHEXInteger:(NSInteger)hex;
|
||||
+ (NSColor *)computeColor:(id)colour;
|
||||
+ (NSColor *)colorFromString:(NSString *)string;
|
||||
+ (NSColor *)colorFromHEXString:(NSString *)string;
|
||||
+ (NSColor *)colorFromHEXString:(NSString *)string
|
||||
alpha:(CGFloat)alpha;
|
||||
containsAlphaComponent:(BOOL *)containsAlphaComponent;
|
||||
+ (BOOL)HEXContainsAlphaComponent:(NSUInteger)hex;
|
||||
+ (unsigned long)lengthOfHEXInteger:(NSUInteger)hex;
|
||||
+ (NSColor *)colorFromRString:(NSString *)rString
|
||||
gString:(NSString *)gString
|
||||
bString:(NSString *)bString
|
||||
aString:(NSString *)aString;
|
||||
+ (NSColor *)colorFromPredefinedColorName:(NSString *)name;
|
||||
+ (NSString *)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color;
|
||||
+ (NSColor *)changeAlphaOnColor:(NSColor *)color
|
||||
|
||||
@@ -11,168 +11,198 @@
|
||||
|
||||
@implementation IJSVGColor
|
||||
|
||||
static NSMutableDictionary * _colorTree = nil;
|
||||
static NSDictionary * _colorTree = nil;
|
||||
|
||||
CGFloat * IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness)
|
||||
{
|
||||
hue *= (1.f/360.f);
|
||||
hue = (hue - floorf(hue));
|
||||
saturation *= 0.01;
|
||||
lightness *= 0.01;
|
||||
lightness *= 2.f;
|
||||
|
||||
CGFloat s = saturation * ((lightness < 1.f) ? lightness : (2.f - lightness));
|
||||
CGFloat brightness = (lightness + s) * .5f;
|
||||
if(s != 0.f) {
|
||||
s = (2.f * s) / (lightness + s);
|
||||
}
|
||||
CGFloat * floats = (CGFloat *)malloc(3*sizeof(CGFloat));
|
||||
floats[0] = hue;
|
||||
floats[1] = s;
|
||||
floats[2] = brightness;
|
||||
return floats;
|
||||
};
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[[self class] _generateTree];
|
||||
[self.class _generateTree];
|
||||
}
|
||||
|
||||
+ (NSColorSpace *)defaultColorSpace
|
||||
{
|
||||
return NSColorSpace.deviceRGBColorSpace;
|
||||
}
|
||||
|
||||
+ (NSColor *)computeColorSpace:(NSColor *)color
|
||||
{
|
||||
NSColorSpace * space = [self defaultColorSpace];
|
||||
if(color.colorSpace != space) {
|
||||
color = [color colorUsingColorSpace:space];
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
+ (void)_generateTree
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
||||
_colorTree = [[NSMutableDictionary alloc] init];
|
||||
// add the colours in
|
||||
[_colorTree setObject:@"f0f8ff" forKey:@"aliceblue"];
|
||||
[_colorTree setObject:@"faebd7" forKey:@"antiquewhite"];
|
||||
[_colorTree setObject:@"00ffff" forKey:@"aqua"];
|
||||
[_colorTree setObject:@"7fffd4" forKey:@"aquamarine"];
|
||||
[_colorTree setObject:@"f0ffff" forKey:@"azure"];
|
||||
[_colorTree setObject:@"f5f5dc" forKey:@"beige"];
|
||||
[_colorTree setObject:@"ffe4c4" forKey:@"bisque"];
|
||||
[_colorTree setObject:@"000000" forKey:@"black"];
|
||||
[_colorTree setObject:@"ffebcd" forKey:@"blanchedalmond"];
|
||||
[_colorTree setObject:@"0000ff" forKey:@"blue"];
|
||||
[_colorTree setObject:@"8a2be2" forKey:@"blueviolet"];
|
||||
[_colorTree setObject:@"a52a2a" forKey:@"brown"];
|
||||
[_colorTree setObject:@"deb887" forKey:@"burlywood"];
|
||||
[_colorTree setObject:@"5f9ea0" forKey:@"cadetblue"];
|
||||
[_colorTree setObject:@"7fff00" forKey:@"chartreuse"];
|
||||
[_colorTree setObject:@"d2691e" forKey:@"chocolate"];
|
||||
[_colorTree setObject:@"ff7f50" forKey:@"coral"];
|
||||
[_colorTree setObject:@"6495ed" forKey:@"cornflowerblue"];
|
||||
[_colorTree setObject:@"fff8dc" forKey:@"cornsilk"];
|
||||
[_colorTree setObject:@"dc143c" forKey:@"crimson"];
|
||||
[_colorTree setObject:@"00ffff" forKey:@"cyan"];
|
||||
[_colorTree setObject:@"00008b" forKey:@"darkblue"];
|
||||
[_colorTree setObject:@"008b8b" forKey:@"darkcyan"];
|
||||
[_colorTree setObject:@"b8860b" forKey:@"darkgoldenrod"];
|
||||
[_colorTree setObject:@"a9a9a9" forKey:@"darkgray"];
|
||||
[_colorTree setObject:@"006400" forKey:@"darkgreen"];
|
||||
[_colorTree setObject:@"a9a9a9" forKey:@"darkgrey"];
|
||||
[_colorTree setObject:@"bdb76b" forKey:@"darkkhaki"];
|
||||
[_colorTree setObject:@"8b008b" forKey:@"darkmagenta"];
|
||||
[_colorTree setObject:@"556b2f" forKey:@"darkolivegreen"];
|
||||
[_colorTree setObject:@"ff8c00" forKey:@"darkorange"];
|
||||
[_colorTree setObject:@"9932cc" forKey:@"darkorchid"];
|
||||
[_colorTree setObject:@"8b0000" forKey:@"darkred"];
|
||||
[_colorTree setObject:@"e9967a" forKey:@"darksalmon"];
|
||||
[_colorTree setObject:@"8fbc8f" forKey:@"darkseagreen"];
|
||||
[_colorTree setObject:@"483d8b" forKey:@"darkslateblue"];
|
||||
[_colorTree setObject:@"2f4f4f" forKey:@"darkslategray"];
|
||||
[_colorTree setObject:@"2f4f4f" forKey:@"darkslategrey"];
|
||||
[_colorTree setObject:@"00ced1" forKey:@"darkturquoise"];
|
||||
[_colorTree setObject:@"9400d3" forKey:@"darkviolet"];
|
||||
[_colorTree setObject:@"ff1493" forKey:@"deeppink"];
|
||||
[_colorTree setObject:@"00bfff" forKey:@"deepskyblue"];
|
||||
[_colorTree setObject:@"696969" forKey:@"dimgray"];
|
||||
[_colorTree setObject:@"696969" forKey:@"dimgrey"];
|
||||
[_colorTree setObject:@"1e90ff" forKey:@"dodgerblue"];
|
||||
[_colorTree setObject:@"b22222" forKey:@"firebrick"];
|
||||
[_colorTree setObject:@"fffaf0" forKey:@"floralwhite"];
|
||||
[_colorTree setObject:@"228b22" forKey:@"forestgreen"];
|
||||
[_colorTree setObject:@"ff00ff" forKey:@"fuchsia"];
|
||||
[_colorTree setObject:@"dcdcdc" forKey:@"gainsboro"];
|
||||
[_colorTree setObject:@"f8f8ff" forKey:@"ghostwhite"];
|
||||
[_colorTree setObject:@"ffd700" forKey:@"gold"];
|
||||
[_colorTree setObject:@"daa520" forKey:@"goldenrod"];
|
||||
[_colorTree setObject:@"808080" forKey:@"gray"];
|
||||
[_colorTree setObject:@"008000" forKey:@"green"];
|
||||
[_colorTree setObject:@"adff2f" forKey:@"greenyellow"];
|
||||
[_colorTree setObject:@"808080" forKey:@"grey"];
|
||||
[_colorTree setObject:@"f0fff0" forKey:@"honeydew"];
|
||||
[_colorTree setObject:@"ff69b4" forKey:@"hotpink"];
|
||||
[_colorTree setObject:@"cd5c5c" forKey:@"indianred"];
|
||||
[_colorTree setObject:@"4b0082" forKey:@"indigo"];
|
||||
[_colorTree setObject:@"fffff0" forKey:@"ivory"];
|
||||
[_colorTree setObject:@"f0e68c" forKey:@"khaki"];
|
||||
[_colorTree setObject:@"e6e6fa" forKey:@"lavender"];
|
||||
[_colorTree setObject:@"fff0f5" forKey:@"lavenderblush"];
|
||||
[_colorTree setObject:@"7cfc00" forKey:@"lawngreen"];
|
||||
[_colorTree setObject:@"fffacd" forKey:@"lemonchiffon"];
|
||||
[_colorTree setObject:@"add8e6" forKey:@"lightblue"];
|
||||
[_colorTree setObject:@"f08080" forKey:@"lightcoral"];
|
||||
[_colorTree setObject:@"e0ffff" forKey:@"lightcyan"];
|
||||
[_colorTree setObject:@"fafad2" forKey:@"lightgoldenrodyellow"];
|
||||
[_colorTree setObject:@"d3d3d3" forKey:@"lightgray"];
|
||||
[_colorTree setObject:@"90ee90" forKey:@"lightgreen"];
|
||||
[_colorTree setObject:@"d3d3d3" forKey:@"lightgrey"];
|
||||
[_colorTree setObject:@"ffb6c1" forKey:@"lightpink"];
|
||||
[_colorTree setObject:@"ffa07a" forKey:@"lightsalmon"];
|
||||
[_colorTree setObject:@"20b2aa" forKey:@"lightseagreen"];
|
||||
[_colorTree setObject:@"87cefa" forKey:@"lightskyblue"];
|
||||
[_colorTree setObject:@"778899" forKey:@"lightslategray"];
|
||||
[_colorTree setObject:@"778899" forKey:@"lightslategrey"];
|
||||
[_colorTree setObject:@"b0c4de" forKey:@"lightsteelblue"];
|
||||
[_colorTree setObject:@"ffffe0" forKey:@"lightyellow"];
|
||||
[_colorTree setObject:@"00ff00" forKey:@"lime"];
|
||||
[_colorTree setObject:@"32cd32" forKey:@"limegreen"];
|
||||
[_colorTree setObject:@"faf0e6" forKey:@"linen"];
|
||||
[_colorTree setObject:@"ff00ff" forKey:@"magenta"];
|
||||
[_colorTree setObject:@"800000" forKey:@"maroon"];
|
||||
[_colorTree setObject:@"66cdaa" forKey:@"mediumaquamarine"];
|
||||
[_colorTree setObject:@"0000cd" forKey:@"mediumblue"];
|
||||
[_colorTree setObject:@"ba55d3" forKey:@"mediumorchid"];
|
||||
[_colorTree setObject:@"9370db" forKey:@"mediumpurple"];
|
||||
[_colorTree setObject:@"3cb371" forKey:@"mediumseagreen"];
|
||||
[_colorTree setObject:@"7b68ee" forKey:@"mediumslateblue"];
|
||||
[_colorTree setObject:@"00fa9a" forKey:@"mediumspringgreen"];
|
||||
[_colorTree setObject:@"48d1cc" forKey:@"mediumturquoise"];
|
||||
[_colorTree setObject:@"c71585" forKey:@"mediumvioletred"];
|
||||
[_colorTree setObject:@"191970" forKey:@"midnightblue"];
|
||||
[_colorTree setObject:@"f5fffa" forKey:@"mintcream"];
|
||||
[_colorTree setObject:@"ffe4e1" forKey:@"mistyrose"];
|
||||
[_colorTree setObject:@"ffe4b5" forKey:@"moccasin"];
|
||||
[_colorTree setObject:@"ffdead" forKey:@"navajowhite"];
|
||||
[_colorTree setObject:@"000080" forKey:@"navy"];
|
||||
[_colorTree setObject:@"fdf5e6" forKey:@"oldlace"];
|
||||
[_colorTree setObject:@"808000" forKey:@"olive"];
|
||||
[_colorTree setObject:@"6b8e23" forKey:@"olivedrab"];
|
||||
[_colorTree setObject:@"ffa500" forKey:@"orange"];
|
||||
[_colorTree setObject:@"ff4500" forKey:@"orangered"];
|
||||
[_colorTree setObject:@"da70d6" forKey:@"orchid"];
|
||||
[_colorTree setObject:@"eee8aa" forKey:@"palegoldenrod"];
|
||||
[_colorTree setObject:@"98fb98" forKey:@"palegreen"];
|
||||
[_colorTree setObject:@"afeeee" forKey:@"paleturquoise"];
|
||||
[_colorTree setObject:@"db7093" forKey:@"palevioletred"];
|
||||
[_colorTree setObject:@"ffefd5" forKey:@"papayawhip"];
|
||||
[_colorTree setObject:@"ffdab9" forKey:@"peachpuff"];
|
||||
[_colorTree setObject:@"cd853f" forKey:@"peru"];
|
||||
[_colorTree setObject:@"ffc0cb" forKey:@"pink"];
|
||||
[_colorTree setObject:@"dda0dd" forKey:@"plum"];
|
||||
[_colorTree setObject:@"b0e0e6" forKey:@"powderblue"];
|
||||
[_colorTree setObject:@"800080" forKey:@"purple"];
|
||||
[_colorTree setObject:@"ff0000" forKey:@"red"];
|
||||
[_colorTree setObject:@"bc8f8f" forKey:@"rosybrown"];
|
||||
[_colorTree setObject:@"4169e1" forKey:@"royalblue"];
|
||||
[_colorTree setObject:@"8b4513" forKey:@"saddlebrown"];
|
||||
[_colorTree setObject:@"fa8072" forKey:@"salmon"];
|
||||
[_colorTree setObject:@"f4a460" forKey:@"sandybrown"];
|
||||
[_colorTree setObject:@"2e8b57" forKey:@"seagreen"];
|
||||
[_colorTree setObject:@"fff5ee" forKey:@"seashell"];
|
||||
[_colorTree setObject:@"a0522d" forKey:@"sienna"];
|
||||
[_colorTree setObject:@"c0c0c0" forKey:@"silver"];
|
||||
[_colorTree setObject:@"87ceeb" forKey:@"skyblue"];
|
||||
[_colorTree setObject:@"6a5acd" forKey:@"slateblue"];
|
||||
[_colorTree setObject:@"708090" forKey:@"slategray"];
|
||||
[_colorTree setObject:@"708090" forKey:@"slategrey"];
|
||||
[_colorTree setObject:@"fffafa" forKey:@"snow"];
|
||||
[_colorTree setObject:@"00ff7f" forKey:@"springgreen"];
|
||||
[_colorTree setObject:@"4682b4" forKey:@"steelblue"];
|
||||
[_colorTree setObject:@"d2b48c" forKey:@"tan"];
|
||||
[_colorTree setObject:@"008080" forKey:@"teal"];
|
||||
[_colorTree setObject:@"d8bfd8" forKey:@"thistle"];
|
||||
[_colorTree setObject:@"ff6347" forKey:@"tomato"];
|
||||
[_colorTree setObject:@"40e0d0" forKey:@"turquoise"];
|
||||
[_colorTree setObject:@"ee82ee" forKey:@"violet"];
|
||||
[_colorTree setObject:@"f5deb3" forKey:@"wheat"];
|
||||
[_colorTree setObject:@"ffffff" forKey:@"white"];
|
||||
[_colorTree setObject:@"f5f5f5" forKey:@"whitesmoke"];
|
||||
[_colorTree setObject:@"ffff00" forKey:@"yellow"];
|
||||
[_colorTree setObject:@"9acd32" forKey:@"yellowgreen"];
|
||||
_colorTree = [@{
|
||||
@"aliceblue":@(0xf0f8ff),
|
||||
@"antiquewhite":@(0xfaebd7),
|
||||
@"aqua":@(0x00ffff),
|
||||
@"aquamarine":@(0x7fffd4),
|
||||
@"azure":@(0xf0ffff),
|
||||
@"beige":@(0xf5f5dc),
|
||||
@"bisque":@(0xffe4c4),
|
||||
@"black":@(0x000000),
|
||||
@"blanchedalmond":@(0xffebcd),
|
||||
@"blue":@(0x0000ff),
|
||||
@"blueviolet":@(0x8a2be2),
|
||||
@"brown":@(0xa52a2a),
|
||||
@"burlywood":@(0xdeb887),
|
||||
@"cadetblue":@(0x5f9ea0),
|
||||
@"chartreuse":@(0x7fff00),
|
||||
@"chocolate":@(0xd2691e),
|
||||
@"coral":@(0xff7f50),
|
||||
@"cornflowerblue":@(0x6495ed),
|
||||
@"cornsilk":@(0xfff8dc),
|
||||
@"crimson":@(0xdc143c),
|
||||
@"currentcolor":@(0x000000),
|
||||
@"cyan":@(0x00ffff),
|
||||
@"darkblue":@(0x00008b),
|
||||
@"darkcyan":@(0x008b8b),
|
||||
@"darkgoldenrod":@(0xb8860b),
|
||||
@"darkgray":@(0xa9a9a9),
|
||||
@"darkgreen":@(0x006400),
|
||||
@"darkgrey":@(0xa9a9a9),
|
||||
@"darkkhaki":@(0xbdb76b),
|
||||
@"darkmagenta":@(0x8b008b),
|
||||
@"darkolivegreen":@(0x556b2f),
|
||||
@"darkorange":@(0xff8c00),
|
||||
@"darkorchid":@(0x9932cc),
|
||||
@"darkred":@(0x8b0000),
|
||||
@"darksalmon":@(0xe9967a),
|
||||
@"darkseagreen":@(0x8fbc8f),
|
||||
@"darkslateblue":@(0x483d8b),
|
||||
@"darkslategray":@(0x2f4f4f),
|
||||
@"darkturquoise":@(0x00ced1),
|
||||
@"darkviolet":@(0x9400d3),
|
||||
@"deeppink":@(0xff1493),
|
||||
@"deepskyblue":@(0x00bfff),
|
||||
@"dimgray":@(0x696969),
|
||||
@"dimgrey":@(0x696969),
|
||||
@"dodgerblue":@(0x1e90ff),
|
||||
@"firebrick":@(0xb22222),
|
||||
@"floralwhite":@(0xfffaf0),
|
||||
@"forestgreen":@(0x228b22),
|
||||
@"fuchsia":@(0xff00ff),
|
||||
@"gainsboro":@(0xdcdcdc),
|
||||
@"ghostwhite":@(0xf8f8ff),
|
||||
@"gold":@(0xffd700),
|
||||
@"goldenrod":@(0xdaa520),
|
||||
@"gray":@(0x808080),
|
||||
@"green":@(0x008000),
|
||||
@"greenyellow":@(0xadff2f),
|
||||
@"grey":@(0x808080),
|
||||
@"honeydew":@(0xf0fff0),
|
||||
@"hotpink":@(0xff69b4),
|
||||
@"indianred":@(0xcd5c5c),
|
||||
@"indigo":@(0x4b0082),
|
||||
@"ivory":@(0xfffff0),
|
||||
@"khaki":@(0xf0e68c),
|
||||
@"lavender":@(0xe6e6fa),
|
||||
@"lavenderblush":@(0xfff0f5),
|
||||
@"lawngreen":@(0x7cfc00),
|
||||
@"lemonchiffon":@(0xfffacd),
|
||||
@"lightblue":@(0xadd8e6),
|
||||
@"lightcoral":@(0xf08080),
|
||||
@"lightcyan":@(0xe0ffff),
|
||||
@"lightgoldenrodyellow":@(0xfafad2),
|
||||
@"lightgray":@(0xd3d3d3),
|
||||
@"lightgreen":@(0x90ee90),
|
||||
@"lightgrey":@(0xd3d3d3),
|
||||
@"lightpink":@(0xffb6c1),
|
||||
@"lightsalmon":@(0xffa07a),
|
||||
@"lightseagreen":@(0x20b2aa),
|
||||
@"lightskyblue":@(0x87cefa),
|
||||
@"lightslategray":@(0x778899),
|
||||
@"lightsteelblue":@(0xb0c4de),
|
||||
@"lightyellow":@(0xffffe0),
|
||||
@"lime":@(0x00ff00),
|
||||
@"limegreen":@(0x32cd32),
|
||||
@"linen":@(0xfaf0e6),
|
||||
@"magenta":@(0xff00ff),
|
||||
@"maroon":@(0x800000),
|
||||
@"mediumaquamarine":@(0x66cdaa),
|
||||
@"mediumblue":@(0x0000cd),
|
||||
@"mediumorchid":@(0xba55d3),
|
||||
@"mediumpurple":@(0x9370db),
|
||||
@"mediumseagreen":@(0x3cb371),
|
||||
@"mediumslateblue":@(0x7b68ee),
|
||||
@"mediumspringgreen":@(0x00fa9a),
|
||||
@"mediumturquoise":@(0x48d1cc),
|
||||
@"mediumvioletred":@(0xc71585),
|
||||
@"midnightblue":@(0x191970),
|
||||
@"mintcream":@(0xf5fffa),
|
||||
@"mistyrose":@(0xffe4e1),
|
||||
@"moccasin":@(0xffe4b5),
|
||||
@"navajowhite":@(0xffdead),
|
||||
@"navy":@(0x000080),
|
||||
@"oldlace":@(0xfdf5e6),
|
||||
@"olive":@(0x808000),
|
||||
@"olivedrab":@(0x6b8e23),
|
||||
@"orange":@(0xffa500),
|
||||
@"orangered":@(0xff4500),
|
||||
@"orchid":@(0xda70d6),
|
||||
@"palegoldenrod":@(0xeee8aa),
|
||||
@"palegreen":@(0x98fb98),
|
||||
@"paleturquoise":@(0xafeeee),
|
||||
@"palevioletred":@(0xdb7093),
|
||||
@"papayawhip":@(0xffefd5),
|
||||
@"peachpuff":@(0xffdab9),
|
||||
@"peru":@(0xcd853f),
|
||||
@"pink":@(0xffc0cb),
|
||||
@"plum":@(0xdda0dd),
|
||||
@"powderblue":@(0xb0e0e6),
|
||||
@"purple":@(0x800080),
|
||||
@"red":@(0xff0000),
|
||||
@"rosybrown":@(0xbc8f8f),
|
||||
@"royalblue":@(0x4169e1),
|
||||
@"saddlebrown":@(0x8b4513),
|
||||
@"salmon":@(0xfa8072),
|
||||
@"sandybrown":@(0xf4a460),
|
||||
@"seagreen":@(0x2e8b57),
|
||||
@"seashell":@(0xfff5ee),
|
||||
@"sienna":@(0xa0522d),
|
||||
@"silver":@(0xc0c0c0),
|
||||
@"skyblue":@(0x87ceeb),
|
||||
@"slateblue":@(0x6a5acd),
|
||||
@"slategrey":@(0x708090),
|
||||
@"snow":@(0xfffafa),
|
||||
@"springgreen":@(0x00ff7f),
|
||||
@"steelblue":@(0x4682b4),
|
||||
@"tan":@(0xd2b48c),
|
||||
@"teal":@(0x008080),
|
||||
@"thistle":@(0xd8bfd8),
|
||||
@"tomato":@(0xff6347),
|
||||
@"turquoise":@(0x40e0d0),
|
||||
@"violet":@(0xee82ee),
|
||||
@"wheat":@(0xf5deb3),
|
||||
@"white":@(0xffffff),
|
||||
@"whitesmoke":@(0xf5f5f5),
|
||||
@"yellow":@(0xffff00),
|
||||
@"yellowgreen":@(0x9acd32)
|
||||
} retain];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -183,81 +213,184 @@ static NSMutableDictionary * _colorTree = nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSColor *)colorFromRString:(NSString *)rString
|
||||
gString:(NSString *)gString
|
||||
bString:(NSString *)bString
|
||||
aString:(NSString *)aString
|
||||
{
|
||||
return [self colorFromRUnit:[IJSVGUnitLength unitWithString:rString]
|
||||
gUnit:[IJSVGUnitLength unitWithString:gString]
|
||||
bUnit:[IJSVGUnitLength unitWithString:bString]
|
||||
aUnit:[IJSVGUnitLength unitWithString:aString]];
|
||||
}
|
||||
|
||||
+ (NSColor *)colorFromRUnit:(IJSVGUnitLength *)rUnit
|
||||
gUnit:(IJSVGUnitLength *)gUnit
|
||||
bUnit:(IJSVGUnitLength *)bUnit
|
||||
aUnit:(IJSVGUnitLength *)aUnit
|
||||
{
|
||||
CGFloat r = rUnit.type == IJSVGUnitLengthTypePercentage ?
|
||||
[rUnit computeValue:255.f] : [rUnit computeValue:1.f];
|
||||
CGFloat g = gUnit.type == IJSVGUnitLengthTypePercentage ?
|
||||
[gUnit computeValue:255.f] : [gUnit computeValue:1.f];
|
||||
CGFloat b = bUnit.type == IJSVGUnitLengthTypePercentage ?
|
||||
[bUnit computeValue:255.f] : [bUnit computeValue:1.f];
|
||||
CGFloat a = [aUnit computeValue:100.f];
|
||||
return [self computeColorSpace:[NSColor colorWithDeviceRed:(r/255.f)
|
||||
green:(g/255.f)
|
||||
blue:(b/255.f)
|
||||
alpha:a]];
|
||||
}
|
||||
|
||||
+ (NSColor *)colorFromString:(NSString *)string
|
||||
{
|
||||
if( [string length] < 3 )
|
||||
return nil;
|
||||
|
||||
string = [string lowercaseString];
|
||||
NSColor * color = [[self class] colorFromPredefinedColorName:string];
|
||||
if( color != nil )
|
||||
return color;
|
||||
NSCharacterSet * set = NSCharacterSet.whitespaceAndNewlineCharacterSet;
|
||||
string = [string stringByTrimmingCharactersInSet:set];
|
||||
|
||||
if( [[string lowercaseString] isEqualToString:@"none"] )
|
||||
return [NSColor clearColor];
|
||||
if( [string length] < 3 ) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSColor * color = nil;
|
||||
string = [string lowercaseString];
|
||||
if([self.class isHex:string] == NO) {
|
||||
color = [self.class colorFromPredefinedColorName:string];
|
||||
if( color != nil ) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
// is simply a clear color, dont fill
|
||||
if( [[string lowercaseString] isEqualToString:@"none"] ) {
|
||||
return [self computeColorSpace:NSColor.clearColor];
|
||||
}
|
||||
|
||||
// is it RGB?
|
||||
if( [[string substringToIndex:3] isEqualToString:@"rgb"] )
|
||||
{
|
||||
if( [[string substringToIndex:3] isEqualToString:@"rgb"] ) {
|
||||
NSRange range = [IJSVGUtils rangeOfParentheses:string];
|
||||
NSString * rgbString = [string substringWithRange:range];
|
||||
NSArray * parts = [rgbString ijsvg_componentsSeparatedByChars:","];
|
||||
NSString * alpha = @"100%";
|
||||
if(parts.count == 4) {
|
||||
alpha = parts[3];
|
||||
}
|
||||
return [self colorFromRString:parts[0]
|
||||
gString:parts[1]
|
||||
bString:parts[2]
|
||||
aString:alpha];
|
||||
}
|
||||
|
||||
// is it HSL?
|
||||
if([[string substringToIndex:3] isEqualToString:@"hsl"]) {
|
||||
NSInteger count = 0;
|
||||
CGFloat * params = [IJSVGUtils commandParameters:string
|
||||
count:&count];
|
||||
CGFloat alpha = 1;
|
||||
if( count == 4 )
|
||||
if(count == 4) {
|
||||
alpha = params[3];
|
||||
color = [NSColor colorWithDeviceRed:params[0]/255
|
||||
green:params[1]/255
|
||||
blue:params[2]/255
|
||||
}
|
||||
|
||||
// convert HSL to HSB
|
||||
CGFloat * hsb = IJSVGColorCSSHSLToHSB(params[0], params[1], params[2]);
|
||||
color = [NSColor colorWithDeviceHue:hsb[0]
|
||||
saturation:hsb[1]
|
||||
brightness:hsb[2]
|
||||
alpha:alpha];
|
||||
|
||||
color = [self computeColorSpace:color];
|
||||
|
||||
// memory clean!
|
||||
free(hsb);
|
||||
free(params);
|
||||
return color;
|
||||
}
|
||||
|
||||
color = [[self class] colorFromHEXString:string
|
||||
alpha:1.f];
|
||||
color = [self.class colorFromHEXString:string];
|
||||
return color;
|
||||
}
|
||||
|
||||
+ (NSColor *)colorFromPredefinedColorName:(NSString *)name
|
||||
{
|
||||
NSString * hex = nil;
|
||||
NSNumber * hex = nil;
|
||||
name = [name.lowercaseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
if( ( hex = [_colorTree objectForKey:name] ) == nil )
|
||||
if((hex = _colorTree[name]) == nil ) {
|
||||
return nil;
|
||||
return [[self class] colorFromHEXString:hex
|
||||
alpha:1.f];
|
||||
}
|
||||
return [self.class colorFromHEXInteger:hex.integerValue];
|
||||
}
|
||||
|
||||
+ (NSString *)colorStringFromColor:(NSColor *)color
|
||||
{
|
||||
IJSVGColorStringOptions options = IJSVGColorStringOptionDefault;
|
||||
return [self colorStringFromColor:color
|
||||
forceHex:NO];
|
||||
options:options];
|
||||
}
|
||||
|
||||
+ (NSString *)colorStringFromColor:(NSColor *)color
|
||||
forceHex:(BOOL)forceHex
|
||||
options:(IJSVGColorStringOptions)options
|
||||
{
|
||||
// convert to RGB
|
||||
color = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
|
||||
color = [self computeColorSpace:color];
|
||||
|
||||
int red = color.redComponent * 0xFF;
|
||||
int green = color.greenComponent * 0xFF;
|
||||
int blue = color.blueComponent * 0xFF;
|
||||
int alpha = (int)(color.alphaComponent*100);
|
||||
|
||||
BOOL forceHex = (options & IJSVGColorStringOptionForceHEX) != 0;
|
||||
BOOL allowShortHand = (options & IJSVGColorStringOptionAllowShortHand) != 0;
|
||||
BOOL allowRRGGBBAA = (options & IJSVGColorStringOptionAllowRRGGBBAA) != 0;
|
||||
|
||||
// jsut return none
|
||||
if(alpha == 0 && forceHex == NO) {
|
||||
return @"none";
|
||||
}
|
||||
|
||||
// always return hex unless criteria is met
|
||||
if(forceHex || alpha == 100 ||
|
||||
if(forceHex == YES || allowRRGGBBAA == YES || alpha == 100 ||
|
||||
(red == 0 && green == 0 && blue == 0 && alpha == 0) ||
|
||||
(red == 255 && green == 255 && blue == 255 && alpha == 100)) {
|
||||
// just return hex
|
||||
|
||||
// we need to make sure the last 2 chars
|
||||
// are the same or we cant enable shorthand
|
||||
if(allowRRGGBBAA == YES) {
|
||||
NSString * alphaHexString = [NSString stringWithFormat:@"%02X",
|
||||
(int)(color.alphaComponent * 0xFF)];
|
||||
if([alphaHexString characterAtIndex:0] !=
|
||||
[alphaHexString characterAtIndex:1]) {
|
||||
allowShortHand = NO;
|
||||
}
|
||||
}
|
||||
|
||||
if(allowShortHand == YES) {
|
||||
NSString * r = [NSString stringWithFormat:@"%02X",red];
|
||||
NSString * g = [NSString stringWithFormat:@"%02X",green];
|
||||
NSString * b = [NSString stringWithFormat:@"%02X",blue];
|
||||
if([r characterAtIndex:0] == [r characterAtIndex:1] &&
|
||||
[g characterAtIndex:0] == [g characterAtIndex:1] &&
|
||||
[b characterAtIndex:0] == [b characterAtIndex:1]) {
|
||||
// allow shorthand alpha
|
||||
if(allowRRGGBBAA == YES && alpha != 100) {
|
||||
NSString * a = [NSString stringWithFormat:@"%02X",
|
||||
(int)(color.alphaComponent * 0xFF)];
|
||||
return [NSString stringWithFormat:@"#%c%c%c%c",
|
||||
[r characterAtIndex:0], [g characterAtIndex:0],
|
||||
[b characterAtIndex:0], [a characterAtIndex:0]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"#%c%c%c",[r characterAtIndex:0],
|
||||
[g characterAtIndex:0],[b characterAtIndex:0]];
|
||||
}
|
||||
}
|
||||
if(allowRRGGBBAA == YES && alpha != 100) {
|
||||
return [NSString stringWithFormat:@"#%02X%02X%02X%02X",red,green,
|
||||
blue,(int)(color.alphaComponent * 0xFF)];
|
||||
}
|
||||
return [NSString stringWithFormat:@"#%02X%02X%02X",red,green,blue];
|
||||
}
|
||||
return [NSString stringWithFormat:@"rgba(%d, %d, %d, %d)",red, green, blue, alpha];
|
||||
|
||||
// note the %g, CSS alpha is 0 to 1, not 0 - 100, my bad!
|
||||
return [NSString stringWithFormat:@"rgba(%d,%d,%d,%g)",red, green, blue,
|
||||
((float)alpha/100.f)];
|
||||
}
|
||||
|
||||
+ (NSString *)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color
|
||||
@@ -565,59 +698,100 @@ static NSMutableDictionary * _colorTree = nil;
|
||||
+ (NSColor *)changeAlphaOnColor:(NSColor *)color
|
||||
to:(CGFloat)alphaValue
|
||||
{
|
||||
color = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
|
||||
return [NSColor colorWithDeviceRed:[color redComponent]
|
||||
green:[color greenComponent]
|
||||
blue:[color blueComponent]
|
||||
alpha:alphaValue];
|
||||
color = [self computeColorSpace:color];
|
||||
return [self computeColorSpace:[NSColor colorWithDeviceRed:color.redComponent
|
||||
green:color.greenComponent
|
||||
blue:color.blueComponent
|
||||
alpha:alphaValue]];
|
||||
}
|
||||
|
||||
+ (BOOL)isColor:(NSString *)string
|
||||
{
|
||||
return [[string substringToIndex:1] isEqualToString:@"#"] || [[string substringToIndex:3] isEqualToString:@"rgb"];
|
||||
return [[string substringToIndex:1] isEqualToString:@"#"] ||
|
||||
[[string substringToIndex:3] isEqualToString:@"rgb"];
|
||||
}
|
||||
|
||||
+ (BOOL)isHex:(NSString *)string
|
||||
{
|
||||
NSCharacterSet *chars = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef#"] invertedSet];
|
||||
return [string rangeOfCharacterFromSet:chars].location == NSNotFound;
|
||||
const char * validList = "0123456789ABCDEFabcdef#";
|
||||
for(NSInteger i = 0; i < string.length; i++) {
|
||||
char c = [string characterAtIndex:i];
|
||||
if(strchr(validList, c) == NULL) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (unsigned long)lengthOfHEXInteger:(NSUInteger)hex
|
||||
{
|
||||
char * buffer;
|
||||
asprintf(&buffer, "%lX", (long)hex);
|
||||
unsigned long length = strlen(buffer);
|
||||
free(buffer);
|
||||
return length;
|
||||
}
|
||||
|
||||
+ (BOOL)HEXContainsAlphaComponent:(NSUInteger)hex
|
||||
{
|
||||
return [self lengthOfHEXInteger:hex] == 8;
|
||||
}
|
||||
|
||||
+ (NSColor *)colorFromHEXInteger:(NSInteger)hex
|
||||
{
|
||||
CGFloat alpha = 1.f;
|
||||
if([self HEXContainsAlphaComponent:hex] == YES) {
|
||||
alpha = (hex & 0xFF) / 255.f;
|
||||
hex = hex >> 8;
|
||||
}
|
||||
return [self computeColorSpace:[NSColor colorWithDeviceRed:((hex >> 16) & 0xFF) / 255.f
|
||||
green:((hex >> 8) & 0xFF) / 255.f
|
||||
blue:(hex & 0xFF) / 255.f
|
||||
alpha:alpha]];
|
||||
}
|
||||
|
||||
+ (unsigned long)HEXFromArbitraryHexString:(NSString *)aString
|
||||
{
|
||||
const char * hexString = [aString cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
return strtoul(hexString, NULL, 16);
|
||||
}
|
||||
|
||||
+ (NSColor *)colorFromHEXString:(NSString *)string
|
||||
alpha:(CGFloat)alpha
|
||||
{
|
||||
return [self colorFromHEXString:string
|
||||
containsAlphaComponent:nil];
|
||||
}
|
||||
|
||||
+ (NSColor *)colorFromHEXString:(NSString *)string
|
||||
containsAlphaComponent:(BOOL *)containsAlphaComponent
|
||||
{
|
||||
// absolutely no string
|
||||
if( string == nil || string.length == 0 || ![[self class] isHex:string] )
|
||||
if( string == nil || string.length == 0 || ![self.class isHex:string] ) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if( [[string substringToIndex:1] isEqualToString:@"#"] )
|
||||
if( [[string substringToIndex:1] isEqualToString:@"#"] ) {
|
||||
string = [string substringFromIndex:1];
|
||||
}
|
||||
|
||||
// whats the length?
|
||||
if(string.length == 3) {
|
||||
NSUInteger length = string.length;
|
||||
if(length == 3 || length == 4) {
|
||||
// shorthand...
|
||||
NSMutableString * str = [[[NSMutableString alloc] init] autorelease];
|
||||
for( NSInteger i = 0; i < string.length; i++ )
|
||||
{
|
||||
NSString * sub = [string substringWithRange:NSMakeRange( i, 1)];
|
||||
for( NSInteger i = 0; i < length; i++ ) {
|
||||
NSString * sub = [string substringWithRange:NSMakeRange(i, 1)];
|
||||
[str appendFormat:@"%@%@",sub,sub];
|
||||
}
|
||||
string = str;
|
||||
}
|
||||
|
||||
NSScanner * scanner = [NSScanner scannerWithString:string];
|
||||
unsigned int hex;
|
||||
if( [scanner scanHexInt:&hex] )
|
||||
{
|
||||
NSInteger r = (hex>>16) & 0xFF;
|
||||
NSInteger g = (hex>>8) & 0xFF;
|
||||
NSInteger b = (hex) & 0xFF;
|
||||
return [NSColor colorWithDeviceRed:r/255.f
|
||||
green:g/255.f
|
||||
blue:b/255.f
|
||||
alpha:alpha];
|
||||
// now convert rest to hex
|
||||
unsigned long hex = [self HEXFromArbitraryHexString:string];
|
||||
if(containsAlphaComponent != nil) {
|
||||
*containsAlphaComponent = [self HEXContainsAlphaComponent:hex];
|
||||
}
|
||||
return nil;
|
||||
return [self colorFromHEXInteger:hex];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// IJSVGColorList.h
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 07/07/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGColor.h"
|
||||
|
||||
@interface IJSVGColorList : NSObject <NSCopying> {
|
||||
|
||||
@private
|
||||
NSMutableDictionary<NSColor *, NSColor *> * _replacementColorTree;
|
||||
NSMutableSet<NSColor *> * _colors;
|
||||
}
|
||||
|
||||
- (NSColor *)proposedColorForColor:(NSColor *)color;
|
||||
- (void)removeAllReplacementColors;
|
||||
- (void)removeReplacementColor:(NSColor *)color;
|
||||
- (void)setReplacementColor:(NSColor *)newColor
|
||||
forColor:(NSColor *)color;
|
||||
- (void)setReplacementColors:(NSDictionary<NSColor *, NSColor *> *)colors
|
||||
clearExistingColors:(BOOL)clearExistingColors;
|
||||
|
||||
- (void)addColorsFromList:(IJSVGColorList *)sheet;
|
||||
- (NSSet<NSColor *> *)colors;
|
||||
- (void)addColor:(NSColor *)color;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// IJSVGColorList.m
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 07/07/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGColorList.h"
|
||||
|
||||
@implementation IJSVGColorList
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_replacementColorTree release], _replacementColorTree = nil;
|
||||
[_colors release], _colors = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
_replacementColorTree = [[NSMutableDictionary alloc] init];
|
||||
_colors = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
IJSVGColorList * sheet = [[self.class alloc] init];
|
||||
[sheet setReplacementColors:[_replacementColorTree.copy autorelease]
|
||||
clearExistingColors:YES];
|
||||
return sheet;
|
||||
}
|
||||
|
||||
- (NSColor *)proposedColorForColor:(NSColor *)color
|
||||
{
|
||||
// nothing found, just return color
|
||||
if(_replacementColorTree == nil || _replacementColorTree.count == 0) {
|
||||
return color;
|
||||
}
|
||||
|
||||
// check the mappings
|
||||
NSColor * found = nil;
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
if((found = _replacementColorTree[color]) != nil) {
|
||||
return found;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
- (void)_invalidateColorTree
|
||||
{
|
||||
[_replacementColorTree release], _replacementColorTree = nil;
|
||||
_replacementColorTree = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
- (void)removeAllReplacementColors
|
||||
{
|
||||
[self _invalidateColorTree];
|
||||
}
|
||||
|
||||
- (void)removeReplacementColor:(NSColor *)color
|
||||
{
|
||||
if(_replacementColorTree == nil) {
|
||||
return;
|
||||
}
|
||||
[_replacementColorTree removeObjectForKey:[IJSVGColor computeColorSpace:color]];
|
||||
}
|
||||
|
||||
- (void)setReplacementColor:(NSColor *)newColor
|
||||
forColor:(NSColor *)color
|
||||
{
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
newColor = [IJSVGColor computeColorSpace:newColor];
|
||||
_replacementColorTree[color] = newColor;
|
||||
}
|
||||
|
||||
- (void)setReplacementColors:(NSDictionary<NSColor *, NSColor *> *)colors
|
||||
clearExistingColors:(BOOL)clearExistingColors
|
||||
{
|
||||
if(clearExistingColors == YES) {
|
||||
[self _invalidateColorTree];
|
||||
}
|
||||
for(NSColor * oldColor in colors) {
|
||||
[self setReplacementColor:colors[oldColor]
|
||||
forColor:oldColor];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSSet<NSColor *> *)colors
|
||||
{
|
||||
return [NSSet setWithSet:_colors];
|
||||
}
|
||||
|
||||
- (void)addColorsFromList:(IJSVGColorList *)sheet
|
||||
{
|
||||
[_colors addObjectsFromArray:sheet.colors.allObjects];
|
||||
}
|
||||
|
||||
- (void)addColor:(NSColor *)color
|
||||
{
|
||||
[_colors addObject:[IJSVGColor computeColorSpace:color]];
|
||||
}
|
||||
|
||||
- (void)removeColor:(NSColor *)color
|
||||
{
|
||||
[_colors removeObject:[IJSVGColor computeColorSpace:color]];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -9,27 +9,13 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGPath.h"
|
||||
|
||||
static const NSInteger IJSVGCustomVariableParameterCount = NSNotFound;
|
||||
|
||||
typedef NS_ENUM( NSInteger, IJSVGCommandType ) {
|
||||
IJSVGCommandTypeAbsolute,
|
||||
IJSVGCommandTypeRelative
|
||||
};
|
||||
|
||||
@class IJSVGCommand;
|
||||
|
||||
@protocol IJSVGCommandProtocol <NSObject>
|
||||
|
||||
@required
|
||||
+ (void)runWithParams:(CGFloat *)params
|
||||
paramCount:(NSInteger)count
|
||||
command:(IJSVGCommand *)currentCommand
|
||||
previousCommand:(IJSVGCommand *)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath *)path;
|
||||
|
||||
+ (NSInteger)requiredParameterCount;
|
||||
|
||||
@end
|
||||
|
||||
@interface IJSVGCommand : NSObject {
|
||||
NSString * commandString;
|
||||
NSString * command;
|
||||
@@ -40,7 +26,7 @@ typedef NS_ENUM( NSInteger, IJSVGCommandType ) {
|
||||
IJSVGCommandType type;
|
||||
IJSVGCommand * previousCommand;
|
||||
NSInteger _currentIndex;
|
||||
Class<IJSVGCommandProtocol> commandClass;
|
||||
BOOL isSubCommand;
|
||||
}
|
||||
|
||||
@property ( nonatomic, copy ) NSString * commandString;
|
||||
@@ -49,19 +35,28 @@ typedef NS_ENUM( NSInteger, IJSVGCommandType ) {
|
||||
@property ( nonatomic, assign ) NSInteger parameterCount;
|
||||
@property ( nonatomic, assign ) NSInteger requiredParameters;
|
||||
@property ( nonatomic, assign ) IJSVGCommandType type;
|
||||
@property ( nonatomic, retain ) NSMutableArray * subCommands;
|
||||
@property ( nonatomic, assign ) Class<IJSVGCommandProtocol> commandClass;
|
||||
@property ( nonatomic, retain ) NSMutableArray<IJSVGCommand *> * subCommands;
|
||||
@property ( nonatomic, assign ) IJSVGCommand * previousCommand;
|
||||
@property ( nonatomic, assign ) BOOL isSubCommand;
|
||||
|
||||
- (id)initWithCommandString:(NSString *)commandString;
|
||||
|
||||
+ (Class)commandClassForCommandChar:(char)aChar;
|
||||
+ (NSInteger)requiredParameterCount;
|
||||
+ (NSPoint)readCoordinatePair:(CGFloat *)pairs
|
||||
index:(NSInteger)index;
|
||||
+ (void)runWithParams:(CGFloat *)params
|
||||
paramCount:(NSInteger)count
|
||||
command:(IJSVGCommand *)currentCommand
|
||||
previousCommand:(IJSVGCommand *)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath *)path;
|
||||
+ (void)parseParams:(CGFloat *)params
|
||||
paramCount:(NSInteger)paramCount
|
||||
intoArray:(NSMutableArray<IJSVGCommand *> *)commands
|
||||
parentCommand:(IJSVGCommand *)parentCommand;
|
||||
|
||||
+ (void)registerClass:(Class)aClass
|
||||
forCommand:(NSString *)command;
|
||||
+ (NSDictionary *)registeredCommandClasses;
|
||||
+ (Class<IJSVGCommandProtocol>)commandClassForCommandLetter:(NSString *)str;
|
||||
- (id)initWithCommandString:(NSString *)commandString;
|
||||
- (IJSVGCommand *)subcommandWithParameters:(CGFloat *)subParams
|
||||
previousCommand:(IJSVGCommand *)command;
|
||||
|
||||
- (CGFloat)readFloat;
|
||||
- (NSPoint)readPoint;
|
||||
|
||||
@@ -9,6 +9,17 @@
|
||||
#import "IJSVGCommand.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
#import "IJSVGCommandEllipticalArc.h"
|
||||
#import "IJSVGCommandMove.h"
|
||||
#import "IJSVGCommandClose.h"
|
||||
#import "IJSVGCommandCurve.h"
|
||||
#import "IJSVGCommandLineTo.h"
|
||||
#import "IJSVGCommandVerticalLine.h"
|
||||
#import "IJSVGCommandHorizontalLine.h"
|
||||
#import "IJSVGCommandSmoothCurve.h"
|
||||
#import "IJSVGCommandQuadraticCurve.h"
|
||||
#import "IJSVGCommandSmoothQuadraticCurve.h"
|
||||
|
||||
@implementation IJSVGCommand
|
||||
|
||||
@synthesize commandString;
|
||||
@@ -16,69 +27,35 @@
|
||||
@synthesize parameterCount;
|
||||
@synthesize parameters;
|
||||
@synthesize subCommands;
|
||||
@synthesize commandClass;
|
||||
@synthesize requiredParameters;
|
||||
@synthesize type;
|
||||
@synthesize previousCommand;
|
||||
@synthesize isSubCommand;
|
||||
|
||||
static NSMutableDictionary * _classes = nil;
|
||||
|
||||
- (void)dealloc
|
||||
+ (BOOL)requiresCustomParameterParsing
|
||||
{
|
||||
[commandString release], commandString = nil;
|
||||
[command release], command = nil;
|
||||
[subCommands release], subCommands = nil;
|
||||
free( parameters );
|
||||
[super dealloc];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id)initWithCommandString:(NSString *)str
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
+ (void)runWithParams:(CGFloat *)params
|
||||
paramCount:(NSInteger)count
|
||||
command:(IJSVGCommand *)currentCommand
|
||||
previousCommand:(IJSVGCommand *)command
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath *)path
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)parseParams:(CGFloat *)params
|
||||
paramCount:(NSInteger)paramCount
|
||||
intoArray:(NSMutableArray<IJSVGCommand *> *)commands
|
||||
parentCommand:(IJSVGCommand *)parentCommand
|
||||
{
|
||||
if( ( self = [super init] ) != nil )
|
||||
{
|
||||
// work out the basics
|
||||
_currentIndex = 0;
|
||||
subCommands = [[NSMutableArray alloc] init];
|
||||
command = [[str substringToIndex:1] copy];
|
||||
type = [IJSVGUtils typeForCommandString:self.command];
|
||||
commandClass = [[self class] commandClassForCommandLetter:self.command];
|
||||
parameters = [IJSVGUtils commandParameters:str count:¶meterCount];
|
||||
requiredParameters = [self.commandClass requiredParameterCount];
|
||||
|
||||
// now work out the sets of parameters we have
|
||||
// each command could have a series of subcommands
|
||||
// if there is a multiple of commands in a command
|
||||
// then we need to work those out...
|
||||
NSInteger sets = 1;
|
||||
if( self.requiredParameters != 0 ) {
|
||||
sets = self.parameterCount/self.requiredParameters;
|
||||
}
|
||||
|
||||
// interate over the sets
|
||||
for( NSInteger i = 0; i < sets; i++ ) {
|
||||
// memory for this will be handled by the created subcommand
|
||||
CGFloat * subParams = 0;
|
||||
if( self.requiredParameters != 0 ) {
|
||||
subParams = (CGFloat*)malloc(self.requiredParameters*sizeof(CGFloat));
|
||||
for( NSInteger p = 0; p < self.requiredParameters; p++ ) {
|
||||
subParams[p] = self.parameters[i*self.requiredParameters+p];
|
||||
}
|
||||
}
|
||||
|
||||
// create a subcommand per set
|
||||
IJSVGCommand * c = [[[[self class] alloc] init] autorelease];
|
||||
c.parameterCount = self.requiredParameters;
|
||||
c.parameters = subParams;
|
||||
c.type = self.type;
|
||||
c.command = self.command;
|
||||
c.previousCommand = [self.subCommands lastObject];
|
||||
c.commandClass = self.commandClass;
|
||||
|
||||
// add it to our tree
|
||||
[self.subCommands addObject:c];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (NSPoint)readCoordinatePair:(CGFloat *)pairs
|
||||
@@ -87,33 +64,112 @@ static NSMutableDictionary * _classes = nil;
|
||||
return NSMakePoint( pairs[index*2], pairs[index*2+1]);
|
||||
}
|
||||
|
||||
+ (void)registerClass:(Class)aClass
|
||||
forCommand:(NSString *)command
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_classes = [[NSMutableDictionary alloc] init];
|
||||
});
|
||||
[_classes setObject:NSStringFromClass(aClass)
|
||||
forKey:command];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)registeredCommandClasses
|
||||
{
|
||||
return _classes;
|
||||
}
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
// register here...
|
||||
}
|
||||
|
||||
+ (Class<IJSVGCommandProtocol>)commandClassForCommandLetter:(NSString *)str
|
||||
+ (Class)commandClassForCommandChar:(char)aChar
|
||||
{
|
||||
NSString * command = nil;
|
||||
if( ( command = [_classes objectForKey:[str lowercaseString]] ) == nil )
|
||||
return nil;
|
||||
return NSClassFromString(command);
|
||||
aChar = tolower(aChar);
|
||||
switch(aChar) {
|
||||
case 'a': return IJSVGCommandEllipticalArc.class;
|
||||
case 'c': return IJSVGCommandCurve.class;
|
||||
case 'h': return IJSVGCommandHorizontalLine.class;
|
||||
case 'l': return IJSVGCommandLineTo.class;
|
||||
case 'm': return IJSVGCommandMove.class;
|
||||
case 'q': return IJSVGCommandQuadraticCurve.class;
|
||||
case 's': return IJSVGCommandSmoothCurve.class;
|
||||
case 't': return IJSVGCommandSmoothQuadraticCurve.class;
|
||||
case 'v': return IJSVGCommandVerticalLine.class;
|
||||
case 'z': return IJSVGCommandClose.class;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[commandString release], commandString = nil;
|
||||
[command release], command = nil;
|
||||
[subCommands release], subCommands = nil;
|
||||
free(parameters), parameters = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithCommandString:(NSString *)str
|
||||
{
|
||||
if( ( self = [super init] ) != nil ) {
|
||||
// work out the basics
|
||||
_currentIndex = 0;
|
||||
command = [[str substringToIndex:1] copy];
|
||||
type = [IJSVGUtils typeForCommandString:self.command];
|
||||
parameters = [IJSVGUtils commandParameters:str
|
||||
count:¶meterCount];
|
||||
requiredParameters = [self.class requiredParameterCount];
|
||||
|
||||
// check what required params we need
|
||||
if(requiredParameters == IJSVGCustomVariableParameterCount) {
|
||||
// looks like we require variable params
|
||||
subCommands = [[NSMutableArray alloc] init];
|
||||
|
||||
// parse the custom params
|
||||
[self.class parseParams:parameters
|
||||
paramCount:parameterCount
|
||||
intoArray:subCommands
|
||||
parentCommand:self];
|
||||
} else {
|
||||
// now work out the sets of parameters we have
|
||||
// each command could have a series of subcommands
|
||||
// if there is a multiple of commands in a command
|
||||
// then we need to work those out...
|
||||
NSInteger sets = 1;
|
||||
if(self.requiredParameters != 0) {
|
||||
sets = (self.parameterCount/self.requiredParameters);
|
||||
}
|
||||
|
||||
subCommands = [[NSMutableArray alloc] initWithCapacity:sets];
|
||||
|
||||
// interate over the sets
|
||||
IJSVGCommand * lastCommand = nil;
|
||||
for( NSInteger i = 0; i < sets; i++ ) {
|
||||
// memory for this will be handled by the created subcommand
|
||||
CGFloat * subParams = 0;
|
||||
if( self.requiredParameters != 0 ) {
|
||||
subParams = (CGFloat*)malloc(self.requiredParameters*sizeof(CGFloat));
|
||||
for( NSInteger p = 0; p < self.requiredParameters; p++ ) {
|
||||
subParams[p] = self.parameters[i*self.requiredParameters+p];
|
||||
}
|
||||
}
|
||||
|
||||
// generate the subcommand
|
||||
IJSVGCommand * command = [self subcommandWithParameters:subParams
|
||||
previousCommand:lastCommand];
|
||||
|
||||
// make sure we assign the last command or hell breaks
|
||||
// lose and the firey demons will run wild, namely, commands will break
|
||||
// if they are multiples of a set
|
||||
lastCommand = command;
|
||||
|
||||
// add it to our tree
|
||||
[subCommands addObject:command];
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (IJSVGCommand *)subcommandWithParameters:(CGFloat *)subParams
|
||||
previousCommand:(IJSVGCommand *)aPreviousCommand
|
||||
{
|
||||
// create a subcommand per set
|
||||
IJSVGCommand * c = [[[self.class alloc] init] autorelease];
|
||||
c.parameterCount = self.requiredParameters;
|
||||
c.parameters = subParams;
|
||||
c.type = self.type;
|
||||
c.command = self.command;
|
||||
c.previousCommand = aPreviousCommand;
|
||||
c.isSubCommand = aPreviousCommand != nil;
|
||||
return c;
|
||||
}
|
||||
|
||||
- (CGFloat)readFloat
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandClose : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandClose : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
|
||||
@implementation IJSVGCommandClose
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"z"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandCurve : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandCurve : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
|
||||
@implementation IJSVGCommandCurve
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"c"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 6;
|
||||
@@ -28,17 +22,15 @@
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath *)path
|
||||
{
|
||||
if( type == IJSVGCommandTypeAbsolute )
|
||||
{
|
||||
if( type == IJSVGCommandTypeAbsolute ) {
|
||||
[[path currentSubpath] curveToPoint:NSMakePoint( params[4], params[5])
|
||||
controlPoint1:NSMakePoint( params[0], params[1])
|
||||
controlPoint2:NSMakePoint( params[2], params[3])];
|
||||
return;
|
||||
}
|
||||
NSPoint point = [[path currentSubpath] currentPoint];
|
||||
[[path currentSubpath] curveToPoint:NSMakePoint( point.x + params[4], point.y + params[5])
|
||||
controlPoint1:NSMakePoint( point.x + params[0], point.y + params[1])
|
||||
controlPoint2:NSMakePoint( point.x + params[2], point.y + params[3])];
|
||||
[[path currentSubpath] relativeCurveToPoint:NSMakePoint( params[4], params[5])
|
||||
controlPoint1:NSMakePoint( params[0], params[1])
|
||||
controlPoint2:NSMakePoint( params[2], params[3])];
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandArc : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandEllipticalArc : IJSVGCommand
|
||||
|
||||
@end
|
||||
@@ -6,16 +6,10 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGCommandArc.h"
|
||||
#import "IJSVGCommandEllipticalArc.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@implementation IJSVGCommandArc
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"a"];
|
||||
}
|
||||
@implementation IJSVGCommandEllipticalArc
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
@@ -29,10 +23,6 @@
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath *)path
|
||||
{
|
||||
|
||||
// command was taken from: https://github.com/jmenter/JAMSVGImage/blob/89b375c0c3203355a0c693e3b805458415bf4e29/Classes/JAMSVGImage/Path%20and%20Parser/JAMStyledBezierPathFactory.m
|
||||
// and modified to purpose inside this to be converted into degrees and not radians
|
||||
|
||||
CGPoint radii = CGPointZero;
|
||||
CGPoint arcEndPoint = CGPointZero;
|
||||
CGPoint arcStartPoint = path.currentPoint;
|
||||
@@ -46,7 +36,7 @@
|
||||
sweepFlag = [currentCommand readBOOL];
|
||||
arcEndPoint = [currentCommand readPoint];
|
||||
|
||||
if ( type == IJSVGCommandTypeRelative ) {
|
||||
if (type == IJSVGCommandTypeRelative) {
|
||||
arcEndPoint.x += path.currentPoint.x;
|
||||
arcEndPoint.y += path.currentPoint.y;
|
||||
}
|
||||
@@ -75,15 +65,28 @@
|
||||
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat radius = MAX(radii.x, radii.y);
|
||||
CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) : CGPointMake(radii.x / radii.y, 1);
|
||||
CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) :
|
||||
CGPointMake(radii.x / radii.y, 1);
|
||||
|
||||
NSAffineTransform * trans = [NSAffineTransform transform];
|
||||
[trans translateXBy:-centerPoint.x yBy:-centerPoint.y];
|
||||
[trans rotateByRadians:-xAxisRotation];
|
||||
[trans scaleXBy:(1/scale.x) yBy:(1/scale.y)];
|
||||
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
|
||||
trans = [NSAffineTransform transform];
|
||||
[trans rotateByRadians:-xAxisRotation];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
|
||||
trans = [NSAffineTransform transform];
|
||||
[trans scaleXBy:(1/scale.x) yBy:(1/scale.y)];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
|
||||
[path.currentSubpath appendBezierPathWithArcWithCenter:NSZeroPoint
|
||||
radius:radius
|
||||
startAngle:radians_to_degrees(startAngle)
|
||||
@@ -91,12 +94,16 @@
|
||||
clockwise:!sweepFlag];
|
||||
|
||||
trans = [NSAffineTransform transform];
|
||||
[trans translateXBy:centerPoint.x yBy:centerPoint.y];
|
||||
[trans rotateByRadians:xAxisRotation];
|
||||
[trans scaleXBy:scale.x yBy:scale.y];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
|
||||
trans = [NSAffineTransform transform];
|
||||
[trans rotateByRadians:xAxisRotation];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
|
||||
trans = [NSAffineTransform transform];
|
||||
[trans translateXBy:centerPoint.x yBy:centerPoint.y];
|
||||
[path.currentSubpath transformUsingAffineTransform:trans];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandHorizontalLine : NSObject <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandHorizontalLine : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
|
||||
@implementation IJSVGCommandHorizontalLine
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"h"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 1;
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandLineTo : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandLineTo : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
|
||||
@implementation IJSVGCommandLineTo
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"l"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 2;
|
||||
@@ -28,12 +22,11 @@
|
||||
type:(IJSVGCommandType)type
|
||||
path:(IJSVGPath *)path
|
||||
{
|
||||
if( type == IJSVGCommandTypeAbsolute )
|
||||
{
|
||||
if( type == IJSVGCommandTypeAbsolute ) {
|
||||
[[path currentSubpath] lineToPoint:NSMakePoint( params[0], params[1])];
|
||||
return;
|
||||
}
|
||||
NSPoint point = NSMakePoint( [path currentSubpath].currentPoint.x + params[0],
|
||||
NSPoint point = NSMakePoint([path currentSubpath].currentPoint.x + params[0],
|
||||
[path currentSubpath].currentPoint.y + params[1]);
|
||||
[[path currentSubpath] lineToPoint:point];
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandMove : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandMove : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
|
||||
@implementation IJSVGCommandMove
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"m"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 2;
|
||||
@@ -32,8 +26,7 @@
|
||||
{
|
||||
// move to's allow more then one move to, but if there are more then one,
|
||||
// we need to run the line to instead...who knew!
|
||||
if( command.commandClass == [self class])
|
||||
{
|
||||
if( command.class == self.class && currentCommand.isSubCommand == YES) {
|
||||
[IJSVGCommandLineTo runWithParams:params
|
||||
paramCount:count
|
||||
command:currentCommand
|
||||
@@ -44,8 +37,7 @@
|
||||
}
|
||||
|
||||
// actual move to command
|
||||
if( type == IJSVGCommandTypeAbsolute )
|
||||
{
|
||||
if( type == IJSVGCommandTypeAbsolute ) {
|
||||
[[path currentSubpath] moveToPoint:NSMakePoint( params[0], params[1])];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandQuadraticCurve : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandQuadraticCurve : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,12 +11,6 @@
|
||||
|
||||
@implementation IJSVGCommandQuadraticCurve
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"q"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 4;
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandSmoothCurve : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandSmoothCurve : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
|
||||
@implementation IJSVGCommandSmoothCurve
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"s"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 4;
|
||||
@@ -31,14 +25,10 @@
|
||||
path:(IJSVGPath *)path
|
||||
{
|
||||
NSPoint firstControl = NSMakePoint( [path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y );
|
||||
if( command != nil )
|
||||
{
|
||||
if( command.commandClass == [IJSVGCommandCurve class] || command.commandClass == [self class] )
|
||||
{
|
||||
if( command.commandClass == [IJSVGCommandCurve class] )
|
||||
{
|
||||
if( command.type == IJSVGCommandTypeAbsolute )
|
||||
{
|
||||
if( command != nil ) {
|
||||
if( command.class == [IJSVGCommandCurve class] || command.class == self.class ) {
|
||||
if( command.class == [IJSVGCommandCurve class] ) {
|
||||
if( command.type == IJSVGCommandTypeAbsolute ) {
|
||||
firstControl = NSMakePoint(-1*command.parameters[2] + 2*[path currentSubpath].currentPoint.x,
|
||||
-1*command.parameters[3] + 2*[path currentSubpath].currentPoint.y);
|
||||
} else {
|
||||
@@ -60,8 +50,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if( type == IJSVGCommandTypeAbsolute )
|
||||
{
|
||||
if( type == IJSVGCommandTypeAbsolute ) {
|
||||
[[path currentSubpath] curveToPoint:NSMakePoint( params[2], params[3])
|
||||
controlPoint1:NSMakePoint( firstControl.x, firstControl.y )
|
||||
controlPoint2:NSMakePoint(params[0], params[1])];
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandCommandSmoothQuadraticCurve : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandSmoothQuadraticCurve : IJSVGCommand
|
||||
|
||||
@end
|
||||
@@ -6,17 +6,11 @@
|
||||
// Copyright (c) 2014 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGCommandCommandSmoothQuadraticCurve.h"
|
||||
#import "IJSVGCommandSmoothQuadraticCurve.h"
|
||||
#import "IJSVGUtils.h"
|
||||
#import "IJSVGCommandQuadraticCurve.h"
|
||||
|
||||
@implementation IJSVGCommandCommandSmoothQuadraticCurve
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"t"];
|
||||
}
|
||||
@implementation IJSVGCommandSmoothQuadraticCurve
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
@@ -31,13 +25,10 @@
|
||||
path:(IJSVGPath *)path
|
||||
{
|
||||
NSPoint commandPoint = NSMakePoint( [path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y );
|
||||
if( command != nil )
|
||||
{
|
||||
if( command.commandClass == [IJSVGCommandQuadraticCurve class] )
|
||||
{
|
||||
if( command != nil ) {
|
||||
if( command.class == IJSVGCommandQuadraticCurve.class ) {
|
||||
// quadratic curve
|
||||
if( command.type == IJSVGCommandTypeAbsolute )
|
||||
{
|
||||
if( command.type == IJSVGCommandTypeAbsolute ) {
|
||||
commandPoint = NSMakePoint(-1*command.parameters[0] + 2*[path currentSubpath].currentPoint.x,
|
||||
-1*command.parameters[1] + 2*[path currentSubpath].currentPoint.y);
|
||||
} else {
|
||||
@@ -46,15 +37,14 @@
|
||||
commandPoint = CGPointMake(-1*(command.parameters[0] + oldPoint.x) + 2*([path currentSubpath].currentPoint.x),
|
||||
-1*(command.parameters[1] + oldPoint.y) + 2*[path currentSubpath].currentPoint.y);
|
||||
}
|
||||
} else if( command.commandClass == [self class] ) {
|
||||
} else if(command.class == self.class) {
|
||||
// smooth quadratic curve
|
||||
commandPoint = CGPointMake(-1*(path.lastControlPoint.x) + 2*([path currentSubpath].currentPoint.x),
|
||||
-1*(path.lastControlPoint.y) + 2*[path currentSubpath].currentPoint.y);
|
||||
}
|
||||
}
|
||||
path.lastControlPoint = commandPoint;
|
||||
if( type == IJSVGCommandTypeAbsolute )
|
||||
{
|
||||
if( type == IJSVGCommandTypeAbsolute ) {
|
||||
[[path currentSubpath] addQuadCurveToPoint:NSMakePoint(params[0], params[1])
|
||||
controlPoint:commandPoint];
|
||||
return;
|
||||
@@ -9,6 +9,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGCommand.h"
|
||||
|
||||
@interface IJSVGCommandVerticalLine : IJSVGCommand <IJSVGCommandProtocol>
|
||||
@interface IJSVGCommandVerticalLine : IJSVGCommand
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
|
||||
@implementation IJSVGCommandVerticalLine
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"v"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 1;
|
||||
|
||||
@@ -15,41 +15,56 @@ typedef void (^IJSVGCGPathHandler)(const CGPathElement * pathElement);
|
||||
void IJSVGExporterPathCaller(void * info, const CGPathElement * pathElement);
|
||||
|
||||
typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
|
||||
IJSVGExporterOptionNone = 1 << 0,
|
||||
IJSVGExporterOptionRemoveUselessGroups = 1 << 1,
|
||||
IJSVGExporterOptionRemoveUselessDef = 1 << 2,
|
||||
IJSVGExporterOptionMoveAttributesToGroup = 1 << 3,
|
||||
IJSVGExporterOptionCreateUseForPaths = 1 << 4,
|
||||
IJSVGExporterOptionSortAttributes = 1 << 5,
|
||||
IJSVGExporterOptionCollapseGroups = 1 << 6,
|
||||
IJSVGExporteroptionCleanupPaths = 1 << 7,
|
||||
IJSVGExporterOptionCleanupPaths = 1 << 7,
|
||||
IJSVGExporterOptionRemoveHiddenElements = 1 << 8,
|
||||
IJSVGExporterOptionScaleToSizeIfNecessary = 1 << 9,
|
||||
IJSVGExporterOptionCompressOutput = 1 << 10,
|
||||
IJSVGExporterOptionCollapseGradients = 1 << 11,
|
||||
IJSVGExporterOptionCreateClasses = 1 << 12,
|
||||
IJSVGExporterOptionRemoveWidthHeightAttributes = 1 << 13,
|
||||
IJSVGExporterOptionColorAllowRRGGBBAA = 1 << 14,
|
||||
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef|
|
||||
IJSVGExporterOptionRemoveUselessGroups|
|
||||
IJSVGExporterOptionCreateUseForPaths|
|
||||
IJSVGExporterOptionMoveAttributesToGroup|
|
||||
IJSVGExporterOptionSortAttributes|
|
||||
IJSVGExporterOptionCollapseGroups|
|
||||
IJSVGExporteroptionCleanupPaths
|
||||
IJSVGExporterOptionCleanupPaths|
|
||||
IJSVGExporterOptionRemoveHiddenElements|
|
||||
IJSVGExporterOptionScaleToSizeIfNecessary|
|
||||
IJSVGExporterOptionCompressOutput|
|
||||
IJSVGExporterOptionCollapseGradients|
|
||||
IJSVGExporterOptionRemoveWidthHeightAttributes|
|
||||
IJSVGExporterOptionColorAllowRRGGBBAA
|
||||
};
|
||||
|
||||
BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option);
|
||||
|
||||
@interface IJSVGExporter : NSObject {
|
||||
|
||||
@private
|
||||
IJSVG * _svg;
|
||||
CGSize _size;
|
||||
IJSVGExporterOptions _options;
|
||||
NSXMLDocument * _dom;
|
||||
NSXMLElement * _defElement;
|
||||
NSInteger _gradCount;
|
||||
NSInteger _patternCount;
|
||||
NSInteger _imageCount;
|
||||
NSInteger _maskCount;
|
||||
NSInteger _pathCount;
|
||||
|
||||
NSXMLElement * _scaledRootNode;
|
||||
NSInteger _idCount;
|
||||
NSInteger _shortIdCount;
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) NSString * title;
|
||||
@property (nonatomic, copy) NSString * description;
|
||||
|
||||
- (id)initWithSVG:(IJSVG *)svg
|
||||
size:(CGSize)size
|
||||
options:(IJSVGExporterOptions)options;
|
||||
- (NSString *)SVGString;
|
||||
- (NSData *)SVGData;
|
||||
|
||||
@@ -64,8 +64,11 @@
|
||||
// move
|
||||
case 'M':
|
||||
case 'm': {
|
||||
str = [NSString stringWithFormat:@"%c%g,%g",
|
||||
instruction.instruction,data[0],data[1]];
|
||||
char * buffer;
|
||||
asprintf(&buffer, "%c%g,%g", instruction.instruction, data[0], data[1]);
|
||||
str = [NSString stringWithCString:buffer
|
||||
encoding:NSUTF8StringEncoding];
|
||||
free(buffer);
|
||||
[pathData addObject:str];
|
||||
break;
|
||||
}
|
||||
@@ -75,8 +78,11 @@
|
||||
case 'v':
|
||||
case 'H':
|
||||
case 'h': {
|
||||
str = [NSString stringWithFormat:@"%c%g",
|
||||
instruction.instruction,data[0]];
|
||||
char * buffer;
|
||||
asprintf(&buffer, "%c%g", instruction.instruction, data[0]);
|
||||
str = [NSString stringWithCString:buffer
|
||||
encoding:NSUTF8StringEncoding];
|
||||
free(buffer);
|
||||
[pathData addObject:str];
|
||||
break;
|
||||
}
|
||||
@@ -84,8 +90,11 @@
|
||||
// line
|
||||
case 'L':
|
||||
case 'l': {
|
||||
str = [NSString stringWithFormat:@"%c%g,%g",
|
||||
instruction.instruction, data[0], data[1]];
|
||||
char * buffer;
|
||||
asprintf(&buffer, "%c%g,%g",instruction.instruction, data[0], data[1]);
|
||||
str = [NSString stringWithCString:buffer
|
||||
encoding:NSUTF8StringEncoding];
|
||||
free(buffer);
|
||||
[pathData addObject:str];
|
||||
break;
|
||||
}
|
||||
@@ -93,9 +102,12 @@
|
||||
// curve
|
||||
case 'C':
|
||||
case 'c': {
|
||||
str = [NSString stringWithFormat:@"%c%g,%g %g,%g %g,%g",
|
||||
instruction.instruction, data[0], data[1],
|
||||
data[2], data[3], data[4], data[5]];
|
||||
char * buffer;
|
||||
asprintf(&buffer, "%c%g,%g %g,%g %g,%g", instruction.instruction,
|
||||
data[0], data[1], data[2], data[3], data[4], data[5]);
|
||||
str = [NSString stringWithCString:buffer
|
||||
encoding:NSUTF8StringEncoding];
|
||||
free(buffer);
|
||||
[pathData addObject:str];
|
||||
break;
|
||||
}
|
||||
@@ -103,9 +115,12 @@
|
||||
// quadratic curve
|
||||
case 'Q':
|
||||
case 'q': {
|
||||
str = [NSString stringWithFormat:@"%c%g,%g %g,%g",
|
||||
instruction.instruction, data[0], data[1],
|
||||
data[2], data[3]];
|
||||
char * buffer;
|
||||
asprintf(&buffer, "%c%g,%g %g,%g", instruction.instruction,
|
||||
data[0], data[1], data[2], data[3]);
|
||||
str = [NSString stringWithCString:buffer
|
||||
encoding:NSUTF8StringEncoding];
|
||||
free(buffer);
|
||||
[pathData addObject:str];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -7,18 +7,23 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVG.h"
|
||||
|
||||
typedef void (^IJSVGFontConverterEnumerateBlock)(NSString * unicode, IJSVG * svg);
|
||||
|
||||
@interface IJSVGFontConverter : NSObject {
|
||||
|
||||
@private
|
||||
NSURL * _url;
|
||||
NSFont * _font;
|
||||
NSMutableDictionary * _paths;
|
||||
NSMutableDictionary<NSString *, id> * _transformedPaths;
|
||||
}
|
||||
|
||||
- (id)initWithFontAtFileURL:(NSURL *)url;
|
||||
- (NSDictionary *)paths;
|
||||
+ (NSBezierPath *)bezierpathFromCGPath:(CGPathRef)path;
|
||||
- (NSFont *)font;
|
||||
- (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block;
|
||||
|
||||
+ (IJSVG *)convertIJSVGPathToSVG:(IJSVGPath *)path;
|
||||
+ (IJSVG *)convertPathToSVG:(CGPathRef)path;
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
|
||||
#import "IJSVGFontConverter.h"
|
||||
#import "IJSVGBezierPathAdditions.h"
|
||||
#import "IJSVGShapeLayer.h"
|
||||
|
||||
@implementation IJSVGFontConverter
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_paths release], _paths = nil;
|
||||
[_transformedPaths release], _transformedPaths = nil;
|
||||
[_url release], _url = nil;
|
||||
[_font release], _font = nil;
|
||||
[super dealloc];
|
||||
@@ -21,8 +22,7 @@
|
||||
|
||||
- (id)initWithFontAtFileURL:(NSURL *)url
|
||||
{
|
||||
if( ( self = [super init] ) != nil )
|
||||
{
|
||||
if( ( self = [super init] ) != nil ) {
|
||||
_url = [url copy];
|
||||
|
||||
// load the font
|
||||
@@ -48,20 +48,16 @@
|
||||
{
|
||||
NSCharacterSet * charSet = _font.coveredCharacterSet;
|
||||
NSMutableArray * array = [[[NSMutableArray alloc] init] autorelease];
|
||||
for( int plane = 0; plane <= 16; plane++ )
|
||||
{
|
||||
if( [charSet hasMemberInPlane:plane] )
|
||||
{
|
||||
NSStringEncoding encoding = NSUTF32LittleEndianStringEncoding;
|
||||
for( int plane = 0; plane <= 16; plane++ ) {
|
||||
if( [charSet hasMemberInPlane:plane] ) {
|
||||
UTF32Char c;
|
||||
for( c = plane << 16; c < (plane+1) << 16; c++ )
|
||||
{
|
||||
if( [charSet longCharacterIsMember:c] )
|
||||
{
|
||||
for( c = plane << 16; c < (plane+1) << 16; c++ ) {
|
||||
if( [charSet longCharacterIsMember:c] ) {
|
||||
UTF32Char c1 = NSSwapHostIntToLittle(c);
|
||||
// add it...
|
||||
[array addObject:[[[NSString alloc] initWithBytes:&c1
|
||||
length:4
|
||||
encoding:NSUTF32LittleEndianStringEncoding] autorelease]];
|
||||
encoding:encoding] autorelease]];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,14 +67,8 @@
|
||||
|
||||
- (void)generateMap
|
||||
{
|
||||
// we have already been made!
|
||||
if( _paths.count != 0 )
|
||||
return;
|
||||
|
||||
_paths = [[NSMutableDictionary alloc] init];
|
||||
CTFontRef font = (CTFontRef)_font;
|
||||
for( NSString * charString in [self allCharacters] )
|
||||
{
|
||||
for( NSString * charString in [self allCharacters] ) {
|
||||
// get the characters in each char
|
||||
NSUInteger count = charString.length;
|
||||
unichar characters[count];
|
||||
@@ -89,93 +79,52 @@
|
||||
CGGlyph glyphs[count];
|
||||
CTFontGetGlyphsForCharacters( font, characters, glyphs, count);
|
||||
CGPathRef path = CTFontCreatePathForGlyph( font, glyphs[0], NULL );
|
||||
if( path != NULL )
|
||||
{
|
||||
NSString * k = [NSString stringWithFormat:@"%04x",[charString characterAtIndex:0]];
|
||||
[self parseCGPath:path
|
||||
forCharacterString:k];
|
||||
if(path != NULL) {
|
||||
// add SVG to the dictionary
|
||||
NSString * key = [NSString stringWithFormat:@"%04x",[charString characterAtIndex:0]];
|
||||
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:path];
|
||||
_transformedPaths[key] = (id)flippedPath;
|
||||
CGPathRelease(flippedPath);
|
||||
}
|
||||
CGPathRelease(path);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parseCGPath:(CGPathRef)path
|
||||
forCharacterString:(NSString *)string
|
||||
- (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block
|
||||
{
|
||||
[_paths setObject:[[self class] bezierpathFromCGPath:path]
|
||||
forKey:string];
|
||||
}
|
||||
|
||||
- (NSDictionary *)paths
|
||||
{
|
||||
[self generateMap];
|
||||
return _paths;
|
||||
}
|
||||
|
||||
static void IJSVGCGPathCallback(void * info, const CGPathElement * element)
|
||||
{
|
||||
NSBezierPath * path = (NSBezierPath *)info;
|
||||
CGPoint * points = element->points;
|
||||
switch( element->type )
|
||||
{
|
||||
// move to
|
||||
case kCGPathElementMoveToPoint:
|
||||
{
|
||||
[path moveToPoint:NSMakePoint( points[0].x, points[0].y)];
|
||||
break;
|
||||
}
|
||||
|
||||
// line to
|
||||
case kCGPathElementAddLineToPoint:
|
||||
{
|
||||
[path lineToPoint:NSMakePoint( points[0].x, points[0].y)];;
|
||||
break;
|
||||
}
|
||||
|
||||
// quad curve
|
||||
case kCGPathElementAddQuadCurveToPoint:
|
||||
{
|
||||
[path addQuadCurveToPoint:points[1] controlPoint:points[0]];
|
||||
break;
|
||||
}
|
||||
|
||||
// curve to
|
||||
case kCGPathElementAddCurveToPoint:
|
||||
{
|
||||
[path curveToPoint:NSMakePoint(points[2].x, points[2].y)
|
||||
controlPoint1:NSMakePoint( points[0].x, points[0].y)
|
||||
controlPoint2:NSMakePoint( points[1].x, points[1].y)];
|
||||
break;
|
||||
}
|
||||
|
||||
// close
|
||||
case kCGPathElementCloseSubpath: {
|
||||
[path closePath];
|
||||
break;
|
||||
}
|
||||
if(_transformedPaths == nil) {
|
||||
_transformedPaths = [[NSMutableDictionary alloc] init];
|
||||
[self generateMap];
|
||||
}
|
||||
|
||||
for(NSString * key in _transformedPaths.allKeys) {
|
||||
block(key, [self.class convertPathToSVG:(CGPathRef)_transformedPaths[key]]);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSBezierPath *)bezierpathFromCGPath:(CGPathRef)path
|
||||
+ (IJSVG *)convertIJSVGPathToSVG:(IJSVGPath *)path
|
||||
{
|
||||
NSBezierPath * bezPath = [NSBezierPath bezierPath];
|
||||
|
||||
// pass the path
|
||||
CGPathApply( path, bezPath, IJSVGCGPathCallback );
|
||||
|
||||
// the glyph will be upside down, so we need to turn it up the right way!
|
||||
NSAffineTransform * trans = [NSAffineTransform transform];
|
||||
|
||||
// scale -1 on the Y axis so its now correct but to far up
|
||||
[trans scaleXBy:1.f
|
||||
yBy:-1.f];
|
||||
|
||||
// move it back down by its height
|
||||
[trans translateXBy:0.f
|
||||
yBy:bezPath.controlPointBounds.size.height];
|
||||
|
||||
[bezPath transformUsingAffineTransform:trans];
|
||||
return bezPath;
|
||||
CGPathRef cgPath = [IJSVGUtils newCGPathFromBezierPath:path.path];
|
||||
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:cgPath];
|
||||
IJSVG * svg = [self convertPathToSVG:flippedPath];
|
||||
CGPathRelease(flippedPath);
|
||||
CGPathRelease(cgPath);
|
||||
return svg;
|
||||
}
|
||||
|
||||
+ (IJSVG *)convertPathToSVG:(CGPathRef)path
|
||||
{
|
||||
__block IJSVG * svg = nil;
|
||||
IJSVGObtainTransactionLock(^{
|
||||
IJSVGGroupLayer * layer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
IJSVGShapeLayer * shape = [[[IJSVGShapeLayer alloc] init] autorelease];
|
||||
[layer addSublayer:shape];
|
||||
shape.path = path;
|
||||
CGRect box = CGPathGetPathBoundingBox(path);
|
||||
svg = [[IJSVG alloc] initWithSVGLayer:layer
|
||||
viewBox:box];
|
||||
}, NO);
|
||||
return [svg autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,23 +9,30 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGDef.h"
|
||||
#import "IJSVGTransform.h"
|
||||
#import "IJSVGColorList.h"
|
||||
|
||||
@interface IJSVGGradient : IJSVGNode
|
||||
|
||||
@property ( nonatomic, retain ) NSGradient * gradient;
|
||||
@property ( nonatomic, assign ) CGFloat angle;
|
||||
@property ( nonatomic, assign ) CGPoint startPoint;
|
||||
@property ( nonatomic, assign ) CGPoint endPoint;
|
||||
@property ( nonatomic, assign ) CGGradientRef CGGradient;
|
||||
@property ( nonatomic, retain ) IJSVGUnitLength * x1;
|
||||
@property ( nonatomic, retain ) IJSVGUnitLength * x2;
|
||||
@property ( nonatomic, retain ) IJSVGUnitLength * y1;
|
||||
@property ( nonatomic, retain ) IJSVGUnitLength * y2;
|
||||
@property ( nonatomic, retain) IJSVGColorList * colorList;
|
||||
|
||||
+ (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element
|
||||
colors:(NSArray **)someColors;
|
||||
- (CGGradientRef)CGGradient;
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
rect:(NSRect)rect;
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox;
|
||||
|
||||
- (void)_debugStart:(CGPoint)startPoint
|
||||
end:(CGPoint)endPoint
|
||||
context:(CGContextRef)ctx;
|
||||
|
||||
- (IJSVGColorList *)computedColorList;
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
@implementation IJSVGGradient
|
||||
|
||||
@synthesize gradient, CGGradient;
|
||||
@synthesize angle, startPoint, endPoint;
|
||||
@synthesize x1, x2, y1, y2;
|
||||
@synthesize colorList = _colorList;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
@@ -21,7 +21,8 @@
|
||||
[y1 release], y1 = nil;
|
||||
[y2 release], y2 = nil;
|
||||
[gradient release], gradient = nil;
|
||||
if( CGGradient != nil ) {
|
||||
[_colorList release], _colorList = nil;
|
||||
if(CGGradient != nil) {
|
||||
CGGradientRelease(CGGradient);
|
||||
}
|
||||
[super dealloc];
|
||||
@@ -31,25 +32,29 @@
|
||||
{
|
||||
IJSVGGradient * clone = [super copyWithZone:zone];
|
||||
clone.gradient = [[self.gradient copy] autorelease];
|
||||
clone.startPoint = self.startPoint;
|
||||
clone.endPoint = self.endPoint;
|
||||
return clone;
|
||||
}
|
||||
|
||||
- (void)setColorList:(IJSVGColorList *)list
|
||||
{
|
||||
[_colorList release], _colorList = nil;
|
||||
_colorList = list.retain;
|
||||
if(CGGradient != nil) {
|
||||
CGGradientRelease(CGGradient);
|
||||
}
|
||||
}
|
||||
|
||||
+ (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element
|
||||
colors:(NSArray **)someColors
|
||||
{
|
||||
// find each stop element
|
||||
NSArray * stops = [element nodesForXPath:@"stop"
|
||||
error:nil];
|
||||
|
||||
NSMutableArray * colors = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSArray * stops = [element children];
|
||||
NSMutableArray * colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease];
|
||||
CGFloat * stopsParams = (CGFloat *)malloc(stops.count*sizeof(CGFloat));
|
||||
NSInteger i = 0;
|
||||
for( NSXMLElement * stop in stops )
|
||||
{
|
||||
for( NSXMLElement * stop in stops ) {
|
||||
// find the offset
|
||||
CGFloat offset = [[[stop attributeForName:@"offset"] stringValue] floatValue];
|
||||
CGFloat offset = [stop attributeForName:@"offset"].stringValue.floatValue;
|
||||
if( offset > 1.f ) {
|
||||
offset /= 100.f;
|
||||
}
|
||||
@@ -60,53 +65,69 @@
|
||||
CGFloat stopOpacity = 1.f;
|
||||
NSXMLNode * stopOpacityAttribute = [stop attributeForName:@"stop-opacity"];
|
||||
if( stopOpacityAttribute != nil ) {
|
||||
stopOpacity = [[stopOpacityAttribute stringValue] floatValue];
|
||||
stopOpacity = stopOpacityAttribute.stringValue.floatValue;
|
||||
}
|
||||
|
||||
// find the stop color
|
||||
NSColor * stopColor = [IJSVGColor colorFromHEXString:[[stop attributeForName:@"stop-color"] stringValue]
|
||||
alpha:stopOpacity];
|
||||
|
||||
// no hex, grab it from predefined
|
||||
if( stopColor == nil )
|
||||
{
|
||||
stopColor = [IJSVGColor colorFromPredefinedColorName:[[stop attributeForName:@"stop-color"] stringValue]];
|
||||
if( stopColor != nil && stopOpacity != 1.f ) {
|
||||
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
|
||||
to:stopOpacity];
|
||||
}
|
||||
}
|
||||
|
||||
// add it into the array
|
||||
if( stopColor != nil ) {
|
||||
[(NSMutableArray *)colors addObject:stopColor];
|
||||
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]];
|
||||
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?
|
||||
NSNumber * number = nil;
|
||||
if( (number = [style property:@"stop-opacity"] ) != nil ) {
|
||||
NSString * numberString = nil;
|
||||
if( (numberString = [style property:@"stop-opacity"] ) != nil ) {
|
||||
color = [IJSVGColor changeAlphaOnColor:color
|
||||
to:[number floatValue]];
|
||||
to:numberString.floatValue];
|
||||
} else {
|
||||
color = [IJSVGColor changeAlphaOnColor:color
|
||||
to:stopOpacity];
|
||||
}
|
||||
[(NSMutableArray *)colors addObject:color];
|
||||
stopColor = color;
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
}
|
||||
*someColors = colors;
|
||||
return stopsParams;
|
||||
}
|
||||
|
||||
- (IJSVGColorList *)computedColorList
|
||||
{
|
||||
IJSVGColorList * sheet = [[[IJSVGColorList alloc] init] autorelease];
|
||||
NSInteger num = self.gradient.numberOfColorStops;
|
||||
for(NSInteger i = 0; i < num; i++) {
|
||||
NSColor * color;
|
||||
[self.gradient getColor:&color
|
||||
location:nil
|
||||
atIndex:i];
|
||||
[sheet addColor:color];
|
||||
}
|
||||
return sheet;
|
||||
}
|
||||
|
||||
- (CGGradientRef)CGGradient
|
||||
{
|
||||
// store it in the cache
|
||||
@@ -117,23 +138,42 @@
|
||||
// actually create the gradient
|
||||
NSInteger num = self.gradient.numberOfColorStops;
|
||||
CGFloat * locations = malloc(sizeof(CGFloat)*num);
|
||||
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num, &kCFTypeArrayCallBacks);
|
||||
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num,
|
||||
&kCFTypeArrayCallBacks);
|
||||
for( NSInteger i = 0; i < num; i++ ) {
|
||||
NSColor * color;
|
||||
[self.gradient getColor:&color
|
||||
location:&locations[i]
|
||||
atIndex:i];
|
||||
if(_colorList != nil) {
|
||||
color = [_colorList proposedColorForColor:color];
|
||||
}
|
||||
CFArrayAppendValue(colors, color.CGColor);
|
||||
}
|
||||
CGGradientRef result = CGGradientCreateWithColors(self.gradient.colorSpace.CGColorSpace, colors, locations);
|
||||
CGGradientRef result = CGGradientCreateWithColors(self.gradient.colorSpace.CGColorSpace,
|
||||
colors, locations);
|
||||
CFRelease(colors);
|
||||
free(locations);
|
||||
return CGGradient = result;
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
rect:(NSRect)rect
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_debugStart:(CGPoint)startPoint
|
||||
end:(CGPoint)endPoint
|
||||
context:(CGContextRef)ctx
|
||||
{
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextSetStrokeColorWithColor(ctx, NSColor.blackColor.CGColor);
|
||||
CGContextSetLineWidth(ctx, 1.f);
|
||||
CGContextMoveToPoint(ctx, startPoint.x, startPoint.y);
|
||||
CGContextAddLineToPoint(ctx, endPoint.x, endPoint.y);
|
||||
CGContextStrokePath(ctx);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) CGRect viewBox;
|
||||
@property (nonatomic, retain) IJSVGGradient * gradient;
|
||||
@property (nonatomic, assign) CGAffineTransform absoluteTransform;
|
||||
@property (nonatomic, assign) CGRect objectRect;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
|
||||
@implementation IJSVGGradientLayer
|
||||
|
||||
@synthesize viewBox;
|
||||
@synthesize gradient;
|
||||
@synthesize absoluteTransform;
|
||||
@synthesize objectRect;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
@@ -22,10 +25,60 @@
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
self.requiresBackingScaleHelp = YES;
|
||||
self.shouldRasterize = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setGradient:(IJSVGGradient *)newGradient
|
||||
{
|
||||
if(gradient != nil) {
|
||||
[gradient release], gradient = nil;
|
||||
}
|
||||
gradient = [newGradient retain];
|
||||
|
||||
// lets check its alpha properties on the colors
|
||||
BOOL hasAlphaChannel = NO;
|
||||
NSInteger stops = gradient.gradient.numberOfColorStops;
|
||||
for(NSInteger i = 0; i < stops; i++) {
|
||||
NSColor * color = nil;
|
||||
[gradient.gradient getColor:&color
|
||||
location:NULL
|
||||
atIndex:i];
|
||||
if(color.alphaComponent != 1.f) {
|
||||
hasAlphaChannel = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.opaque = hasAlphaChannel == NO;
|
||||
}
|
||||
|
||||
- (void)setOpacity:(float)opacity
|
||||
{
|
||||
if(opacity != 1.f) {
|
||||
self.opaque = NO;
|
||||
}
|
||||
[super setOpacity:opacity];
|
||||
}
|
||||
|
||||
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
|
||||
{
|
||||
switch (self.renderQuality) {
|
||||
case IJSVGRenderQualityOptimized: {
|
||||
backingScaleFactor = (backingScaleFactor * .35f);
|
||||
break;
|
||||
}
|
||||
case IJSVGRenderQualityLow: {
|
||||
backingScaleFactor = (backingScaleFactor * .05f);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
[super setBackingScaleFactor:backingScaleFactor];
|
||||
}
|
||||
|
||||
- (void)drawInContext:(CGContextRef)ctx
|
||||
{
|
||||
[super drawInContext:ctx];
|
||||
@@ -36,7 +89,15 @@
|
||||
}
|
||||
|
||||
// draw the gradient
|
||||
[self.gradient drawInContextRef:ctx rect:self.bounds];
|
||||
CGAffineTransform trans = CGAffineTransformMakeTranslation(-CGRectGetMinX(objectRect),
|
||||
-CGRectGetMinY(objectRect));
|
||||
CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform,trans);
|
||||
CGContextSaveGState(ctx);
|
||||
[self.gradient drawInContextRef:ctx
|
||||
objectRect:objectRect
|
||||
absoluteTransform:transform
|
||||
viewPort:self.viewBox];
|
||||
CGContextRestoreGState(ctx);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// IJSVGGradientUnitLength.h
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 29/03/2017.
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGUnitLength.h"
|
||||
|
||||
@interface IJSVGGradientUnitLength : IJSVGUnitLength
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// IJSVGGradientUnitLength.m
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 29/03/2017.
|
||||
// Copyright © 2017 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGGradientUnitLength.h"
|
||||
|
||||
@implementation IJSVGGradientUnitLength
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
if(self.type == IJSVGUnitLengthTypePercentage) {
|
||||
return [NSString stringWithFormat:@"%g",self.value];
|
||||
}
|
||||
return [super stringValue];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ - %ld",[super description],self.children.count];
|
||||
return [NSString stringWithFormat:@"%@ - %@",[super description],self.children];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,10 +22,16 @@
|
||||
|
||||
- (void)loadFromBase64EncodedString:(NSString *)encodedString
|
||||
{
|
||||
if([encodedString hasPrefix:@"data:"]) {
|
||||
encodedString = [encodedString stringByReplacingOccurrencesOfString:@"\\s+"
|
||||
withString:@""
|
||||
options:NSRegularExpressionSearch
|
||||
range:NSMakeRange(0, encodedString.length)];
|
||||
}
|
||||
NSURL * URL = [NSURL URLWithString:encodedString];
|
||||
NSData * data = [NSData dataWithContentsOfURL:URL];
|
||||
|
||||
// no data, jsut ignore...invalid probably
|
||||
// no data, just ignore...invalid probably
|
||||
if(data == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,14 +28,28 @@
|
||||
// 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))
|
||||
.size = CGSizeMake(CGImageGetWidth(imageRef),
|
||||
CGImageGetHeight(imageRef))
|
||||
};
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplay
|
||||
{
|
||||
// swap the content around on call
|
||||
// because set needs display discards previous
|
||||
// content - yolo!
|
||||
id oldContent = self.contents;
|
||||
[super setNeedsDisplay];
|
||||
self.contents = oldContent;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// IJSVGImageRep.h
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 15/03/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "IJSVGParser.h"
|
||||
|
||||
@class IJSVG;
|
||||
|
||||
@interface IJSVGImageRep : NSImageRep {
|
||||
|
||||
@private
|
||||
IJSVG * _svg;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) CGRect viewBox;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// IJSVGImageRep.m
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 15/03/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGImageRep.h"
|
||||
#import "IJSVG.h"
|
||||
|
||||
@implementation IJSVGImageRep
|
||||
|
||||
@synthesize viewBox = _viewBox;
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[NSBitmapImageRep registerImageRepClass:self];
|
||||
}
|
||||
|
||||
+ (BOOL)canInitWithData:(NSData *)data
|
||||
{
|
||||
return [IJSVGParser isDataSVG:data];
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)imageTypes
|
||||
{
|
||||
return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"];
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)imageUnfilteredTypes
|
||||
{
|
||||
return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"];
|
||||
}
|
||||
|
||||
+ (NSArray<NSImageRep *> *)imageRepsWithData:(NSData *)data
|
||||
{
|
||||
IJSVGImageRep * instance = [self imageRepWithData:data];
|
||||
if(instance == nil) {
|
||||
return @[];
|
||||
}
|
||||
return @[instance];
|
||||
}
|
||||
|
||||
+ (instancetype)imageRepWithData:(NSData *)data
|
||||
{
|
||||
return [[[self alloc] initWithData:data] autorelease];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_svg release], _svg = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
// grab the string from the data
|
||||
// its more then likely UTF-8...
|
||||
NSString * string = [[[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding] autorelease];
|
||||
|
||||
_svg = [[IJSVG alloc] initWithSVGString:string];
|
||||
|
||||
// no valid SVG, just return nil;
|
||||
if(_svg == nil) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
// set default properties
|
||||
self.pixelsWide = _svg.viewBox.size.width;
|
||||
self.pixelsHigh = _svg.viewBox.size.height;
|
||||
self.size = _svg.viewBox.size;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)draw
|
||||
{
|
||||
[_svg drawInRect:self.viewBox];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)drawAtPoint:(NSPoint)point
|
||||
{
|
||||
[_svg drawAtPoint:point
|
||||
size:_svg.viewBox.size];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)drawInRect:(NSRect)rect
|
||||
{
|
||||
[_svg drawInRect:rect];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGRect)viewBox
|
||||
{
|
||||
return _svg.viewBox;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -8,60 +8,38 @@
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "IJSVGTransaction.h"
|
||||
#import "IJSVGRendering.h"
|
||||
|
||||
@class IJSVGShapeLayer;
|
||||
@class IJSVGGradientLayer;
|
||||
@class IJSVGPatternLayer;
|
||||
@class IJSVGStrokeLayer;
|
||||
|
||||
#define IJSVG_LAYER_ADD_SUBVIEW_DEFAULT_IMPLEMENTATION \
|
||||
- (void)addSublayer:(CALayer *)layer { \
|
||||
if([layer isKindOfClass:[IJSVGLayer class]] == NO && \
|
||||
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) { \
|
||||
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.", \
|
||||
[layer class]]; \
|
||||
NSException * exception = [NSException exceptionWithName:@"IJSVGInvalidSublayerException"\
|
||||
reason:r \
|
||||
userInfo:nil];\
|
||||
@throw exception; \
|
||||
}\
|
||||
[super addSublayer:layer];\
|
||||
} \
|
||||
\
|
||||
- (void)setBackingScaleFactor:(CGFloat)newFactor \
|
||||
{ \
|
||||
if(self.backingScaleFactor == newFactor) { \
|
||||
return; \
|
||||
} \
|
||||
backingScaleFactor = newFactor; \
|
||||
self.contentsScale = newFactor; \
|
||||
self.rasterizationScale = newFactor; \
|
||||
[self setNeedsDisplay]; \
|
||||
};
|
||||
|
||||
#define IJSVG_LAYER_DEFAULT_PROPERTIES \
|
||||
@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer; \
|
||||
@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer; \
|
||||
@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer; \
|
||||
@property (nonatomic, assign) BOOL requiresBackingScaleHelp; \
|
||||
@property (nonatomic, assign) CGFloat backingScaleFactor;
|
||||
|
||||
#define IJSVG_LAYER_DEFAULT_SYNTHESIZE \
|
||||
@synthesize gradientFillLayer; \
|
||||
@synthesize patternFillLayer; \
|
||||
@synthesize strokeLayer; \
|
||||
@synthesize requiresBackingScaleHelp; \
|
||||
@synthesize backingScaleFactor;
|
||||
|
||||
#define IJSVG_LAYER_DEFAULT_DEALLOC_INSTRUCTIONS \
|
||||
IJSVGBeginTransactionLock(); \
|
||||
[super dealloc]; \
|
||||
IJSVGEndTransactionLock();
|
||||
@class IJSVGGroupLayer;
|
||||
|
||||
@interface IJSVGLayer : CALayer {
|
||||
|
||||
@private
|
||||
IJSVGLayer * _maskingLayer;
|
||||
}
|
||||
|
||||
IJSVG_LAYER_DEFAULT_PROPERTIES
|
||||
@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer;
|
||||
@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer;
|
||||
@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer;
|
||||
@property (nonatomic, assign) IJSVGGradientLayer * gradientStrokeLayer;
|
||||
@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer;
|
||||
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
|
||||
@property (nonatomic, assign) CGFloat backingScaleFactor;
|
||||
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
|
||||
@property (nonatomic, assign) CGBlendMode blendingMode;
|
||||
@property (nonatomic, assign) CGPoint absoluteOrigin;
|
||||
@property (nonatomic, assign) BOOL convertMasksToPaths;
|
||||
|
||||
+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer;
|
||||
+ (void)recursivelyWalkLayer:(CALayer *)layer
|
||||
withBlock:(void (^)(CALayer * layer, BOOL isMask))block;
|
||||
|
||||
- (void)applySublayerMaskToContext:(CGContextRef)context
|
||||
forSublayer:(IJSVGLayer *)sublayer
|
||||
withOffset:(CGPoint)offset;
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,19 +8,177 @@
|
||||
|
||||
#import "IJSVGLayer.h"
|
||||
#import "IJSVGShapeLayer.h"
|
||||
#import "IJSVGGroupLayer.h"
|
||||
#import "IJSVG.h"
|
||||
|
||||
|
||||
@implementation IJSVGLayer
|
||||
|
||||
IJSVG_LAYER_DEFAULT_SYNTHESIZE
|
||||
@synthesize gradientFillLayer;
|
||||
@synthesize patternFillLayer;
|
||||
@synthesize gradientStrokeLayer;
|
||||
@synthesize patternStrokeLayer;
|
||||
@synthesize strokeLayer;
|
||||
@synthesize requiresBackingScaleHelp;
|
||||
@synthesize backingScaleFactor;
|
||||
@synthesize blendingMode;
|
||||
@synthesize convertMasksToPaths;
|
||||
|
||||
#ifndef __clang_analyzer__
|
||||
- (void)dealloc
|
||||
{
|
||||
IJSVG_LAYER_DEFAULT_DEALLOC_INSTRUCTIONS
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
#endif
|
||||
|
||||
IJSVG_LAYER_ADD_SUBVIEW_DEFAULT_IMPLEMENTATION
|
||||
+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer
|
||||
{
|
||||
NSMutableArray * arr = [[[NSMutableArray alloc] init] autorelease];
|
||||
for(CALayer * subLayer in layer.sublayers) {
|
||||
if(subLayer.sublayers.count != 0) {
|
||||
NSArray * moreLayers = [self deepestSublayersOfLayer:(IJSVGLayer *)subLayer];
|
||||
[arr addObjectsFromArray:moreLayers];
|
||||
} else {
|
||||
[arr addObject:subLayer];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
+ (void)recursivelyWalkLayer:(CALayer *)layer
|
||||
withBlock:(void (^)(CALayer * layer, BOOL isMask))block
|
||||
{
|
||||
// call for layer and mask if there is one
|
||||
block(layer, NO);
|
||||
|
||||
// do the mask too!
|
||||
if(layer.mask != nil) {
|
||||
block(layer.mask, YES);
|
||||
}
|
||||
|
||||
// sublayers!!
|
||||
for(CALayer * aLayer in layer.sublayers) {
|
||||
[self recursivelyWalkLayer:aLayer
|
||||
withBlock:block];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addSublayer:(CALayer *)layer
|
||||
{
|
||||
if([layer isKindOfClass:[IJSVGLayer class]] == NO &&
|
||||
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) {
|
||||
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.",
|
||||
[layer class]];
|
||||
NSException * exception = [NSException exceptionWithName:@"IJSVGInvalidSublayerException"
|
||||
reason:r
|
||||
userInfo:nil];
|
||||
@throw exception;
|
||||
}
|
||||
[super addSublayer:layer];
|
||||
}
|
||||
|
||||
- (void)setBackingScaleFactor:(CGFloat)newFactor
|
||||
{
|
||||
if(self.backingScaleFactor == newFactor) {
|
||||
return;
|
||||
}
|
||||
backingScaleFactor = newFactor;
|
||||
self.contentsScale = newFactor;
|
||||
self.rasterizationScale = newFactor;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)_customRenderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if(self.convertMasksToPaths == YES && _maskingLayer != nil) {
|
||||
CGContextSaveGState(ctx);
|
||||
[self applySublayerMaskToContext:ctx
|
||||
forSublayer:(IJSVGLayer *)self
|
||||
withOffset:CGPointZero];
|
||||
[super renderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
return;
|
||||
}
|
||||
[super renderInContext:ctx];
|
||||
}
|
||||
|
||||
- (void)setConvertMasksToPaths:(BOOL)flag
|
||||
{
|
||||
if(convertMasksToPaths == flag) {
|
||||
return;
|
||||
}
|
||||
convertMasksToPaths = flag;
|
||||
if(flag == YES) {
|
||||
if(_maskingLayer != nil){
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
}
|
||||
_maskingLayer = [(IJSVGLayer *)self.mask retain];
|
||||
self.mask = nil;
|
||||
} else {
|
||||
self.mask = _maskingLayer;
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applySublayerMaskToContext:(CGContextRef)context
|
||||
forSublayer:(IJSVGLayer *)sublayer
|
||||
withOffset:(CGPoint)offset
|
||||
{
|
||||
// apply any transforms needed
|
||||
CGPoint layerOffset = offset;
|
||||
CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(sublayer.transform);
|
||||
CGContextConcatCTM( context, CGAffineTransformInvert(sublayerTransform) );
|
||||
|
||||
// walk up the superlayer chain
|
||||
CALayer * superlayer = self.superlayer;
|
||||
if (IJSVGIsSVGLayer(superlayer) == YES) {
|
||||
[(IJSVGLayer *)superlayer applySublayerMaskToContext:context
|
||||
forSublayer:(IJSVGLayer *)self
|
||||
withOffset:layerOffset];
|
||||
}
|
||||
|
||||
// grab the masking layer
|
||||
IJSVGShapeLayer * maskingLayer = [self maskingLayer];
|
||||
|
||||
// if its a group we need to get the lowest level children
|
||||
// and walk up the chain again
|
||||
if([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
|
||||
NSArray * subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer];
|
||||
for(IJSVGLayer * subLayer in subs) {
|
||||
[subLayer applySublayerMaskToContext:context
|
||||
forSublayer:(IJSVGLayer *)self
|
||||
withOffset:layerOffset];
|
||||
}
|
||||
} else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
|
||||
// is a shape, go for it!
|
||||
CGPathRef maskPath = maskingLayer.path;
|
||||
CGContextTranslateCTM(context, -layerOffset.x, -layerOffset.y);
|
||||
CGContextAddPath(context, maskPath);
|
||||
CGContextClip(context);
|
||||
CGContextTranslateCTM(context, layerOffset.x, layerOffset.y);
|
||||
}
|
||||
CGContextConcatCTM(context, sublayerTransform);
|
||||
}
|
||||
|
||||
- (IJSVGShapeLayer *)maskingLayer
|
||||
{
|
||||
return (IJSVGShapeLayer *)_maskingLayer ?: nil;
|
||||
}
|
||||
|
||||
- (void)renderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if(self.blendingMode != kCGBlendModeNormal) {
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextSetBlendMode(ctx, self.blendingMode);
|
||||
[self _customRenderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
return;
|
||||
}
|
||||
[self _customRenderInContext:ctx];
|
||||
}
|
||||
|
||||
- (id<CAAction>)actionForKey:(NSString *)event
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGRenderingStyle.h"
|
||||
|
||||
@class IJSVGLayer;
|
||||
|
||||
@@ -15,8 +16,9 @@
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSColor * fillColor;
|
||||
@property (nonatomic, retain) NSColor * strokeColor;
|
||||
@property (nonatomic, assign) CGRect viewBox;
|
||||
@property (nonatomic, retain) IJSVGRenderingStyle * style;
|
||||
|
||||
|
||||
- (IJSVGLayer *)layerForNode:(IJSVGNode *)node;
|
||||
|
||||
|
||||
@@ -26,18 +26,22 @@
|
||||
|
||||
@implementation IJSVGLayerTree
|
||||
|
||||
#define DEFAULT_SHAPE_FILL_COLOR [NSColor blackColor].CGColor
|
||||
|
||||
@synthesize fillColor;
|
||||
@synthesize strokeColor;
|
||||
@synthesize viewBox;
|
||||
@synthesize style = _style;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[fillColor release], fillColor = nil;
|
||||
[strokeColor release], strokeColor = nil;
|
||||
[_style release], _style = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (IJSVGLayer *)layerForNode:(IJSVGNode *)node
|
||||
{
|
||||
IJSVGLayer * layer = nil;
|
||||
@@ -54,44 +58,67 @@
|
||||
layer = [self layerForImage:(IJSVGImage *)node];
|
||||
}
|
||||
|
||||
// apply any basic defaults
|
||||
[self applyDefaultsToLayer:layer
|
||||
fromNode:node];
|
||||
[self applyDefaultsToLayer:layer fromNode:node];
|
||||
|
||||
return [self proposedLayerAfterApplyingTransforms:layer
|
||||
transforms:node.transforms];
|
||||
// create the new layer
|
||||
layer = [self applyTransforms:node.transforms
|
||||
toLayer:layer
|
||||
fromNode:node];
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
- (IJSVGLayer *)proposedLayerAfterApplyingTransforms:(IJSVGLayer *)layer
|
||||
transforms:(NSArray<IJSVGTransform *> *)transforms
|
||||
- (IJSVGLayer *)applyTransforms:(NSArray<IJSVGTransform *> *)transforms
|
||||
toLayer:(IJSVGLayer *)layer
|
||||
fromNode:(IJSVGNode *)node
|
||||
|
||||
{
|
||||
// any x and y?
|
||||
CGFloat x = [node.x computeValue:layer.frame.size.width];
|
||||
CGFloat y = [node.y computeValue:layer.frame.size.height];
|
||||
|
||||
// do some magic transform
|
||||
if(transforms.count == 0 && x == 0.f && y == 0.f) {
|
||||
return layer;
|
||||
}
|
||||
|
||||
if(x != 0.f || y != 0.f) {
|
||||
// we must add translate to the stack
|
||||
NSMutableArray * trans = nil;
|
||||
if(transforms != nil) {
|
||||
trans = [[transforms mutableCopy] autorelease];
|
||||
} else {
|
||||
trans = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
|
||||
}
|
||||
[trans addObject:[IJSVGTransform transformByTranslatingX:x y:y]];
|
||||
transforms = trans;
|
||||
}
|
||||
|
||||
// add any transforms
|
||||
if(transforms.count != 0) {
|
||||
IJSVGLayer * topLayer = nil;
|
||||
IJSVGLayer * parentLayer = nil;
|
||||
IJSVGLayer * topLayer = nil;
|
||||
IJSVGLayer * parentLayer = nil;
|
||||
|
||||
for(IJSVGTransform * transform in transforms) {
|
||||
// make sure we apply the transform to the parent
|
||||
// so they stack
|
||||
IJSVGGroupLayer * childLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
childLayer.affineTransform = transform.CGAffineTransform;
|
||||
|
||||
for(IJSVGTransform * transform in transforms) {
|
||||
// make sure we apply the transform to the parent
|
||||
// so they stack
|
||||
IJSVGGroupLayer * childLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
childLayer.affineTransform = transform.CGAffineTransform;
|
||||
|
||||
// add it to the parent layer
|
||||
if(parentLayer != nil) {
|
||||
[parentLayer addSublayer:childLayer];
|
||||
} else {
|
||||
// make sure we keep track of the top most layer
|
||||
topLayer = childLayer;
|
||||
}
|
||||
|
||||
// reset parent layer to the new child
|
||||
parentLayer = childLayer;
|
||||
// add it to the parent layer
|
||||
if(parentLayer != nil) {
|
||||
[parentLayer addSublayer:childLayer];
|
||||
} else {
|
||||
// make sure we keep track of the top most layer
|
||||
topLayer = childLayer;
|
||||
}
|
||||
|
||||
// swap the layer around
|
||||
[parentLayer addSublayer:layer];
|
||||
layer = topLayer;
|
||||
// reset parent layer to the new child
|
||||
parentLayer = childLayer;
|
||||
}
|
||||
|
||||
// swap the layer around
|
||||
[parentLayer addSublayer:layer];
|
||||
layer = topLayer;
|
||||
return layer;
|
||||
}
|
||||
|
||||
@@ -99,37 +126,59 @@
|
||||
fromNode:(IJSVGNode *)node
|
||||
{
|
||||
CGFloat opacity = node.opacity.value;
|
||||
if(opacity == 0.f) {
|
||||
opacity = 1.f;
|
||||
}
|
||||
layer.opacity = opacity;
|
||||
|
||||
// setup the blending mode
|
||||
if(node.blendMode != IJSVGBlendModeNormal) {
|
||||
layer.blendingMode = (CGBlendMode)node.blendMode;
|
||||
}
|
||||
|
||||
// display?
|
||||
if(node.shouldRender == NO) {
|
||||
layer.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (IJSVGLayer *)layerForImage:(IJSVGImage *)image
|
||||
{
|
||||
IJSVGImageLayer * layer = [[[IJSVGImageLayer alloc] initWithCGImage:image.CGImage] autorelease];
|
||||
layer.frame = CGRectMake(image.x.value, image.y.value, image.width.value, image.height.value);
|
||||
layer.affineTransform = CGAffineTransformConcat(layer.affineTransform,
|
||||
CGAffineTransformMakeScale( 1.f, -1.f));
|
||||
|
||||
// make sure we set the width and height correctly,
|
||||
// as this may not be exactly the same as the size of the
|
||||
// given image
|
||||
CGRect frame = layer.frame;
|
||||
frame.size.width = image.width.value;
|
||||
frame.size.height = image.height.value;
|
||||
layer.frame = frame;
|
||||
return layer;
|
||||
}
|
||||
|
||||
- (IJSVGLayer *)layerForGroup:(IJSVGGroup *)group
|
||||
{
|
||||
|
||||
// grab the sub layer tree from the SVG
|
||||
if(group.svg != nil) {
|
||||
return [self layerForGroup:group.svg.rootNode];
|
||||
}
|
||||
|
||||
IJSVGGroupLayer * groupLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
|
||||
for(IJSVGNode * node in group.children) {
|
||||
[groupLayer addSublayer:[self layerForNode:node]];
|
||||
}
|
||||
groupLayer.frame = (CGRect){
|
||||
.origin = (CGPoint){
|
||||
.x = group.x.value,
|
||||
.y = group.y.value
|
||||
},
|
||||
.origin = CGPointZero,
|
||||
.size = (CGSize){
|
||||
.width = group.width.value,
|
||||
.height = group.height.value
|
||||
}
|
||||
};
|
||||
|
||||
// mask it - forgot groups can have masks too, doh! simple
|
||||
// enough to apply though, recursion ftw!
|
||||
[self maskLayer:groupLayer
|
||||
fromNode:group];
|
||||
return groupLayer;
|
||||
}
|
||||
|
||||
@@ -151,16 +200,21 @@
|
||||
}
|
||||
|
||||
- (IJSVGShapeLayer *)basicLayerForPath:(IJSVGPath *)path
|
||||
originalBoundingBox:(CGRect *)originalBoundingBox
|
||||
{
|
||||
// setup path and layer
|
||||
IJSVGShapeLayer * layer = [[[IJSVGShapeLayer alloc] init] autorelease];
|
||||
CGPathRef introPath = [path newPathRefByAutoClosingPath:NO];
|
||||
|
||||
CGRect bounds = [self correctedBounds:CGPathGetBoundingBox(introPath)];
|
||||
*originalBoundingBox = CGRectIntegral(CGPathGetBoundingBox(introPath));
|
||||
layer.originalPathOrigin = (*originalBoundingBox).origin;
|
||||
|
||||
CGRect bounds = [self correctedBounds:*originalBoundingBox];
|
||||
|
||||
// zero back the path
|
||||
CGAffineTransform trans = CGAffineTransformMakeTranslation(-bounds.origin.x,
|
||||
-bounds.origin.y);
|
||||
|
||||
CGPathRef transformedPath = CGPathCreateCopyByTransformingPath(introPath, &trans);
|
||||
layer.path = transformedPath;
|
||||
|
||||
@@ -169,7 +223,7 @@
|
||||
CGPathRelease(introPath);
|
||||
|
||||
// set the bounds
|
||||
layer.frame = bounds;
|
||||
layer.frame = CGRectIntegral(bounds);
|
||||
|
||||
// basic fill color and rule
|
||||
layer.fillColor = nil;
|
||||
@@ -178,7 +232,7 @@
|
||||
}
|
||||
|
||||
- (IJSVGShapeLayer *)layerMaskFromLayer:(CAShapeLayer *)layer
|
||||
fromNode:(IJSVGNode *)node
|
||||
fromNode:(IJSVGNode *)node
|
||||
{
|
||||
IJSVGShapeLayer * mask = [[[IJSVGShapeLayer alloc] init] autorelease];
|
||||
mask.fillColor = [NSColor blackColor].CGColor;
|
||||
@@ -186,73 +240,59 @@
|
||||
return mask;
|
||||
}
|
||||
|
||||
- (CGAffineTransform)absoluteTransform:(IJSVGNode *)node
|
||||
{
|
||||
CGAffineTransform parentAbsoluteTransform = CGAffineTransformIdentity;
|
||||
IJSVGNode * intermediateNode = node.intermediateParentNode;
|
||||
IJSVGNode * parentSVGNode = node;
|
||||
while((parentSVGNode = parentSVGNode.parentNode) != nil) {
|
||||
if(node == intermediateNode) {
|
||||
continue;
|
||||
}
|
||||
parentAbsoluteTransform = [self absoluteTransform:parentSVGNode];
|
||||
}
|
||||
return CGAffineTransformConcat(IJSVGConcatTransforms(node.transforms),
|
||||
parentAbsoluteTransform);
|
||||
}
|
||||
|
||||
- (IJSVGLayer *)layerForPath:(IJSVGPath *)path
|
||||
{
|
||||
// is there a sub SVG?
|
||||
if(path.svg != nil) {
|
||||
// grab the sub layer tree from the SVG
|
||||
return [path.svg layerWithTree:self];
|
||||
}
|
||||
// grab the basic shape layer
|
||||
CGRect originalShapeBounds;
|
||||
IJSVGShapeLayer * layer = [self basicLayerForPath:path
|
||||
originalBoundingBox:&originalShapeBounds];
|
||||
|
||||
// garb the basic shape layer
|
||||
IJSVGShapeLayer * layer = [self basicLayerForPath:path];
|
||||
CGRect pathBoundingBox = CGPathGetBoundingBox(layer.path);
|
||||
BOOL hasStroke = (path.strokeColor != nil ||
|
||||
path.strokePattern != nil ||
|
||||
path.strokeGradient != nil);
|
||||
|
||||
// any gradient?
|
||||
if(self.fillColor == nil && path.fillGradient != nil) {
|
||||
if(_style.fillColor == nil && path.fillGradient != nil) {
|
||||
|
||||
// add the mask
|
||||
IJSVGShapeLayer * mask = [self layerMaskFromLayer:layer
|
||||
fromNode:path];
|
||||
// create the gradient
|
||||
IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer
|
||||
gradient:path.fillGradient
|
||||
fromNode:path
|
||||
objectRect:originalShapeBounds
|
||||
shouldMask:YES];
|
||||
|
||||
// the gradient drawing layer
|
||||
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
|
||||
gradLayer.frame = pathBoundingBox;
|
||||
gradLayer.gradient = path.fillGradient;
|
||||
gradLayer.mask = mask;
|
||||
|
||||
// is there a fill opacity?
|
||||
if(path.fillOpacity.value != 0.f) {
|
||||
gradLayer.opacity = path.fillOpacity.value;
|
||||
}
|
||||
|
||||
// display it
|
||||
[gradLayer setNeedsDisplay];
|
||||
|
||||
// add the gradient
|
||||
// add the gradient and set it against the layer
|
||||
[layer addSublayer:gradLayer];
|
||||
|
||||
// assign it
|
||||
layer.gradientFillLayer = gradLayer;
|
||||
|
||||
if(path.fillGradient.units == IJSVGUnitUserSpaceOnUse) {
|
||||
// move back if needed
|
||||
gradLayer.frame = (CGRect){
|
||||
.size = gradLayer.frame.size,
|
||||
.origin = CGPointMake(-(gradLayer.frame.origin.x),
|
||||
-(gradLayer.frame.origin.y))
|
||||
};
|
||||
}
|
||||
|
||||
} else if(self.fillColor == nil && path.fillPattern != nil) {
|
||||
} else if(_style.fillColor == nil && path.fillPattern != nil) {
|
||||
|
||||
// create the pattern, this is actually not as easy as it may seem
|
||||
IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease];
|
||||
patternLayer.patternNode = path.fillPattern;
|
||||
patternLayer.pattern = [self layerForNode:path.fillPattern];
|
||||
patternLayer.frame = pathBoundingBox;
|
||||
|
||||
// add the mask
|
||||
patternLayer.mask = [self layerMaskFromLayer:layer
|
||||
fromNode:path];
|
||||
|
||||
// display it
|
||||
[patternLayer setNeedsDisplay];
|
||||
|
||||
IJSVGPatternLayer * patternLayer = [self patternLayerForLayer:layer
|
||||
pattern:path.fillPattern
|
||||
fromNode:path];
|
||||
// add it
|
||||
[layer addSublayer:patternLayer];
|
||||
|
||||
// assign it
|
||||
// apply offsets
|
||||
[self applyOffsetsToLayer:patternLayer
|
||||
fromNode:path.fillPattern];
|
||||
|
||||
layer.patternFillLayer = patternLayer;
|
||||
|
||||
} else {
|
||||
@@ -262,63 +302,320 @@
|
||||
NSColor * fColor = path.fillColor;
|
||||
BOOL hasColor = (fColor.alphaComponent == 0.f || fColor == nil) == NO;
|
||||
BOOL hasFill = path.fillPattern != nil || path.fillGradient != nil;
|
||||
if(self.fillColor && (hasFill || hasColor || fColor == nil)) {
|
||||
fColor = self.fillColor;
|
||||
if(_style.fillColor && (hasFill || hasColor || fColor == nil)) {
|
||||
fColor = _style.fillColor;
|
||||
} else if(fColor != nil && path.fillOpacity.value != 1.f) {
|
||||
fColor = [IJSVGColor changeAlphaOnColor:fColor
|
||||
to:path.fillOpacity.value];
|
||||
}
|
||||
|
||||
// anything changed by user?
|
||||
fColor = [_style.colorList proposedColorForColor:fColor];
|
||||
|
||||
// just set the color
|
||||
layer.fillColor = fColor.CGColor ?: DEFAULT_SHAPE_FILL_COLOR;
|
||||
if(fColor != nil) {
|
||||
layer.fillColor = fColor.CGColor;
|
||||
} else {
|
||||
// use default color
|
||||
NSColor * defColor = [IJSVGColor computeColorSpace:NSColor.blackColor];
|
||||
if(path.fillOpacity.value != 1.f) {
|
||||
defColor = [IJSVGColor changeAlphaOnColor:defColor
|
||||
to:path.fillOpacity.value];
|
||||
}
|
||||
|
||||
// work out if anything was changed by user
|
||||
NSColor * proposedColor = [_style.colorList proposedColorForColor:defColor];
|
||||
layer.fillColor = proposedColor.CGColor;
|
||||
}
|
||||
}
|
||||
|
||||
// stroke it
|
||||
if(path.strokeColor != nil) {
|
||||
if(hasStroke == YES) {
|
||||
|
||||
// same as fill, dont use global if the alpha is 0.f
|
||||
NSColor * sColor = path.strokeColor;
|
||||
if(self.strokeColor != nil && (sColor != nil && sColor.alphaComponent != 0.f)) {
|
||||
sColor = self.strokeColor;
|
||||
// load the stroke layer
|
||||
IJSVGStrokeLayer * strokeLayer = [self strokeLayer:layer
|
||||
fromNode:path];
|
||||
|
||||
// reset the node
|
||||
BOOL moveStrokeLayer = NO;
|
||||
if(_style.strokeColor == nil && path.strokeGradient != nil) {
|
||||
|
||||
// force reset of the mask colour as we need to use the stroke layer
|
||||
// as the mask for the stroke gradient
|
||||
strokeLayer.strokeColor = [IJSVGColor computeColorSpace:NSColor.blackColor].CGColor;
|
||||
|
||||
// create the gradient
|
||||
IJSVGGradientLayer * gradLayer = [self gradientStrokeLayerForLayer:layer
|
||||
gradient:path.strokeGradient
|
||||
fromNode:path
|
||||
objectRect:originalShapeBounds];
|
||||
|
||||
moveStrokeLayer = YES;
|
||||
gradLayer.mask = strokeLayer;
|
||||
gradLayer.opacity = strokeLayer.opacity;
|
||||
|
||||
// add it
|
||||
[layer addSublayer:gradLayer];
|
||||
layer.strokeLayer = strokeLayer;
|
||||
layer.gradientStrokeLayer = gradLayer;
|
||||
|
||||
} else if(_style.strokeColor == nil && path.strokePattern != nil) {
|
||||
|
||||
// force reset of the mask
|
||||
strokeLayer.strokeColor = [IJSVGColor computeColorSpace:NSColor.blackColor].CGColor;
|
||||
|
||||
// create the pattern
|
||||
IJSVGPatternLayer * patternLayer = [self patternStrokeLayerForLayer:layer
|
||||
pattern:path.strokePattern
|
||||
fromNode:path];
|
||||
|
||||
// set the mask for it
|
||||
moveStrokeLayer = YES;
|
||||
patternLayer.mask = strokeLayer;
|
||||
patternLayer.opacity = strokeLayer.opacity;
|
||||
|
||||
// add it
|
||||
[layer addSublayer:patternLayer];
|
||||
layer.strokeLayer = strokeLayer;
|
||||
layer.patternStrokeLayer = (IJSVGPatternLayer *)patternLayer;
|
||||
|
||||
} else {
|
||||
// just add the coloured layer
|
||||
[layer addSublayer:strokeLayer];
|
||||
layer.strokeLayer = strokeLayer;
|
||||
}
|
||||
|
||||
// stroke layer
|
||||
IJSVGStrokeLayer * strokeLayer = [[[IJSVGStrokeLayer alloc] init] autorelease];
|
||||
strokeLayer.path = layer.path;
|
||||
strokeLayer.fillColor = nil;
|
||||
strokeLayer.strokeColor = sColor.CGColor;
|
||||
|
||||
CGFloat lineWidth = 1.f;
|
||||
if(path.strokeWidth.value > 0.f) {
|
||||
lineWidth = path.strokeWidth.value;
|
||||
// if we required to move the stroke layer
|
||||
// then move it in based on half of what the stroke
|
||||
// width is, as strokes are draw on the center
|
||||
if(moveStrokeLayer) {
|
||||
CGFloat layerStrokeWidth = strokeLayer.lineWidth;
|
||||
CGRect rect = strokeLayer.frame;
|
||||
rect.origin.x += (layerStrokeWidth*.5f);
|
||||
rect.origin.y += (layerStrokeWidth*.5f);
|
||||
strokeLayer.frame = rect;
|
||||
}
|
||||
|
||||
// line styles
|
||||
strokeLayer.lineWidth = lineWidth;
|
||||
strokeLayer.lineCap = [self lineCap:path.lineCapStyle];
|
||||
strokeLayer.lineJoin = [self lineJoin:path.lineJoinStyle];
|
||||
strokeLayer.miterLimit = lineWidth;
|
||||
|
||||
CGFloat strokeOpacity = 1.f;
|
||||
if(path.strokeOpacity.value != 0.f) {
|
||||
strokeOpacity = path.strokeOpacity.value;
|
||||
}
|
||||
strokeLayer.opacity = strokeOpacity;
|
||||
|
||||
// dashing
|
||||
strokeLayer.lineDashPhase = path.strokeDashOffset.value;
|
||||
strokeLayer.lineDashPattern = [self lineDashPattern:path];
|
||||
|
||||
// add the stroke layer
|
||||
[layer addSublayer:strokeLayer];
|
||||
|
||||
// add it
|
||||
layer.strokeLayer = strokeLayer;
|
||||
}
|
||||
|
||||
// apply masking
|
||||
[self maskLayer:(IJSVGLayer *)layer
|
||||
fromNode:path];
|
||||
|
||||
return (IJSVGLayer *)layer;
|
||||
}
|
||||
|
||||
- (CGRect)correctBounds:(CGRect)bounds
|
||||
forStrokedPath:(IJSVGNode *)path
|
||||
{
|
||||
// minus half the stroke width from x and y
|
||||
// plus the stroke width to width and height
|
||||
CGFloat val = path.strokeWidth.value;
|
||||
bounds.origin.x -= (val*.5f);
|
||||
bounds.origin.y -= (val*.5f);
|
||||
bounds.size.width += val;
|
||||
bounds.size.height += val;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (IJSVGGradientLayer *)gradientStrokeLayerForLayer:(IJSVGShapeLayer *)layer
|
||||
gradient:(IJSVGGradient *)gradient
|
||||
fromNode:(IJSVGNode *)path
|
||||
objectRect:(CGRect)objectRect
|
||||
{
|
||||
// the gradient drawing layer
|
||||
IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer
|
||||
gradient:gradient
|
||||
fromNode:path
|
||||
objectRect:objectRect
|
||||
shouldMask:NO];
|
||||
|
||||
// set the bounds
|
||||
CGRect bounds = CGPathGetBoundingBox(layer.path);
|
||||
bounds = [self correctBounds:bounds forStrokedPath:path];
|
||||
gradLayer.frame = bounds;
|
||||
return gradLayer;
|
||||
}
|
||||
|
||||
|
||||
- (IJSVGGradientLayer *)gradientLayerForLayer:(IJSVGShapeLayer *)layer
|
||||
gradient:(IJSVGGradient *)gradient
|
||||
fromNode:(IJSVGNode *)path
|
||||
objectRect:(CGRect)objectRect
|
||||
shouldMask:(BOOL)shouldMask
|
||||
{
|
||||
// the gradient drawing layer
|
||||
gradient.colorList = _style.colorList;
|
||||
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
|
||||
gradLayer.viewBox = self.viewBox;
|
||||
gradLayer.frame = layer.bounds;
|
||||
gradLayer.gradient = gradient;
|
||||
gradLayer.absoluteTransform = [self absoluteTransform:path];
|
||||
gradLayer.objectRect = CGRectApplyAffineTransform(objectRect,
|
||||
gradLayer.absoluteTransform);
|
||||
|
||||
if(shouldMask == YES) {
|
||||
// add the mask
|
||||
IJSVGShapeLayer * mask = [self layerMaskFromLayer:layer
|
||||
fromNode:path];
|
||||
gradLayer.mask = mask;
|
||||
}
|
||||
|
||||
// is there a fill opacity?
|
||||
if(path.fillOpacity.value != 0.f) {
|
||||
gradLayer.opacity = path.fillOpacity.value;
|
||||
}
|
||||
gradLayer.masksToBounds = YES;
|
||||
return gradLayer;
|
||||
}
|
||||
|
||||
- (IJSVGPatternLayer *)patternStrokeLayerForLayer:(IJSVGShapeLayer *)layer
|
||||
pattern:(IJSVGPattern *)pattern
|
||||
fromNode:(IJSVGNode *)path
|
||||
{
|
||||
// create the pattern, this is actually not as easy as it may seem
|
||||
IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease];
|
||||
patternLayer.patternNode = pattern;
|
||||
patternLayer.pattern = [self layerForNode:pattern];
|
||||
|
||||
// is there a fill opacity?
|
||||
if(path.fillOpacity.value != 0.f) {
|
||||
patternLayer.opacity = path.fillOpacity.value;
|
||||
}
|
||||
|
||||
// set the bounds
|
||||
CGRect bounds = CGPathGetBoundingBox(layer.path);
|
||||
bounds = [self correctBounds:bounds forStrokedPath:path];
|
||||
patternLayer.frame = bounds;
|
||||
patternLayer.masksToBounds = YES;
|
||||
|
||||
// display
|
||||
[patternLayer setNeedsDisplay];
|
||||
return patternLayer;
|
||||
}
|
||||
|
||||
- (IJSVGPatternLayer *)patternLayerForLayer:(IJSVGShapeLayer *)layer
|
||||
pattern:(IJSVGPattern *)pattern
|
||||
fromNode:(IJSVGNode *)path
|
||||
{
|
||||
// create the pattern, this is actually not as easy as it may seem
|
||||
IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease];
|
||||
patternLayer.patternNode = pattern;
|
||||
patternLayer.pattern = [self layerForNode:pattern];
|
||||
patternLayer.frame = CGPathGetBoundingBox(layer.path);
|
||||
|
||||
// is there a fill opacity?
|
||||
if(path.fillOpacity.value != 0.f) {
|
||||
patternLayer.opacity = path.fillOpacity.value;
|
||||
}
|
||||
|
||||
// add the mask
|
||||
patternLayer.mask = [self layerMaskFromLayer:layer
|
||||
fromNode:path];
|
||||
|
||||
// display
|
||||
[patternLayer setNeedsDisplay];
|
||||
patternLayer.masksToBounds = YES;
|
||||
|
||||
return patternLayer;
|
||||
}
|
||||
|
||||
- (void)applyOffsetsToLayer:(IJSVGLayer *)layer
|
||||
fromNode:(IJSVGNode *)node
|
||||
{
|
||||
// make sure it has a superlayer
|
||||
if(layer.superlayer == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
// grab the x and y
|
||||
IJSVGUnitLength * x = nil;
|
||||
IJSVGUnitLength * y = nil;
|
||||
|
||||
// sort out the rect
|
||||
CGRect rect = layer.superlayer.frame;
|
||||
CGRect frame = layer.frame;
|
||||
|
||||
// x
|
||||
if((x = node.x) != nil) {
|
||||
frame.origin.x = [x computeValue:rect.size.width];
|
||||
}
|
||||
|
||||
// y
|
||||
if((y = node.y) != nil) {
|
||||
frame.origin.y = [y computeValue:rect.size.height];
|
||||
}
|
||||
|
||||
// update the frame
|
||||
if(CGRectEqualToRect(frame, layer.frame) == NO) {
|
||||
layer.frame = frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (IJSVGStrokeLayer *)strokeLayer:(IJSVGShapeLayer *)layer
|
||||
fromNode:(IJSVGPath *)path
|
||||
{
|
||||
// same as fill, dont use global if the alpha is 0.f, but do use it
|
||||
// if there is a pattern or gradient
|
||||
NSColor * sColor = path.strokeColor;
|
||||
if(_style.strokeColor != nil &&
|
||||
((sColor != nil && sColor.alphaComponent != 0.f) ||
|
||||
path.strokePattern != nil || path.strokeGradient != nil )) {
|
||||
sColor = _style.strokeColor;
|
||||
}
|
||||
|
||||
sColor = [_style.colorList proposedColorForColor:sColor];
|
||||
|
||||
// stroke layer
|
||||
IJSVGStrokeLayer * strokeLayer = [[[IJSVGStrokeLayer alloc] init] autorelease];
|
||||
strokeLayer.path = layer.path;
|
||||
strokeLayer.fillColor = nil;
|
||||
strokeLayer.strokeColor = sColor.CGColor;
|
||||
|
||||
CGFloat lineWidth = 1.f;
|
||||
if(_style.lineWidth != IJSVGInheritedFloatValue) {
|
||||
lineWidth = _style.lineWidth;
|
||||
} else {
|
||||
lineWidth = path.strokeWidth.value;
|
||||
}
|
||||
|
||||
// work out line styles
|
||||
IJSVGLineCapStyle lCapStyle;
|
||||
IJSVGLineJoinStyle lJoinStyle;
|
||||
|
||||
// forced cap style
|
||||
if(_style.lineCapStyle != IJSVGLineCapStyleNone) {
|
||||
lCapStyle = _style.lineCapStyle;
|
||||
} else {
|
||||
lCapStyle = path.lineCapStyle;
|
||||
}
|
||||
|
||||
// forced join style
|
||||
if(_style.lineJoinStyle != IJSVGLineJoinStyleNone) {
|
||||
lJoinStyle = _style.lineJoinStyle;
|
||||
} else {
|
||||
lJoinStyle = path.lineJoinStyle;
|
||||
}
|
||||
|
||||
// line styles
|
||||
strokeLayer.lineWidth = lineWidth;
|
||||
strokeLayer.lineCap = [self lineCap:lCapStyle];
|
||||
strokeLayer.lineJoin = [self lineJoin:lJoinStyle];
|
||||
|
||||
CGFloat strokeOpacity = 1.f;
|
||||
if(path.strokeOpacity.value != 0.f) {
|
||||
strokeOpacity = path.strokeOpacity.value;
|
||||
}
|
||||
strokeLayer.opacity = strokeOpacity;
|
||||
|
||||
// dashing
|
||||
strokeLayer.lineDashPhase = path.strokeDashOffset.value;
|
||||
strokeLayer.lineDashPattern = [self lineDashPattern:path];
|
||||
|
||||
return strokeLayer;
|
||||
}
|
||||
|
||||
- (void)maskLayer:(IJSVGLayer *)layer
|
||||
fromNode:(IJSVGNode *)node
|
||||
{
|
||||
@@ -354,7 +651,7 @@
|
||||
|
||||
// recursive colourize for each item
|
||||
[self _recursiveColorLayersFromLayer:maskLayer
|
||||
withColor:[NSColor whiteColor].CGColor];
|
||||
withColor:[IJSVGColor computeColorSpace:NSColor.whiteColor].CGColor];
|
||||
|
||||
// add the mask
|
||||
layer.mask = maskLayer;
|
||||
@@ -448,4 +745,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)log:(IJSVGLayer *)layer
|
||||
depth:(NSInteger)depth {
|
||||
NSLog(@"%@%@: %@, Transforms: %@",[@"" stringByPaddingToLength:depth
|
||||
withString:@"\t"
|
||||
startingAtIndex:0],layer,
|
||||
NSStringFromRect(layer.frame),
|
||||
[IJSVGTransform affineTransformToSVGTransformAttributeString:layer.affineTransform]);
|
||||
for(IJSVGLayer * sublayer in layer.sublayers) {
|
||||
[self log:(IJSVGLayer *)sublayer
|
||||
depth:depth++];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
@interface IJSVGLinearGradient : IJSVGGradient
|
||||
|
||||
+ (NSGradient *)parseGradient:(NSXMLElement *)element
|
||||
gradient:(IJSVGLinearGradient *)aGradient
|
||||
startPoint:(CGPoint *)startPoint
|
||||
endPoint:(CGPoint *)endPoint;
|
||||
gradient:(IJSVGLinearGradient *)aGradient;
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,81 +13,74 @@
|
||||
|
||||
+ (NSGradient *)parseGradient:(NSXMLElement *)element
|
||||
gradient:(IJSVGLinearGradient *)aGradient
|
||||
startPoint:(CGPoint *)startPoint
|
||||
endPoint:(CGPoint *)endPoint
|
||||
{
|
||||
|
||||
CGFloat px1 = [[element attributeForName:@"x1"] stringValue].floatValue;
|
||||
CGFloat px2 = [[element attributeForName:@"x2"] stringValue].floatValue;
|
||||
CGFloat py1 = [[element attributeForName:@"y1"] stringValue].floatValue;
|
||||
CGFloat py2 = [[element attributeForName:@"y2"] stringValue].floatValue;
|
||||
|
||||
// work out each coord, and work out if its a % or not
|
||||
// annoyingly we need to check them all against each other -_-
|
||||
BOOL isPercent = NO;
|
||||
if(px1 <= 1.f && px2 <= 1.f && py1 <= 1.f && py2 <= 1.f) {
|
||||
isPercent = YES;
|
||||
} else if((px1 >= 0.f && px1 <= 1.f) && (px2 >= 0.f && px2 <= 1.f) &&
|
||||
(py1 >= 0.f && py1 <= 1.f) && (py2 >= 0.f && py2 <= 1.f)) {
|
||||
isPercent = YES;
|
||||
}
|
||||
|
||||
// assume its a vertical / horizonal
|
||||
if(isPercent == NO) {
|
||||
// just ask unit for the value
|
||||
aGradient.x1 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"x1"] stringValue] ?: @"0"];
|
||||
aGradient.x2 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"x2"] stringValue] ?: @"100"];
|
||||
aGradient.y1 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"y1"] stringValue] ?: @"0"];
|
||||
aGradient.y2 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"y2"] stringValue] ?: @"0"];
|
||||
} else {
|
||||
// make sure its a percent!
|
||||
aGradient.x1 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"x1"] stringValue] ?: @"0"];
|
||||
aGradient.x2 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"x2"] stringValue] ?: @"100"];
|
||||
aGradient.y1 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"y1"] stringValue] ?: @"0"];
|
||||
aGradient.y2 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"y2"] stringValue] ?: @"0"];
|
||||
}
|
||||
// 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");
|
||||
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
|
||||
CGFloat * stopsParams = [self.class computeColorStopsFromString:element
|
||||
colors:&colors];
|
||||
|
||||
// create the gradient with the colours
|
||||
NSGradient * grad = [[[NSGradient alloc] initWithColors:colors
|
||||
NSGradient * grad = [[NSGradient alloc] initWithColors:colors
|
||||
atLocations:stopsParams
|
||||
colorSpace:[NSColorSpace genericRGBColorSpace]] autorelease];
|
||||
colorSpace:IJSVGColor.defaultColorSpace];
|
||||
|
||||
free(stopsParams);
|
||||
return grad;
|
||||
return [grad autorelease];
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
rect:(NSRect)rect
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox
|
||||
{
|
||||
// grab the start and end point
|
||||
CGPoint aStartPoint = (CGPoint){
|
||||
.x = [self.x1 computeValue:rect.size.width],
|
||||
.y = [self.y1 computeValue:rect.size.height]
|
||||
};
|
||||
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
|
||||
|
||||
CGPoint aEndPoint = (CGPoint){
|
||||
.x = [self.x2 computeValue:rect.size.width],
|
||||
.y = [self.y2 computeValue:rect.size.height]
|
||||
};
|
||||
CGPoint gradientStartPoint = CGPointZero;
|
||||
CGPoint gradientEndPoint = CGPointZero;
|
||||
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
|
||||
|
||||
// convert the nsgradient to a CGGradient
|
||||
CGGradientRef gRef = [self CGGradient];
|
||||
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
|
||||
|
||||
// apply transform for each point
|
||||
for( IJSVGTransform * transform in self.transforms ) {
|
||||
CGAffineTransform trans = transform.CGAffineTransform;
|
||||
aStartPoint = CGPointApplyAffineTransform(aStartPoint, trans);
|
||||
aEndPoint = CGPointApplyAffineTransform(aEndPoint, trans);
|
||||
// make sure we apply the absolute position to
|
||||
// transform us back into the correct space
|
||||
if(inUserSpace == YES) {
|
||||
CGContextConcatCTM(ctx, absoluteTransform);
|
||||
}
|
||||
|
||||
CGFloat width = CGRectGetWidth(boundingBox);
|
||||
CGFloat height = CGRectGetHeight(boundingBox);
|
||||
gradientStartPoint = CGPointMake([self.x1 computeValue:width],
|
||||
[self.y1 computeValue:height]);
|
||||
|
||||
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
|
||||
[self.y2 computeValue:height]);
|
||||
|
||||
// transform the context
|
||||
CGContextConcatCTM(ctx, selfTransform);
|
||||
|
||||
// draw the gradient
|
||||
CGGradientDrawingOptions opt = kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation;
|
||||
CGContextDrawLinearGradient(ctx, gRef, aStartPoint, aEndPoint, opt);
|
||||
CGGradientDrawingOptions options =
|
||||
kCGGradientDrawsBeforeStartLocation|
|
||||
kCGGradientDrawsAfterEndLocation;
|
||||
|
||||
CGContextDrawLinearGradient(ctx, self.CGGradient, gradientStartPoint,
|
||||
gradientEndPoint, options);
|
||||
|
||||
#ifdef IJSVG_DEBUG
|
||||
[self _debugStart:gradientStartPoint
|
||||
end:gradientEndPoint
|
||||
context:ctx];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
@class IJSVGGradient;
|
||||
@class IJSVGGroup;
|
||||
@class IJSVGPattern;
|
||||
@class IJSVGTransform;
|
||||
|
||||
typedef NS_ENUM( NSInteger, IJSVGNodeType ) {
|
||||
IJSVGNodeTypeGroup,
|
||||
@@ -39,6 +40,8 @@ typedef NS_ENUM( NSInteger, IJSVGNodeType ) {
|
||||
IJSVGNodeTypeSVG,
|
||||
IJSVGNodeTypeText,
|
||||
IJSVGNodeTypeTextSpan,
|
||||
IJSVGNodeTypeStyle,
|
||||
IJSVGNodeTypeSwitch,
|
||||
IJSVGNodeTypeNotFound,
|
||||
};
|
||||
|
||||
@@ -49,6 +52,7 @@ typedef NS_ENUM( NSInteger, IJSVGWindingRule ) {
|
||||
};
|
||||
|
||||
typedef NS_ENUM( NSInteger, IJSVGLineCapStyle ) {
|
||||
IJSVGLineCapStyleNone,
|
||||
IJSVGLineCapStyleButt,
|
||||
IJSVGLineCapStyleRound,
|
||||
IJSVGLineCapStyleSquare,
|
||||
@@ -56,6 +60,7 @@ typedef NS_ENUM( NSInteger, IJSVGLineCapStyle ) {
|
||||
};
|
||||
|
||||
typedef NS_ENUM( NSInteger, IJSVGLineJoinStyle ) {
|
||||
IJSVGLineJoinStyleNone,
|
||||
IJSVGLineJoinStyleMiter,
|
||||
IJSVGLineJoinStyleRound,
|
||||
IJSVGLineJoinStyleBevel,
|
||||
@@ -68,10 +73,23 @@ typedef NS_OPTIONS( NSInteger, IJSVGFontTraits ) {
|
||||
IJSVGFontTraitItalic = 1 << 2
|
||||
};
|
||||
|
||||
typedef NS_ENUM( NSInteger, IJSVGUnitType) {
|
||||
IJSVGUnitUserSpaceOnUse,
|
||||
IJSVGUnitObjectBoundingBox,
|
||||
IJSVGUnitInherit
|
||||
typedef NS_ENUM( NSInteger, IJSVGBlendMode) {
|
||||
IJSVGBlendModeNormal = kCGBlendModeNormal,
|
||||
IJSVGBlendModeMultiply = kCGBlendModeMultiply,
|
||||
IJSVGBlendModeScreen = kCGBlendModeScreen,
|
||||
IJSVGBlendModeOverlay = kCGBlendModeOverlay,
|
||||
IJSVGBlendModeDarken = kCGBlendModeDarken,
|
||||
IJSVGBlendModeLighten = kCGBlendModeLighten,
|
||||
IJSVGBlendModeColorDodge = kCGBlendModeColorDodge,
|
||||
IJSVGBlendModeColorBurn = kCGBlendModeColorBurn,
|
||||
IJSVGBlendModeHardLight = kCGBlendModeHardLight,
|
||||
IJSVGBlendModeSoftLight = kCGBlendModeSoftLight,
|
||||
IJSVGBlendModeDifference = kCGBlendModeDifference,
|
||||
IJSVGBlendModeExclusion = kCGBlendModeExclusion,
|
||||
IJSVGBlendModeHue = kCGBlendModeHue,
|
||||
IJSVGBlendModeSaturation = kCGBlendModeSaturation,
|
||||
IJSVGBlendModeColor = kCGBlendModeColor,
|
||||
IJSVGBlendModeLuminosity = kCGBlendModeLuminosity
|
||||
};
|
||||
|
||||
static CGFloat IJSVGInheritedFloatValue = -99.9999991;
|
||||
@@ -97,21 +115,25 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991;
|
||||
@property ( nonatomic, retain ) NSColor * strokeColor;
|
||||
@property ( nonatomic, copy ) NSString * identifier;
|
||||
@property ( nonatomic, assign ) IJSVGNode * parentNode;
|
||||
@property ( nonatomic, assign ) IJSVGNode * intermediateParentNode;
|
||||
@property ( nonatomic, retain ) IJSVGGroup * clipPath;
|
||||
@property ( nonatomic, retain ) IJSVGGroup * mask;
|
||||
@property ( nonatomic, assign ) IJSVGWindingRule windingRule;
|
||||
@property ( nonatomic, assign ) IJSVGLineCapStyle lineCapStyle;
|
||||
@property ( nonatomic, assign ) IJSVGLineJoinStyle lineJoinStyle;
|
||||
@property ( nonatomic, retain ) NSArray * transforms;
|
||||
@property ( nonatomic, retain ) 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, retain ) IJSVGUnitLength * strokeDashOffset;
|
||||
@property ( nonatomic, retain ) IJSVG * svg;
|
||||
@property ( nonatomic, assign ) IJSVGUnitType contentUnits;
|
||||
@property ( nonatomic, assign ) IJSVGUnitType units;
|
||||
@property ( nonatomic, assign ) IJSVGBlendMode blendMode;
|
||||
|
||||
+ (IJSVGNodeType)typeForString:(NSString *)string
|
||||
kind:(NSXMLNodeKind)kind;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGDef.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@implementation IJSVGNode
|
||||
|
||||
@@ -29,11 +30,14 @@
|
||||
@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;
|
||||
@@ -45,6 +49,7 @@
|
||||
@synthesize mask;
|
||||
@synthesize units;
|
||||
@synthesize contentUnits;
|
||||
@synthesize blendMode;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
@@ -60,6 +65,8 @@
|
||||
[strokeDashOffset release], strokeDashOffset = nil;
|
||||
[unicode release], unicode = nil;
|
||||
[fillGradient release], fillGradient = nil;
|
||||
[strokeGradient release], strokeGradient = nil;
|
||||
[strokePattern release], strokePattern = nil;
|
||||
[transforms release], transforms = nil;
|
||||
[fillColor release], fillColor = nil;
|
||||
[strokeColor release], strokeColor = nil;
|
||||
@@ -79,6 +86,10 @@
|
||||
kind:(NSXMLNodeKind)kind
|
||||
{
|
||||
string = [string lowercaseString];
|
||||
if([string isEqualToString:@"style"])
|
||||
return IJSVGNodeTypeStyle;
|
||||
if([string isEqualToString:@"switch"])
|
||||
return IJSVGNodeTypeSwitch;
|
||||
if( [string isEqualToString:@"defs"] )
|
||||
return IJSVGNodeTypeDef;
|
||||
if( [string isEqualToString:@"g"] )
|
||||
@@ -122,6 +133,12 @@
|
||||
if([string isEqualToString:@"tspan"] || kind == NSXMLTextKind) {
|
||||
return IJSVGNodeTypeTextSpan;
|
||||
}
|
||||
|
||||
// are we commong HTML? - if so just treat as a group
|
||||
if(IJSVGIsCommonHTMLElementName(string) == YES) {
|
||||
return IJSVGNodeTypeGroup;
|
||||
}
|
||||
|
||||
return IJSVGNodeTypeNotFound;
|
||||
}
|
||||
|
||||
@@ -129,6 +146,7 @@
|
||||
{
|
||||
if( ( self = [self initWithDef:YES] ) != nil )
|
||||
{
|
||||
self.opacity = [IJSVGUnitLength unitWithFloat:1];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -148,6 +166,8 @@
|
||||
|
||||
self.fillGradient = node.fillGradient;
|
||||
self.fillPattern = node.fillPattern;
|
||||
self.strokeGradient = node.strokeGradient;
|
||||
self.strokePattern = node.strokePattern;
|
||||
|
||||
self.fillColor = node.fillColor;
|
||||
self.strokeColor = node.strokeColor;
|
||||
@@ -172,6 +192,7 @@
|
||||
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));
|
||||
@@ -183,7 +204,7 @@
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
IJSVGNode * node = [[self class] allocWithZone:zone];
|
||||
IJSVGNode * node = [self.class allocWithZone:zone];
|
||||
[node applyPropertiesFromNode:self];
|
||||
return node;
|
||||
}
|
||||
@@ -194,15 +215,24 @@
|
||||
{
|
||||
self.opacity = [IJSVGUnitLength unitWithFloat:0.f];
|
||||
self.fillOpacity = [IJSVGUnitLength unitWithFloat:1.f];
|
||||
self.strokeOpacity = [IJSVGUnitLength unitWithFloat:1.f];
|
||||
self.fillOpacity.inherit = YES;
|
||||
|
||||
self.strokeDashOffset = [IJSVGUnitLength unitWithFloat:0.f];
|
||||
self.shouldRender = YES;
|
||||
self.strokeWidth = [IJSVGUnitLength unitWithFloat:0.f];
|
||||
|
||||
self.strokeOpacity = [IJSVGUnitLength unitWithFloat:1.f];
|
||||
self.strokeOpacity.inherit = YES;
|
||||
|
||||
self.strokeWidth = [IJSVGUnitLength unitWithFloat:1.f];
|
||||
self.strokeWidth.inherit = YES;
|
||||
|
||||
self.windingRule = IJSVGWindingRuleInherit;
|
||||
self.lineCapStyle = IJSVGLineCapStyleInherit;
|
||||
self.lineJoinStyle = IJSVGLineJoinStyleInherit;
|
||||
self.units = IJSVGUnitInherit;
|
||||
|
||||
self.blendMode = IJSVGBlendModeNormal;
|
||||
|
||||
if( flag ) {
|
||||
def = [[IJSVGDef alloc] init];
|
||||
}
|
||||
@@ -213,10 +243,12 @@
|
||||
- (IJSVGDef *)defForID:(NSString *)anID
|
||||
{
|
||||
IJSVGDef * aDef = nil;
|
||||
if( (aDef = [def defForID:anID]) != nil )
|
||||
if( (aDef = [def defForID:anID]) != nil ) {
|
||||
return aDef;
|
||||
if( parentNode != nil )
|
||||
}
|
||||
if( parentNode != nil ) {
|
||||
return [parentNode defForID:anID];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -228,7 +260,7 @@
|
||||
// winding rule can inherit..
|
||||
- (IJSVGWindingRule)windingRule
|
||||
{
|
||||
if( windingRule == IJSVGWindingRuleInherit && parentNode != nil ) {
|
||||
if(windingRule == IJSVGWindingRuleInherit && parentNode != nil) {
|
||||
return parentNode.windingRule;
|
||||
}
|
||||
return windingRule;
|
||||
@@ -236,20 +268,20 @@
|
||||
|
||||
- (IJSVGLineCapStyle)lineCapStyle
|
||||
{
|
||||
if( lineCapStyle == IJSVGLineCapStyleInherit )
|
||||
{
|
||||
if( parentNode != nil )
|
||||
if( lineCapStyle == IJSVGLineCapStyleInherit ) {
|
||||
if( parentNode != nil ) {
|
||||
return parentNode.lineCapStyle;
|
||||
}
|
||||
}
|
||||
return lineCapStyle;
|
||||
}
|
||||
|
||||
- (IJSVGLineJoinStyle)lineJoinStyle
|
||||
{
|
||||
if( lineJoinStyle == IJSVGLineJoinStyleInherit )
|
||||
{
|
||||
if( parentNode != nil )
|
||||
if( lineJoinStyle == IJSVGLineJoinStyleInherit ) {
|
||||
if( parentNode != nil ) {
|
||||
return parentNode.lineJoinStyle;
|
||||
}
|
||||
}
|
||||
return lineJoinStyle;
|
||||
}
|
||||
@@ -307,8 +339,9 @@
|
||||
// must be on the path, it can also be on the
|
||||
- (NSColor *)fillColor
|
||||
{
|
||||
if( fillColor == nil && parentNode != nil )
|
||||
if( fillColor == nil && parentNode != nil ) {
|
||||
return parentNode.fillColor;
|
||||
}
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
@@ -332,4 +365,24 @@
|
||||
return fillPattern;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGGradient *)strokeGradient
|
||||
{
|
||||
if(strokeGradient == nil && parentNode != nil) {
|
||||
return parentNode.strokeGradient;
|
||||
}
|
||||
return strokeGradient;
|
||||
}
|
||||
|
||||
// these are all recursive, so go up the chain
|
||||
// if they dont exist on this specific node
|
||||
- (IJSVGPattern *)strokePattern
|
||||
{
|
||||
if(strokePattern == nil && parentNode != nil) {
|
||||
return parentNode.strokePattern;
|
||||
}
|
||||
return strokePattern;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -49,6 +49,7 @@ 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";
|
||||
@@ -92,7 +93,9 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
|
||||
IJSVGStyleSheet * _styleSheet;
|
||||
NSMutableArray * _parsedNodes;
|
||||
NSMutableDictionary * _defNodes;
|
||||
NSMutableDictionary * _baseDefNodes;
|
||||
NSMutableArray<IJSVG *> * _svgs;
|
||||
NSMutableArray * _definedGroups;
|
||||
|
||||
struct {
|
||||
unsigned int shouldHandleForeignObject: 1;
|
||||
@@ -104,6 +107,8 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
|
||||
@property ( nonatomic, readonly ) NSRect viewBox;
|
||||
@property ( nonatomic, readonly ) NSSize proposedViewSize;
|
||||
|
||||
+ (BOOL)isDataSVG:(NSData *)data;
|
||||
|
||||
- (id)initWithSVGString:(NSString *)string
|
||||
error:(NSError **)error
|
||||
delegate:(id<IJSVGParserDelegate>)delegate;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
self.requiresBackingScaleHelp = YES;
|
||||
self.shouldRasterize = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
@property ( nonatomic, retain ) IJSVGUnitLength * radius;
|
||||
|
||||
+ (NSGradient *)parseGradient:(NSXMLElement *)element
|
||||
gradient:(IJSVGRadialGradient *)gradient
|
||||
startPoint:(CGPoint *)startPoint
|
||||
endPoint:(CGPoint *)endPoint;
|
||||
gradient:(IJSVGRadialGradient *)gradient;
|
||||
|
||||
@end
|
||||
|
||||
@@ -34,123 +34,130 @@
|
||||
grad.cx = self.cx;
|
||||
grad.cy = self.cy;
|
||||
grad.radius = self.radius;
|
||||
grad.startPoint = self.startPoint;
|
||||
grad.endPoint = self.endPoint;
|
||||
return grad;
|
||||
}
|
||||
|
||||
|
||||
+ (NSGradient *)parseGradient:(NSXMLElement *)element
|
||||
gradient:(IJSVGRadialGradient *)gradient
|
||||
startPoint:(CGPoint *)startPoint
|
||||
endPoint:(CGPoint *)endPoint
|
||||
{
|
||||
// cx defaults to 50% if not specified
|
||||
NSDictionary * kv = @{@"cx":@"cx",
|
||||
@"cy":@"cy",
|
||||
@"r":@"radius",
|
||||
@"fx":@"fx"};
|
||||
@"r":@"radius"};
|
||||
|
||||
for(NSString * key in kv.allKeys) {
|
||||
NSString * str = [element attributeForName:key].stringValue;
|
||||
IJSVGUnitLength * unit = nil;
|
||||
if(str != nil) {
|
||||
unit = [IJSVGUnitLength unitWithPercentageString:str];
|
||||
unit = [IJSVGUnitLength unitWithString:str
|
||||
fromUnitType:gradient.units];
|
||||
} else {
|
||||
unit = [IJSVGUnitLength unitWithPercentageFloat:50];
|
||||
// spec says to say 50% for missing property default
|
||||
unit = [IJSVGUnitLength unitWithPercentageFloat:.5f];
|
||||
}
|
||||
[gradient setValue:unit
|
||||
forKey:kv[key]];
|
||||
}
|
||||
|
||||
// fy defaults to cy if not specified
|
||||
NSString * fy = [element attributeForName:@"fy"].stringValue;
|
||||
if(fy != nil) {
|
||||
gradient.fy = [IJSVGUnitLength unitWithPercentageString:fy];
|
||||
} else {
|
||||
gradient.fy = gradient.cy;
|
||||
// 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];
|
||||
}
|
||||
|
||||
if( gradient.gradient != nil )
|
||||
NSString * fy = [element attributeForName:@"fy"].stringValue;
|
||||
if(fx != nil) {
|
||||
gradient.fy = [IJSVGUnitLength unitWithString:fy
|
||||
fromUnitType:gradient.units];
|
||||
}
|
||||
|
||||
if( gradient.gradient != nil ) {
|
||||
return nil;
|
||||
|
||||
*startPoint = CGPointMake(gradient.cx.valueAsPercentage, gradient.cy.valueAsPercentage);
|
||||
*endPoint = CGPointMake(gradient.fx.valueAsPercentage, gradient.fy.valueAsPercentage);
|
||||
}
|
||||
|
||||
NSArray * colors = nil;
|
||||
CGFloat * colorStops = [[self class] computeColorStopsFromString:element colors:&colors];
|
||||
CGFloat * colorStops = [self.class computeColorStopsFromString:element colors:&colors];
|
||||
NSGradient * ret = [[[NSGradient alloc] initWithColors:colors
|
||||
atLocations:colorStops
|
||||
colorSpace:[NSColorSpace genericRGBColorSpace]] autorelease];
|
||||
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
|
||||
free(colorStops);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (CGFloat)_handleTransform:(IJSVGTransform *)transform
|
||||
bounds:(CGRect)bounds
|
||||
index:(NSInteger)index
|
||||
value:(CGFloat)value
|
||||
{
|
||||
// rotate transform, assume its based on percentages
|
||||
// if lower then 0 is specified for 1 or 2
|
||||
CGFloat max = bounds.size.width>bounds.size.height?bounds.size.width:bounds.size.height;
|
||||
if( transform.command == IJSVGTransformCommandRotate ) {
|
||||
switch(index) {
|
||||
case 1:
|
||||
case 2: {
|
||||
if(value<1.f) {
|
||||
return (max*value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
rect:(NSRect)rect
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox
|
||||
{
|
||||
CGRect bounds = rect;
|
||||
for( IJSVGTransform * transform in self.transforms ) {
|
||||
IJSVGTransformParameterModifier modifier = ^CGFloat(NSInteger index, CGFloat value) {
|
||||
return [self _handleTransform:transform
|
||||
bounds:bounds
|
||||
index:index
|
||||
value:value];
|
||||
};
|
||||
CGContextConcatCTM(ctx, [transform CGAffineTransformWithModifier:modifier]);
|
||||
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);
|
||||
}
|
||||
|
||||
CGPoint sp = self.startPoint;
|
||||
CGPoint ep = self.endPoint;
|
||||
|
||||
if( self.startPoint.x == .5f ) {
|
||||
sp.x = bounds.size.width*self.startPoint.x;
|
||||
// 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);
|
||||
|
||||
if(self.startPoint.y == .5f) {
|
||||
sp.y = bounds.size.height*self.startPoint.y;
|
||||
}
|
||||
|
||||
if(self.endPoint.x == .5f) {
|
||||
ep.x = bounds.size.width*self.endPoint.x;
|
||||
}
|
||||
|
||||
if(self.endPoint.y == .5f) {
|
||||
ep.y = bounds.size.height*self.endPoint.y;
|
||||
}
|
||||
|
||||
CGFloat r = self.radius.value;
|
||||
if(r == .5f) {
|
||||
r = (sp.x>sp.y?sp.x:sp.y);
|
||||
}
|
||||
|
||||
// actually perform the draw
|
||||
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation;
|
||||
CGGradientRef grad = self.CGGradient;
|
||||
CGContextDrawRadialGradient(ctx, grad, sp, 0.f, ep, r, options);
|
||||
#ifdef IJSVG_DEBUG_GRADIENTS
|
||||
[self _debugStart:gradientStartPoint
|
||||
end:gradientEndPoint
|
||||
context:ctx];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// IJSVGRendering.h
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 14/03/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
|
||||
typedef NS_ENUM(NSInteger, IJSVGRenderQuality) {
|
||||
IJSVGRenderQualityFullResolution, // slowest to render
|
||||
IJSVGRenderQualityOptimized, // best of both worlds
|
||||
IJSVGRenderQualityLow // fast rendering
|
||||
};
|
||||
|
||||
@interface IJSVGRendering : NSObject
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// IJSVGRendering.m
|
||||
// IJSVGExample
|
||||
//
|
||||
// Created by Curtis Hard on 14/03/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGRendering.h"
|
||||
|
||||
@implementation IJSVGRendering
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// IJSVGStyleList.h
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 09/07/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGColorList.h"
|
||||
|
||||
@interface IJSVGRenderingStyle : NSObject
|
||||
|
||||
@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle;
|
||||
@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle;
|
||||
@property (nonatomic, assign) CGFloat lineWidth;
|
||||
@property (nonatomic, retain) IJSVGColorList * colorList;
|
||||
@property (nonatomic, retain) NSColor * fillColor;
|
||||
@property (nonatomic, retain) NSColor * strokeColor;
|
||||
|
||||
+ (NSArray<NSString *> *)observableProperties;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// IJSVGStyleList.m
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 09/07/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGRenderingStyle.h"
|
||||
|
||||
@implementation IJSVGRenderingStyle
|
||||
|
||||
@synthesize colorList = _colorList;
|
||||
@synthesize lineCapStyle = _lineCapStyle;
|
||||
@synthesize lineJoinStyle = _lineJoinStyle;
|
||||
@synthesize lineWidth = _lineWidth;
|
||||
@synthesize fillColor = _fillColor;
|
||||
@synthesize strokeColor = _strokeColor;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_fillColor release], _fillColor = nil;
|
||||
[_strokeColor release], _strokeColor = nil;
|
||||
[_colorList release], _colorList = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
_lineCapStyle = IJSVGLineCapStyleNone;
|
||||
_lineJoinStyle = IJSVGLineJoinStyleNone;
|
||||
_lineWidth = IJSVGInheritedFloatValue;
|
||||
_colorList = [[IJSVGColorList alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)observableProperties
|
||||
{
|
||||
unsigned int count;
|
||||
objc_property_t * properties = class_copyPropertyList(IJSVGRenderingStyle.class,
|
||||
&count);
|
||||
NSMutableArray * names = [[[NSMutableArray alloc] initWithCapacity:count] autorelease];
|
||||
for(int i = 0; i < count; i++) {
|
||||
objc_property_t property = properties[i];
|
||||
const char * name = property_getName(property);
|
||||
NSString * stringName = [NSString stringWithCString:name
|
||||
encoding:NSUTF8StringEncoding];
|
||||
[names addObject:stringName];
|
||||
}
|
||||
free(properties);
|
||||
return names;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -8,9 +8,29 @@
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "IJSVGLayer.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@interface IJSVGShapeLayer : CAShapeLayer
|
||||
@interface IJSVGShapeLayer : CAShapeLayer {
|
||||
|
||||
@private
|
||||
IJSVGLayer * _maskingLayer;
|
||||
}
|
||||
|
||||
IJSVG_LAYER_DEFAULT_PROPERTIES
|
||||
@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer;
|
||||
@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer;
|
||||
@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer;
|
||||
@property (nonatomic, assign) IJSVGGradientLayer * gradientStrokeLayer;
|
||||
@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer;
|
||||
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
|
||||
@property (nonatomic, assign) CGFloat backingScaleFactor;
|
||||
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
|
||||
@property (nonatomic, assign) CGBlendMode blendingMode;
|
||||
@property (nonatomic, assign) CGPoint absoluteOrigin;
|
||||
@property (nonatomic, assign) CGPoint originalPathOrigin;
|
||||
@property (nonatomic, assign) BOOL convertMasksToPaths;
|
||||
|
||||
- (void)applySublayerMaskToContext:(CGContextRef)context
|
||||
forSublayer:(IJSVGLayer *)sublayer
|
||||
withOffset:(CGPoint)offset;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,16 +7,156 @@
|
||||
//
|
||||
|
||||
#import "IJSVGShapeLayer.h"
|
||||
#import "IJSVGGroupLayer.h"
|
||||
|
||||
@implementation IJSVGShapeLayer
|
||||
|
||||
IJSVG_LAYER_DEFAULT_SYNTHESIZE
|
||||
@synthesize gradientFillLayer;
|
||||
@synthesize patternFillLayer;
|
||||
@synthesize gradientStrokeLayer;
|
||||
@synthesize patternStrokeLayer;
|
||||
@synthesize strokeLayer;
|
||||
@synthesize requiresBackingScaleHelp;
|
||||
@synthesize backingScaleFactor;
|
||||
@synthesize blendingMode;
|
||||
@synthesize convertMasksToPaths;
|
||||
@synthesize originalPathOrigin;
|
||||
@synthesize renderQuality;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
IJSVG_LAYER_DEFAULT_DEALLOC_INSTRUCTIONS
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
IJSVG_LAYER_ADD_SUBVIEW_DEFAULT_IMPLEMENTATION
|
||||
- (void)addSublayer:(CALayer *)layer {
|
||||
if([layer isKindOfClass:[IJSVGLayer class]] == NO &&
|
||||
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) {
|
||||
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.",
|
||||
[layer class]];
|
||||
NSException * exception = [NSException exceptionWithName:@"IJSVGInvalidSublayerException"
|
||||
reason:r
|
||||
userInfo:nil];
|
||||
@throw exception;
|
||||
}
|
||||
[super addSublayer:layer];
|
||||
}
|
||||
|
||||
- (void)setBackingScaleFactor:(CGFloat)newFactor
|
||||
{
|
||||
if(self.backingScaleFactor == newFactor) {
|
||||
return;
|
||||
}
|
||||
backingScaleFactor = newFactor;
|
||||
self.contentsScale = newFactor;
|
||||
self.rasterizationScale = newFactor;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)_customRenderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if(self.convertMasksToPaths == YES && _maskingLayer != nil) {
|
||||
CGContextSaveGState(ctx);
|
||||
[self applySublayerMaskToContext:ctx
|
||||
forSublayer:(IJSVGLayer *)self
|
||||
withOffset:CGPointZero];
|
||||
[super renderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
return;
|
||||
}
|
||||
[super renderInContext:ctx];
|
||||
}
|
||||
|
||||
- (void)setConvertMasksToPaths:(BOOL)flag
|
||||
{
|
||||
if(convertMasksToPaths == flag) {
|
||||
return;
|
||||
}
|
||||
convertMasksToPaths = flag;
|
||||
if(flag == YES) {
|
||||
if(_maskingLayer != nil) {
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
}
|
||||
_maskingLayer = [(IJSVGLayer *)self.mask retain];
|
||||
self.mask = nil;
|
||||
} else {
|
||||
self.mask = _maskingLayer;
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applySublayerMaskToContext:(CGContextRef)context
|
||||
forSublayer:(IJSVGLayer *)sublayer
|
||||
withOffset:(CGPoint)offset
|
||||
{
|
||||
// apply any transforms needed
|
||||
CGPoint layerOffset = offset;
|
||||
CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(sublayer.transform);
|
||||
CGContextConcatCTM( context, CGAffineTransformInvert(sublayerTransform) );
|
||||
|
||||
// walk up the superlayer chain
|
||||
CALayer * superlayer = self.superlayer;
|
||||
if (IJSVGIsSVGLayer(superlayer) == YES) {
|
||||
[(IJSVGLayer *)superlayer applySublayerMaskToContext:context
|
||||
forSublayer:(IJSVGLayer *)self
|
||||
withOffset:layerOffset];
|
||||
}
|
||||
|
||||
// grab the masking layer
|
||||
IJSVGShapeLayer * maskingLayer = [self maskingLayer];
|
||||
|
||||
// if its a group we need to get the lowest level children
|
||||
// and walk up the chain again
|
||||
if([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
|
||||
NSArray * subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer];
|
||||
for(IJSVGLayer * subLayer in subs) {
|
||||
[subLayer applySublayerMaskToContext:context
|
||||
forSublayer:(IJSVGLayer *)self
|
||||
withOffset:layerOffset];
|
||||
}
|
||||
} else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
|
||||
// is a shape, go for it!
|
||||
CGPathRef maskPath = maskingLayer.path;
|
||||
CGContextTranslateCTM(context, -layerOffset.x, -layerOffset.y);
|
||||
CGContextAddPath(context, maskPath);
|
||||
CGContextClip(context);
|
||||
CGContextTranslateCTM(context, layerOffset.x, layerOffset.y);
|
||||
}
|
||||
CGContextConcatCTM(context, sublayerTransform);
|
||||
}
|
||||
|
||||
- (IJSVGShapeLayer *)maskingLayer
|
||||
{
|
||||
return (IJSVGShapeLayer *)_maskingLayer ?: nil;
|
||||
}
|
||||
|
||||
- (void)renderInContext:(CGContextRef)ctx
|
||||
{
|
||||
if(self.blendingMode != kCGBlendModeNormal) {
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextSetBlendMode(ctx, self.blendingMode);
|
||||
[self _customRenderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
return;
|
||||
}
|
||||
[self _customRenderInContext:ctx];
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (id<CAAction>)actionForKey:(NSString *)event
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// IJSVGStringAdditions.h
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 07/06/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSString (IJSVGAdditions)
|
||||
|
||||
- (NSArray<NSString *> *)ijsvg_componentsSeparatedByChars:(char *)aChar;
|
||||
- (BOOL)ijsvg_isNumeric;
|
||||
- (BOOL)ijsvg_containsAlpha;
|
||||
- (NSArray *)ijsvg_componentsSplitByWhiteSpace;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// IJSVGStringAdditions.m
|
||||
// IconJar
|
||||
//
|
||||
// Created by Curtis Hard on 07/06/2019.
|
||||
// Copyright © 2019 Curtis Hard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IJSVGStringAdditions.h"
|
||||
|
||||
@implementation NSString (IJSVGAdditions)
|
||||
|
||||
- (NSArray<NSString *> *)ijsvg_componentsSeparatedByChars:(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;
|
||||
|
||||
// block for easy comparison
|
||||
NSUInteger aLength = strlen(aChar);
|
||||
BOOL (^charsContainsChar)(char anotherChar) = ^(char anotherChar) {
|
||||
for(NSInteger i = 0; i < aLength; i++) {
|
||||
if(aChar[i] == anotherChar) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
};
|
||||
|
||||
for(NSInteger i = 0; i < length; i++) {
|
||||
|
||||
// the char
|
||||
unichar theChar = [self characterAtIndex:i];
|
||||
|
||||
// start the buffer
|
||||
BOOL isEqualToChar = charsContainsChar(theChar);
|
||||
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]];
|
||||
free(chars);
|
||||
|
||||
// restart and realloc the memory
|
||||
ind = 0;
|
||||
chars = (unichar *)calloc(sizeof(unichar), self.length);
|
||||
}
|
||||
}
|
||||
free(chars);
|
||||
return comp;
|
||||
}
|
||||
|
||||
- (BOOL)ijsvg_containsAlpha
|
||||
{
|
||||
const char * buffer = self.UTF8String;
|
||||
unsigned long length = strlen(buffer);
|
||||
for( int i = 0; i < length; i++ ) {
|
||||
if( isalpha(buffer[i]) ) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)ijsvg_isNumeric
|
||||
{
|
||||
const char * buffer = self.UTF8String;
|
||||
unsigned long length = strlen(buffer);
|
||||
for(int i = 0; i < length; i++) {
|
||||
if(!isnumber(buffer[i])) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray *)ijsvg_componentsSplitByWhiteSpace
|
||||
{
|
||||
return [self componentsSeparatedByChars:"\t\n\r "];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -44,25 +44,44 @@
|
||||
|
||||
+ (IJSVGStyle *)parseStyleString:(NSString *)string
|
||||
{
|
||||
static NSRegularExpression * _reg = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
IJSVGStyle * style = [[[self class] alloc] init];
|
||||
dispatch_once(&onceToken, ^{
|
||||
_reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z\\-]+)\\:([^;]+)\\;?"
|
||||
options:0
|
||||
error:nil];
|
||||
});
|
||||
[_reg enumerateMatchesInString:string
|
||||
options:0
|
||||
range:NSMakeRange( 0, string.length )
|
||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
NSString * key = [string substringWithRange:[result rangeAtIndex:1]];
|
||||
NSString * value = [string substringWithRange:[result rangeAtIndex:2]];
|
||||
[[self class] computeStyleProperty:key
|
||||
value:value
|
||||
style:style];
|
||||
}];
|
||||
return [style autorelease];
|
||||
IJSVGStyle * style = [[[self.class alloc] init] autorelease];
|
||||
NSInteger length = string.length;
|
||||
NSInteger index = 0;
|
||||
NSString * key = nil;
|
||||
NSString * value = nil;
|
||||
|
||||
// iterate over the string - its actually really simple what we need
|
||||
// to do
|
||||
for(NSInteger i = 0; i < length; i++) {
|
||||
unichar c = [string characterAtIndex:i];
|
||||
|
||||
// find the key
|
||||
if(c == ':') {
|
||||
key = [string substringWithRange:NSMakeRange(index, (i-index))];
|
||||
index = i+1;
|
||||
}
|
||||
|
||||
// find the value
|
||||
else if(c == ';' || i == (length-1)) {
|
||||
NSInteger chomp;
|
||||
if(i == (length-1) && c != ';') {
|
||||
chomp = (i-(index-1));
|
||||
} else {
|
||||
chomp = (i-index);
|
||||
}
|
||||
value = [string substringWithRange:NSMakeRange(index, chomp)];
|
||||
index = i+1;
|
||||
}
|
||||
|
||||
// set the propery if it actually exists
|
||||
if(key != nil && value != nil) {
|
||||
[style setPropertyValue:[self.class trimString:value]
|
||||
forProperty:[self.class trimString:key]];
|
||||
key = nil;
|
||||
value = nil;
|
||||
}
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
+ (NSString *)trimString:(NSString *)string
|
||||
@@ -75,22 +94,6 @@
|
||||
return @[@"fill",@"stroke-colour",@"stop-color",@"stroke"];
|
||||
}
|
||||
|
||||
+ (void)computeStyleProperty:(NSString *)key
|
||||
value:(NSString *)value
|
||||
style:(IJSVGStyle *)style
|
||||
{
|
||||
key = [[self class] trimString:key];
|
||||
value = [[self class] trimString:value];
|
||||
[style setPropertyValue:value
|
||||
forProperty:key];
|
||||
|
||||
}
|
||||
|
||||
+ (BOOL)isNumeric:(NSString *)string
|
||||
{
|
||||
return [[NSScanner scannerWithString:string] scanFloat:NULL];
|
||||
}
|
||||
|
||||
- (void)setProperties:(NSDictionary *)properties
|
||||
replaceAll:(BOOL)flag
|
||||
{
|
||||
|
||||
@@ -71,12 +71,16 @@
|
||||
// create a new selector if not found
|
||||
if((selector = [_selectors objectForKey:selectorName]) == nil) {
|
||||
selector = [[[IJSVGStyleSheetSelector alloc] initWithSelectorString:selectorName] autorelease];
|
||||
[_selectors setObject:selector
|
||||
forKey:selectorName];
|
||||
if(selector != nil) {
|
||||
[_selectors setObject:selector
|
||||
forKey:selectorName];
|
||||
}
|
||||
}
|
||||
|
||||
// add it to our list
|
||||
[array addObject:selector];
|
||||
if(selector != nil) {
|
||||
[array addObject:selector];
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@@ -257,7 +257,12 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
|
||||
{
|
||||
selector = [string copy];
|
||||
_rawSelectors = [[NSMutableArray alloc] init];
|
||||
[self _compile];
|
||||
|
||||
// failed to compile
|
||||
if([self _compile] == NO) {
|
||||
[self release], self = nil;
|
||||
return nil;
|
||||
}
|
||||
[self _calculate];
|
||||
}
|
||||
return self;
|
||||
@@ -283,23 +288,55 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_compile
|
||||
- (BOOL)validateSelector:(NSString *)string
|
||||
{
|
||||
char * invalidChars = "@:;*()[]";
|
||||
NSUInteger length = strlen(invalidChars);
|
||||
NSUInteger sLength = string.length;
|
||||
for(NSUInteger i = 0; i < length; i++) {
|
||||
for(NSUInteger s = 0; s < sLength; s++) {
|
||||
// if found invalid char, just return NO instantly
|
||||
if(invalidChars[i] == [string characterAtIndex:s]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_compile
|
||||
{
|
||||
|
||||
// completely unsupported
|
||||
if([self validateSelector:selector] == NO) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// keychar lookup
|
||||
char * keychars = "#+.>~ ";
|
||||
NSUInteger aLength = strlen(keychars);
|
||||
BOOL (^isKeyChar)(char anotherChar) = ^(char anotherChar) {
|
||||
for(NSInteger i = 0; i < aLength; i++) {
|
||||
if(keychars[i] == anotherChar) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
};
|
||||
|
||||
|
||||
NSUInteger length = selector.length;
|
||||
NSMutableArray * sels = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSCharacterSet * alphaNumeric = [NSCharacterSet characterSetWithCharactersInString:@"_-abcdefghijklmnopqrstuvwxyz0123456789"];
|
||||
IJSVGStyleSheetSelectorRaw * rawSelector = [[[IJSVGStyleSheetSelectorRaw alloc] init] autorelease];
|
||||
|
||||
for(NSUInteger i = 0; i < length; i++)
|
||||
{
|
||||
for(NSUInteger i = 0; i < length; i++) {
|
||||
unichar c = [selector characterAtIndex:i];
|
||||
|
||||
// beginning of class
|
||||
if( c == '.' ) {
|
||||
i++;
|
||||
for(NSUInteger a = i; a < length; a++ ) {
|
||||
unichar ca = [selector characterAtIndex:a];
|
||||
if([alphaNumeric characterIsMember:ca] == NO || a == length-1) {
|
||||
if(isKeyChar(ca) == YES || a == length-1) {
|
||||
// if at end, add 1 to a so it gets the last character
|
||||
if( a == length-1 ) {
|
||||
a++;
|
||||
@@ -316,7 +353,7 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
|
||||
i++;
|
||||
for(NSUInteger a = i; a < length; a++ ) {
|
||||
unichar ca = [selector characterAtIndex:a];
|
||||
if([alphaNumeric characterIsMember:ca] == NO || a == length-1) {
|
||||
if(isKeyChar(ca) == YES || a == length-1) {
|
||||
// if at end, add 1 to a so it gets the last character
|
||||
if( a == length-1 ) {
|
||||
a++;
|
||||
@@ -375,7 +412,7 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
|
||||
else {
|
||||
for( NSUInteger a = i; a < length; a++ ) {
|
||||
unichar ca = [selector characterAtIndex:a];
|
||||
if([alphaNumeric characterIsMember:ca] == NO || a == length-1) {
|
||||
if(isKeyChar(ca) == YES || a == length-1) {
|
||||
if( a == length-1 ) {
|
||||
a++;
|
||||
}
|
||||
@@ -397,6 +434,7 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
|
||||
}
|
||||
// now its compiled, we need to reverse the selectors
|
||||
[_rawSelectors addObjectsFromArray:[sels reverseObjectEnumerator].allObjects];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,13 +9,24 @@
|
||||
#import "IJSVGTransaction.h"
|
||||
|
||||
void IJSVGBeginTransactionLock() {
|
||||
if(NSThread.isMainThread == YES) {
|
||||
return;
|
||||
}
|
||||
[CATransaction begin];
|
||||
[CATransaction lock];
|
||||
if(@available(macOS 10.14, *)) {} else {
|
||||
[CATransaction lock];
|
||||
}
|
||||
[CATransaction setDisableActions:YES];
|
||||
};
|
||||
|
||||
void IJSVGEndTransactionLock() {
|
||||
[CATransaction unlock];
|
||||
if(NSThread.isMainThread == YES) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(@available(macOS 10.14, *)) {} else {
|
||||
[CATransaction unlock];
|
||||
}
|
||||
[CATransaction commit];
|
||||
};
|
||||
|
||||
|
||||
@@ -9,11 +9,16 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@class IJSVGTransform;
|
||||
|
||||
typedef CGFloat (^IJSVGTransformParameterModifier)(NSInteger index, CGFloat value);
|
||||
typedef void (^IJSVGTransformApplyBlock)(IJSVGTransform * transform);
|
||||
|
||||
typedef NS_OPTIONS( NSInteger, IJSVGTransformCommand ) {
|
||||
IJSVGTransformCommandMatrix,
|
||||
IJSVGTransformCommandTranslate,
|
||||
IJSVGTransformCommandTranslateX,
|
||||
IJSVGTransformCommandTranslateY,
|
||||
IJSVGTransformCommandScale,
|
||||
IJSVGTransformCommandRotate,
|
||||
IJSVGTransformCommandSkewX,
|
||||
@@ -35,12 +40,21 @@ typedef NS_OPTIONS( NSInteger, IJSVGTransformCommand ) {
|
||||
@property ( nonatomic, assign ) NSInteger parameterCount;
|
||||
@property ( nonatomic, assign ) NSInteger sort;
|
||||
|
||||
NSString * IJSVGDebugAffineTransform(CGAffineTransform transform);
|
||||
NSString * IJSVGDebugTransforms(NSArray<IJSVGTransform *> * transforms);
|
||||
void IJSVGApplyTransform(NSArray<IJSVGTransform *> * transforms, IJSVGTransformApplyBlock block);
|
||||
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform *> * transforms);
|
||||
|
||||
+ (NSArray<IJSVGTransform *> *)transformsFromAffineTransform:(CGAffineTransform)affineTransform;
|
||||
+ (NSArray *)transformsForString:(NSString *)string;
|
||||
+ (NSBezierPath *)transformedPath:(IJSVGPath *)path;
|
||||
+ (NSArray<NSString *> *)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform;
|
||||
+ (NSString *)affineTransformToSVGMatrixString:(CGAffineTransform)affineTransform;
|
||||
- (CGAffineTransform)CGAffineTransform;
|
||||
- (CGAffineTransform)CGAffineTransformWithModifier:(IJSVGTransformParameterModifier)modifier;
|
||||
- (CGAffineTransform)stackIdentity:(CGAffineTransform)identity;
|
||||
- (void)recalculateWithBounds:(CGRect)bounds;
|
||||
+ (IJSVGTransform *)transformByTranslatingX:(CGFloat)x
|
||||
y:(CGFloat)y;
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
IJSVGTransform * trans = [[[self class] alloc] init];
|
||||
IJSVGTransform * trans = [[self.class alloc] init];
|
||||
trans.command = self.command;
|
||||
trans.parameters = (CGFloat*)malloc(sizeof(CGFloat)*self.parameterCount);
|
||||
trans.sort = sort;
|
||||
@@ -33,6 +33,51 @@
|
||||
return trans;
|
||||
}
|
||||
|
||||
NSString * IJSVGDebugAffineTransform(CGAffineTransform transform)
|
||||
{
|
||||
NSMutableArray * strings = [[[NSMutableArray alloc] init] autorelease];
|
||||
[strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform]];
|
||||
return [strings componentsJoinedByString:@" "];
|
||||
}
|
||||
|
||||
NSString * IJSVGDebugTransforms(NSArray<IJSVGTransform *> * transforms)
|
||||
{
|
||||
NSMutableArray * strings = [[[NSMutableArray alloc] init] autorelease];
|
||||
IJSVGApplyTransform(transforms, ^(IJSVGTransform *transform) {
|
||||
[strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform.CGAffineTransform]];
|
||||
});
|
||||
return [strings componentsJoinedByString:@" "];
|
||||
}
|
||||
|
||||
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform *> * transforms)
|
||||
{
|
||||
__block CGAffineTransform trans = CGAffineTransformIdentity;
|
||||
IJSVGApplyTransform(transforms, ^(IJSVGTransform *transform) {
|
||||
trans = CGAffineTransformConcat(trans, transform.CGAffineTransform);
|
||||
});
|
||||
return trans;
|
||||
}
|
||||
|
||||
void IJSVGApplyTransform(NSArray<IJSVGTransform *> * transforms, IJSVGTransformApplyBlock block)
|
||||
{
|
||||
for(IJSVGTransform * transform in transforms) {
|
||||
block(transform);
|
||||
}
|
||||
};
|
||||
|
||||
+ (IJSVGTransform *)transformByTranslatingX:(CGFloat)x
|
||||
y:(CGFloat)y
|
||||
{
|
||||
IJSVGTransform * transform = [[[self alloc] init] autorelease];
|
||||
transform.command = IJSVGTransformCommandTranslate;
|
||||
transform.parameterCount = 2;
|
||||
CGFloat * params = (CGFloat *)malloc(sizeof(CGFloat)*2);
|
||||
params[0] = x;
|
||||
params[1] = y;
|
||||
transform.parameters = params;
|
||||
return transform;
|
||||
}
|
||||
|
||||
- (void)recalculateWithBounds:(CGRect)bounds
|
||||
{
|
||||
CGFloat max = bounds.size.width>bounds.size.height?bounds.size.width:bounds.size.height;
|
||||
@@ -55,6 +100,10 @@
|
||||
return IJSVGTransformCommandMatrix;
|
||||
if( [str isEqualToString:@"translate"] )
|
||||
return IJSVGTransformCommandTranslate;
|
||||
if([str isEqualToString:@"translatex"])
|
||||
return IJSVGTransformCommandTranslateX;
|
||||
if([str isEqualToString:@"translatey"])
|
||||
return IJSVGTransformCommandTranslateY;
|
||||
if( [str isEqualToString:@"scale"] )
|
||||
return IJSVGTransformCommandScale;
|
||||
if( [str isEqualToString:@"skewx"])
|
||||
@@ -75,6 +124,8 @@
|
||||
return 1;
|
||||
case IJSVGTransformCommandMatrix:
|
||||
return 2;
|
||||
case IJSVGTransformCommandTranslateX:
|
||||
case IJSVGTransformCommandTranslateY:
|
||||
case IJSVGTransformCommandTranslate:
|
||||
return -1;
|
||||
default:
|
||||
@@ -88,7 +139,7 @@
|
||||
static NSRegularExpression * _reg = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z]+)\\((.*?)\\)"
|
||||
_reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z]+)\\(([^\\)]+)\\)"
|
||||
options:0
|
||||
error:nil];
|
||||
});
|
||||
@@ -97,22 +148,23 @@
|
||||
[_reg enumerateMatchesInString:string
|
||||
options:0
|
||||
range:NSMakeRange( 0, string.length )
|
||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
|
||||
{
|
||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
NSString * command = [string substringWithRange:[result rangeAtIndex:1]];
|
||||
IJSVGTransformCommand commandType = [[self class] commandForCommandString:command];
|
||||
if( commandType == IJSVGTransformCommandNotImplemented )
|
||||
IJSVGTransformCommand commandType = [self.class commandForCommandString:command];
|
||||
if( commandType == IJSVGTransformCommandNotImplemented ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// create the transform
|
||||
NSString * params = [string substringWithRange:[result rangeAtIndex:2]];
|
||||
IJSVGTransform * transform = [[[[self class] alloc] init] autorelease];
|
||||
IJSVGTransform * transform = [[[self.class alloc] init] autorelease];
|
||||
NSInteger count = 0;
|
||||
transform.command = commandType;
|
||||
transform.parameters = [IJSVGUtils commandParameters:params
|
||||
count:&count];
|
||||
transform.parameterCount = count;
|
||||
transform.sort = [[self class] sortForTransformCommand:commandType];
|
||||
transform.sort = [self.class sortForTransformCommand:commandType];
|
||||
[transforms addObject:transform];
|
||||
}];
|
||||
}
|
||||
@@ -182,6 +234,18 @@
|
||||
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: {
|
||||
@@ -237,6 +301,16 @@
|
||||
}
|
||||
return CGAffineTransformTranslate(identity, self.parameters[0], self.parameters[1]);
|
||||
}
|
||||
|
||||
// translateX
|
||||
case IJSVGTransformCommandTranslateX: {
|
||||
return CGAffineTransformTranslate(identity, self.parameters[0], 0.f);
|
||||
}
|
||||
|
||||
// translateY
|
||||
case IJSVGTransformCommandTranslateY: {
|
||||
return CGAffineTransformTranslate(identity, 0.f, self.parameters[0]);
|
||||
}
|
||||
|
||||
// rotate
|
||||
case IJSVGTransformCommandRotate: {
|
||||
@@ -313,9 +387,9 @@
|
||||
p0 = modifier(0,p0);
|
||||
p1 = modifier(1,p1);
|
||||
p2 = modifier(2,p2);
|
||||
p3 = modifier(2,p3);
|
||||
p4 = modifier(2,p4);
|
||||
p5 = modifier(2,p5);
|
||||
p3 = modifier(3,p3);
|
||||
p4 = modifier(4,p4);
|
||||
p5 = modifier(5,p5);
|
||||
}
|
||||
return CGAffineTransformMake(p0, p1, p2, p3, p4, p5);
|
||||
}
|
||||
@@ -334,6 +408,24 @@
|
||||
return CGAffineTransformMakeTranslation(p0, p1);
|
||||
}
|
||||
|
||||
// translateX
|
||||
case IJSVGTransformCommandTranslateX: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
if(modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
}
|
||||
return CGAffineTransformMakeTranslation(p0, 0.f);
|
||||
}
|
||||
|
||||
// translateY
|
||||
case IJSVGTransformCommandTranslateY: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
if(modifier != nil) {
|
||||
p0 = modifier(0, p0);
|
||||
}
|
||||
return CGAffineTransformMakeTranslation(0.f, p0);
|
||||
}
|
||||
|
||||
// scale
|
||||
case IJSVGTransformCommandScale: {
|
||||
CGFloat p0 = self.parameters[0];
|
||||
@@ -400,6 +492,19 @@
|
||||
return CGAffineTransformIdentity;
|
||||
}
|
||||
|
||||
+ (NSArray<IJSVGTransform *> *)transformsFromAffineTransform:(CGAffineTransform)affineTransform
|
||||
{
|
||||
NSArray * strings = [self affineTransformToSVGTransformAttributeString:affineTransform];
|
||||
return [self transformsForString:[strings componentsJoinedByString:@" "]];
|
||||
}
|
||||
|
||||
+ (NSString *)affineTransformToSVGMatrixString:(CGAffineTransform)transform
|
||||
{
|
||||
return [NSString stringWithFormat:@"matrix(%g,%g,%g,%g,%g,%g)",
|
||||
transform.a, transform.b, transform.c, transform.d,
|
||||
transform.tx, transform.ty];
|
||||
}
|
||||
|
||||
// this is an Object-C version of the matrixToTransform method from SVGO
|
||||
+ (NSArray<NSString *> *)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform
|
||||
{
|
||||
@@ -414,6 +519,7 @@
|
||||
|
||||
CGFloat sx = sqrtf(data[0]*data[0] + data[1] * data[1]);
|
||||
CGFloat sy = (data[0]*data[3] - data[1]*data[2])/sx;
|
||||
|
||||
CGFloat colSum = data[0]*data[2] + data[1]*data[3];
|
||||
CGFloat rowSum = data[0]*data[1] + data[2]*data[3];
|
||||
BOOL scaleBefore = rowSum != 0.f || (sx == sy);
|
||||
@@ -439,8 +545,8 @@
|
||||
sy = data[3];
|
||||
} else if(colSum == 0.f || (sx == 1.f && sy == 1.f) || scaleBefore == NO) {
|
||||
if(scaleBefore == NO) {
|
||||
sx = (data[0] < 0.f ? -1.f : 1.f * sqrtf(data[0] * data[0] + data[2] * data[2]));
|
||||
sy = (data[3] < 0.f ? -1.f : 1.f * sqrtf(data[1] * data[1] + data[3] * data[3]));
|
||||
sx = (data[0] < 0.f ? -1.f : 1.f) * sqrtf(data[0] * data[0] + data[2] * data[2]);
|
||||
sy = (data[3] < 0.f ? -1.f : 1.f) * sqrtf(data[1] * data[1] + data[3] * data[3]);
|
||||
NSString * str = nil;
|
||||
if(sx == sy) {
|
||||
str = [NSString stringWithFormat:@"scale(%g)",sx];
|
||||
@@ -499,5 +605,11 @@
|
||||
return trans;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ %@",[super description],
|
||||
[self.class affineTransformToSVGTransformAttributeString:self.CGAffineTransform]];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||