Compare commits

...

50 Commits

Author SHA1 Message Date
Curtis Hard ffb55b0f31 Fixes viewBox origin translate 2018-03-02 13:28:40 +00:00
Curtis Hard a4c032afa2 Added clip to viewport 2018-02-28 21:29:11 +00:00
Curtis Hard abe8f4cba5 Fixes drawInRect not obeying origin 2018-02-28 21:00:20 +00:00
Curtis Hard a16842271b Resolves namespaces correctly + added common HTML list to be parsed as groups 2018-02-26 13:46:41 +00:00
Curtis Hard 58126e06e4 Fixes! 2018-02-25 21:58:49 +00:00
Curtis Hard 5af5e054ab Fixed defNode being removed 2018-02-23 22:37:53 +00:00
Curtis Hard edd3aa1f33 excluded various elements from diff 2018-02-23 16:29:54 +00:00
Curtis Hard 3366bc4fa5 Better optimaztion 2018-02-23 14:05:03 +00:00
Curtis Hard 104002183b Added rudimenatry inline styles -> stylesheet 2018-02-22 22:17:50 +00:00
Curtis Hard 7010b7ea50 Correct order of cleanup 2018-02-22 13:33:32 +00:00
Curtis Hard 5266a8c07a corrent length of string 2018-02-22 08:22:17 +00:00
Curtis Hard caf55e8bdf removes useless def if required 2018-02-21 20:45:17 +00:00
Curtis Hard 8160d05eba Refactor of a few methods 2018-02-20 14:12:02 +00:00
Curtis Hard a6d6a06521 Added collpasing of gradients 2018-02-20 09:40:21 +00:00
Curtis Hard 103a4d71f6 Reduced floats even more 2018-02-19 19:07:30 +00:00
Curtis Hard 98874b1d2c More compression goodness 2018-02-19 18:53:02 +00:00
Curtis Hard e742db31e0 Added intermediateParent 2018-02-19 14:02:15 +00:00
Curtis Hard 198fd09f07 Fixes! and performance increases 2018-02-19 11:51:37 +00:00
Curtis Hard 3493194b1b Scale computation 2018-02-19 08:20:02 +00:00
Curtis Hard 0016775eaf More goodness 2018-02-18 22:33:26 +00:00
Curtis Hard 304a04cc22 Vastly improved the exporter 2018-02-18 22:32:04 +00:00
Curtis Hard e4fd0af582 This is insanely important! 2018-02-18 15:20:28 +00:00
Curtis Hard 69a2a0c97e Refactor 2018-02-04 22:02:19 +00:00
Curtis Hard 5299bb0479 will continue to use CoreAnimation for the time being 2018-02-04 21:58:21 +00:00
Curtis Hard 4f1943cad1 Fixes gradient strokes 2018-02-04 21:57:46 +00:00
Curtis Hard f02d186293 trying to get masks to work 2018-02-04 11:15:04 +00:00
Curtis Hard 3291718cfb Beginning of quartz renderer 2018-02-02 22:35:22 +00:00
Curtis Hard 6fbaaf5884 Removed useless log 2018-01-29 22:32:08 +00:00
Curtis Hard abc65797ea I think gradients work :D 2018-01-29 21:37:45 +00:00
Curtis Hard af5a1c2718 Possible fx and fy things… 2018-01-28 22:18:02 +00:00
Curtis Hard fb9a5282b9 Even more gradient fixes 2018-01-28 19:22:40 +00:00
Curtis Hard d83933a103 Various improvements 2018-01-28 14:21:50 +00:00
Curtis Hard bd7a0d5021 Start to linear 2018-01-27 22:26:33 +00:00
Curtis Hard a9a038568c This kind of actually works... 2018-01-27 21:14:25 +00:00
Curtis Hard 77fbb38b6f I guess this could be a good start?
Posssible start of fixes?
2018-01-27 20:32:13 +00:00
Curtis Hard 12c3191569 Added method for findind absolute position 2018-01-27 15:32:15 +00:00
Curtis Hard e3e9626ef7 Fixes crash due to parentNode on temp groups being released 2018-01-27 14:25:03 +00:00
Curtis Hard 1160d89f16 Fixes use statements with transforms 2018-01-26 22:29:22 +00:00
Curtis Hard 1575cbfde8 Moved color tree over to modern syntax 2018-01-26 18:16:03 +00:00
Curtis Hard 5c4c2eee91 Added HSL/HSLA support 2018-01-25 18:23:53 +00:00
Curtis Hard 087b13e58f Various image loading issues resolved from base64 images 2018-01-24 22:24:43 +00:00
Curtis Hard 1183e167aa Rect issue fix 2018-01-24 21:21:41 +00:00
Curtis Hard 4dbfc59437 Moved transforms over from being concatinated to seperate calls 2018-01-24 21:19:24 +00:00
Curtis Hard 409bd509fa Fixes color issue 2018-01-24 20:30:38 +00:00
Curtis Hard 8ae1d1b4e0 Removed check as its not needed here 2018-01-24 18:41:08 +00:00
Curtis Hard 7243fbe5ff Added excludeAttributes list to parseCommonAttributes
added x and y to that list for rect
2018-01-24 18:35:43 +00:00
Curtis Hard 51b9a5e85f Added isSubcommand to IJSVGCommand
- Fixes move command going awol when preceding move commands are not subcommands (woah)
2018-01-23 19:53:04 +00:00
Curtis Hard 40098589de removed reverseObjectEnumerator
IJSVGTransform already deals with this at parse stage (was a test from earlier), spec states transforms are applied in reverse order (which parser already dealth with :-))
2018-01-22 22:04:48 +00:00
Curtis Hard 7cb96b21f2 Removed use of origin here as its computed in apply defaults 2018-01-22 22:01:56 +00:00
Curtis Hard 1bff7c6970 Various fixes… still going… 2018-01-22 21:48:59 +00:00
53 changed files with 24225 additions and 912 deletions
@@ -8,6 +8,12 @@
/* Begin PBXBuildFile section */
343A19181FB2212C000652A2 /* IJSVGGradientUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */; };
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 */; };
@@ -33,6 +39,8 @@
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 */; };
@@ -43,6 +51,8 @@
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 */; };
59D1E39E2022577500C54672 /* IJSVGQuartzRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59D1E39D2022577500C54672 /* IJSVGQuartzRenderer.m */; };
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 */; };
@@ -93,6 +103,12 @@
/* 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>"; };
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>"; };
@@ -139,6 +155,8 @@
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>"; };
@@ -157,6 +175,9 @@
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>"; };
59D1E39C2022577500C54672 /* IJSVGQuartzRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGQuartzRenderer.h; sourceTree = "<group>"; };
59D1E39D2022577500C54672 /* IJSVGQuartzRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGQuartzRenderer.m; 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>"; };
@@ -294,6 +315,15 @@
5956657A19B62F4600D805FF /* Supporting Files */ = {
isa = PBXGroup;
children = (
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 */,
@@ -439,6 +469,8 @@
597046A11E24352700A60138 /* IJSVGStrokeLayer.m */,
59E0F5EB1E29964700F757F7 /* IJSVGUnitLength.h */,
59E0F5EC1E29964700F757F7 /* IJSVGUnitLength.m */,
59D1E39C2022577500C54672 /* IJSVGQuartzRenderer.h */,
59D1E39D2022577500C54672 /* IJSVGQuartzRenderer.m */,
);
name = source;
path = ../../source;
@@ -488,7 +520,7 @@
5956656F19B62F4600D805FF /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = "Curtis Hard";
TargetAttributes = {
5956657619B62F4600D805FF = {
@@ -526,13 +558,22 @@
files = (
59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */,
5956658219B62F4600D805FF /* Images.xcassets in Resources */,
590C87ED201FA08C004A1554 /* intertwingly.svg in Resources */,
590C87F1201FBF27004A1554 /* AJ_Digital_Camera.svg in Resources */,
590C87EF201FA093004A1554 /* NewTux.svg in Resources */,
59265CE81C4F840400F333F0 /* css.svg in Resources */,
595665DE19B6309C00D805FF /* test.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 */,
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;
@@ -555,6 +596,7 @@
59E2646919BA240D008A6FDB /* IJSVGStyle.m in Sources */,
59E2646419BA240D008A6FDB /* IJSVGLinearGradient.m in Sources */,
595665DC19B6302600D805FF /* README.md in Sources */,
59D1E39E2022577500C54672 /* IJSVGQuartzRenderer.m in Sources */,
5941DAFD1CF9BC9B00B3A911 /* IJSVGImage.m in Sources */,
599465DE1C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m in Sources */,
5948DED61BB2BFE5004156FF /* IJSVGWriter.m in Sources */,
@@ -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"
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 515 KiB

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -671,19 +671,41 @@
<window title="IJSVGExample" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" 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="contentRect" x="335" y="390" width="600" height="479"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="556" height="679"/>
<view key="contentView" misplaced="YES" id="EiT-Mj-1SZ">
<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"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="frame" x="0.0" y="0.0" width="600" height="385"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
</customView>
<button verticalHuggingPriority="750" misplaced="YES" id="gpW-KV-dZb">
<rect key="frame" x="14" y="431" width="205" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Render with CoreAnimation" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="b5N-FF-ykt">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="switchToCoreAnimation:" target="hhC-1S-CCX" id="318-qP-1z4"/>
</connections>
</button>
<button verticalHuggingPriority="750" misplaced="YES" id="68n-xB-I0F">
<rect key="frame" x="14" y="398" width="205" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Render with CoreGraphics" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Tcq-b5-8Y0">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="switchToCoreGraphics:" target="hhC-1S-CCX" id="gzP-YM-P2p"/>
</connections>
</button>
</subviews>
</view>
<point key="canvasLocation" x="184" y="628"/>
<point key="canvasLocation" x="98" y="496.5"/>
</window>
</objects>
</document>
+13
View File
@@ -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

+72
View File
@@ -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

+1 -1
View File
@@ -12,7 +12,7 @@
- (IJSVG *)svg
{
return [[IJSVG svgNamed:@"paperplane"] retain];
return [[IJSVG svgNamed:@"heart"] retain];
}
@end
+2 -1
View File
@@ -15,6 +15,7 @@
}
- (IBAction)switchToCoreGraphics:(id)sender;
- (IBAction)switchToCoreAnimation:(id)sender;
@end
+13 -1
View File
@@ -29,9 +29,21 @@
return self;
}
- (void)switchToCoreGraphics:(id)sender
{
svg.renderingEngine = IJSVGRenderingEngineQuartz;
[self setNeedsDisplay:YES];
}
- (void)switchToCoreAnimation:(id)sender
{
svg.renderingEngine = IJSVGRenderingEngineLayered;
[self setNeedsDisplay:YES];
}
- (IJSVG *)svg
{
return [IJSVG svgNamed:@"test"];
return [IJSVG svgNamed:@"clipped"];
}
- (void)drawRect:(NSRect)dirtyRect
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 515 KiB

+20
View File
@@ -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

+30
View File
@@ -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,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

+5
View File
@@ -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,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

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 522 KiB

+10
View File
@@ -13,6 +13,7 @@
#import "IJSVGGroupLayer.h"
#import "IJSVGImageLayer.h"
#import "IJSVGExporter.h"
#import "IJSVGQuartzRenderer.h"
@class IJSVG;
@@ -36,6 +37,11 @@ withSVGString:(NSString *)subSVGString;
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
typedef NS_ENUM(NSInteger, IJSVGRenderingEngine) {
IJSVGRenderingEngineCoreGraphics,
IJSVGRenderingEngineCoreAnimation
};
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
@private
@@ -47,7 +53,9 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
CGRect _viewBox;
CGSize _proposedViewSize;
CGFloat _lastProposedBackingScale;
CGFloat _backingScale;
NSMutableDictionary * _replacementColors;
IJSVGQuartzRenderer * _quartzRenderer;
struct {
unsigned int shouldHandleForeignObject: 1;
@@ -70,6 +78,8 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle;
@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle;
@property (nonatomic, assign) IJSVGRenderingEngine renderingEngine;
@property (nonatomic, assign) BOOL clipToViewport;
- (void)prepForDrawingInView:(NSView *)view;
- (BOOL)isFont;
+49 -17
View File
@@ -19,6 +19,8 @@
@synthesize lineCapStyle;
@synthesize lineJoinStyle;
@synthesize renderingBackingScaleHelper;
@synthesize renderingEngine;
@synthesize clipToViewport;
- (void)dealloc
{
@@ -28,6 +30,7 @@
[_group release], _group = nil;
[_layerTree release], _layerTree = nil;
[_replacementColors release], _replacementColors = nil;
[_quartzRenderer release], _quartzRenderer = nil;
[super dealloc];
}
@@ -333,7 +336,14 @@
- (void)_setupBasicsFromAnyInitializer
{
_lastProposedBackingScale = 1.f;
renderingEngine = IJSVGRenderingEngineCoreAnimation;
self.clipToViewport = YES;
// setup low level backing scale
_lastProposedBackingScale = 0.f;
self.renderingBackingScaleHelper = ^CGFloat{
return 1.f;
};
}
- (NSString *)identifier
@@ -557,6 +567,7 @@
- (CGFloat)computeBackingScale:(CGFloat)actualScale
{
_backingScale = actualScale;
return (CGFloat)(_scale + actualScale);
}
@@ -566,8 +577,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;
@@ -607,17 +618,11 @@
@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( error != NULL ) {
@@ -630,12 +635,17 @@
}
// clip to mask
CGContextClipToRect( ref, viewPort);
if(self.clipToViewport == YES) {
CGContextClipToRect( ref, viewPort);
}
tX -= (_viewBox.origin.x*_scale);
tY -= (_viewBox.origin.y*_scale);
// add the origin back onto the viewport
viewPort.origin.x -= round((_viewBox.origin.x)*_scale);
viewPort.origin.y -= round((_viewBox.origin.y)*_scale);
viewPort = CGRectIntegral(viewPort);
CGContextTranslateCTM( ref, tX, tY );
// transforms
CGContextTranslateCTM( ref, viewPort.origin.x, viewPort.origin.y);
CGContextScaleCTM( ref, _scale, _scale );
// render the layer, its really important we lock
@@ -648,7 +658,27 @@
}
// render the layers
[self.layer renderInContext:ref];
switch(self.renderingEngine) {
// CoreGraphics / Quartz
case IJSVGRenderingEngineCoreGraphics: {
if(_quartzRenderer == nil) {
// init the renderer if its not already defined
_quartzRenderer = [[IJSVGQuartzRenderer alloc] init];
}
_quartzRenderer.scale = _scale;
_quartzRenderer.backingScale = _backingScale;
_quartzRenderer.viewPort = viewPort;
// render it
[_quartzRenderer renderLayer:self.layer
inContext:ref];
break;
}
// CALayer tree
case IJSVGRenderingEngineCoreAnimation: {
[self.layer renderInContext:ref];
}
}
IJSVGEndTransactionLock();
}
@catch (NSException *exception) {
@@ -681,8 +711,9 @@
// walk the tree
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
if(((IJSVGLayer *)layer).requiresBackingScaleHelp == YES) {
((IJSVGLayer *)layer).backingScaleFactor = scale;
IJSVGLayer * propLayer = ((IJSVGLayer *)layer);
if(propLayer.requiresBackingScaleHelp == YES) {
propLayer.backingScaleFactor = scale;
}
};
@@ -738,6 +769,7 @@
// force rebuild of the tree
IJSVGBeginTransactionLock();
_layerTree = [[tree layerForNode:_group] retain];
IJSVGEndTransactionLock();
return _layerTree;
}
+4 -1
View File
@@ -160,11 +160,14 @@ 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;
forceHex:(BOOL)forceHex
allowShorthand:(BOOL)allowShorthand;
+ (NSString *)colorStringFromColor:(NSColor *)color;
+ (NSColor *)computeColor:(id)colour;
+ (NSColor *)colorFromString:(NSString *)string;
+211 -158
View File
@@ -11,8 +11,27 @@
@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
{
@@ -37,157 +56,156 @@ static NSMutableDictionary * _colorTree = nil;
{
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:@"000000" forKey:@"currentcolor"];
[_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":@"f0f8ff",
@"antiquewhite":@"faebd7",
@"aqua":@"00ffff",
@"aquamarine":@"7fffd4",
@"azure":@"f0ffff",
@"beige":@"f5f5dc",
@"bisque":@"ffe4c4",
@"black":@"000000",
@"blanchedalmond":@"ffebcd",
@"blue":@"0000ff",
@"blueviolet":@"8a2be2",
@"brown":@"a52a2a",
@"burlywood":@"deb887",
@"cadetblue":@"5f9ea0",
@"chartreuse":@"7fff00",
@"chocolate":@"d2691e",
@"coral":@"ff7f50",
@"cornflowerblue":@"6495ed",
@"cornsilk":@"fff8dc",
@"crimson":@"dc143c",
@"currentcolor":@"000000",
@"cyan":@"00ffff",
@"darkblue":@"00008b",
@"darkcyan":@"008b8b",
@"darkgoldenrod":@"b8860b",
@"darkgray":@"a9a9a9",
@"darkgreen":@"006400",
@"darkgrey":@"a9a9a9",
@"darkkhaki":@"bdb76b",
@"darkmagenta":@"8b008b",
@"darkolivegreen":@"556b2f",
@"darkorange":@"ff8c00",
@"darkorchid":@"9932cc",
@"darkred":@"8b0000",
@"darksalmon":@"e9967a",
@"darkseagreen":@"8fbc8f",
@"darkslateblue":@"483d8b",
@"darkslategray":@"2f4f4f",
@"darkslategrey":@"2f4f4f",
@"darkturquoise":@"00ced1",
@"darkviolet":@"9400d3",
@"deeppink":@"ff1493",
@"deepskyblue":@"00bfff",
@"dimgray":@"696969",
@"dimgrey":@"696969",
@"dodgerblue":@"1e90ff",
@"firebrick":@"b22222",
@"floralwhite":@"fffaf0",
@"forestgreen":@"228b22",
@"fuchsia":@"ff00ff",
@"gainsboro":@"dcdcdc",
@"ghostwhite":@"f8f8ff",
@"gold":@"ffd700",
@"goldenrod":@"daa520",
@"gray":@"808080",
@"green":@"008000",
@"greenyellow":@"adff2f",
@"grey":@"808080",
@"honeydew":@"f0fff0",
@"hotpink":@"ff69b4",
@"indianred":@"cd5c5c",
@"indigo":@"4b0082",
@"ivory":@"fffff0",
@"khaki":@"f0e68c",
@"lavender":@"e6e6fa",
@"lavenderblush":@"fff0f5",
@"lawngreen":@"7cfc00",
@"lemonchiffon":@"fffacd",
@"lightblue":@"add8e6",
@"lightcoral":@"f08080",
@"lightcyan":@"e0ffff",
@"lightgoldenrodyellow":@"fafad2",
@"lightgray":@"d3d3d3",
@"lightgreen":@"90ee90",
@"lightgrey":@"d3d3d3",
@"lightpink":@"ffb6c1",
@"lightsalmon":@"ffa07a",
@"lightseagreen":@"20b2aa",
@"lightskyblue":@"87cefa",
@"lightslategray":@"778899",
@"lightslategrey":@"778899",
@"lightsteelblue":@"b0c4de",
@"lightyellow":@"ffffe0",
@"lime":@"00ff00",
@"limegreen":@"32cd32",
@"linen":@"faf0e6",
@"magenta":@"ff00ff",
@"maroon":@"800000",
@"mediumaquamarine":@"66cdaa",
@"mediumblue":@"0000cd",
@"mediumorchid":@"ba55d3",
@"mediumpurple":@"9370db",
@"mediumseagreen":@"3cb371",
@"mediumslateblue":@"7b68ee",
@"mediumspringgreen":@"00fa9a",
@"mediumturquoise":@"48d1cc",
@"mediumvioletred":@"c71585",
@"midnightblue":@"191970",
@"mintcream":@"f5fffa",
@"mistyrose":@"ffe4e1",
@"moccasin":@"ffe4b5",
@"navajowhite":@"ffdead",
@"navy":@"000080",
@"oldlace":@"fdf5e6",
@"olive":@"808000",
@"olivedrab":@"6b8e23",
@"orange":@"ffa500",
@"orangered":@"ff4500",
@"orchid":@"da70d6",
@"palegoldenrod":@"eee8aa",
@"palegreen":@"98fb98",
@"paleturquoise":@"afeeee",
@"palevioletred":@"db7093",
@"papayawhip":@"ffefd5",
@"peachpuff":@"ffdab9",
@"peru":@"cd853f",
@"pink":@"ffc0cb",
@"plum":@"dda0dd",
@"powderblue":@"b0e0e6",
@"purple":@"800080",
@"red":@"ff0000",
@"rosybrown":@"bc8f8f",
@"royalblue":@"4169e1",
@"saddlebrown":@"8b4513",
@"salmon":@"fa8072",
@"sandybrown":@"f4a460",
@"seagreen":@"2e8b57",
@"seashell":@"fff5ee",
@"sienna":@"a0522d",
@"silver":@"c0c0c0",
@"skyblue":@"87ceeb",
@"slateblue":@"6a5acd",
@"slategray":@"708090",
@"slategrey":@"708090",
@"snow":@"fffafa",
@"springgreen":@"00ff7f",
@"steelblue":@"4682b4",
@"tan":@"d2b48c",
@"teal":@"008080",
@"thistle":@"d8bfd8",
@"tomato":@"ff6347",
@"turquoise":@"40e0d0",
@"violet":@"ee82ee",
@"wheat":@"f5deb3",
@"white":@"ffffff",
@"whitesmoke":@"f5f5f5",
@"yellow":@"ffff00",
@"yellowgreen":@"9acd32"
} retain];
});
}
@@ -226,14 +244,37 @@ static NSMutableDictionary * _colorTree = nil;
if( count == 4 ) {
alpha = params[3];
}
color = [NSColor colorWithDeviceRed:params[0]/255
green:params[1]/255
blue:params[2]/255
color = [NSColor colorWithDeviceRed:params[0]/255.f
green:params[1]/255.f
blue:params[2]/255.f
alpha:alpha];
free(params);
return color;
}
// is it HSL?
if([[string substringToIndex:3] isEqualToString:@"hsl"]) {
NSInteger count = 0;
CGFloat * params = [IJSVGUtils commandParameters:string
count:&count];
CGFloat alpha = 1;
if(count == 4) {
alpha = params[3];
}
// convert HSL to HSB
CGFloat * hsb = IJSVGColorCSSHSLToHSB(params[0], params[1], params[2]);
color = [NSColor colorWithDeviceHue:hsb[0]
saturation:hsb[1]
brightness:hsb[2]
alpha:alpha];
// memory clean!
free(hsb);
free(params);
return color;
}
color = [[self class] colorFromHEXString:string
alpha:1.f];
return color;
@@ -252,11 +293,13 @@ static NSMutableDictionary * _colorTree = nil;
+ (NSString *)colorStringFromColor:(NSColor *)color
{
return [self colorStringFromColor:color
forceHex:NO];
forceHex:NO
allowShorthand:YES];
}
+ (NSString *)colorStringFromColor:(NSColor *)color
forceHex:(BOOL)forceHex
allowShorthand:(BOOL)allowShorthand
{
// convert to RGB
color = [self computeColorSpace:color];
@@ -275,12 +318,22 @@ static NSMutableDictionary * _colorTree = nil;
if(forceHex || alpha == 100 ||
(red == 0 && green == 0 && blue == 0 && alpha == 0) ||
(red == 255 && green == 255 && blue == 255 && alpha == 100)) {
// just return hex
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]) {
return [NSString stringWithFormat:@"#%c%c%c",[r characterAtIndex:0],
[g characterAtIndex:0],[b characterAtIndex:0]];
}
}
return [NSString stringWithFormat:@"#%02X%02X%02X",red,green,blue];
}
// note the %g, CSS alpha is 0 to 1, not 0 - 100, my bad!
return [NSString stringWithFormat:@"rgba(%d, %d, %d, %g)",red, green, blue,
return [NSString stringWithFormat:@"rgba(%d,%d,%d,%g)",red, green, blue,
((float)alpha/100.f)];
}
+2
View File
@@ -41,6 +41,7 @@ typedef NS_ENUM( NSInteger, IJSVGCommandType ) {
IJSVGCommand * previousCommand;
NSInteger _currentIndex;
Class<IJSVGCommandProtocol> commandClass;
BOOL isSubCommand;
}
@property ( nonatomic, copy ) NSString * commandString;
@@ -52,6 +53,7 @@ typedef NS_ENUM( NSInteger, IJSVGCommandType ) {
@property ( nonatomic, retain ) NSMutableArray * subCommands;
@property ( nonatomic, assign ) Class<IJSVGCommandProtocol> commandClass;
@property ( nonatomic, assign ) IJSVGCommand * previousCommand;
@property ( nonatomic, assign ) BOOL isSubCommand;
- (id)initWithCommandString:(NSString *)commandString;
+3 -1
View File
@@ -20,6 +20,7 @@
@synthesize requiredParameters;
@synthesize type;
@synthesize previousCommand;
@synthesize isSubCommand;
static NSMutableDictionary * _classes = nil;
@@ -71,8 +72,9 @@ static NSMutableDictionary * _classes = nil;
c.parameters = subParams;
c.type = self.type;
c.command = self.command;
c.previousCommand = [self.subCommands lastObject];
c.previousCommand = self.subCommands.lastObject;
c.commandClass = self.commandClass;
c.isSubCommand = i == 0 ? NO : YES;
// add it to our tree
[self.subCommands addObject:c];
+16 -10
View File
@@ -29,10 +29,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 +42,7 @@
sweepFlag = [currentCommand readBOOL];
arcEndPoint = [currentCommand readPoint];
if ( type == IJSVGCommandTypeRelative ) {
if (type == IJSVGCommandTypeRelative) {
arcEndPoint.x += path.currentPoint.x;
arcEndPoint.y += path.currentPoint.y;
}
@@ -82,13 +78,19 @@
}
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
@@ -98,12 +100,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
+4 -6
View File
@@ -28,17 +28,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])];
}
+2 -3
View File
@@ -28,12 +28,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];
}
+2 -4
View File
@@ -32,8 +32,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.commandClass == [self class] && currentCommand.isSubCommand == YES) {
[IJSVGCommandLineTo runWithParams:params
paramCount:count
command:currentCommand
@@ -44,8 +43,7 @@
}
// actual move to command
if( type == IJSVGCommandTypeAbsolute )
{
if( type == IJSVGCommandTypeAbsolute ) {
[[path currentSubpath] moveToPoint:NSMakePoint( params[0], params[1])];
return;
}
+6 -7
View File
@@ -26,6 +26,8 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
IJSVGExporterOptionRemoveHiddenElements = 1 << 8,
IJSVGExporterOptionScaleToSizeIfNecessary = 1 << 9,
IJSVGExporterOptionCompressOutput = 1 << 10,
IJSVGExporterOptionCollapseGradients = 1 << 11,
IJSVGExporterOptionCreateClasses = 1 << 12,
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef|
IJSVGExporterOptionRemoveUselessGroups|
IJSVGExporterOptionCreateUseForPaths|
@@ -35,7 +37,8 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
IJSVGExporterOptionCleanupPaths|
IJSVGExporterOptionRemoveHiddenElements|
IJSVGExporterOptionScaleToSizeIfNecessary|
IJSVGExporterOptionCompressOutput
IJSVGExporterOptionCompressOutput|
IJSVGExporterOptionCollapseGradients
};
@interface IJSVGExporter : NSObject {
@@ -46,13 +49,9 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
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;
+326 -217
View File
@@ -31,56 +31,69 @@
@synthesize title;
@synthesize description;
const NSArray * IJSVGShortCharacterArray()
{
static NSArray * _array;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_array = [@[@"a",@"b",@"c",@"d",@"e",@"f",@"g",@"h",@"i",@"j",@"k",@"l",
@"m",@"n",@"o",@"p",@"q",@"r",@"s",@"t",@"u",@"v",@"w",@"x",@"y",@"z",
@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L",
@"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",@"U",@"V",@"W",@"X",@"Y",@"Z"] retain];
});
return _array;
}
const NSArray * IJSVGInheritableAttributes()
{
static NSArray * _attributes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_attributes = [@[
@"clip-rule",
@"color",
@"color-interpolation",
@"color-interpolation-filters",
@"color-profile",
@"color-rendering",
@"cursor",
@"direction",
@"fill",
@"fill-opacity",
@"fill-rule",
@"font",
@"font-family",
@"font-size",
@"font-size-adjust",
@"font-stretch",
@"font-style",
@"font-variant",
@"font-weight",
@"glyph-orientation-horizontal",
@"glyph-orientation-vertical",
@"image-rendering",
@"kerning",
@"letter-spacing",
@"marker",
@"marker-end",
@"marker-mid",
@"marker-start",
@"pointer-events",
@"shape-rendering",
@"stroke",
@"stroke-dasharray",
@"stroke-dashoffset",
@"stroke-linecap",
@"stroke-linejoin",
@"stroke-miterlimit",
@"stroke-opacity",
@"stroke-width",
@"text-anchor",
@"text-rendering",
@"visibility",
@"white-space",
@"word-spacing",
@"writing-mode"] retain];
@"clip-rule",
@"color",
@"color-interpolation",
@"color-interpolation-filters",
@"color-profile",
@"color-rendering",
@"cursor",
@"direction",
@"fill",
@"fill-opacity",
@"fill-rule",
@"font",
@"font-family",
@"font-size",
@"font-size-adjust",
@"font-stretch",
@"font-style",
@"font-variant",
@"font-weight",
@"glyph-orientation-horizontal",
@"glyph-orientation-vertical",
@"image-rendering",
@"kerning",
@"letter-spacing",
@"marker",
@"marker-end",
@"marker-mid",
@"marker-start",
@"pointer-events",
@"shape-rendering",
@"stroke",
@"stroke-dasharray",
@"stroke-dashoffset",
@"stroke-linecap",
@"stroke-linejoin",
@"stroke-miterlimit",
@"stroke-opacity",
@"stroke-width",
@"text-anchor",
@"text-rendering",
@"visibility",
@"white-space",
@"word-spacing",
@"writing-mode"] retain];
});
return _attributes;
}
@@ -97,11 +110,6 @@ NSDictionary * IJSVGElementAttributeDictionary(NSXMLElement * element) {
return dict;
};
NSString * IJSVGShortFloatString(CGFloat f)
{
return [NSString stringWithFormat:@"%g",f];
};
NSString * IJSVGHashURL(NSString * key) {
return [NSString stringWithFormat:@"url(#%@)",key];
};
@@ -165,11 +173,11 @@ NSString * IJSVGHash(NSString * key) {
// sort out viewbox
NSRect viewBox = _svg.viewBox;
NSDictionary * attributes = @{
@"viewBox":[self viewBoxWithRect:viewBox],
@"version": [NSString stringWithFormat:@"%g",XML_DOC_VERSION],
@"xmlns": XML_DOC_NS,
@"xmlns:xlink": XML_DOC_NSXLINK
};
@"viewBox":[self viewBoxWithRect:viewBox],
@"version": [NSString stringWithFormat:@"%g",XML_DOC_VERSION],
@"xmlns": XML_DOC_NS,
@"xmlns:xlink": XML_DOC_NSXLINK
};
// was there a size set?
if(CGSizeEqualToSize(CGSizeZero, _size) == NO &&
@@ -219,6 +227,19 @@ NSString * IJSVGHash(NSString * key) {
return root;
}
- (NSString *)generateID
{
const NSArray * chars = IJSVGShortCharacterArray();
if(_idCount < chars.count) {
return chars[_idCount++];
}
if((_idCount % chars.count) == 0) {
_shortIdCount++;
}
return [NSString stringWithFormat:@"%@%ld",chars[(_idCount++ % chars.count)],_shortIdCount];
}
- (void)_prepare
{
// create the stand alone DOM
@@ -226,18 +247,28 @@ NSString * IJSVGHash(NSString * key) {
_dom.version = XML_DOCTYPE_VERSION;
_dom.characterEncoding = XML_DOC_CHARSET;
// add defs in
[_dom.rootElement addChild:[self defElement]];
// sort out header
// sort out stuff, so here we go...
[self _recursiveParseFromLayer:_svg.layer
intoElement:(_scaledRootNode?:_dom.rootElement)];
// this needs to be added incase it needs to be cleaned
NSXMLElement * defNode = [self defElement];
if(defNode.childCount != 0) {
[_dom.rootElement insertChild:[self defElement]
atIndex:0];
}
// cleanup
[self _cleanup];
// could had been removed during cleaning process needs to be added back in!
if(defNode.childCount != 0 && defNode.parent == nil) {
[_dom.rootElement insertChild:[self defElement]
atIndex:0];
}
// add generator
NSXMLNode * generatorNode = [[[NSXMLNode alloc] initWithKind:NSXMLCommentKind] autorelease];
generatorNode.stringValue = XML_DOC_GENERATOR;
@@ -262,11 +293,6 @@ NSString * IJSVGHash(NSString * key) {
[self _cleanDef];
}
// move any possible attributes to its parent group
if((_options & IJSVGExporterOptionMoveAttributesToGroup) != 0) {
[self _moveAttributesToGroup];
}
// collapse groups
if((_options & IJSVGExporterOptionCollapseGroups) != 0) {
[self _collapseGroups];
@@ -286,6 +312,65 @@ NSString * IJSVGHash(NSString * key) {
if((_options & IJSVGExporterOptionCollapseGroups) != 0) {
[self _compressGroups];
}
// collapse gradients?
if((_options & IJSVGExporterOptionCollapseGradients) != 0) {
[self _collapseGradients];
}
// create classes?
if((_options & IJSVGExporterOptionCreateClasses) != 0) {
[self _createClasses];
}
// move attributes to group
if((_options & IJSVGExporterOptionMoveAttributesToGroup) != 0) {
[self _moveAttributesToGroupWithElement:_dom.rootElement];
}
}
- (void)_createClasses
{
const NSArray * inhert = IJSVGInheritableAttributes();
NSArray<NSXMLElement *> * elements = [_dom nodesForXPath:@"//*"
error:nil];
NSMutableDictionary * rules = [[[NSMutableDictionary alloc] init] autorelease];
for(NSXMLElement * element in elements) {
NSDictionary * inhertEl = [self intersectableAttributes:IJSVGElementAttributeDictionary(element)
inheritableAttributes:inhert];
NSString * styles = [self styleSheetRulesFromDictionary:inhertEl];
NSString * className = nil;
if((className = [rules objectForKey:styles]) == nil) {
className = [NSString stringWithFormat:@"%@",[self generateID]];
rules[styles] = className;
}
for(NSString * attributeName in inhertEl) {
[element removeAttributeForName:attributeName];
}
IJSVGApplyAttributesToElement(@{@"class":className},element);
}
// add styles to dom
NSXMLElement * styles = [[[NSXMLElement alloc] initWithName:@"style"] autorelease];
NSXMLNode * node = [[[NSXMLNode alloc] initWithKind:NSXMLTextKind] autorelease];
NSMutableArray * classes = [[[NSMutableArray alloc] initWithCapacity:rules.count] autorelease];
for(NSString * r in rules) {
[classes addObject:[NSString stringWithFormat:@".%@%@",rules[r],r]];
}
node.stringValue = [classes componentsJoinedByString:@""];
[styles addChild:node];
[_dom.rootElement insertChild:styles atIndex:0];
}
- (NSString *)styleSheetRulesFromDictionary:(NSDictionary *)dict
{
NSMutableArray * array = [[[NSMutableArray alloc] initWithCapacity:dict.count] autorelease];
for(NSString * key in dict.allKeys) {
[array addObject:[NSString stringWithFormat:@"%@: %@;",key,dict[key]]];
}
return [NSString stringWithFormat:@"{%@}",[array componentsJoinedByString:@" "]];
}
- (void)_sortAttributesOnElement:(NSXMLElement *)element
@@ -304,85 +389,116 @@ NSString * IJSVGHash(NSString * key) {
{
// find any elements where they have a style, but the element itself
// must not be in the defs
NSArray<NSXMLElement *> * elements = [_dom nodesForXPath:@"//*[@style][not(ancestor::defs)]"
NSArray<NSXMLElement *> * elements = [_dom nodesForXPath:@"//*[@display='none']"
error:nil];
for(NSXMLElement * element in elements) {
// parse the style
NSString * styleString = [element attributeForName:@"style"].stringValue;
IJSVGStyle * style = [IJSVGStyle parseStyleString:styleString];
if([[style property:@"display"] isEqualToString:@"none"]) {
// this can be removed!
NSXMLElement * parent = (NSXMLElement *)element.parent;
[parent removeChildAtIndex:element.index];
NSXMLElement * parent = (NSXMLElement *)element.parent;
[parent removeChildAtIndex:element.index];
}
}
- (void)_collapseGradients
{
NSString * xPath = @"//defs/*[self::linearGradient or self::radialGradient]";
NSArray<NSXMLElement *> * gradients = [_dom nodesForXPath:xPath error:nil];
for(NSInteger i = 0; i < gradients.count; i++) {
if(i != 0) {
NSXMLElement * gradientA = gradients[i];
NSXMLElement * gradientB = nil;
for(NSInteger s = (i - 1); s >= 0; s--) {
gradientB = gradients[s];
if([self compareElementChildren:gradientA toElement:gradientB] == YES) {
NSString * idString = [gradientB attributeForName:@"id"].stringValue;
if(idString == nil || idString.length == 0) {
idString = [self generateID];
IJSVGApplyAttributesToElement(@{@"id":idString}, gradientB);
}
NSDictionary * atts = @{@"xlink:href":IJSVGHash(idString)};
IJSVGApplyAttributesToElement(atts, gradientA);
[gradientA setChildren:nil];
break;
}
}
}
}
}
- (void)_moveAttributesToGroup
- (BOOL)compareElementChildren:(NSXMLElement *)element
toElement:(NSXMLElement *)toElement
{
@autoreleasepool {
NSArray * childrenA = element.children;
NSArray * childrenB = toElement.children;
if(childrenA.count != childrenB.count) {
return NO;
}
for(NSInteger i = 0; i < childrenA.count; i++) {
NSXMLElement * childA = childrenA[i];
NSXMLElement * childB = childrenB[i];
if([self compareElement:childA withElement:childB] == NO) {
return NO;
}
}
return YES;
}
- (void)_moveAttributesToGroupWithElement:(NSXMLElement *)parentElement
{
const NSArray * excludedNodes = @[@"script",@"style",@"defs"];
if([excludedNodes containsObject:parentElement.name] == YES) {
return;
}
const NSArray * inheritableAttributes = IJSVGInheritableAttributes();
NSDictionary * intersection = @{};
NSMutableArray * grouped = [[[NSMutableArray alloc] init] autorelease];
NSInteger counter = 0;
NSInteger size = parentElement.childCount - 1;
for(NSXMLElement * element in parentElement.children) {
NSArray<NSXMLElement *> * groups = [_dom nodesForXPath:@"//g"
error:nil];
NSDictionary * attributes = [self intersectableAttributes:IJSVGElementAttributeDictionary(element)
inheritableAttributes:inheritableAttributes];
const NSArray * inheritableAttributes = IJSVGInheritableAttributes();
if(intersection.count == 0) {
intersection = attributes;
}
for(NSXMLElement * group in groups) {
@autoreleasepool {
NSDictionary * intersection = @{};
// does it have a mask/clip?
BOOL hasClip = [group attributeForName:@"clip-path"] != nil ||
[group attributeForName:@"mask"] != nil;
NSMutableArray * intersected = [[[NSMutableArray alloc] init] autorelease];
// loop around each child
for(NSXMLElement * child in group.children) {
if(child.attributes.count == 0) {
continue;
}
// straight add on
NSDictionary * atts = [self intersectableAttributes:IJSVGElementAttributeDictionary(child)
inheritableAttributes:inheritableAttributes];
if(intersection.count == 0) {
intersection = atts;
} else {
// work out the intersection
NSDictionary * dict = nil;
dict = [self intersectionInheritableAttributes:intersection
currentAttributes:atts
inheritableAttributes:inheritableAttributes];
// break if nothing
if(dict == nil) {
continue;
}
// add them
intersection = dict;
}
// add the child to array
[intersected addObject:child];
NSDictionary * dict = [self intersectionInheritableAttributes:intersection
currentAttributes:attributes
inheritableAttributes:inheritableAttributes];
for(NSString * attributeToRemove in dict.allKeys) {
[element removeAttributeForName:attributeToRemove];
}
if(dict != nil) {
[grouped addObject:element];
}
if(dict == nil || counter == size) {
if(grouped.count > 1) {
NSXMLElement * groupElement = [[[NSXMLElement alloc] initWithName:@"g"] autorelease];
NSXMLElement * lastElement = (NSXMLElement *)grouped.lastObject;
NSInteger index = lastElement.index;
[parentElement replaceChildAtIndex:index withNode:groupElement];
for(NSXMLElement * elementToGroup in grouped) {
[elementToGroup detach];
[groupElement addChild:elementToGroup];
}
if(intersected.count != 0 && hasClip == NO) {
for(NSXMLElement * child in intersected) {
for(NSString * attributeName in intersection.allKeys) {
// remove attribute
[child removeAttributeForName:attributeName];
// add the
NSDictionary * atts = nil;
atts = @{attributeName:intersection[attributeName]};
IJSVGApplyAttributesToElement(atts, group);
}
}
IJSVGApplyAttributesToElement(intersection, groupElement);
} else {
if(grouped.count == 1) {
NSXMLElement * onlyElement = (NSXMLElement *)grouped.lastObject;
IJSVGApplyAttributesToElement(intersection, onlyElement);
}
}
intersection = @{};
[grouped removeAllObjects];
}
counter++;
}
}
@@ -406,6 +522,10 @@ NSString * IJSVGHash(NSString * key) {
for(NSString * key in newAttributes.allKeys) {
// make sure they are the same and
// they are inheritable
if([currentAttributes objectForKey:key] == nil) {
return nil;
}
if([currentAttributes objectForKey:key] != nil &&
[inheritableAtts containsObject:key] &&
[newAttributes[key] isEqualToString:currentAttributes[key]]) {
@@ -478,7 +598,7 @@ NSString * IJSVGHash(NSString * key) {
[(NSXMLElement *)n.parent removeChildAtIndex:n.index];
}
}
}
- (void)_collapseGroups
@@ -486,11 +606,10 @@ NSString * IJSVGHash(NSString * key) {
NSArray * groups = [_dom nodesForXPath:@"//g" error:nil];
const NSArray * inheritable = IJSVGInheritableAttributes();
for(NSXMLElement * group in groups) {
// dont do anything due to it being referenced
if([group attributeForName:@"id"] != nil ||
[group attributeForName:@"transform"] != nil) {
continue;
if([group attributeForName:@"id"] != nil) {
return;
}
if(group.attributes.count != 0 && group.children.count == 1) {
@@ -501,31 +620,35 @@ NSString * IJSVGHash(NSString * key) {
continue;
}
for(NSXMLNode * gAttribute in group.attributes) {
// if it just doesnt have the attriute, just add it
if([child attributeForName:gAttribute.name] == NO) {
// remove first, or throws a wobbly
[group removeAttributeForName:gAttribute.name];
[child addAttribute:gAttribute];
} else if([gAttribute.name isEqualToString:@"transform"]) {
// transform requires concatination
NSXMLNode * childTransform = [child attributeForName:@"transform"];
childTransform.stringValue = [NSString stringWithFormat:@"%@ %@",
gAttribute.stringValue, childTransform.stringValue];
} else if([inheritable containsObject:gAttribute.name] == NO) {
// if its not inheritable, only remove it if its not equal
NSXMLNode * aAtt = [child attributeForName:gAttribute.name];
if(aAtt == nil || (aAtt != nil && [aAtt.stringValue isEqualToString:gAttribute.stringValue] == NO)) {
continue;
}
}
[group removeAttributeForName:gAttribute.name];
}
for(NSXMLNode * gAttribute in group.attributes) {
// if it just doesnt have the attriute, just add it
if([child attributeForName:gAttribute.name] == NO) {
// remove first, or throws a wobbly
[group removeAttributeForName:gAttribute.name];
[child addAttribute:gAttribute];
} else if([gAttribute.name isEqualToString:@"transform"]) {
// transform requires concatination
NSXMLNode * childTransform = [child attributeForName:@"transform"];
childTransform.stringValue = [NSString stringWithFormat:@"%@ %@",
gAttribute.stringValue, childTransform.stringValue];
} else if([inheritable containsObject:gAttribute.name] == NO) {
// if its not inheritable, only remove it if its not equal
NSXMLNode * aAtt = [child attributeForName:gAttribute.name];
if(aAtt == nil || (aAtt != nil && [aAtt.stringValue isEqualToString:gAttribute.stringValue] == NO)) {
continue;
}
}
[group removeAttributeForName:gAttribute.name];
}
// remove the group as its useless!
if(group.attributes.count == 0) {
[child detach];
[(NSXMLElement *)group.parent replaceChildAtIndex:group.index
withNode:child];
}
}
}
}
@@ -577,7 +700,7 @@ NSString * IJSVGHash(NSString * key) {
element.name = @"path";
NSDictionary * atts = @{@"d":data,
@"id":[NSString stringWithFormat:@"path-%ld",(++_pathCount)]};
@"id":[self generateID]};
IJSVGApplyAttributesToElement(atts, element);
// store it against the def
@@ -648,39 +771,13 @@ NSString * IJSVGHash(NSString * key) {
- (void)applyTransformToElement:(NSXMLElement *)element
fromLayer:(IJSVGLayer *)layer
{
// dont do anything, they are the same
CGFloat x = layer.frame.origin.x;
CGFloat y = layer.frame.origin.y;
// check for x or y..they must be included
if(CGAffineTransformEqualToTransform(layer.affineTransform, CGAffineTransformIdentity) &&
x == 0.f && y == 0.f) {
CGAffineTransform transform = layer.affineTransform;
if(CGAffineTransformEqualToTransform(transform, CGAffineTransformIdentity) == YES) {
return;
}
// construct the matrix
CGAffineTransform transform = layer.affineTransform;
// was there already x and y transform?
BOOL hasXTransform = transform.tx != 0.f;
BOOL hasYTransform = transform.ty != 0.f;
// move the x and y position
if(x != 0.f || y != 0.f) {
transform = CGAffineTransformConcat( transform, CGAffineTransformMakeTranslation( x, y ));
}
// x and y were not given so just transform
if(hasXTransform) {
transform.tx /= 2.f;
}
if(hasYTransform) {
transform.ty /= 2.f;
}
// append the string
NSArray * transformArray = [IJSVGTransform affineTransformToSVGTransformAttributeString:transform];
NSString * transformStr = [transformArray componentsJoinedByString:@" "];
NSString * transformStr = [IJSVGTransform affineTransformToSVGMatrixString:transform];
// apply it to the node
IJSVGApplyAttributesToElement(@{@"transform":transformStr},element);
@@ -708,6 +805,9 @@ NSString * IJSVGHash(NSString * key) {
- (NSString *)base64EncodedStringFromCGImage:(CGImageRef)image
{
if(image == nil) {
return nil;
}
// convert the CGImage into an NSImage
NSBitmapImageRep * rep = [[[NSBitmapImageRep alloc] initWithCGImage:image] autorelease];
@@ -733,7 +833,7 @@ NSString * IJSVGHash(NSString * key) {
patternElement.name = @"pattern";
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
dict[@"id"] = [NSString stringWithFormat:@"pattern-%ld",(++_patternCount)];
dict[@"id"] = [self generateID];
dict[@"width"] = IJSVGShortFloatString(layer.patternNode.width.value);
dict[@"height"] = IJSVGShortFloatString(layer.patternNode.height.value);
@@ -780,12 +880,12 @@ NSString * IJSVGHash(NSString * key) {
toElement:(NSXMLElement *)element
{
IJSVGGradient * gradient = layer.gradient;
NSString * gradKey = [NSString stringWithFormat:@"gradient-%ld",(++_gradCount)];
NSString * gradKey = [self generateID];
NSXMLElement * gradientElement = [[[NSXMLElement alloc] init] autorelease];
// work out linear gradient
if([gradient isKindOfClass:[IJSVGLinearGradient class]]) {
IJSVGLinearGradient * lGradient = (IJSVGLinearGradient *)gradient;
gradientElement.name = @"linearGradient";
NSDictionary * dict = @{@"id":gradKey,
@@ -838,12 +938,21 @@ NSString * IJSVGHash(NSString * key) {
atts[@"offset"] = [NSString stringWithFormat:@"%g%%",(location*100)];
// add the color
atts[@"stop-color"] = [IJSVGColor colorStringFromColor:aColor
forceHex:YES];
NSString * stopColor = [IJSVGColor colorStringFromColor:aColor
forceHex:YES
allowShorthand:YES];
if([stopColor isEqualToString:@"#000000"] == NO) {
atts[@"stop-color"] = stopColor;
}
// we need to work out the color at this point, annoyingly...
CGFloat opacity = aColor.alphaComponent;
atts[@"stop-opacity"] = [NSString stringWithFormat:@"%g",opacity];
// is opacity is equal to 1, no need to add it as spec
// defaults opacity to 1 anyway :)
if(opacity != 1.f) {
atts[@"stop-opacity"] = IJSVGShortFloatStringWithPrecision(opacity, 2);
}
// att the attributes
@@ -859,24 +968,9 @@ NSString * IJSVGHash(NSString * key) {
// work out the transform
NSArray * transforms = layer.gradient.transforms;
if(transforms.count != 0.f) {
CGAffineTransform transform = [self affineTransformFromTransforms:transforms];
// work out if there is x and y translate
BOOL hasXTransform = transform.tx != 0.f;
BOOL hasYTransform = transform.ty != 0.f;
// x and y were not given so just transform
if(hasXTransform) {
transform.tx /= 2.f;
}
if(hasYTransform) {
transform.ty /= 2.f;
}
// apply the attributes
NSArray * transforms = [IJSVGTransform affineTransformToSVGTransformAttributeString:transform];
NSString * tString = [transforms componentsJoinedByString:@" "];
IJSVGApplyAttributesToElement(@{@"gradientTransform":tString}, gradientElement);
CGAffineTransform transform = IJSVGConcatTransforms(transforms);
NSString * transformString = [IJSVGTransform affineTransformToSVGMatrixString:transform];
IJSVGApplyAttributesToElement(@{@"gradientTransform":transformString}, gradientElement);
}
// add it to the element passed in
@@ -885,7 +979,7 @@ NSString * IJSVGHash(NSString * key) {
// fill opacity
if(layer.opacity != 1.f) {
IJSVGApplyAttributesToElement(@{@"fill-opacity":IJSVGShortFloatString(layer.opacity)}, element);
IJSVGApplyAttributesToElement(@{@"fill-opacity":IJSVGShortFloatStringWithPrecision(layer.opacity,2)}, element);
}
} else {
IJSVGApplyAttributesToElement(@{@"stroke":IJSVGHashURL(gradKey)}, element);
@@ -905,13 +999,16 @@ NSString * IJSVGHash(NSString * key) {
fromParent:(NSXMLElement *)parent
{
NSString * base64String = [self base64EncodedStringFromCGImage:(CGImageRef)layer.contents];
if(base64String == nil || layer.contents == nil) {
return nil;
}
// image element for the SVG
NSXMLElement * imageElement = [[[NSXMLElement alloc] init] autorelease];
imageElement.name = @"image";
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
dict[@"id"] = [NSString stringWithFormat:@"image-%ld",(++_imageCount)];
dict[@"id"] = [self generateID];
dict[@"width"] = IJSVGShortFloatString(layer.frame.size.width);
dict[@"height"] = IJSVGShortFloatString(layer.frame.size.height);
dict[@"xlink:href"] = base64String;
@@ -936,10 +1033,17 @@ NSString * IJSVGHash(NSString * key) {
e.name = @"path";
CGPathRef path = layer.path;
// copy the path as we want to translate
CGAffineTransform trans = CGAffineTransformMakeTranslation(layer.originalPathOrigin.x,
layer.originalPathOrigin.y);
CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &trans);
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
// path
dict[@"d"] = [self pathFromCGPath:path];
dict[@"d"] = [self pathFromCGPath:transformPath];
CGPathRelease(transformPath);
// work out even odd rule
if([layer.fillRule isEqualToString:kCAFillRuleNonZero] == NO) {
@@ -996,7 +1100,7 @@ NSString * IJSVGHash(NSString * key) {
parentLayer:(IJSVGPatternLayer *)layer
stroke:YES
toElement:e];
} else if(strokeLayer.strokeColor != nil) {
NSColor * strokeColor = [NSColor colorWithCGColor:strokeLayer.strokeColor];
NSString * strokeColorString = [IJSVGColor colorStringFromColor:strokeColor];
@@ -1004,6 +1108,10 @@ NSString * IJSVGHash(NSString * key) {
// could be none
if(strokeColorString != nil) {
dict[@"stroke"] = strokeColorString;
if([strokeColorString isEqualToString:@"none"] == YES) {
// remove the stroke width as its completely useless
[dict removeObjectForKey:@"stroke-width"];
}
}
}
@@ -1045,7 +1153,7 @@ NSString * IJSVGHash(NSString * key) {
}
}
// apply the attributes
IJSVGApplyAttributesToElement(dict, e);
@@ -1062,7 +1170,7 @@ NSString * IJSVGHash(NSString * key) {
// opacity
if(layer.opacity != 1.f) {
dict[@"opacity"] = IJSVGShortFloatString(layer.opacity);
dict[@"opacity"] = IJSVGShortFloatStringWithPrecision(layer.opacity,2);
}
// blendmode - we only every apply a stylesheet blend mode
@@ -1111,7 +1219,7 @@ NSString * IJSVGHash(NSString * key) {
mask.name = @"mask";
// create the key
NSString * maskKey = [NSString stringWithFormat:@"mask-%ld",(++_maskCount)];
NSString * maskKey = [self generateID];
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
dict[@"id"] = maskKey;
dict[@"maskContentUnits"] = @"userSpaceOnUse";
@@ -1229,3 +1337,4 @@ void IJSVGExporterPathCaller(void * info, const CGPathElement * pathElement) {
}
@end
+3 -4
View File
@@ -13,9 +13,6 @@
@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;
@@ -26,6 +23,8 @@
colors:(NSArray **)someColors;
- (CGGradientRef)CGGradient;
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect;
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox;
@end
+5 -9
View File
@@ -11,7 +11,6 @@
@implementation IJSVGGradient
@synthesize gradient, CGGradient;
@synthesize angle, startPoint, endPoint;
@synthesize x1, x2, y1, y2;
- (void)dealloc
@@ -31,8 +30,6 @@
{
IJSVGGradient * clone = [super copyWithZone:zone];
clone.gradient = [[self.gradient copy] autorelease];
clone.startPoint = self.startPoint;
clone.endPoint = self.endPoint;
return clone;
}
@@ -40,14 +37,11 @@
colors:(NSArray **)someColors
{
// find each stop element
NSArray * stops = [element nodesForXPath:@"stop"
error:nil];
NSArray * stops = [element children];
NSMutableArray * colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease];
CGFloat * stopsParams = (CGFloat *)malloc(stops.count*sizeof(CGFloat));
NSInteger i = 0;
for( NSXMLElement * stop in stops )
{
for( NSXMLElement * stop in stops ) {
// find the offset
CGFloat offset = [stop attributeForName:@"offset"].stringValue.floatValue;
if( offset > 1.f ) {
@@ -134,7 +128,9 @@
}
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
{
}
+4
View File
@@ -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
+11 -1
View File
@@ -10,7 +10,10 @@
@implementation IJSVGGradientLayer
@synthesize viewBox;
@synthesize gradient;
@synthesize absoluteTransform;
@synthesize objectRect;
- (void)dealloc
{
@@ -36,7 +39,14 @@
}
// draw the gradient
[self.gradient drawInContextRef:ctx rect:self.bounds];
CGAffineTransform trans = CGAffineTransformMakeTranslation(-CGRectGetMinX(objectRect),
-CGRectGetMinY(objectRect));
CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform,trans);
[self.gradient drawInContextRef:ctx
objectRect:objectRect
absoluteTransform:transform
viewPort:self.viewBox];
}
@end
+7 -1
View File
@@ -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;
}
+12 -2
View File
@@ -34,11 +34,21 @@
// 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
+8 -21
View File
@@ -32,7 +32,6 @@
IJSVGEndTransactionLock();
}
+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer
{
NSMutableArray * arr = [[[NSMutableArray alloc] init] autorelease];
@@ -80,14 +79,14 @@
- (void)setBackingScaleFactor:(CGFloat)newFactor
{
if(self.backingScaleFactor == newFactor) {
return;
}
backingScaleFactor = newFactor;
self.contentsScale = newFactor;
self.rasterizationScale = newFactor;
[self setNeedsDisplay];
}
if(self.backingScaleFactor == newFactor) {
return;
}
backingScaleFactor = newFactor;
self.contentsScale = newFactor;
self.rasterizationScale = newFactor;
[self setNeedsDisplay];
}
- (void)_customRenderInContext:(CGContextRef)ctx
{
@@ -176,18 +175,6 @@
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;
}
@end
+124 -89
View File
@@ -67,44 +67,50 @@
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];
return layer;
}
- (IJSVGLayer *)proposedLayerAfterApplyingTransforms:(IJSVGLayer *)layer
transforms:(NSArray<IJSVGTransform *> *)transforms
- (IJSVGLayer *)applyTransforms:(NSArray<IJSVGTransform *> *)transforms
toLayer:(IJSVGLayer *)layer
{
// do some magic transform
if(transforms.count == 0) {
return layer;
}
// 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;
}
@@ -127,14 +133,25 @@
layer.hidden = YES;
}
CGRect frame = layer.frame;
frame.origin.x += [node.x computeValue:frame.size.width];
frame.origin.y += [node.y computeValue:frame.size.height];
layer.frame = frame;
}
- (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;
}
@@ -145,10 +162,7 @@
[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
@@ -180,16 +194,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;
@@ -198,9 +217,7 @@
CGPathRelease(introPath);
// set the bounds
bounds.origin.x += path.x.value;
bounds.origin.y += path.y.value;
layer.frame = bounds;
layer.frame = CGRectIntegral(bounds);
// basic fill color and rule
layer.fillColor = nil;
@@ -217,6 +234,26 @@
return mask;
}
- (CGAffineTransform)absoluteTransform:(IJSVGNode *)node
{
CGAffineTransform parentAbsoluteTransform = CGAffineTransformIdentity;
IJSVGNode * intermediateNode = node.intermediateParentNode;
node = node.parentNode;
while(node != nil) {
// intermediateParent should be skipped as these are elements
// created by use statements and are technically fake elements, but the
// spec says use them for the transforms, yolo!
if(node == intermediateNode) {
node = node.parentNode;
continue;
}
CGAffineTransform trans = IJSVGConcatTransforms(node.transforms);
parentAbsoluteTransform = CGAffineTransformConcat(trans,parentAbsoluteTransform);
node = node.parentNode;
}
return parentAbsoluteTransform;
}
- (IJSVGLayer *)layerForPath:(IJSVGPath *)path
{
// is there a sub SVG?
@@ -226,7 +263,13 @@
}
// garb the basic shape layer
IJSVGShapeLayer * layer = [self basicLayerForPath:path];
CGRect originalShapeBounds;
IJSVGShapeLayer * layer = [self basicLayerForPath:path
originalBoundingBox:&originalShapeBounds];
BOOL hasStroke = (path.strokeColor != nil ||
path.strokePattern != nil ||
path.strokeGradient != nil);
// any gradient?
if(self.fillColor == nil && path.fillGradient != nil) {
@@ -234,15 +277,12 @@
// create the gradient
IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer
gradient:path.fillGradient
fromNode:path];
fromNode:path
objectRect:originalShapeBounds
shouldMask:YES];
// add the gradient and set it against the layer
[layer addSublayer:gradLayer];
// apply offsets
[self applyOffsetsToLayer:gradLayer
fromNode:path.fillGradient];
layer.gradientFillLayer = gradLayer;
} else if(self.fillColor == nil && path.fillPattern != nil) {
@@ -264,6 +304,9 @@
// only use the global if its set and the current colors
// alpha channel is not 0.f, otherwise its a blank clear color,
// aka, not filled in
NSColor * fColor = path.fillColor;
BOOL hasColor = (fColor.alphaComponent == 0.f || fColor == nil) == NO;
BOOL hasFill = path.fillPattern != nil || path.fillGradient != nil;
@@ -292,9 +335,7 @@
}
// stroke it
if(path.strokeColor != nil ||
path.strokePattern != nil ||
path.strokeGradient != nil) {
if(hasStroke == YES) {
// load the stroke layer
IJSVGStrokeLayer * strokeLayer = [self strokeLayer:layer
@@ -311,7 +352,8 @@
// create the gradient
IJSVGGradientLayer * gradLayer = [self gradientStrokeLayerForLayer:layer
gradient:path.strokeGradient
fromNode:path];
fromNode:path
objectRect:originalShapeBounds];
moveStrokeLayer = YES;
gradLayer.mask = strokeLayer;
@@ -402,33 +444,19 @@
- (IJSVGGradientLayer *)gradientStrokeLayerForLayer:(IJSVGShapeLayer *)layer
gradient:(IJSVGGradient *)gradient
fromNode:(IJSVGNode *)path
objectRect:(CGRect)objectRect
{
// the gradient drawing layer
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
gradLayer.gradient = gradient;
// is there a fill opacity?
if(path.fillOpacity.value != 0.f) {
gradLayer.opacity = path.fillOpacity.value;
}
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;
// display it
[gradLayer setNeedsDisplay];
if(path.fillGradient.units == IJSVGUnitUserSpaceOnUse) {
// move back if needed
gradLayer.frame = (CGRect){
.size = gradLayer.frame.size,
.origin = CGPointMake(-fabs(gradLayer.frame.origin.x),
-fabs(gradLayer.frame.origin.y))
};
}
return gradLayer;
}
@@ -436,34 +464,28 @@
- (IJSVGGradientLayer *)gradientLayerForLayer:(IJSVGShapeLayer *)layer
gradient:(IJSVGGradient *)gradient
fromNode:(IJSVGNode *)path
objectRect:(CGRect)objectRect
shouldMask:(BOOL)shouldMask
{
// add the mask
IJSVGShapeLayer * mask = [self layerMaskFromLayer:layer
fromNode:path];
// the gradient drawing layer
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
gradLayer.frame = CGPathGetBoundingBox(((IJSVGShapeLayer *)layer).path);
gradLayer.viewBox = self.viewBox;
gradLayer.frame = layer.bounds;
gradLayer.gradient = gradient;
gradLayer.mask = mask;
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;
}
// display it
[gradLayer setNeedsDisplay];
if(path.fillGradient.units == IJSVGUnitUserSpaceOnUse) {
// move back if needed
gradLayer.frame = (CGRect){
.size = gradLayer.frame.size,
.origin = CGPointMake(-fabs(gradLayer.frame.origin.x),
-fabs(gradLayer.frame.origin.y))
};
}
return gradLayer;
}
@@ -551,7 +573,7 @@
}
- (IJSVGStrokeLayer *)strokeLayer:(IJSVGShapeLayer *)layer
fromNode:(IJSVGNode *)path
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
@@ -742,4 +764,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
+1 -3
View File
@@ -12,8 +12,6 @@
@interface IJSVGLinearGradient : IJSVGGradient
+ (NSGradient *)parseGradient:(NSXMLElement *)element
gradient:(IJSVGLinearGradient *)aGradient
startPoint:(CGPoint *)startPoint
endPoint:(CGPoint *)endPoint;
gradient:(IJSVGLinearGradient *)aGradient;
@end
+47 -30
View File
@@ -13,8 +13,6 @@
+ (NSGradient *)parseGradient:(NSXMLElement *)element
gradient:(IJSVGLinearGradient *)aGradient
startPoint:(CGPoint *)startPoint
endPoint:(CGPoint *)endPoint
{
CGFloat px1 = [[element attributeForName:@"x1"] stringValue].floatValue;
@@ -25,10 +23,8 @@
// 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)) {
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;
}
@@ -62,32 +58,53 @@
}
- (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 gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
CGAffineTransform absTransform = absoluteTransform;
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
#pragma mark User Space On Use
CGContextSaveGState(ctx);
{
if(inUserSpace == YES) {
CGFloat width = CGRectGetWidth(viewBox);
CGFloat height = CGRectGetHeight(viewBox);
gradientStartPoint = CGPointMake([self.x1 computeValue:width],
[self.y1 computeValue:height]);
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
[self.y2 computeValue:height]);
// transform absolute - due to user space
CGContextConcatCTM(ctx, absTransform);
} else {
#pragma mark Object Bounding Box
CGFloat width = CGRectGetWidth(objectRect);
CGFloat height = CGRectGetHeight(objectRect);
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 options = kCGGradientDrawsBeforeStartLocation|
kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(ctx, self.CGGradient, gradientStartPoint,
gradientEndPoint, options);
};
CGPoint aEndPoint = (CGPoint){
.x = [self.x2 computeValue:rect.size.width],
.y = [self.y2 computeValue:rect.size.height]
};
// convert the nsgradient to a CGGradient
CGGradientRef gRef = [self CGGradient];
// apply transform for each point
for( IJSVGTransform * transform in self.transforms ) {
CGAffineTransform trans = transform.CGAffineTransform;
aStartPoint = CGPointApplyAffineTransform(aStartPoint, trans);
aEndPoint = CGPointApplyAffineTransform(aEndPoint, trans);
}
// draw the gradient
CGGradientDrawingOptions opt = kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(ctx, gRef, aStartPoint, aEndPoint, opt);
CGContextRestoreGState(ctx);
}
@end
+3 -1
View File
@@ -16,6 +16,7 @@
@class IJSVGGradient;
@class IJSVGGroup;
@class IJSVGPattern;
@class IJSVGTransform;
typedef NS_ENUM( NSInteger, IJSVGNodeType ) {
IJSVGNodeTypeGroup,
@@ -120,12 +121,13 @@ 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;
+21 -10
View File
@@ -8,6 +8,7 @@
#import "IJSVGNode.h"
#import "IJSVGDef.h"
#import "IJSVGUtils.h"
@implementation IJSVGNode
@@ -29,6 +30,7 @@
@synthesize opacity;
@synthesize identifier;
@synthesize parentNode;
@synthesize intermediateParentNode;
@synthesize transforms;
@synthesize windingRule;
@synthesize def;
@@ -131,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;
}
@@ -233,10 +241,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;
}
@@ -248,7 +258,7 @@
// winding rule can inherit..
- (IJSVGWindingRule)windingRule
{
if( windingRule == IJSVGWindingRuleInherit && parentNode != nil ) {
if(windingRule == IJSVGWindingRuleInherit && parentNode != nil) {
return parentNode.windingRule;
}
return windingRule;
@@ -256,20 +266,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;
}
@@ -327,8 +337,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;
}
+1
View File
@@ -95,6 +95,7 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
NSMutableDictionary * _defNodes;
NSMutableDictionary * _baseDefNodes;
NSMutableArray<IJSVG *> * _svgs;
NSMutableArray * _definedGroups;
struct {
unsigned int shouldHandleForeignObject: 1;
+152 -154
View File
@@ -45,6 +45,7 @@
[_parsedNodes release], _parsedNodes = nil;
[_defNodes release], _defNodes = nil;
[_baseDefNodes release], _baseDefNodes = nil;
[_definedGroups release], _definedGroups = nil;
[_svgs release], _svgs = nil;
[super dealloc];
}
@@ -178,7 +179,8 @@
// parse common attributes on the SVG element
[self _parseElementForCommonAttributes:svgElement
node:self];
node:self
ignoreAttributes:nil];
// find the sizebox!
NSXMLNode * attribute = nil;
@@ -224,7 +226,8 @@
// now everything has been done we need to compute the style tree
for(NSDictionary * dict in _parsedNodes) {
[self _postParseElementForCommonAttributes:dict[@"element"]
node:dict[@"node"]];
node:dict[@"node"]
ignoreAttributes:nil];
}
// dont need the style sheet or the parsed nodes as this point
@@ -235,6 +238,7 @@
- (void)_postParseElementForCommonAttributes:(NSXMLElement *)element
node:(IJSVGNode *)node
ignoreAttributes:(NSArray *)ignoredAttributes
{
// first of all, compute a style sheet
@@ -244,6 +248,9 @@
// attribute helpers
typedef void (^cp)(NSString *);
void (^attr)(const NSString *, cp) = ^(NSString * key, cp block) {
if([ignoredAttributes containsObject:key]) {
return;
}
NSString * v = [element attributeForName:key].stringValue
?: [style property:key];
if(v != nil && v.length != 0) {
@@ -397,12 +404,15 @@
node.fillPattern = (IJSVGPattern *)obj;
}
} else {
// its a color
node.fillColor = [IJSVGColor colorFromString:value];
if(node.fillOpacity.value != 1.f) {
node.fillColor = [IJSVGColor changeAlphaOnColor:node.fillColor
to:node.fillOpacity.value];
}
}
});
// fill opacity
attr(IJSVGAttributeFillOpacity, ^(NSString * value) {
if(node.fillOpacity.value != 1.f) {
node.fillColor = [IJSVGColor changeAlphaOnColor:node.fillColor
to:node.fillOpacity.value];
}
});
@@ -425,22 +435,34 @@
}
- (id)definedObjectForID:(NSString *)anID
xmlElement:(NSXMLElement **)element
{
// check base def nodes first, then check rest of document
NSXMLElement * parseElement = _baseDefNodes[anID] ?: _defNodes[anID];
if(parseElement != nil) {
// parse the element
IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease];
// parse the block
if(element != nil && element != NULL) {
*element = parseElement;
}
IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease];
[self _parseBaseBlock:parseElement
intoGroup:group
def:NO];
if(_definedGroups == nil) {
_definedGroups = [[NSMutableArray alloc] init];
}
[_definedGroups addObject:group];
return [group defForID:anID];
}
return nil;
}
- (id)definedObjectForID:(NSString *)anID
{
return [self definedObjectForID:anID
xmlElement:nil];
}
- (BOOL)isFont
{
return [_glyphs count] != 0;
@@ -476,9 +498,11 @@
- (void)_parseElementForCommonAttributes:(NSXMLElement *)element
node:(IJSVGNode *)node
ignoreAttributes:(NSArray *)ignoredAttributes
{
[self _postParseElementForCommonAttributes:element
node:node];
node:node
ignoreAttributes:ignoredAttributes];
}
- (void)_setupDefaultsForNode:(IJSVGNode *)node
@@ -511,7 +535,7 @@
for(NSXMLElement * element in anElement.children) {
// not a def
if([IJSVGNode typeForString:element.name
if([IJSVGNode typeForString:element.localName
kind:element.kind] != IJSVGNodeTypeDef) {
continue;
}
@@ -519,7 +543,7 @@
// store each object
for(NSXMLElement * childDef in element.children) {
// is there any stylesheets within this?
IJSVGNodeType childType = [IJSVGNode typeForString:childDef.name
IJSVGNodeType childType = [IJSVGNode typeForString:childDef.localName
kind:element.kind];
switch(childType) {
@@ -552,7 +576,7 @@
intoGroup:(IJSVGGroup *)parentGroup
def:(BOOL)flag
{
NSString * subName = element.name;
NSString * subName = element.localName;
NSXMLNodeKind nodeKind = element.kind;
IJSVGNodeType aType = [IJSVGNode typeForString:subName
kind:nodeKind];
@@ -587,7 +611,8 @@
// grab common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
// work out the SVG
NSError * error = nil;
@@ -632,7 +657,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
// pass the commands for it
[self _parsePathCommandData:[[element attributeForName:(NSString *)IJSVGAttributeD] stringValue]
@@ -673,7 +699,8 @@
// find common attributes
[self _setupDefaultsForNode:group];
[self _parseElementForCommonAttributes:element
node:group];
node:group
ignoreAttributes:nil];
// recursively parse blocks
[self _parseBlock:element
@@ -699,7 +726,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
[self _parsePathCommandData:[[element attributeForName:(NSString *)IJSVGAttributeD] stringValue]
intoPath:path];
@@ -721,7 +749,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
[self _parsePolygon:element
intoPath:path];
[parentGroup addDef:path];
@@ -743,7 +772,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
[self _parsePolyline:element
intoPath:path];
[parentGroup addDef:path];
@@ -767,7 +797,8 @@
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:@[@"x",@"y"]];
[parentGroup addDef:path];
break;
}
@@ -785,7 +816,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
[self _parseLine:element
intoPath:path];
[parentGroup addDef:path];
@@ -807,7 +839,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
[self _parseCircle:element
intoPath:path];
[parentGroup addDef:path];
@@ -828,7 +861,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
[self _parseEllipse:element
intoPath:path];
[parentGroup addDef:path];
@@ -847,13 +881,30 @@
node.identifier = nil;
}
node.parentNode = parentGroup;
// at this point, we need to create another group!
IJSVGGroup * subGroup = [[[IJSVGGroup alloc] init] autorelease];
subGroup.parentNode = parentGroup;
[subGroup addChild:node];
node.parentNode = subGroup;
node.intermediateParentNode = subGroup;
// is there a width and height?
CGFloat x = [element attributeForName:(NSString *)IJSVGAttributeX].stringValue.floatValue;
CGFloat y = [element attributeForName:(NSString *)IJSVGAttributeY].stringValue.floatValue;
// we need to add a transform to the subgroup
subGroup.transforms = @[[IJSVGTransform transformByTranslatingX:x y:y]];
if(!flag) {
[parentGroup addChild:node];
[parentGroup addChild:subGroup];
}
// parse attributes from element onto group - but spec
// says ignore x, y, width, height and xlink:href...
[self _parseElementForCommonAttributes:element
node:node];
node:node
ignoreAttributes:@[@"x",@"y",@"width",
@"height",@"xlink:href"]];
[parentGroup addDef:node];
break;
@@ -864,43 +915,36 @@
NSString * xlink = [[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue];
NSString * xlinkID = [xlink substringFromIndex:1];
IJSVGNode * node = [self definedObjectForID:xlinkID];
NSXMLElement * referenceElement;
IJSVGNode * node = [self definedObjectForID:xlinkID
xmlElement:&referenceElement];
if( node != nil ) {
// we are a clone
NSXMLElement * elementCopy = [self mergedElement:element
withReferenceElement:referenceElement];
IJSVGLinearGradient * grad = [[[IJSVGLinearGradient alloc] init] autorelease];
grad.type = aType;
[grad applyPropertiesFromNode:node];
grad.gradient = [[[(IJSVGGradient *)node gradient] copy] autorelease];
CGPoint startPoint, endPoint;
[IJSVGLinearGradient parseGradient:element
gradient:grad
startPoint:&startPoint
endPoint:&endPoint];
grad.gradient = [IJSVGLinearGradient parseGradient:elementCopy
gradient:grad];
[self _setupDefaultsForNode:grad];
[self _parseElementForCommonAttributes:element
node:grad];
grad.startPoint = startPoint;
grad.endPoint = endPoint;
[self _parseElementForCommonAttributes:elementCopy
node:grad
ignoreAttributes:nil];
[parentGroup addDef:grad];
break;
}
IJSVGLinearGradient * gradient = [[[IJSVGLinearGradient alloc] init] autorelease];
gradient.type = aType;
CGPoint startPoint, endPoint;
gradient.gradient = [IJSVGLinearGradient parseGradient:element
gradient:gradient
startPoint:&startPoint
endPoint:&endPoint];
gradient:gradient];
[self _setupDefaultsForNode:gradient];
[self _parseElementForCommonAttributes:element
node:gradient];
gradient.startPoint = startPoint;
gradient.endPoint = endPoint;
node:gradient
ignoreAttributes:nil];
[parentGroup addDef:gradient];
break;
}
@@ -910,44 +954,37 @@
NSString * xlink = [[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue];
NSString * xlinkID = [xlink substringFromIndex:1];
IJSVGNode * node = [self definedObjectForID:xlinkID];
if( node != nil )
{
NSXMLElement * referenceElement;
IJSVGNode * node = [self definedObjectForID:xlinkID
xmlElement:&referenceElement];
if( node != nil ) {
// we are a clone
IJSVGRadialGradient * grad = [[[IJSVGRadialGradient alloc] init] autorelease];
grad.type = aType;
[grad applyPropertiesFromNode:node];
grad.gradient = [[[(IJSVGGradient *)node gradient] copy] autorelease];
CGPoint startPoint, endPoint;
[IJSVGRadialGradient parseGradient:element
gradient:grad
startPoint:&startPoint
endPoint:&endPoint];
NSXMLElement * elementCopy = [self mergedElement:element
withReferenceElement:referenceElement];
grad.gradient = [IJSVGRadialGradient parseGradient:elementCopy
gradient:grad];
[self _setupDefaultsForNode:grad];
[self _parseElementForCommonAttributes:element
node:grad];
grad.startPoint = startPoint;
grad.endPoint = endPoint;
[self _parseElementForCommonAttributes:elementCopy
node:grad
ignoreAttributes:nil];
[parentGroup addDef:grad];
break;
}
IJSVGRadialGradient * gradient = [[[IJSVGRadialGradient alloc] init] autorelease];
gradient.type = aType;
CGPoint startPoint, endPoint;
gradient.gradient = [IJSVGRadialGradient parseGradient:element
gradient:gradient
startPoint:&startPoint
endPoint:&endPoint];
gradient.startPoint = startPoint;
gradient.endPoint = endPoint;
gradient:gradient];
[self _setupDefaultsForNode:gradient];
[self _parseElementForCommonAttributes:element
node:gradient];
node:gradient
ignoreAttributes:nil];
[parentGroup addDef:gradient];
break;
}
@@ -964,7 +1001,8 @@
// find common attributes
[self _parseElementForCommonAttributes:element
node:group];
node:group
ignoreAttributes:nil];
// recursively parse blocks
[self _parseBlock:element
@@ -982,7 +1020,8 @@
// find common attributes
[self _parseElementForCommonAttributes:element
node:pattern];
node:pattern
ignoreAttributes:nil];
// pattern has children
[self _parseBlock:element
@@ -1001,7 +1040,8 @@
// find common attributes
[self _parseElementForCommonAttributes:element
node:image];
node:image
ignoreAttributes:nil];
// from base64
[image loadFromBase64EncodedString:[[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue]];
@@ -1015,6 +1055,18 @@
}
}
- (NSXMLElement *)mergedElement:(NSXMLElement *)element
withReferenceElement:(NSXMLElement *)reference
{
NSXMLElement * copy = [[reference copy] autorelease];
for(NSXMLNode * attribute in element.attributes) {
[copy removeAttributeForName:attribute.name];
attribute = [[attribute copy] autorelease];
[copy addAttribute:attribute];
}
return copy;
}
- (void)_parseBlock:(NSXMLElement *)anElement
intoGroup:(IJSVGGroup*)parentGroup
def:(BOOL)flag
@@ -1188,8 +1240,7 @@
NSInteger count = 0;
CGFloat * params = [IJSVGUtils commandParameters:points
count:&count];
if( (count % 2) != 0 )
{
if( (count % 2) != 0 ) {
// error occured, free the params
free(params);
return;
@@ -1198,12 +1249,12 @@
// construct a command
NSMutableString * str = [[[NSMutableString alloc] init] autorelease];
[str appendFormat:@"M%f,%f L",params[0],params[1]];
for( NSInteger i = 2; i < count; i+=2 )
{
for( NSInteger i = 2; i < count; i+=2 ) {
[str appendFormat:@"%f,%f ",params[i],params[i+1]];
}
if( closePath )
if( closePath ) {
[str appendString:@"z"];
}
[self _parsePathCommandData:str
intoPath:path];
free(params);
@@ -1213,86 +1264,33 @@
- (void)_parseRect:(NSXMLElement *)element
intoPath:(IJSVGPath *)path
{
CGFloat aX, aY, aWidth, aHeight;
if([self namespacedAttribute:(NSString *)IJSVGAttributeX
element:element] != nil) {
// already namespaced, find them
aX = [[self namespacedAttribute:(NSString *)IJSVGAttributeX
element:element] floatValue];
aY = [[self namespacedAttribute:(NSString *)IJSVGAttributeY
element:element] floatValue];
aWidth = [IJSVGUtils floatValue:[self namespacedAttribute:(NSString *)IJSVGAttributeWidth
element:element]
fallBackForPercent:self.viewBox.size.width];
aHeight = [IJSVGUtils floatValue:[self namespacedAttribute:(NSString *)IJSVGAttributeHeight
element:element]
fallBackForPercent:self.viewBox.size.height];
} else {
// reassign X
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeX
value:[[element attributeForName:(NSString *)IJSVGAttributeX] stringValue]
element:element];
aX = [[[element attributeForName:(NSString *)IJSVGAttributeX] stringValue] floatValue];
// reassign Y
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeY
value:[[element attributeForName:(NSString *)IJSVGAttributeY] stringValue]
element:element];
aY = [[[element attributeForName:(NSString *)IJSVGAttributeY] stringValue] floatValue];
// reassign width
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeWidth
value:[[element attributeForName:(NSString *)IJSVGAttributeWidth] stringValue]
element:element];
aWidth = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeWidth] stringValue]
fallBackForPercent:self.viewBox.size.width];
// reassign height
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeHeight
value:[[element attributeForName:(NSString *)IJSVGAttributeHeight] stringValue]
element:element];
aHeight = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeHeight] stringValue]
fallBackForPercent:self.viewBox.size.height];
// set the namespaced versions as we need to remove the attributes
[element removeAttributeForName:(NSString *)IJSVGAttributeX];
[element removeAttributeForName:(NSString *)IJSVGAttributeY];
[element removeAttributeForName:(NSString *)IJSVGAttributeWidth];
[element removeAttributeForName:(NSString *)IJSVGAttributeHeight];
}
CGFloat rX = [[[element attributeForName:(NSString *)IJSVGAttributeRX] stringValue] floatValue];
CGFloat rY = [[[element attributeForName:(NSString *)IJSVGAttributeRY] stringValue] floatValue];
if( [element attributeForName:(NSString *)IJSVGAttributeRY] == nil ) {
// width and height
CGFloat width = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeWidth] stringValue]
fallBackForPercent:self.viewBox.size.width];
CGFloat height = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeHeight] stringValue]
fallBackForPercent:self.viewBox.size.height];
// rect uses x and y as start of path, not move path object -_-
CGFloat x = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeX] stringValue]
fallBackForPercent:self.viewBox.size.width];
CGFloat y = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeY] stringValue]
fallBackForPercent:self.viewBox.size.height];
// radius
CGFloat rX = [element attributeForName:(NSString *)IJSVGAttributeRX].stringValue.floatValue;
CGFloat rY = [element attributeForName:(NSString *)IJSVGAttributeRY].stringValue.floatValue;
if([element attributeForName:(NSString *)IJSVGAttributeRY] == nil) {
rY = rX;
}
[path overwritePath:[NSBezierPath bezierPathWithRoundedRect:NSMakeRect( aX, aY, aWidth, aHeight)
xRadius:rX
yRadius:rY]];
}
- (NSString *)namespacedAttribute:(NSString *)key
element:(NSXMLElement *)element
{
key = [NSString stringWithFormat:@"ij-svg:%@",key];
if([element attributeForName:key] != nil) {
return [[element attributeForName:key] stringValue];
}
return nil;
}
- (void)applyNamespacedAttribute:(NSString *)key
value:(NSString *)value
element:(NSXMLElement *)element
{
key = [NSString stringWithFormat:@"ij-svg:%@",key];
NSXMLNode * node = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
node.name = key;
node.stringValue= value;
[element addAttribute:node];
NSBezierPath * newPath = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect( x, y, width, height)
xRadius:rX
yRadius:rY];
[path overwritePath:newPath];
}
@end
+24
View File
@@ -0,0 +1,24 @@
//
// IJSVGRenderer.h
// IJSVGExample
//
// Created by Curtis Hard on 31/01/2018.
// Copyright © 2018 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
@class IJSVGLayer;
@interface IJSVGQuartzRenderer : NSObject {
}
@property (nonatomic, assign) CGFloat scale;
@property (nonatomic, assign) CGFloat backingScale;
@property (nonatomic, assign) CGRect viewPort;
- (void)renderLayer:(IJSVGLayer *)layer
inContext:(CGContextRef)context;
@end
+247
View File
@@ -0,0 +1,247 @@
//
// IJSVGRenderer.m
// IJSVGExample
//
// Created by Curtis Hard on 31/01/2018.
// Copyright © 2018 Curtis Hard. All rights reserved.
//
#import "IJSVGQuartzRenderer.h"
#import "IJSVG.h"
#import "IJSVGLayerTree.h"
#import "IJSVGGradientLayer.h"
#import "IJSVGStrokeLayer.h"
@implementation IJSVGQuartzRenderer
@synthesize scale, viewPort, backingScale;
- (void)renderLayer:(IJSVGLayer *)layer
inContext:(CGContextRef)ctx
{
// if layer is hidden, no need to continue
// trying to render it, its useless!
if(layer.hidden == YES) {
return;
}
// check which layers can actually be rendered
if(layer.class == IJSVGStrokeLayer.class ||
layer.class == IJSVGGradientLayer.class) {
return;
}
CGContextSaveGState(ctx);
// apply any transfroms so children also transform too
CGContextConcatCTM(ctx, layer.affineTransform);
CGContextSetAlpha(ctx, layer.opacity);
// is there a mask?!
if(layer.mask != nil) {
IJSVGLayer * maskLayer = (IJSVGLayer *)layer.mask;
CGRect rect;
CGImageRef maskImage = [self newMaskedImageForLayer:maskLayer
proposedRect:&rect];
CGRect maskRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
CGContextClipToMask(ctx, maskRect, maskImage);
CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y);
CGImageRelease(maskImage);
}
// render itself
[self _renderLayer:layer
inContext:ctx];
// render the children recursively
for(IJSVGLayer * sublayer in layer.sublayers) {
[self renderLayer:sublayer
inContext:ctx];
}
CGContextRestoreGState(ctx);
}
- (void)_renderLayer:(IJSVGLayer *)layer
inContext:(CGContextRef)ctx
{
// is a shape layer
if(layer.class == IJSVGShapeLayer.class) {
// move the path
CGContextTranslateCTM(ctx, layer.frame.origin.x,
layer.frame.origin.y);
// find the shape
IJSVGShapeLayer * shape = (IJSVGShapeLayer *)layer;
CGPathRef path = shape.path;
// has just a plain fill color
CGContextSaveGState(ctx); {
CGContextAddPath(ctx, path);
if([shape.fillRule isEqualToString:kCAFillRuleEvenOdd]) {
CGContextEOClip(ctx);
} else {
CGContextClip(ctx);
}
CGContextAddPath(ctx, path);
if(shape.gradientFillLayer == nil) {
if(shape.fillColor != nil) {
CGContextSetFillColorWithColor(ctx, shape.fillColor);
CGContextFillPath(ctx);
}
// has a gradient fill
} else if(shape.gradientFillLayer != nil) {
CGContextSaveGState(ctx); {
CGContextSetAlpha(ctx, shape.gradientFillLayer.opacity);
[shape.gradientFillLayer drawInContext:ctx];
} CGContextRestoreGState(ctx);
}
} CGContextRestoreGState(ctx);
// stroke must be done outside of the fill due to
// clipping path will cause it to render incorrectly
CGContextSaveGState(ctx); {
// any stroke?
if(shape.strokeLayer != nil) {
IJSVGStrokeLayer * strokeLayer = (IJSVGStrokeLayer *)shape.strokeLayer;
if(strokeLayer.strokeColor != nil) {
CGContextSaveGState(ctx); {
// set opacity
CGContextSetAlpha(ctx, strokeLayer.opacity);
CGContextSetLineCap(ctx, [self.class lineCapFromLayer:strokeLayer]);
CGContextSetLineJoin(ctx, [self.class lineJoinFromLayer:strokeLayer]);
// are there any line dashes?
NSArray * dash = strokeLayer.lineDashPattern;
CGFloat * lengths = (CGFloat *)malloc(sizeof(CGFloat)*dash.count);
NSInteger i = 0;
for(NSNumber * number in dash) {
lengths[i++] = number.floatValue;
}
CGContextSetLineDash(ctx, strokeLayer.lineDashPhase,
lengths, dash.count);
free(lengths);
// get bounding box of the current path
CGContextAddPath(ctx, strokeLayer.path);
CGContextSetLineWidth(ctx, strokeLayer.lineWidth);
CGContextSetStrokeColorWithColor(ctx, strokeLayer.strokeColor);
CGContextStrokePath(ctx);
} CGContextRestoreGState(ctx);
}
} else {
CGContextSetLineWidth(ctx, 0.f);
CGContextStrokePath(ctx);
}
} CGContextRestoreGState(ctx);
}
}
+ (CGLineJoin)lineJoinFromLayer:(IJSVGShapeLayer *)layer
{
if([layer.lineJoin isEqualToString:kCALineJoinBevel]) {
return kCGLineJoinBevel;
} else if([layer.lineJoin isEqualToString:kCALineJoinMiter]) {
return kCGLineJoinMiter;
}
return kCGLineJoinRound;
}
+ (CGLineCap)lineCapFromLayer:(IJSVGShapeLayer *)layer
{
if([layer.lineCap isEqualToString:kCALineCapButt]) {
return kCGLineCapButt;
} else if([layer.lineCap isEqualToString:kCALineCapRound]) {
return kCGLineCapRound;
}
return kCGLineCapSquare;
}
+ (CGRect)findFrameForLayer:(IJSVGLayer *)layer
{
CGRect rect = layer.frame;
return [self _recursivelyFindFrameForLayer:layer
rect:rect];
}
+ (CGRect)_recursivelyFindFrameForLayer:(IJSVGLayer *)layer
rect:(CGRect)rect
{
CGRect frame = layer.frame;
if(CGRectGetMinX(frame) < CGRectGetMinX(rect)) {
rect.origin.x = CGRectGetMinX(frame);
}
if(CGRectGetMinY(frame) < CGRectGetMinY(rect)) {
rect.origin.y = CGRectGetMinY(frame);
}
if(CGRectGetMaxX(frame) > CGRectGetMaxX(rect)) {
rect.size.width = CGRectGetMaxX(frame);
}
if(CGRectGetMaxY(frame) > CGRectGetMaxY(rect)) {
rect.size.height = CGRectGetMaxY(frame);
}
for(IJSVGLayer * sublayer in layer.sublayers) {
rect = [self _recursivelyFindFrameForLayer:sublayer
rect:rect];
}
return rect;
}
- (CGRect)convertLayerFrame:(CGRect)rect
{
rect.size.width = fabs(rect.origin.x - rect.size.width);
rect.size.height = fabs(rect.origin.y - rect.size.height);
rect.origin.x = rect.origin.y = 0.f;
return rect;
}
- (CGImageRef)newImageForLayer:(IJSVGLayer *)layer
colorSpace:(CGColorSpaceRef)colorSpace
proposedRect:(CGRect *)proposedRect
{
// create color space and new context
NSRect cRect = [self.class findFrameForLayer:layer];
NSRect convertedSize = [self convertLayerFrame:cRect];
CGSize size = cRect.size;
*proposedRect = cRect;
CGFloat actualScale = self.scale * self.backingScale;
CGContextRef ctx = CGBitmapContextCreate(NULL, size.width * actualScale,
size.height * actualScale,
8, 0, colorSpace,
kCGImageAlphaPremultipliedLast);
CGContextScaleCTM(ctx, actualScale, actualScale);
// render the layer tree into this context
[self renderLayer:layer
inContext:ctx];
// grab image from it
CGImageRef image = CGBitmapContextCreateImage(ctx);
// clean memory
CGContextRelease(ctx);
return image;
}
- (CGImageRef)newMaskedImageForLayer:(IJSVGLayer *)layer
proposedRect:(CGRect *)proposedRect
{
// create color space and new context
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGImageRef image = [self newImageForLayer:layer
colorSpace:colorSpace
proposedRect:proposedRect];
CGColorSpaceRelease(colorSpace);
return image;
}
@end
+1 -3
View File
@@ -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
+92 -77
View File
@@ -34,48 +34,55 @@
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];
} else {
unit = [IJSVGUnitLength unitWithPercentageFloat:50];
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;
gradient.fx = gradient.cx;
gradient.fy = gradient.cy;
// needs fixing
NSString * fx = [element attributeForName:@"fx"].stringValue;
if(fx != nil) {
if(fx.floatValue < 1.f) {
gradient.fx = [IJSVGUnitLength unitWithPercentageString:fx];
} else {
gradient.fx = [IJSVGUnitLength unitWithString:fx];
}
}
if( gradient.gradient != nil )
NSString * fy = [element attributeForName:@"fy"].stringValue;
if(fx != nil) {
if(fx.floatValue < 1.f) {
gradient.fy = [IJSVGUnitLength unitWithPercentageString:fy];
} else {
gradient.fy = [IJSVGUnitLength unitWithString:fy];
}
}
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];
@@ -86,71 +93,79 @@
return ret;
}
- (CGFloat)_handleTransform:(IJSVGTransform *)transform
bounds:(CGRect)bounds
index:(NSInteger)index
value:(CGFloat)value
- (void)drawInContextRef:(CGContextRef)ctx
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
{
// 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);
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGFloat radius = self.radius.value;
CGPoint startPoint = CGPointZero;
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
// transforms
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
CGContextSaveGState(ctx);
{
#pragma mark User Space On Use
if(inUserSpace == YES) {
CGFloat rad = radius*2.f;
startPoint = CGPointMake(self.cx.value, self.cy.value);
// work out the new radius
CGRect rect = CGRectMake(startPoint.x, startPoint.y, rad, rad);
rect = CGRectApplyAffineTransform(rect, selfTransform);
rect = CGRectApplyAffineTransform(rect, absoluteTransform);
radius = CGRectGetHeight(rect)/2.f;
gradientStartPoint = startPoint;
gradientEndPoint = CGPointMake(self.fx.value, self.fy.value);
// apply the absolute position
CGContextConcatCTM(ctx, absoluteTransform);
} else {
#pragma mark Object Bounding Box
// compute size based on percentages
CGFloat x = [self.cx computeValue:CGRectGetWidth(objectRect)];
CGFloat y = [self.cy computeValue:CGRectGetHeight(objectRect)];
startPoint = CGPointMake(x, y);
CGFloat val = MIN(CGRectGetWidth(objectRect), CGRectGetHeight(objectRect));
radius = [self.radius computeValue:val];
CGFloat ex = [self.fx computeValue:CGRectGetWidth(objectRect)];
CGFloat ey = [self.fy computeValue:CGRectGetHeight(objectRect)];
gradientEndPoint = CGPointMake(ex, ey);
gradientStartPoint = startPoint;
// transform if width or height is not equal
if(CGRectGetWidth(objectRect) != CGRectGetHeight(objectRect)) {
CGAffineTransform tr = CGAffineTransformMakeTranslation(gradientStartPoint.x,
gradientStartPoint.y);
if(CGRectGetWidth(objectRect) > CGRectGetHeight(objectRect)) {
tr = CGAffineTransformScale(tr, CGRectGetWidth(objectRect)/CGRectGetHeight(objectRect), 1);
} else {
tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(objectRect)/CGRectGetWidth(objectRect));
}
break;
tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y);
selfTransform = CGAffineTransformConcat(tr, selfTransform);
}
}
}
return value;
}
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect
{
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]);
}
#pragma mark Default drawing
// transform the context
CGContextConcatCTM(ctx, selfTransform);
CGPoint sp = self.startPoint;
CGPoint ep = self.endPoint;
if( self.startPoint.x == .5f ) {
sp.x = bounds.size.width*self.startPoint.x;
}
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);
// draw the gradient
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation|
kCGGradientDrawsAfterEndLocation;
CGContextDrawRadialGradient(ctx, self.CGGradient,
gradientEndPoint, 0, gradientStartPoint,
radius, options);
};
CGContextRestoreGState(ctx);
}
@end
+1
View File
@@ -25,6 +25,7 @@
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) CGPoint originalPathOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
- (void)applySublayerMaskToContext:(CGContextRef)context
+1
View File
@@ -20,6 +20,7 @@
@synthesize backingScaleFactor;
@synthesize blendingMode;
@synthesize convertMasksToPaths;
@synthesize originalPathOrigin;
- (void)dealloc
{
+12
View File
@@ -9,7 +9,10 @@
#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,
@@ -35,12 +38,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
+66 -1
View File
@@ -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;
@@ -101,8 +146,9 @@
{
NSString * command = [string substringWithRange:[result rangeAtIndex:1]];
IJSVGTransformCommand commandType = [[self class] commandForCommandString:command];
if( commandType == IJSVGTransformCommandNotImplemented )
if( commandType == IJSVGTransformCommandNotImplemented ) {
return;
}
// create the transform
NSString * params = [string substringWithRange:[result rangeAtIndex:2]];
@@ -400,6 +446,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
{
@@ -500,5 +559,11 @@
return trans;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ %@",[super description],
[self.class affineTransformToSVGTransformAttributeString:self.CGAffineTransform]];
}
@end
+6
View File
@@ -18,6 +18,12 @@ CGFloat angle( CGPoint a, CGPoint b );
CGFloat radians_to_degrees( CGFloat radians);
CGFloat degrees_to_radians( CGFloat degrees );
BOOL IJSVGIsCommonHTMLElementName(NSString * str);
NSArray * IJSVGCommonHTMLElementNames();
NSString * IJSVGShortFloatString(CGFloat f);
NSString * IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision);
BOOL IJSVGIsLegalCommandCharacter(unichar aChar);
BOOL IJSVGIsSVGLayer(CALayer * layer);
+ (IJSVGCommandType)typeForCommandString:(NSString *)string;
+166 -1
View File
@@ -12,6 +12,170 @@
@implementation IJSVGUtils
BOOL IJSVGIsCommonHTMLElementName(NSString * str)
{
str = str.lowercaseString;
return [IJSVGCommonHTMLElementNames() containsObject:str];
};
NSArray * IJSVGCommonHTMLElementNames()
{
static NSArray * names = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
names = [@[@"a",
@"abbr",
@"acronym",
@"abbr",
@"address",
@"applet",
@"embed",
@"object",
@"area",
@"article",
@"aside",
@"audio",
@"b",
@"base",
@"basefont",
@"bdi",
@"bdo",
@"big",
@"blockquote",
@"body",
@"br",
@"button",
@"canvas",
@"caption",
@"center",
@"cite",
@"code",
@"col",
@"colgroup",
@"colgroup",
@"datalist",
@"dd",
@"del",
@"details",
@"dfn",
@"dialog",
@"dir",
@"ul",
@"div",
@"dl",
@"dt",
@"em",
@"embed",
@"fieldset",
@"figcaption",
@"figure",
@"figure",
@"font",
@"footer",
@"form",
@"frame",
@"frameset",
@"h1",
@"h6",
@"head",
@"header",
@"hr",
@"html",
@"i",
@"iframe",
@"img",
@"input",
@"ins",
@"kbd",
@"label",
@"input",
@"legend",
@"fieldset",
@"li",
@"link",
@"main",
@"map",
@"mark",
@"menu",
@"menuitem",
@"meta",
@"meter",
@"nav",
@"noframes",
@"noscript",
@"object",
@"ol",
@"optgroup",
@"option",
@"output",
@"p",
@"param",
@"picture",
@"pre",
@"progress",
@"q",
@"rp",
@"rt",
@"ruby",
@"s",
@"samp",
@"script",
@"section",
@"select",
@"small",
@"source",
@"video",
@"audio",
@"span",
@"strike",
@"del",
@"s",
@"strong",
@"style",
@"sub",
@"summary",
@"details",
@"sup",
@"table",
@"tbody",
@"td",
@"template",
@"textarea",
@"tfoot",
@"th",
@"thead",
@"time",
@"title",
@"tr",
@"track",
@"video",
@"audio",
@"tt",
@"u",
@"ul",
@"var",
@"video",
@"wbr"] retain];
});
return names;
};
NSString * IJSVGShortFloatString(CGFloat f)
{
return [NSString stringWithFormat:@"%g",f];
};
NSString * IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision)
{
NSString * format = [NSString stringWithFormat:@"%@.%ld%@",@"%",precision,@"f"];
NSString * ret = [NSString stringWithFormat:format,f];
// can it be reduced even more?
if(ret.floatValue == (float)ret.integerValue) {
ret = [NSString stringWithFormat:@"%ld",ret.integerValue];
}
return ret;
};
BOOL IJSVGIsLegalCommandCharacter(unichar aChar)
{
char * validChars = "MmZzLlHhVvCcSsQqTtAa";
@@ -253,7 +417,6 @@ CGFloat degrees_to_radians( CGFloat degrees )
// sizes for the string buffer
NSInteger defSize = 50;
NSInteger size = defSize;
NSInteger sLength = string.length;
// default memory size for the floats
NSInteger defFloatSize = 100;
@@ -265,6 +428,8 @@ CGFloat degrees_to_radians( CGFloat degrees )
const char * cString = [string cStringUsingEncoding:NSUTF8StringEncoding];
const char * validChars = "0123456789eE+-.";
NSInteger sLength = strlen(cString);
// buffer for the returned floats
CGFloat * floats = (CGFloat *)malloc(sizeof(CGFloat)*defFloatSize);