Compare commits

...

35 Commits

Author SHA1 Message Date
Curtis Hard 399e9271b4 Pretty much working 2019-03-19 21:43:09 +00:00
Curtis Hard f9107094a4 Added IJSVGImageRep 2019-03-15 21:41:03 +00:00
Curtis Hard 7a64c122cf #oops 2019-03-15 09:45:18 +00:00
Curtis Hard 8ee96c4a5b Fixes gradient clipping and masking issues 2019-03-15 09:41:24 +00:00
Curtis Hard 7cace854bd Fixes duplicate colors 2019-03-14 21:37:17 +00:00
Curtis Hard 91cf59bd32 Gradient layer now works out if it can be opaque or not 2019-03-14 20:51:19 +00:00
Curtis Hard b5e15445a5 Added renderingQuality property to IJSVG 2019-03-14 20:11:49 +00:00
Curtis Hard e7577a3e76 Various performance increases
- mainly due to gradients having a party off-screen
2019-03-14 16:50:34 +00:00
Curtis Hard 25b38fa128 Various performance increases 2019-03-13 22:19:30 +00:00
Curtis Hard 8ef14224dd Fixes memory crash 2019-03-11 09:44:39 +00:00
Curtis Hard ebfc31cdb1 Ongoing performance increases 2019-03-10 21:24:45 +00:00
Curtis Hard ccfcfbf228 This fixes fillOpacity not inheriting correctly 2019-03-08 15:43:11 +00:00
Curtis Hard 4fe1d594b0 Some reason, this is not needed on 10.14
- removed for perf reasons, still does if needed, does the check for the OS
2019-03-06 21:38:57 +00:00
Curtis Hard 61d5bb99d5 Swappwd strtod over to strtod_l to use POSIX
- reuses memory instead of malloc every string, massive performance increase
2019-03-02 19:49:36 +00:00
Curtis Hard faccec3e01 Swappted atof with strtod - performs alot better 2019-03-02 14:17:28 +00:00
Curtis Hard 66e9c9000e This improves performance by using a prebuild switch of command classes instead of registering from the command class iteself 2019-03-01 21:45:19 +00:00
Curtis Hard 2006e68c2a Updated for 10.14 2018-12-02 21:52:49 +00:00
Curtis Hard 01aea1129d Added tint color 2018-10-09 15:58:59 +01:00
Curtis Hard 388982d37b Added IJSVGExporterOptionRemoveWidthHeightAttributes option to exporter 2018-08-24 21:55:51 +01:00
Curtis Hard 941130d1f2 Removed DOM discard 2018-06-03 21:27:43 +01:00
Curtis Hard b9e964dc50 Style over attribute order 2018-05-20 22:08:30 +01:00
Curtis Hard 8532819b6a Updated generator 2018-05-07 22:03:00 +01:00
Curtis Hard e576803bb7 Fixes opacity issue, defaults to 1.0 unless specified otherwise 2018-04-30 21:48:01 +01:00
Curtis Hard a6a802a36b Fixes crashes for use elements that cannot find their linked object 2018-04-14 18:41:41 +01:00
Curtis Hard b50963292c Fixes crash with restoring context 2018-03-27 19:16:20 +01:00
Curtis Hard c40c63c48d Fixes compiler error -_- 2018-03-04 13:44:38 +00:00
Curtis Hard 6d21b56416 Fixes nested SVG’s origins 2018-03-02 15:45:07 +00:00
Curtis Hard dbdd8a6971 Removed useless defintion 2018-03-02 15:32:52 +00:00
Curtis Hard b7ba91aa82 Moves frame positions over to transforms 2018-03-02 15:31:41 +00:00
Curtis Hard 98efacf93c Fixes Sub SVG rendering 2018-03-02 14:56:30 +00:00
Curtis Hard 1b3cf5a1a0 Updated Example 2018-03-02 14:12:57 +00:00
Curtis Hard 35f8663631 Gradient stroke SVG 2018-03-02 14:09:50 +00:00
Curtis Hard 6d4eb76803 Squashed commit of the following:
commit ffb55b0f31
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Mar 2 13:28:40 2018 +0000

    Fixes viewBox origin translate

commit a4c032afa2
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 28 21:29:11 2018 +0000

    Added clip to viewport

commit abe8f4cba5
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 28 21:00:20 2018 +0000

    Fixes drawInRect not obeying origin

commit a16842271b
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 26 13:46:41 2018 +0000

    Resolves namespaces correctly + added common HTML list to be parsed as groups

commit 58126e06e4
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 25 21:58:49 2018 +0000

    Fixes!

commit 5af5e054ab
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 22:37:53 2018 +0000

    Fixed defNode being removed

commit edd3aa1f33
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 16:29:54 2018 +0000

    excluded various elements from diff

commit 3366bc4fa5
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 14:05:03 2018 +0000

    Better optimaztion

commit 104002183b
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 22:17:50 2018 +0000

    Added rudimenatry inline styles -> stylesheet

commit 7010b7ea50
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 13:33:32 2018 +0000

    Correct order of cleanup

commit 5266a8c07a
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 08:22:17 2018 +0000

    corrent length of string

commit caf55e8bdf
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 21 20:45:17 2018 +0000

    removes useless def if required

commit 8160d05eba
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Feb 20 14:12:02 2018 +0000

    Refactor of a few methods

commit a6d6a06521
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Feb 20 09:40:21 2018 +0000

    Added collpasing of gradients

commit 103a4d71f6
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 19:07:30 2018 +0000

    Reduced floats even more

commit 98874b1d2c
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 18:53:02 2018 +0000

    More compression goodness

commit e742db31e0
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 14:02:15 2018 +0000

    Added intermediateParent

commit 198fd09f07
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 11:51:37 2018 +0000

    Fixes! and performance increases

commit 3493194b1b
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 08:20:02 2018 +0000

    Scale computation

commit 0016775eaf
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 22:33:26 2018 +0000

    More goodness

commit 304a04cc22
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 22:32:04 2018 +0000

    Vastly improved the exporter

commit e4fd0af582
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 15:20:28 2018 +0000

    This is insanely important!

commit 69a2a0c97e
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 22:02:19 2018 +0000

    Refactor

commit 5299bb0479
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 21:58:21 2018 +0000

    will continue to use CoreAnimation for the time being

commit 4f1943cad1
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 21:57:46 2018 +0000

    Fixes gradient strokes

commit f02d186293
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 11:15:04 2018 +0000

    trying to get masks to work

commit 3291718cfb
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 2 22:35:22 2018 +0000

    Beginning of quartz renderer

commit 6fbaaf5884
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 29 22:32:08 2018 +0000

    Removed useless log

commit abc65797ea
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 29 21:37:45 2018 +0000

    I think gradients work :D

commit af5a1c2718
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 22:18:02 2018 +0000

    Possible fx and fy things…

commit fb9a5282b9
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 19:22:40 2018 +0000

    Even more gradient fixes

commit d83933a103
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 14:21:50 2018 +0000

    Various improvements

commit bd7a0d5021
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 22:26:33 2018 +0000

    Start to linear

commit a9a038568c
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 21:14:25 2018 +0000

    This kind of actually works...

commit 77fbb38b6f
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 20:31:36 2018 +0000

    I guess this could be a good start?

    Posssible start of fixes?

commit 12c3191569
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 15:32:15 2018 +0000

    Added method for findind absolute position

commit e3e9626ef7
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 14:25:03 2018 +0000

    Fixes crash due to parentNode on temp groups being released

commit 1160d89f16
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Jan 26 22:29:22 2018 +0000

    Fixes use statements with transforms

commit 1575cbfde8
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Jan 26 18:16:03 2018 +0000

    Moved color tree over to modern syntax

commit 5c4c2eee91
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Jan 25 18:23:53 2018 +0000

    Added HSL/HSLA support

commit 087b13e58f
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 22:24:43 2018 +0000

    Various image loading issues resolved from base64 images

commit 1183e167aa
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 21:21:41 2018 +0000

    Rect issue fix

commit 4dbfc59437
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 21:19:24 2018 +0000

    Moved transforms over from being concatinated to seperate calls

commit 409bd509fa
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 20:30:38 2018 +0000

    Fixes color issue

commit 8ae1d1b4e0
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 18:41:08 2018 +0000

    Removed check as its not needed here

commit 7243fbe5ff
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 18:35:43 2018 +0000

    Added excludeAttributes list to parseCommonAttributes

    added x and y to that list for rect

commit 51b9a5e85f
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Jan 23 19:53:04 2018 +0000

    Added isSubcommand to IJSVGCommand

    - Fixes move command going awol when preceding move commands are not subcommands (woah)

commit 40098589de
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 22:04:48 2018 +0000

    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 :-))

commit 7cb96b21f2
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 22:01:56 2018 +0000

    Removed use of origin here as its computed in apply defaults

commit 1bff7c6970
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 21:48:07 2018 +0000

    Various fixes… still going…
2018-03-02 13:51:49 +00:00
Curtis Hard 36dae3ad1b Revert "Various fixes… still going…"
This reverts commit 8149293b7b.
2018-01-22 21:48:21 +00:00
Curtis Hard 8149293b7b Various fixes… still going… 2018-01-22 21:48:07 +00:00
67 changed files with 24377 additions and 1128 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,11 @@
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 */; };
59D6C4142049939800F16F13 /* move.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D6C4132049939800F16F13 /* move.svg */; };
59D6C4162049947E00F16F13 /* sprite-1.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D6C4152049947E00F16F13 /* sprite-1.svg */; };
59D6C4182049977E00F16F13 /* fa-brands.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D6C4172049977E00F16F13 /* fa-brands.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 +106,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 +158,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 +178,12 @@
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>"; };
59D6C4132049939800F16F13 /* move.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = move.svg; sourceTree = "<group>"; };
59D6C4152049947E00F16F13 /* sprite-1.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "sprite-1.svg"; sourceTree = "<group>"; };
59D6C4172049977E00F16F13 /* fa-brands.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "fa-brands.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 +321,17 @@
5956657A19B62F4600D805FF /* Supporting Files */ = {
isa = PBXGroup;
children = (
59D6C4172049977E00F16F13 /* fa-brands.svg */,
59D1E39F202279CA00C54672 /* Group.svg */,
590C87F5201FD0D4004A1554 /* car.svg */,
590C87F3201FC9E3004A1554 /* radialgradient2.svg */,
590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */,
590C87EC201FA08C004A1554 /* intertwingly.svg */,
59D6C4152049947E00F16F13 /* sprite-1.svg */,
590C87EE201FA092004A1554 /* NewTux.svg */,
590C87EA201F9888004A1554 /* json.svg */,
5991A2AA201E310200913E3B /* heart.svg */,
5991A2A8201E30E600913E3B /* gradients.svg */,
59265CE71C4F840400F333F0 /* css.svg */,
59459CEB19B906FE00CE493B /* clipped.svg */,
59F799E119B880CE00096CB7 /* htc_one.svg */,
@@ -302,6 +340,7 @@
595665DD19B6309C00D805FF /* test.svg */,
5986308619BA104800CF15EA /* linecap.svg */,
5986308B19BA180E00CF15EA /* dashed.svg */,
59D6C4132049939800F16F13 /* move.svg */,
5956657B19B62F4600D805FF /* Info.plist */,
5956657C19B62F4600D805FF /* main.m */,
5956659A19B62F9500D805FF /* IJSVGExample-Prefix.pch */,
@@ -439,6 +478,8 @@
597046A11E24352700A60138 /* IJSVGStrokeLayer.m */,
59E0F5EB1E29964700F757F7 /* IJSVGUnitLength.h */,
59E0F5EC1E29964700F757F7 /* IJSVGUnitLength.m */,
59D1E39C2022577500C54672 /* IJSVGQuartzRenderer.h */,
59D1E39D2022577500C54672 /* IJSVGQuartzRenderer.m */,
);
name = source;
path = ../../source;
@@ -488,7 +529,7 @@
5956656F19B62F4600D805FF /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = "Curtis Hard";
TargetAttributes = {
5956657619B62F4600D805FF = {
@@ -526,13 +567,25 @@
files = (
59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */,
5956658219B62F4600D805FF /* Images.xcassets in Resources */,
590C87ED201FA08C004A1554 /* intertwingly.svg in Resources */,
59D6C4182049977E00F16F13 /* fa-brands.svg in Resources */,
590C87F1201FBF27004A1554 /* AJ_Digital_Camera.svg in Resources */,
590C87EF201FA093004A1554 /* NewTux.svg in Resources */,
59D6C4162049947E00F16F13 /* sprite-1.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 */,
59D6C4142049939800F16F13 /* move.svg in Resources */,
5991A2AB201E310200913E3B /* heart.svg in Resources */,
5986308C19BA180E00CF15EA /* dashed.svg in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -555,6 +608,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,19 @@
<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"/>
<rect key="frame" x="0.0" y="0.0" width="600" height="479"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</customView>
</subviews>
</view>
<point key="canvasLocation" x="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

+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="447px" height="336px" viewBox="0 0 447 336" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>Rectangle</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#1E54F6" offset="0%"></stop>
<stop stop-color="#EE2323" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="0" width="447" height="336"></rect>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Rectangle">
<use fill="#D8D8D8" fill-rule="evenodd" xlink:href="#path-2"></use>
<rect stroke="url(#linearGradient-1)" stroke-width="10" x="5" y="5" width="437" height="326"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 992 B

+1 -1
View File
@@ -12,7 +12,7 @@
- (IJSVG *)svg
{
return [[IJSVG svgNamed:@"paperplane"] retain];
return [[IJSVG svgNamed:@"heart"] retain];
}
@end
+1 -2
View File
@@ -11,10 +11,9 @@
@interface SVGView : NSView {
@private
IJSVG * svg;
}
@end
+3 -2
View File
@@ -22,8 +22,9 @@
if( ( self = [super initWithFrame:frameRect] ) != nil )
{
svg = [self svg];
svg.renderQuality = IJSVGRenderQualityLow;
svg.renderingBackingScaleHelper = ^{
return [svg computeBackingScale:self.window.backingScaleFactor];
return self.window.backingScaleFactor;
};
}
return self;
@@ -31,7 +32,7 @@
- (IJSVG *)svg
{
return [IJSVG svgNamed:@"test"];
return [IJSVG svgNamed:@"car"];
}
- (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

+8 -2
View File
@@ -13,8 +13,10 @@
#import "IJSVGGroupLayer.h"
#import "IJSVGImageLayer.h"
#import "IJSVGExporter.h"
#import "IJSVGRendering.h"
@class IJSVG;
@class IJSVGQuartzRenderer;
void IJSVGBeginTransactionLock();
void IJSVGEndTransactionLock();
@@ -34,8 +36,6 @@ withSVGString:(NSString *)subSVGString;
@end
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
@private
@@ -47,7 +47,10 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
CGRect _viewBox;
CGSize _proposedViewSize;
CGFloat _lastProposedBackingScale;
IJSVGRenderQuality _lastProposedRenderQuality;
CGFloat _backingScale;
NSMutableDictionary * _replacementColors;
IJSVGQuartzRenderer * _quartzRenderer;
struct {
unsigned int shouldHandleForeignObject: 1;
@@ -70,9 +73,12 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle;
@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) BOOL clipToViewport;
- (void)prepForDrawingInView:(NSView *)view;
- (BOOL)isFont;
- (IJSVGGroup *)rootNode;
- (NSRect)viewBox;
- (NSArray<IJSVGPath *> *)glyphs;
- (NSString *)identifier;
+80 -46
View File
@@ -19,16 +19,21 @@
@synthesize lineCapStyle;
@synthesize lineJoinStyle;
@synthesize renderingBackingScaleHelper;
@synthesize clipToViewport;
@synthesize renderQuality;
- (void)dealloc
{
IJSVGBeginTransactionLock();
[renderingBackingScaleHelper release], renderingBackingScaleHelper = nil;
[fillColor release], fillColor = nil;
[strokeColor release], strokeColor = nil;
[_group release], _group = nil;
[_layerTree release], _layerTree = nil;
[_replacementColors release], _replacementColors = nil;
[_quartzRenderer release], _quartzRenderer = nil;
[super dealloc];
IJSVGEndTransactionLock();
}
+ (id)svgNamed:(NSString *)string
@@ -333,7 +338,14 @@
- (void)_setupBasicsFromAnyInitializer
{
_lastProposedBackingScale = 1.f;
self.clipToViewport = YES;
self.renderQuality = IJSVGRenderQualityOptimized;
// setup low level backing scale
_lastProposedBackingScale = 0.f;
self.renderingBackingScaleHelper = ^CGFloat{
return 1.f;
};
}
- (NSString *)identifier
@@ -353,6 +365,11 @@
return _viewBox;
}
- (IJSVGGroup *)rootNode
{
return _group;
}
- (BOOL)isFont
{
return [_group isFont];
@@ -405,7 +422,7 @@
{
NSImage * im = [[[NSImage alloc] initWithSize:aSize] autorelease];
[im lockFocus];
CGContextRef ref = [[NSGraphicsContext currentContext] graphicsPort];
CGContextRef ref = [[NSGraphicsContext currentContext] CGContext];
CGContextSaveGState(ref);
if(flipped) {
CGContextTranslateCTM(ref, 0.f, aSize.height);
@@ -551,12 +568,13 @@
error:(NSError **)error
{
return [self _drawInRect:rect
context:[[NSGraphicsContext currentContext] graphicsPort]
context:[[NSGraphicsContext currentContext] CGContext]
error:error];
}
- (CGFloat)computeBackingScale:(CGFloat)actualScale
{
_backingScale = actualScale;
return (CGFloat)(_scale + actualScale);
}
@@ -566,8 +584,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;
@@ -605,62 +623,71 @@
@synchronized (self) {
CGContextSaveGState(ref);
@try {
[self _beginDraw:rect];
// scale the whole drawing context, but first, we need
// to translate the context so its centered
CGFloat tX = round(rect.size.width/2-(_viewBox.size.width/2)*_scale);
CGFloat tY = round(rect.size.height/2-(_viewBox.size.height/2)*_scale);
// we also need to calculate the viewport so we can clip
// the drawing if needed
BOOL canDraw = NO;
NSRect viewPort = [self computeRectDrawingInRect:rect
isValid:&canDraw];
NSRect viewPort = [self computeRectDrawingInRect:rect isValid:&canDraw];
// check the viewport
if( !canDraw ) {
if( canDraw == NO ) {
if( error != NULL ) {
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
code:IJSVGErrorDrawing
userInfo:nil] autorelease];
}
CGContextRestoreGState(ref);
return NO;
} else {
// clip to mask
if(self.clipToViewport == YES) {
CGContextClipToRect( ref, viewPort);
}
// add the origin back onto the viewport
viewPort.origin.x -= round((_viewBox.origin.x)*_scale);
viewPort.origin.y -= round((_viewBox.origin.y)*_scale);
viewPort = CGRectIntegral(viewPort);
// transforms
CGContextTranslateCTM( ref, viewPort.origin.x, viewPort.origin.y);
CGContextScaleCTM( ref, _scale, _scale );
// render the layer, its really important we lock
// the transaction when drawing
IJSVGBeginTransactionLock();
// do we need to update the backing scales on the
// layers?
if(self.renderingBackingScaleHelper != nil) {
[self _askHelperForBackingScale];
}
CGInterpolationQuality quality;
switch(self.renderQuality) {
case IJSVGRenderQualityLow: {
quality = kCGInterpolationLow;
break;
}
case IJSVGRenderQualityOptimized: {
quality = kCGInterpolationMedium;
break;
}
default: {
quality = kCGInterpolationHigh;
}
}
CGContextSetInterpolationQuality(ref, quality);
[self.layer renderInContext:ref];
IJSVGEndTransactionLock();
}
// clip to mask
CGContextClipToRect( ref, viewPort);
tX -= (_viewBox.origin.x*_scale);
tY -= (_viewBox.origin.y*_scale);
CGContextTranslateCTM( ref, tX, tY );
CGContextScaleCTM( ref, _scale, _scale );
// render the layer, its really important we lock
// the transaction when drawing
IJSVGBeginTransactionLock();
// do we need to update the backing scales on the
// layers?
if(self.renderingBackingScaleHelper != nil) {
[self _askHelperForBackingScale];
}
// render the layers
[self.layer renderInContext:ref];
IJSVGEndTransactionLock();
}
@catch (NSException *exception) {
// just catch and give back a drawing error to the caller
if( error != NULL )
if( error != NULL ) {
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
code:IJSVGErrorDrawing
userInfo:nil] autorelease];
}
}
@finally {
CGContextRestoreGState(ref);
}
CGContextRestoreGState(ref);
}
return (error == nil);
}
@@ -674,15 +701,20 @@
// dont do anything, nothing has changed, no point of iterating over
// every layer for no reason!
if(scale == _lastProposedBackingScale) {
if(scale == _lastProposedBackingScale && renderQuality == _lastProposedRenderQuality) {
return;
}
IJSVGRenderQuality quality = self.renderQuality;
_lastProposedBackingScale = scale;
_lastProposedRenderQuality = quality;
// 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);
propLayer.renderQuality = quality;
if(propLayer.requiresBackingScaleHelp == YES) {
propLayer.backingScaleFactor = scale;
}
};
@@ -770,17 +802,19 @@
// block to find colors in stroke and fill
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
if([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO) {
if([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO && layer.isHidden == NO) {
IJSVGShapeLayer * sLayer = (IJSVGShapeLayer *)layer;
NSColor * color = nil;
if(sLayer.fillColor != nil) {
color = [NSColor colorWithCGColor:sLayer.fillColor];
color = [IJSVGColor computeColorSpace:color];
if(color.alphaComponent != 0.f) {
[colors addObject:color];
}
}
if(sLayer.strokeColor != nil) {
color = [NSColor colorWithCGColor:sLayer.strokeColor];
color = [IJSVGColor computeColorSpace:color];
if(color.alphaComponent != 0.f) {
[colors addObject:color];
}
+5 -1
View File
@@ -160,12 +160,16 @@ 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 *)colorFromHEXInteger:(NSInteger)hex;
+ (NSColor *)computeColor:(id)colour;
+ (NSColor *)colorFromString:(NSString *)string;
+ (NSColor *)colorFromHEXString:(NSString *)string
+245 -185
View File
@@ -11,12 +11,31 @@
@implementation IJSVGColor
static NSMutableDictionary * _colorTree = nil;
static NSDictionary * _colorTree = nil;
CGFloat * IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness)
{
hue *= (1.f/360.f);
hue = (hue - floorf(hue));
saturation *= 0.01;
lightness *= 0.01;
lightness *= 2.f;
CGFloat s = saturation * ((lightness < 1.f) ? lightness : (2.f - lightness));
CGFloat brightness = (lightness + s) * .5f;
if(s != 0.f) {
s = (2.f * s) / (lightness + s);
}
CGFloat * floats = (CGFloat *)malloc(3*sizeof(CGFloat));
floats[0] = hue;
floats[1] = s;
floats[2] = brightness;
return floats;
};
+ (void)load
{
[[self class] _generateTree];
[self.class _generateTree];
}
+ (NSColorSpace *)defaultColorSpace
@@ -37,157 +56,153 @@ 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":@(0xf0f8ff),
@"antiquewhite":@(0xfaebd7),
@"aqua":@(0x00ffff),
@"aquamarine":@(0x7fffd4),
@"azure":@(0xf0ffff),
@"beige":@(0xf5f5dc),
@"bisque":@(0xffe4c4),
@"black":@(0x000000),
@"blanchedalmond":@(0xffebcd),
@"blue":@(0x0000ff),
@"blueviolet":@(0x8a2be2),
@"brown":@(0xa52a2a),
@"burlywood":@(0xdeb887),
@"cadetblue":@(0x5f9ea0),
@"chartreuse":@(0x7fff00),
@"chocolate":@(0xd2691e),
@"coral":@(0xff7f50),
@"cornflowerblue":@(0x6495ed),
@"cornsilk":@(0xfff8dc),
@"crimson":@(0xdc143c),
@"currentcolor":@(0x000000),
@"cyan":@(0x00ffff),
@"darkblue":@(0x00008b),
@"darkcyan":@(0x008b8b),
@"darkgoldenrod":@(0xb8860b),
@"darkgray":@(0xa9a9a9),
@"darkgreen":@(0x006400),
@"darkgrey":@(0xa9a9a9),
@"darkkhaki":@(0xbdb76b),
@"darkmagenta":@(0x8b008b),
@"darkolivegreen":@(0x556b2f),
@"darkorange":@(0xff8c00),
@"darkorchid":@(0x9932cc),
@"darkred":@(0x8b0000),
@"darksalmon":@(0xe9967a),
@"darkseagreen":@(0x8fbc8f),
@"darkslateblue":@(0x483d8b),
@"darkslategray":@(0x2f4f4f),
@"darkturquoise":@(0x00ced1),
@"darkviolet":@(0x9400d3),
@"deeppink":@(0xff1493),
@"deepskyblue":@(0x00bfff),
@"dimgray":@(0x696969),
@"dimgrey":@(0x696969),
@"dodgerblue":@(0x1e90ff),
@"firebrick":@(0xb22222),
@"floralwhite":@(0xfffaf0),
@"forestgreen":@(0x228b22),
@"fuchsia":@(0xff00ff),
@"gainsboro":@(0xdcdcdc),
@"ghostwhite":@(0xf8f8ff),
@"gold":@(0xffd700),
@"goldenrod":@(0xdaa520),
@"gray":@(0x808080),
@"green":@(0x008000),
@"greenyellow":@(0xadff2f),
@"grey":@(0x808080),
@"honeydew":@(0xf0fff0),
@"hotpink":@(0xff69b4),
@"indianred":@(0xcd5c5c),
@"indigo":@(0x4b0082),
@"ivory":@(0xfffff0),
@"khaki":@(0xf0e68c),
@"lavender":@(0xe6e6fa),
@"lavenderblush":@(0xfff0f5),
@"lawngreen":@(0x7cfc00),
@"lemonchiffon":@(0xfffacd),
@"lightblue":@(0xadd8e6),
@"lightcoral":@(0xf08080),
@"lightcyan":@(0xe0ffff),
@"lightgoldenrodyellow":@(0xfafad2),
@"lightgray":@(0xd3d3d3),
@"lightgreen":@(0x90ee90),
@"lightgrey":@(0xd3d3d3),
@"lightpink":@(0xffb6c1),
@"lightsalmon":@(0xffa07a),
@"lightseagreen":@(0x20b2aa),
@"lightskyblue":@(0x87cefa),
@"lightslategray":@(0x778899),
@"lightsteelblue":@(0xb0c4de),
@"lightyellow":@(0xffffe0),
@"lime":@(0x00ff00),
@"limegreen":@(0x32cd32),
@"linen":@(0xfaf0e6),
@"magenta":@(0xff00ff),
@"maroon":@(0x800000),
@"mediumaquamarine":@(0x66cdaa),
@"mediumblue":@(0x0000cd),
@"mediumorchid":@(0xba55d3),
@"mediumpurple":@(0x9370db),
@"mediumseagreen":@(0x3cb371),
@"mediumslateblue":@(0x7b68ee),
@"mediumspringgreen":@(0x00fa9a),
@"mediumturquoise":@(0x48d1cc),
@"mediumvioletred":@(0xc71585),
@"midnightblue":@(0x191970),
@"mintcream":@(0xf5fffa),
@"mistyrose":@(0xffe4e1),
@"moccasin":@(0xffe4b5),
@"navajowhite":@(0xffdead),
@"navy":@(0x000080),
@"oldlace":@(0xfdf5e6),
@"olive":@(0x808000),
@"olivedrab":@(0x6b8e23),
@"orange":@(0xffa500),
@"orangered":@(0xff4500),
@"orchid":@(0xda70d6),
@"palegoldenrod":@(0xeee8aa),
@"palegreen":@(0x98fb98),
@"paleturquoise":@(0xafeeee),
@"palevioletred":@(0xdb7093),
@"papayawhip":@(0xffefd5),
@"peachpuff":@(0xffdab9),
@"peru":@(0xcd853f),
@"pink":@(0xffc0cb),
@"plum":@(0xdda0dd),
@"powderblue":@(0xb0e0e6),
@"purple":@(0x800080),
@"red":@(0xff0000),
@"rosybrown":@(0xbc8f8f),
@"royalblue":@(0x4169e1),
@"saddlebrown":@(0x8b4513),
@"salmon":@(0xfa8072),
@"sandybrown":@(0xf4a460),
@"seagreen":@(0x2e8b57),
@"seashell":@(0xfff5ee),
@"sienna":@(0xa0522d),
@"silver":@(0xc0c0c0),
@"skyblue":@(0x87ceeb),
@"slateblue":@(0x6a5acd),
@"slategrey":@(0x708090),
@"snow":@(0xfffafa),
@"springgreen":@(0x00ff7f),
@"steelblue":@(0x4682b4),
@"tan":@(0xd2b48c),
@"teal":@(0x008080),
@"thistle":@(0xd8bfd8),
@"tomato":@(0xff6347),
@"turquoise":@(0x40e0d0),
@"violet":@(0xee82ee),
@"wheat":@(0xf5deb3),
@"white":@(0xffffff),
@"whitesmoke":@(0xf5f5f5),
@"yellow":@(0xffff00),
@"yellowgreen":@(0x9acd32)
} retain];
});
}
@@ -207,10 +222,13 @@ static NSMutableDictionary * _colorTree = nil;
return nil;
}
NSColor * color = nil;
string = [string lowercaseString];
NSColor * color = [[self class] colorFromPredefinedColorName:string];
if( color != nil ) {
return color;
if([self.class isHex:string] == NO) {
color = [self.class colorFromPredefinedColorName:string];
if( color != nil ) {
return color;
}
}
if( [[string lowercaseString] isEqualToString:@"none"] ) {
@@ -226,37 +244,61 @@ 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;
}
color = [[self class] colorFromHEXString:string
alpha:1.f];
// 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;
}
+ (NSColor *)colorFromPredefinedColorName:(NSString *)name
{
NSString * hex = nil;
NSNumber * hex = nil;
name = [name.lowercaseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if( ( hex = [_colorTree objectForKey:name] ) == nil )
if((hex = _colorTree[name]) == nil ) {
return nil;
return [[self class] colorFromHEXString:hex
alpha:1.f];
}
return [self.class colorFromHEXInteger:hex.integerValue];
}
+ (NSString *)colorStringFromColor:(NSColor *)color
{
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 +317,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)];
}
@@ -598,20 +650,35 @@ static NSMutableDictionary * _colorTree = nil;
+ (BOOL)isColor:(NSString *)string
{
return [[string substringToIndex:1] isEqualToString:@"#"] || [[string substringToIndex:3] isEqualToString:@"rgb"];
return [[string substringToIndex:1] isEqualToString:@"#"] ||
[[string substringToIndex:3] isEqualToString:@"rgb"];
}
+ (BOOL)isHex:(NSString *)string
{
NSCharacterSet *chars = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef#"] invertedSet];
return [string rangeOfCharacterFromSet:chars].location == NSNotFound;
const char * validList = "0123456789ABCDEFabcdef#";
for(NSInteger i = 0; i < string.length; i++) {
char c = [string characterAtIndex:i];
if(strchr(validList, c) == NULL) {
return NO;
}
}
return YES;
}
+ (NSColor *)colorFromHEXInteger:(NSInteger)hex
{
return [NSColor colorWithDeviceRed:((hex >> 16) & 0xFF) / 255.f
green:((hex >> 6) & 0xFF) / 255.f
blue:(hex & 0xFF) / 255.f
alpha:1.f];
}
+ (NSColor *)colorFromHEXString:(NSString *)string
alpha:(CGFloat)alpha
{
// absolutely no string
if( string == nil || string.length == 0 || ![[self class] isHex:string] )
if( string == nil || string.length == 0 || ![self.class isHex:string] )
return nil;
if( [[string substringToIndex:1] isEqualToString:@"#"] )
@@ -629,19 +696,12 @@ static NSMutableDictionary * _colorTree = nil;
string = str;
}
NSScanner * scanner = [NSScanner scannerWithString:string];
unsigned int hex;
if( [scanner scanHexInt:&hex] )
{
NSInteger r = (hex>>16) & 0xFF;
NSInteger g = (hex>>8) & 0xFF;
NSInteger b = (hex) & 0xFF;
return [NSColor colorWithDeviceRed:r/255.f
green:g/255.f
blue:b/255.f
alpha:alpha];
}
return nil;
const char * hexString = [string cStringUsingEncoding:NSUTF8StringEncoding];
unsigned long hex = strtoul(hexString, NULL, 16);
return [NSColor colorWithDeviceRed:((hex>>16) & 0xFF)/255.f
green:((hex>>8) & 0xFF)/255.f
blue:(hex & 0xFF)/255.f
alpha:alpha];
}
@end
+2 -5
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,17 +53,13 @@ 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;
+ (NSPoint)readCoordinatePair:(CGFloat *)pairs
index:(NSInteger)index;
+ (void)registerClass:(Class)aClass
forCommand:(NSString *)command;
+ (NSDictionary *)registeredCommandClasses;
+ (Class<IJSVGCommandProtocol>)commandClassForCommandLetter:(NSString *)str;
- (CGFloat)readFloat;
- (NSPoint)readPoint;
- (BOOL)readBOOL;
+32 -26
View File
@@ -9,6 +9,17 @@
#import "IJSVGCommand.h"
#import "IJSVGUtils.h"
#import "IJSVGCommandArc.h"
#import "IJSVGCommandMove.h"
#import "IJSVGCommandClose.h"
#import "IJSVGCommandCurve.h"
#import "IJSVGCommandLineTo.h"
#import "IJSVGCommandVerticalLine.h"
#import "IJSVGCommandHorizontalLine.h"
#import "IJSVGCommandSmoothCurve.h"
#import "IJSVGCommandQuadraticCurve.h"
#import "IJSVGCommandCommandSmoothQuadraticCurve.h"
@implementation IJSVGCommand
@synthesize commandString;
@@ -20,8 +31,7 @@
@synthesize requiredParameters;
@synthesize type;
@synthesize previousCommand;
static NSMutableDictionary * _classes = nil;
@synthesize isSubCommand;
- (void)dealloc
{
@@ -38,10 +48,9 @@ static NSMutableDictionary * _classes = nil;
{
// work out the basics
_currentIndex = 0;
subCommands = [[NSMutableArray alloc] init];
command = [[str substringToIndex:1] copy];
type = [IJSVGUtils typeForCommandString:self.command];
commandClass = [[self class] commandClassForCommandLetter:self.command];
commandClass = [[self class] commandClassForCommandChar:[self.command characterAtIndex:0]];
parameters = [IJSVGUtils commandParameters:str count:&parameterCount];
requiredParameters = [self.commandClass requiredParameterCount];
@@ -54,6 +63,8 @@ static NSMutableDictionary * _classes = nil;
sets = self.parameterCount/self.requiredParameters;
}
subCommands = [[NSMutableArray alloc] initWithCapacity:sets];
// interate over the sets
for( NSInteger i = 0; i < sets; i++ ) {
// memory for this will be handled by the created subcommand
@@ -71,8 +82,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];
@@ -87,33 +99,27 @@ static NSMutableDictionary * _classes = nil;
return NSMakePoint( pairs[index*2], pairs[index*2+1]);
}
+ (void)registerClass:(Class)aClass
forCommand:(NSString *)command
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_classes = [[NSMutableDictionary alloc] init];
});
[_classes setObject:NSStringFromClass(aClass)
forKey:command];
}
+ (NSDictionary *)registeredCommandClasses
{
return _classes;
}
+ (void)load
{
// register here...
}
+ (Class<IJSVGCommandProtocol>)commandClassForCommandLetter:(NSString *)str
+ (Class<IJSVGCommandProtocol>)commandClassForCommandChar:(char)aChar
{
NSString * command = nil;
if( ( command = [_classes objectForKey:[str lowercaseString]] ) == nil )
return nil;
return NSClassFromString(command);
aChar = tolower(aChar);
switch(aChar) {
case 'a': return IJSVGCommandArc.class;
case 'c': return IJSVGCommandCurve.class;
case 'h': return IJSVGCommandHorizontalLine.class;
case 'l': return IJSVGCommandLineTo.class;
case 'm': return IJSVGCommandMove.class;
case 'q': return IJSVGCommandQuadraticCurve.class;
case 's': return IJSVGCommandSmoothCurve.class;
case 't': return IJSVGCommandCommandSmoothQuadraticCurve.class;
case 'v': return IJSVGCommandVerticalLine.class;
case 'z': return IJSVGCommandClose.class;
}
return nil;
}
- (CGFloat)readFloat
+16 -15
View File
@@ -11,11 +11,6 @@
@implementation IJSVGCommandArc
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"a"];
}
+ (NSInteger)requiredParameterCount
{
@@ -29,10 +24,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 +37,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 +73,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 +95,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
-6
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandClose
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"z"];
}
+ (NSInteger)requiredParameterCount
{
return 0;
@@ -12,12 +12,6 @@
@implementation IJSVGCommandCommandSmoothQuadraticCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"t"];
}
+ (NSInteger)requiredParameterCount
{
return 2;
+4 -12
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"c"];
}
+ (NSInteger)requiredParameterCount
{
return 6;
@@ -28,17 +22,15 @@
type:(IJSVGCommandType)type
path:(IJSVGPath *)path
{
if( type == IJSVGCommandTypeAbsolute )
{
if( type == IJSVGCommandTypeAbsolute ) {
[[path currentSubpath] curveToPoint:NSMakePoint( params[4], params[5])
controlPoint1:NSMakePoint( params[0], params[1])
controlPoint2:NSMakePoint( params[2], params[3])];
return;
}
NSPoint point = [[path currentSubpath] currentPoint];
[[path currentSubpath] curveToPoint:NSMakePoint( point.x + params[4], point.y + params[5])
controlPoint1:NSMakePoint( point.x + params[0], point.y + params[1])
controlPoint2:NSMakePoint( point.x + params[2], point.y + params[3])];
[[path currentSubpath] relativeCurveToPoint:NSMakePoint( params[4], params[5])
controlPoint1:NSMakePoint( params[0], params[1])
controlPoint2:NSMakePoint( params[2], params[3])];
}
-6
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandHorizontalLine
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"h"];
}
+ (NSInteger)requiredParameterCount
{
return 1;
+2 -9
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandLineTo
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"l"];
}
+ (NSInteger)requiredParameterCount
{
return 2;
@@ -28,12 +22,11 @@
type:(IJSVGCommandType)type
path:(IJSVGPath *)path
{
if( type == IJSVGCommandTypeAbsolute )
{
if( type == IJSVGCommandTypeAbsolute ) {
[[path currentSubpath] lineToPoint:NSMakePoint( params[0], params[1])];
return;
}
NSPoint point = NSMakePoint( [path currentSubpath].currentPoint.x + params[0],
NSPoint point = NSMakePoint([path currentSubpath].currentPoint.x + params[0],
[path currentSubpath].currentPoint.y + params[1]);
[[path currentSubpath] lineToPoint:point];
}
+2 -10
View File
@@ -12,12 +12,6 @@
@implementation IJSVGCommandMove
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"m"];
}
+ (NSInteger)requiredParameterCount
{
return 2;
@@ -32,8 +26,7 @@
{
// move to's allow more then one move to, but if there are more then one,
// we need to run the line to instead...who knew!
if( command.commandClass == [self class])
{
if( command.commandClass == [self class] && currentCommand.isSubCommand == YES) {
[IJSVGCommandLineTo runWithParams:params
paramCount:count
command:currentCommand
@@ -44,8 +37,7 @@
}
// actual move to command
if( type == IJSVGCommandTypeAbsolute )
{
if( type == IJSVGCommandTypeAbsolute ) {
[[path currentSubpath] moveToPoint:NSMakePoint( params[0], params[1])];
return;
}
-6
View File
@@ -11,12 +11,6 @@
@implementation IJSVGCommandQuadraticCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"q"];
}
+ (NSInteger)requiredParameterCount
{
return 4;
-6
View File
@@ -12,12 +12,6 @@
@implementation IJSVGCommandSmoothCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"s"];
}
+ (NSInteger)requiredParameterCount
{
return 4;
-6
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandVerticalLine
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"v"];
}
+ (NSInteger)requiredParameterCount
{
return 1;
+8 -7
View File
@@ -26,6 +26,9 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
IJSVGExporterOptionRemoveHiddenElements = 1 << 8,
IJSVGExporterOptionScaleToSizeIfNecessary = 1 << 9,
IJSVGExporterOptionCompressOutput = 1 << 10,
IJSVGExporterOptionCollapseGradients = 1 << 11,
IJSVGExporterOptionCreateClasses = 1 << 12,
IJSVGExporterOptionRemoveWidthHeightAttributes = 1 << 13,
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef|
IJSVGExporterOptionRemoveUselessGroups|
IJSVGExporterOptionCreateUseForPaths|
@@ -35,7 +38,9 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
IJSVGExporterOptionCleanupPaths|
IJSVGExporterOptionRemoveHiddenElements|
IJSVGExporterOptionScaleToSizeIfNecessary|
IJSVGExporterOptionCompressOutput
IJSVGExporterOptionCompressOutput|
IJSVGExporterOptionCollapseGradients|
IJSVGExporterOptionRemoveWidthHeightAttributes
};
@interface IJSVGExporter : NSObject {
@@ -46,13 +51,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;
+335 -218
View File
@@ -26,61 +26,74 @@
#define XML_DOC_NSXLINK @"http://www.w3.org/1999/xlink"
#define XML_DOCTYPE_VERSION @"1.0"
#define XML_DOC_CHARSET @"UTF-8"
#define XML_DOC_GENERATOR @"Generated by IJSVG (https://github.com/curthard89/IJSVG)"
#define XML_DOC_GENERATOR @"Generated by IJSVG (https://github.com/iconjar/IJSVG)"
@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,19 @@ 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
};
// add on width and height unless specified otherwise
if((_options & IJSVGExporterOptionRemoveWidthHeightAttributes) == 0) {
NSMutableDictionary * attDict = [[attributes mutableCopy] autorelease];
attDict[@"width"] = IJSVGShortFloatString(_size.width);
attDict[@"height"] = IJSVGShortFloatString(_size.height);
attributes = [[attDict copy] autorelease];
}
// was there a size set?
if(CGSizeEqualToSize(CGSizeZero, _size) == NO &&
@@ -219,6 +235,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 +255,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 +301,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 +320,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 +397,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 +530,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 +606,7 @@ NSString * IJSVGHash(NSString * key) {
[(NSXMLElement *)n.parent removeChildAtIndex:n.index];
}
}
}
- (void)_collapseGroups
@@ -486,11 +614,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 +628,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 +708,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 +779,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 +813,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 +841,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 +888,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 +946,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 +976,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 +987,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 +1007,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 +1041,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 +1108,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 +1116,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 +1161,7 @@ NSString * IJSVGHash(NSString * key) {
}
}
// apply the attributes
IJSVGApplyAttributesToElement(dict, e);
@@ -1062,7 +1178,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 +1227,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 +1345,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
+62 -1
View File
@@ -10,7 +10,10 @@
@implementation IJSVGGradientLayer
@synthesize viewBox;
@synthesize gradient;
@synthesize absoluteTransform;
@synthesize objectRect;
- (void)dealloc
{
@@ -22,10 +25,60 @@
{
if((self = [super init]) != nil) {
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
}
return self;
}
- (void)setGradient:(IJSVGGradient *)newGradient
{
if(gradient != nil) {
[gradient release], gradient = nil;
}
gradient = [newGradient retain];
// lets check its alpha properties on the colors
BOOL hasAlphaChannel = NO;
NSInteger stops = gradient.gradient.numberOfColorStops;
for(NSInteger i = 0; i < stops; i++) {
NSColor * color = nil;
[gradient.gradient getColor:&color
location:NULL
atIndex:i];
if(color.alphaComponent != 1.f) {
hasAlphaChannel = YES;
break;
}
}
self.opaque = hasAlphaChannel == NO;
}
- (void)setOpacity:(float)opacity
{
if(opacity != 1.f) {
self.opaque = NO;
}
[super setOpacity:opacity];
}
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
switch (self.renderQuality) {
case IJSVGRenderQualityOptimized: {
backingScaleFactor = .35f;
break;
}
case IJSVGRenderQualityLow: {
backingScaleFactor = .05f;
break;
}
default: {
break;
}
}
[super setBackingScaleFactor:backingScaleFactor];
}
- (void)drawInContext:(CGContextRef)ctx
{
[super drawInContext:ctx];
@@ -36,7 +89,15 @@
}
// draw the gradient
[self.gradient drawInContextRef:ctx rect:self.bounds];
CGAffineTransform trans = CGAffineTransformMakeTranslation(-CGRectGetMinX(objectRect),
-CGRectGetMinY(objectRect));
CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform,trans);
CGContextSaveGState(ctx);
[self.gradient drawInContextRef:ctx
objectRect:objectRect
absoluteTransform:transform
viewPort:self.viewBox];
CGContextRestoreGState(ctx);
}
@end
+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;
}
+13 -2
View File
@@ -30,15 +30,26 @@
// make sure we say we need help
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
// set the frame, simple stuff
self.frame = (CGRect){
.origin = CGPointZero,
.size = CGSizeMake( CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef))
.size = CGSizeMake(CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef))
};
}
return self;
}
- (void)setNeedsDisplay
{
// swap the content around on call
// because set needs display discards previous
// content - yolo!
id oldContent = self.contents;
[super setNeedsDisplay];
self.contents = oldContent;
}
@end
+22
View File
@@ -0,0 +1,22 @@
//
// IJSVGImageRep.h
// IJSVGExample
//
// Created by Curtis Hard on 15/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "IJSVGParser.h"
@class IJSVG;
@interface IJSVGImageRep : NSImageRep {
@private
IJSVG * _svg;
}
@property (nonatomic, readonly) CGRect viewBox;
@end
+104
View File
@@ -0,0 +1,104 @@
//
// IJSVGImageRep.m
// IJSVGExample
//
// Created by Curtis Hard on 15/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGImageRep.h"
#import "IJSVG.h"
@implementation IJSVGImageRep
@synthesize viewBox = _viewBox;
+ (void)load
{
[NSBitmapImageRep registerImageRepClass:self];
}
+ (BOOL)canInitWithData:(NSData *)data
{
return [IJSVGParser isDataSVG:data];
}
+ (NSArray<NSString *> *)imageTypes
{
return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"];
}
+ (NSArray<NSString *> *)imageUnfilteredTypes
{
return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"];
}
+ (NSArray<NSImageRep *> *)imageRepsWithData:(NSData *)data
{
IJSVGImageRep * instance = [self imageRepWithData:data];
if(instance == nil) {
return @[];
}
return @[instance];
}
+ (instancetype)imageRepWithData:(NSData *)data
{
return [[self alloc] initWithData:data];
}
- (void)dealloc
{
[_svg release], _svg = nil;
[super dealloc];
}
- (instancetype)initWithData:(NSData *)data
{
if((self = [super init]) != nil) {
// grab the string from the data
// its more then likely UTF-8...
NSString * string = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];
_svg = [[IJSVG alloc] initWithSVGString:string];
// no valid SVG, just return nil;
if(_svg == nil) {
[self release];
return nil;
}
// set default properties
self.pixelsWide = _svg.viewBox.size.width;
self.pixelsHigh = _svg.viewBox.size.height;
self.size = _svg.viewBox.size;
}
return self;
}
- (BOOL)draw
{
[_svg drawInRect:self.viewBox];
return YES;
}
- (BOOL)drawAtPoint:(NSPoint)point
{
[_svg drawAtPoint:point
size:_svg.viewBox.size];
return YES;
}
- (BOOL)drawInRect:(NSRect)rect
{
[_svg drawInRect:rect];
return YES;
}
- (CGRect)viewBox
{
return _svg.viewBox;
}
@end
+2
View File
@@ -8,6 +8,7 @@
#import <QuartzCore/QuartzCore.h>
#import "IJSVGTransaction.h"
#import "IJSVGRendering.h"
@class IJSVGShapeLayer;
@class IJSVGGradientLayer;
@@ -28,6 +29,7 @@
@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer;
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
+13 -22
View File
@@ -26,13 +26,10 @@
- (void)dealloc
{
IJSVGBeginTransactionLock();
[_maskingLayer release], _maskingLayer = nil;
[super dealloc];
IJSVGEndTransactionLock();
}
+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer
{
NSMutableArray * arr = [[[NSMutableArray alloc] init] autorelease];
@@ -65,7 +62,8 @@
}
}
- (void)addSublayer:(CALayer *)layer {
- (void)addSublayer:(CALayer *)layer
{
if([layer isKindOfClass:[IJSVGLayer class]] == NO &&
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) {
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.",
@@ -80,14 +78,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 +174,11 @@
return;
}
[self _customRenderInContext:ctx];
}
}
- (CGPoint)absoluteOrigin
- (id<CAAction>)actionForKey:(NSString *)event
{
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;
return nil;
}
@end
+146 -100
View File
@@ -67,44 +67,67 @@
layer = [self layerForImage:(IJSVGImage *)node];
}
// apply any basic defaults
[self applyDefaultsToLayer:layer
fromNode:node];
[self applyDefaultsToLayer:layer fromNode:node];
return [self proposedLayerAfterApplyingTransforms:layer
transforms:node.transforms];
// create the new layer
layer = [self applyTransforms:node.transforms
toLayer:layer
fromNode:node];
return layer;
}
- (IJSVGLayer *)proposedLayerAfterApplyingTransforms:(IJSVGLayer *)layer
transforms:(NSArray<IJSVGTransform *> *)transforms
- (IJSVGLayer *)applyTransforms:(NSArray<IJSVGTransform *> *)transforms
toLayer:(IJSVGLayer *)layer
fromNode:(IJSVGNode *)node
{
// any x and y?
CGFloat x = [node.x computeValue:layer.frame.size.width];
CGFloat y = [node.y computeValue:layer.frame.size.height];
// do some magic transform
if(transforms.count == 0 && x == 0.f && y == 0.f) {
return layer;
}
if(x != 0.f || y != 0.f) {
// we must add translate to the stack
NSMutableArray * trans = nil;
if(transforms != nil) {
trans = [[transforms mutableCopy] autorelease];
} else {
trans = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
}
[trans addObject:[IJSVGTransform transformByTranslatingX:x y:y]];
transforms = trans;
}
// add any transforms
if(transforms.count != 0) {
IJSVGLayer * topLayer = nil;
IJSVGLayer * parentLayer = nil;
IJSVGLayer * topLayer = nil;
IJSVGLayer * parentLayer = nil;
for(IJSVGTransform * transform in transforms) {
// make sure we apply the transform to the parent
// so they stack
IJSVGGroupLayer * childLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
childLayer.affineTransform = transform.CGAffineTransform;
for(IJSVGTransform * transform in transforms) {
// make sure we apply the transform to the parent
// so they stack
IJSVGGroupLayer * childLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
childLayer.affineTransform = transform.CGAffineTransform;
// add it to the parent layer
if(parentLayer != nil) {
[parentLayer addSublayer:childLayer];
} else {
// make sure we keep track of the top most layer
topLayer = childLayer;
}
// reset parent layer to the new child
parentLayer = childLayer;
// add it to the parent layer
if(parentLayer != nil) {
[parentLayer addSublayer:childLayer];
} else {
// make sure we keep track of the top most layer
topLayer = childLayer;
}
// swap the layer around
[parentLayer addSublayer:layer];
layer = topLayer;
// reset parent layer to the new child
parentLayer = childLayer;
}
// swap the layer around
[parentLayer addSublayer:layer];
layer = topLayer;
return layer;
}
@@ -112,9 +135,6 @@
fromNode:(IJSVGNode *)node
{
CGFloat opacity = node.opacity.value;
if(opacity == 0.f) {
opacity = 1.f;
}
layer.opacity = opacity;
// setup the blending mode
@@ -126,29 +146,38 @@
if(node.shouldRender == NO) {
layer.hidden = YES;
}
}
- (IJSVGLayer *)layerForImage:(IJSVGImage *)image
{
IJSVGImageLayer * layer = [[[IJSVGImageLayer alloc] initWithCGImage:image.CGImage] autorelease];
layer.frame = CGRectMake(image.x.value, image.y.value, image.width.value, image.height.value);
layer.affineTransform = CGAffineTransformConcat(layer.affineTransform,
CGAffineTransformMakeScale( 1.f, -1.f));
// make sure we set the width and height correctly,
// as this may not be exactly the same as the size of the
// given image
CGRect frame = layer.frame;
frame.size.width = image.width.value;
frame.size.height = image.height.value;
layer.frame = frame;
return layer;
}
- (IJSVGLayer *)layerForGroup:(IJSVGGroup *)group
{
// grab the sub layer tree from the SVG
if(group.svg != nil) {
return [self layerForGroup:group.svg.rootNode];
}
IJSVGGroupLayer * groupLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
for(IJSVGNode * node in group.children) {
[groupLayer addSublayer:[self layerForNode:node]];
}
groupLayer.frame = (CGRect){
.origin = (CGPoint){
.x = group.x.value,
.y = group.y.value
},
.origin = CGPointZero,
.size = (CGSize){
.width = group.width.value,
.height = group.height.value
@@ -180,16 +209,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 +232,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,16 +249,36 @@
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?
if(path.svg != nil) {
// grab the sub layer tree from the SVG
return [path.svg layerWithTree:self];
}
// grab the basic shape layer
CGRect originalShapeBounds;
IJSVGShapeLayer * layer = [self basicLayerForPath:path
originalBoundingBox:&originalShapeBounds];
// garb the basic shape layer
IJSVGShapeLayer * layer = [self basicLayerForPath:path];
BOOL hasStroke = (path.strokeColor != nil ||
path.strokePattern != nil ||
path.strokeGradient != nil);
// any gradient?
if(self.fillColor == nil && path.fillGradient != nil) {
@@ -234,15 +286,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) {
@@ -269,6 +318,9 @@
BOOL hasFill = path.fillPattern != nil || path.fillGradient != nil;
if(self.fillColor && (hasFill || hasColor || fColor == nil)) {
fColor = self.fillColor;
} else if(fColor != nil && path.fillOpacity.value != 1.f) {
fColor = [IJSVGColor changeAlphaOnColor:fColor
to:path.fillOpacity.value];
}
// anything changed by user?
@@ -292,9 +344,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 +361,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 +453,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 +473,29 @@
- (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))
};
}
gradLayer.masksToBounds = YES;
return gradLayer;
}
@@ -485,10 +517,10 @@
CGRect bounds = CGPathGetBoundingBox(layer.path);
bounds = [self correctBounds:bounds forStrokedPath:path];
patternLayer.frame = bounds;
patternLayer.masksToBounds = YES;
// display
[patternLayer setNeedsDisplay];
return patternLayer;
}
@@ -513,6 +545,7 @@
// display
[patternLayer setNeedsDisplay];
patternLayer.masksToBounds = YES;
return patternLayer;
}
@@ -551,7 +584,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 +775,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
+40 -27
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;
}
@@ -55,39 +51,56 @@
// create the gradient with the colours
NSGradient * grad = [[NSGradient alloc] initWithColors:colors
atLocations:stopsParams
colorSpace:[NSColorSpace genericRGBColorSpace]];
colorSpace:IJSVGColor.defaultColorSpace];
free(stopsParams);
return [grad autorelease];
}
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
{
// grab the start and end point
CGPoint aStartPoint = (CGPoint){
.x = [self.x1 computeValue:rect.size.width],
.y = [self.y1 computeValue:rect.size.height]
};
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGPoint aEndPoint = (CGPoint){
.x = [self.x2 computeValue:rect.size.width],
.y = [self.y2 computeValue:rect.size.height]
};
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
CGAffineTransform absTransform = absoluteTransform;
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
// 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);
#pragma mark User Space On Use
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 opt = kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(ctx, gRef, aStartPoint, aEndPoint, opt);
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation|
kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(ctx, self.CGGradient, gradientStartPoint,
gradientEndPoint, options);
}
@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;
+23 -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;
}
@@ -138,6 +146,7 @@
{
if( ( self = [self initWithDef:YES] ) != nil )
{
self.opacity = [IJSVGUnitLength unitWithFloat:1];
}
return self;
}
@@ -206,6 +215,7 @@
{
self.opacity = [IJSVGUnitLength unitWithFloat:0.f];
self.fillOpacity = [IJSVGUnitLength unitWithFloat:1.f];
self.fillOpacity.inherit = YES;
self.strokeDashOffset = [IJSVGUnitLength unitWithFloat:0.f];
self.shouldRender = YES;
@@ -233,10 +243,12 @@
- (IJSVGDef *)defForID:(NSString *)anID
{
IJSVGDef * aDef = nil;
if( (aDef = [def defForID:anID]) != nil )
if( (aDef = [def defForID:anID]) != nil ) {
return aDef;
if( parentNode != nil )
}
if( parentNode != nil ) {
return [parentNode defForID:anID];
}
return nil;
}
@@ -248,7 +260,7 @@
// winding rule can inherit..
- (IJSVGWindingRule)windingRule
{
if( windingRule == IJSVGWindingRuleInherit && parentNode != nil ) {
if(windingRule == IJSVGWindingRuleInherit && parentNode != nil) {
return parentNode.windingRule;
}
return windingRule;
@@ -256,20 +268,20 @@
- (IJSVGLineCapStyle)lineCapStyle
{
if( lineCapStyle == IJSVGLineCapStyleInherit )
{
if( parentNode != nil )
if( lineCapStyle == IJSVGLineCapStyleInherit ) {
if( parentNode != nil ) {
return parentNode.lineCapStyle;
}
}
return lineCapStyle;
}
- (IJSVGLineJoinStyle)lineJoinStyle
{
if( lineJoinStyle == IJSVGLineJoinStyleInherit )
{
if( parentNode != nil )
if( lineJoinStyle == IJSVGLineJoinStyleInherit ) {
if( parentNode != nil ) {
return parentNode.lineJoinStyle;
}
}
return lineJoinStyle;
}
@@ -327,8 +339,9 @@
// must be on the path, it can also be on the
- (NSColor *)fillColor
{
if( fillColor == nil && parentNode != nil )
if( fillColor == nil && parentNode != nil ) {
return parentNode.fillColor;
}
return fillColor;
}
+3
View File
@@ -95,6 +95,7 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
NSMutableDictionary * _defNodes;
NSMutableDictionary * _baseDefNodes;
NSMutableArray<IJSVG *> * _svgs;
NSMutableArray * _definedGroups;
struct {
unsigned int shouldHandleForeignObject: 1;
@@ -106,6 +107,8 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
@property ( nonatomic, readonly ) NSRect viewBox;
@property ( nonatomic, readonly ) NSSize proposedViewSize;
+ (BOOL)isDataSVG:(NSData *)data;
- (id)initWithSVGString:(NSString *)string
error:(NSError **)error
delegate:(id<IJSVGParserDelegate>)delegate;
+197 -182
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];
}
@@ -115,6 +116,18 @@
}
+ (BOOL)isDataSVG:(NSData *)data
{
@try {
NSError * error;
NSXMLDocument * doc = [[[NSXMLDocument alloc] initWithData:data
options:0
error:&error] autorelease];
return doc != nil && error == nil;
} @catch(NSException * exception) {}
return NO;
}
- (id)initWithFileURL:(NSURL *)aURL
error:(NSError **)error
delegate:(id<IJSVGParserDelegate>)delegate
@@ -139,10 +152,11 @@
- (void *)_handleErrorWithCode:(NSUInteger)code
error:(NSError **)error
{
if( error )
if( error ) {
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
code:code
userInfo:nil] autorelease];
}
[_document release], _document = nil;
[self release], self = nil;
return nil;
@@ -156,12 +170,12 @@
// check the viewbox
if( NSEqualRects( self.viewBox, NSZeroRect ) ||
self.size.width == 0 || self.size.height == 0 )
{
if( error != NULL )
self.size.width == 0 || self.size.height == 0 ) {
if( error != NULL ) {
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
code:IJSVGErrorInvalidViewBox
userInfo:nil] autorelease];
}
return NO;
}
return YES;
@@ -178,26 +192,25 @@
// parse common attributes on the SVG element
[self _parseElementForCommonAttributes:svgElement
node:self];
node:self
ignoreAttributes:nil];
// find the sizebox!
NSXMLNode * attribute = nil;
if( ( attribute = [svgElement attributeForName:(NSString *)IJSVGAttributeViewBox] ) != nil ) {
// we have a viewbox...
CGFloat * box = [IJSVGUtils parseViewBox:[attribute stringValue]];
viewBox = NSMakeRect( box[0], box[1], box[2], box[3]);
free(box);
} else {
// there is no view box so find the width and height
CGFloat w = [[[svgElement attributeForName:(NSString *)IJSVGAttributeWidth] stringValue] floatValue];
CGFloat h = [[[svgElement attributeForName:(NSString *)IJSVGAttributeHeight] stringValue] floatValue];
if( h == 0.f && w != 0.f )
if( h == 0.f && w != 0.f ) {
h = w;
else if( w == 0.f && h != 0.f )
} else if( w == 0.f && h != 0.f ) {
w = h;
}
viewBox = NSMakeRect( 0.f, 0.f, w, h );
}
@@ -212,7 +225,7 @@
} else if( h == 0 && w != 0.f ) {
h = viewBox.size.height;
}
proposedViewSize = NSMakeSize( w, h );
proposedViewSize = NSMakeSize(w, h);
// the root element is SVG, so iterate over its children
// recursively
@@ -224,7 +237,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 +249,7 @@
- (void)_postParseElementForCommonAttributes:(NSXMLElement *)element
node:(IJSVGNode *)node
ignoreAttributes:(NSArray *)ignoredAttributes
{
// first of all, compute a style sheet
@@ -244,8 +259,11 @@
// attribute helpers
typedef void (^cp)(NSString *);
void (^attr)(const NSString *, cp) = ^(NSString * key, cp block) {
NSString * v = [element attributeForName:key].stringValue
?: [style property:key];
if([ignoredAttributes containsObject:key]) {
return;
}
NSString * v = [style property:key] ?:
[element attributeForName:key].stringValue;
if(v != nil && v.length != 0) {
block(v);
}
@@ -397,12 +415,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 +446,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 +509,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 +546,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 +554,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 +587,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];
@@ -579,15 +614,21 @@
// sub SVG
case IJSVGNodeTypeSVG: {
IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease];
IJSVGGroup * path = [[[IJSVGGroup alloc] init] autorelease];
path.type = aType;
path.name = subName;
path.parentNode = parentGroup;
// grab common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
// if its a sub svg, we can remove the attributes for x and y
// this is required or it could go out of bounds before the exporter
// hits the layers from the groups :)
[element removeAttributeForName:@"x"];
[element removeAttributeForName:@"y"];
// work out the SVG
NSError * error = nil;
@@ -632,7 +673,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 +715,8 @@
// find common attributes
[self _setupDefaultsForNode:group];
[self _parseElementForCommonAttributes:element
node:group];
node:group
ignoreAttributes:nil];
// recursively parse blocks
[self _parseBlock:element
@@ -699,7 +742,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 +765,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 +788,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 +813,8 @@
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:@[@"x",@"y"]];
[parentGroup addDef:path];
break;
}
@@ -785,7 +832,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 +855,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 +877,8 @@
// find common attributes
[self _setupDefaultsForNode:path];
[self _parseElementForCommonAttributes:element
node:path];
node:path
ignoreAttributes:nil];
[self _parseEllipse:element
intoPath:path];
[parentGroup addDef:path];
@@ -842,18 +892,41 @@
NSString * xlinkID = [xlink substringFromIndex:1];
IJSVGNode * node = [self definedObjectForID:xlinkID];
// there was no specified link ID, well, not that we could find,
// so just break
if(node == nil) {
break;
}
// due to this being a carbon clone, we need to clear the ID
if([element attributeForName:(NSString *)IJSVGAttributeID] == nil) {
node.identifier = nil;
}
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 +937,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 +976,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 +1023,8 @@
// find common attributes
[self _parseElementForCommonAttributes:element
node:group];
node:group
ignoreAttributes:nil];
// recursively parse blocks
[self _parseBlock:element
@@ -982,7 +1042,8 @@
// find common attributes
[self _parseElementForCommonAttributes:element
node:pattern];
node:pattern
ignoreAttributes:nil];
// pattern has children
[self _parseBlock:element
@@ -1001,7 +1062,8 @@
// find common attributes
[self _parseElementForCommonAttributes:element
node:image];
node:image
ignoreAttributes:nil];
// from base64
[image loadFromBase64EncodedString:[[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue]];
@@ -1015,6 +1077,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
@@ -1044,16 +1118,14 @@
NSUInteger len = [command length];
// allocate memory for the string buffer for reading
unichar * buffer = (unichar *)calloc( len+1, sizeof(unichar));
[command getCharacters:buffer
range:NSMakeRange(0, len)];
const char * buffer = [command cStringUsingEncoding:NSUTF8StringEncoding];
int defaultBufferSize = 200;
int currentBufferSize = 0;
int currentSize = defaultBufferSize;
unichar * commandBuffer = NULL;
if( len != 0 ) {
if(len != 0) {
commandBuffer = (unichar *)calloc(defaultBufferSize,sizeof(unichar));
}
@@ -1061,17 +1133,18 @@
for( int i = 0; i < len; i++ ) {
unichar currentChar = buffer[i];
unichar nextChar = buffer[i+1];
BOOL atEnd = i == len-1;
BOOL isStartCommand = IJSVGIsLegalCommandCharacter(nextChar);
if( ( currentBufferSize + 1 ) == currentSize ) {
currentSize += defaultBufferSize;
commandBuffer = (unichar *)realloc( commandBuffer, sizeof(unichar)*currentSize);
commandBuffer = (unichar *)realloc(commandBuffer, sizeof(unichar)*currentSize);
}
commandBuffer[currentBufferSize++] = currentChar;
if( isStartCommand || atEnd ) {
if(isStartCommand == YES || atEnd == YES) {
NSString * commandString = [NSString stringWithCharacters:commandBuffer
length:currentBufferSize];
// previous command is actual subcommand
IJSVGCommand * previousCommand = [_currentCommand subCommands].lastObject;
IJSVGCommand * cCommand = [self _parseCommandString:commandString
@@ -1083,19 +1156,15 @@
_currentCommand = cCommand;
}
free(commandBuffer);
commandBuffer = NULL;
if( !atEnd ) {
if(atEnd == NO) {
currentBufferSize = 0;
currentSize = defaultBufferSize;
commandBuffer = (unichar *)calloc(defaultBufferSize,sizeof(unichar));
memset(commandBuffer,'\0', sizeof(unichar)*currentSize);
}
}
}
// free the buffer
free(buffer);
free(commandBuffer);
}
- (IJSVGCommand *)_parseCommandString:(NSString *)string
@@ -1188,8 +1257,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 +1266,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 +1281,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
+1
View File
@@ -24,6 +24,7 @@
{
if((self = [super init]) != nil) {
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
}
return self;
}
+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
+89 -78
View File
@@ -34,123 +34,134 @@
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];
NSGradient * ret = [[[NSGradient alloc] initWithColors:colors
atLocations:colorStops
colorSpace:[NSColorSpace genericRGBColorSpace]] autorelease];
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
free(colorStops);
return ret;
}
- (CGFloat)_handleTransform:(IJSVGTransform *)transform
bounds:(CGRect)bounds
index:(NSInteger)index
value:(CGFloat)value
- (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);
}
break;
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);
#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));
}
tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y);
selfTransform = CGAffineTransformConcat(tr, selfTransform);
}
}
return value;
}
#pragma mark Default drawing
// transform the context
CGContextConcatCTM(ctx, selfTransform);
- (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]);
}
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);
}
@end
+21
View File
@@ -0,0 +1,21 @@
//
// IJSVGRendering.h
// IJSVGExample
//
// Created by Curtis Hard on 14/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
typedef NS_ENUM(NSInteger, IJSVGRenderQuality) {
IJSVGRenderQualityFullResolution, // slowest to render
IJSVGRenderQualityOptimized, // best of both worlds
IJSVGRenderQualityLow // fast rendering
};
@interface IJSVGRendering : NSObject
@end
+13
View File
@@ -0,0 +1,13 @@
//
// IJSVGRendering.m
// IJSVGExample
//
// Created by Curtis Hard on 14/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGRendering.h"
@implementation IJSVGRendering
@end
+2
View File
@@ -23,8 +23,10 @@
@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer;
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) CGPoint originalPathOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
- (void)applySublayerMaskToContext:(CGContextRef)context
+7 -2
View File
@@ -20,13 +20,13 @@
@synthesize backingScaleFactor;
@synthesize blendingMode;
@synthesize convertMasksToPaths;
@synthesize originalPathOrigin;
@synthesize renderQuality;
- (void)dealloc
{
IJSVGBeginTransactionLock();
[_maskingLayer release], _maskingLayer = nil;
[super dealloc];
IJSVGEndTransactionLock();
}
- (void)addSublayer:(CALayer *)layer {
@@ -154,4 +154,9 @@
return point;
}
- (id<CAAction>)actionForKey:(NSString *)event
{
return nil;
}
@end
+13 -2
View File
@@ -9,13 +9,24 @@
#import "IJSVGTransaction.h"
void IJSVGBeginTransactionLock() {
if(NSThread.isMainThread == YES) {
return;
}
[CATransaction begin];
[CATransaction lock];
if(@available(macOS 10.14, *)) {} else {
[CATransaction lock];
}
[CATransaction setDisableActions:YES];
};
void IJSVGEndTransactionLock() {
[CATransaction unlock];
if(NSThread.isMainThread == YES) {
return;
}
if(@available(macOS 10.14, *)) {} else {
[CATransaction unlock];
}
[CATransaction commit];
};
+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
+7
View File
@@ -7,6 +7,7 @@
//
#import <Foundation/Foundation.h>
#include <xlocale.h>
#import "IJSVGCommand.h"
#import "IJSVGGradientUnitLength.h"
@@ -18,6 +19,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;
+181 -22
View File
@@ -12,16 +12,174 @@
@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";
NSUInteger length = strlen(validChars);
for(NSUInteger i = 0; i < length; i++) {
if(aChar == validChars[i]) {
return YES;
}
}
return NO;
const char * validChars = "MmZzLlHhVvCcSsQqTtAa";
return strchr(validChars, aChar) != NULL;
}
BOOL IJSVGIsSVGLayer(CALayer * layer)
@@ -56,7 +214,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
+ (IJSVGCommandType)typeForCommandString:(NSString *)string
{
return [string isEqualToString:[string uppercaseString]] ? IJSVGCommandTypeAbsolute : IJSVGCommandTypeRelative;
return isupper([string characterAtIndex:0]) ? IJSVGCommandTypeAbsolute : IJSVGCommandTypeRelative;
}
+ (NSString *)defURL:(NSString *)string
@@ -235,8 +393,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
+ (CGFloat *)commandParameters:(NSString *)command
count:(NSInteger *)count
{
if( [command isKindOfClass:[NSNumber class]] )
{
if( [command isKindOfClass:[NSNumber class]] ) {
CGFloat * ret = (CGFloat *)malloc(1*sizeof(CGFloat));
ret[0] = [(NSNumber *)command floatValue];
*count = 1;
@@ -251,12 +408,11 @@ CGFloat degrees_to_radians( CGFloat degrees )
{
// default sizes and memory
// sizes for the string buffer
NSInteger defSize = 50;
NSInteger size = defSize;
NSInteger sLength = string.length;
const NSInteger defFloatSize = 30;
const NSInteger defSize = 15;
// default memory size for the floats
NSInteger defFloatSize = 100;
// default memory size for the float
NSInteger size = defSize;
NSInteger floatSize = defFloatSize;
NSInteger i = 0;
@@ -265,6 +421,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);
@@ -281,7 +439,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
nextChar = cString[i+1];
}
bool isValid = strchr(validChars, currentChar);
bool isValid = strchr(validChars, currentChar) != NULL;
// in order to work out the split, its either because the next char is
// a hyphen or a plus, or next char is a decimal and the current number is a decimal
@@ -318,7 +476,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
// is at end of string, or wants to be stopped
// buffer has to actually exist or its completly
// useless and will cause a crash
if(buffer != NULL && (wantsEnd || i == sLength-1)) {
if((buffer != NULL && bufferCount != 0) && (wantsEnd || i == sLength-1)) {
// make sure there is enough room in the float pool
if((counter+1) == floatSize) {
floatSize += defFloatSize;
@@ -326,17 +484,18 @@ CGFloat degrees_to_radians( CGFloat degrees )
}
// add the float
floats[counter++] = atof(buffer);
floats[counter++] = strtod_l(buffer, NULL, NULL);
// memory clean and counter resets
free(buffer);
size = defSize;
memset(buffer, '\0', sizeof(*buffer)*size);
isDecimal = false;
bufferCount = 0;
buffer = NULL;
}
i++;
}
if(buffer != NULL) {
free(buffer);
}
*length = counter;
return floats;
}
+2 -2
View File
@@ -11,10 +11,10 @@
IB_DESIGNABLE
@interface IJSVGView : NSView {
IBInspectable NSString * imageName;
IJSVG * SVG;
IBInspectable NSColor * tintColor;
IJSVG * SVG;
}
@property (nonatomic, retain) IJSVG * SVG;
+3 -2
View File
@@ -41,8 +41,9 @@
// image was set via IB
if(imageName != nil) {
IJSVG * anSVG = [IJSVG svgNamed:imageName];
// dont need the dom, so clean it
[anSVG discardDOM];
if(tintColor != nil) {
anSVG.fillColor = tintColor;
}
self.SVG = anSVG;
}
}