Compare commits

...

94 Commits

Author SHA1 Message Date
Curtis Hard b2604c19aa testing 123 2022-08-17 13:28:56 +01:00
Curtis Hard 258c79d208 Fixes a memory leak 2022-08-04 14:37:07 +01:00
Curtis Hard 5228c87f16 Added nodes matching traits 2022-08-01 21:33:55 +01:00
Curtis Hard 05ec5c5a29 Adds stroke to path on export option
- fixed stroke opacity
- adds convenience method for grabbing a stroke layer from another layer
2022-07-17 17:53:14 +01:00
Curtis Hard 8628b38938 Start of converting strokes to paths 2022-07-13 20:39:03 +01:00
Curtis Hard 3cc8f1f355 Adds feature flags, updates example with correct calls 2022-07-13 19:45:32 +01:00
Curtis Hard c7b56ba877 Added normalisation of viewBox's 2022-07-11 20:35:40 +01:00
Curtis Hard e25b00efb7 Fixes image resizing 2022-07-07 17:51:07 +01:00
Curtis Hard 37d6cc7fd8 FIxes for image export 2022-07-07 17:27:12 +01:00
Curtis Hard b2eaf7ead5 Adds convenience methods for unit sizes 2022-07-07 17:12:05 +01:00
Curtis Hard f60f07ae70 Removed references for delegate as its useless now 2022-07-06 19:01:32 +01:00
Curtis Hard bb9ea4ade8 Fixes aspect ratio method 2022-07-06 17:35:31 +01:00
Curtis Hard d4f96823ec Various testing SVG’s 2022-07-05 17:22:32 +01:00
Curtis Hard c1b024f7a7 Removed refs to delegate and colors 2022-07-05 17:17:30 +01:00
Curtis Hard 2aa004f4b2 Removed font converter as its now useless 2022-07-05 17:06:52 +01:00
Curtis Hard 4a80c51070 Various methods to find nested children 2022-07-04 09:01:03 +01:00
Curtis Hard c8a813a29e Various renaming and refactors 2022-07-02 19:56:59 +01:00
Curtis Hard 6ca015aeb7 Few performance refactors for stylesheets 2022-07-02 12:11:58 +01:00
Curtis Hard 3647c91ab2 Prevents recursion when working out clip-rule 2022-07-02 11:04:51 +01:00
Curtis Hard ee66d25b9e Fixes clipRule on paths 2022-07-01 21:02:31 +01:00
Curtis Hard 03dfc7deb6 Adds clipRule support in 2022-07-01 20:06:10 +01:00
Curtis Hard 1b75f8964d Code formattering and refactor of matching masks on SVGs 2022-07-01 16:25:00 +01:00
Curtis Hard 1506840957 Adds lineCap, lineJoin, width and miterLimit style settings back in 2022-07-01 13:48:34 +01:00
Curtis Hard ae7e1e0196 Fixes absolute to relative path conversion
- adds support for varied dimensions on root SVG when exported
- adds constants for infinite and intrisic sizes
2022-07-01 13:13:07 +01:00
Curtis Hard 20589bfd83 Implement colour changing back into layer tree 2022-06-30 22:34:52 +01:00
Curtis Hard 96156fe1e0 Adds colors and storage into IJSVG 2022-06-30 21:35:40 +01:00
Curtis Hard daf843dd26 start refactor of colorLists 2022-06-30 18:59:37 +01:00
Curtis Hard 8789c7cef7 Adds image exporting + fixes a few things 2022-06-29 18:10:00 +01:00
Curtis Hard 551548579c Fixes circle -> ellipsis parsing 2022-06-28 18:48:12 +01:00
Curtis Hard 5206052905 Adds better pattern export support and also fixes clipPath exporting 2022-06-28 17:58:52 +01:00
Curtis Hard 6ee54e42bb Various improvements and constants 2022-06-28 13:05:05 +01:00
Curtis Hard 38d7fe15ea Adds clipPath support in to exporter 2022-06-27 20:02:08 +01:00
Curtis Hard 0905545edc Few formatting and fixes 2022-06-27 19:22:54 +01:00
Curtis Hard 3ae7f1b6d5 More export fixes 2022-06-27 15:16:27 +01:00
Curtis Hard 23f861584c Initial start of export refactor to use new layer things 2022-06-26 18:53:29 +01:00
Curtis Hard 94b7e3fe87 Fixes lack of viewbox or dimensions 2022-06-12 19:14:59 +01:00
Curtis Hard df7ceb3df1 Tidy up of viewBox code 2022-06-12 17:26:07 +01:00
Curtis Hard 3efea34d76 refactor methods into root class 2022-06-09 22:33:47 +01:00
Curtis Hard 7f74e66e90 Fixes clipPath and possible patterns... 2022-06-09 20:45:37 +01:00
Curtis Hard 35473e11c9 Fixes issue with patterns without a viewBox 2022-06-09 12:57:44 +01:00
Curtis Hard 4d00aab469 Nice refactor of viewBox’s 2022-06-07 19:46:31 +01:00
Curtis Hard bea50a033a Possible fix for gradients and pattern alignment 2022-06-07 11:45:16 +01:00
Curtis Hard fe9226a921 Code tidy 2022-06-06 21:30:31 +01:00
Curtis Hard fa62c7d334 Fix for patterns viewBox 2022-06-06 21:02:21 +01:00
Curtis Hard 3f58044f9d Adds a better call for viewboxes 2022-06-06 20:19:19 +01:00
Curtis Hard 96218c3fbe Images now obey their preserveAspectRatio 2022-06-06 17:50:16 +01:00
Curtis Hard d1b2fc882d Will use clipPaths for stroke patterns and gradient fills 2022-06-06 12:21:43 +01:00
Curtis Hard 008c70079f refactor gradients calls so they are nicer 2022-06-05 21:48:48 +01:00
Curtis Hard 05677c7c82 Fixes scale being applied twice #oops 2022-06-05 12:53:19 +01:00
Curtis Hard 8042ed7dc7 Fix for compiler warnings 2022-06-04 22:11:56 +01:00
Curtis Hard ff0b7e0866 Reverts to vector clippaths for clippaths and groups 2022-06-04 20:10:59 +01:00
Curtis Hard 304cac0a09 Remove integral transform on the rect, it breaks things 2022-06-04 17:20:31 +01:00
Curtis Hard 832527134f Stops defaulting to backing scale from screen 2022-06-04 17:07:34 +01:00
Curtis Hard 8657228b26 Fixes viewPort sizing 2022-06-04 16:50:31 +01:00
Curtis Hard 28c36337c2 Basic clipPath support on layers too 2022-06-04 16:30:18 +01:00
Curtis Hard 44504371ea Added clipPaths support (i think) 2022-06-04 15:51:54 +01:00
Curtis Hard 566527b6c0 Added clipPath as its own node 2022-06-02 16:06:01 +01:00
Curtis Hard e235b833ed Fixes root node positions and size 2022-06-02 16:05:29 +01:00
Curtis Hard 60547feb98 Mostly fixes masks, as far as I can tell 2022-05-28 20:41:39 +01:00
Curtis Hard 153258fa31 Fixes some masking issues 2022-05-25 21:45:58 +01:00
Curtis Hard 77741e3f38 Fixes fill opacity 2022-05-25 15:39:58 +01:00
Curtis Hard 22983a33a7 Fixes mask 2022-05-25 15:03:44 +01:00
Curtis Hard e9421025d9 Added wildcard combinator to stylesheets 2022-05-24 21:00:54 +01:00
Curtis Hard 33bd390f94 Fixes fill opacity for paintable layers 2022-05-24 20:44:47 +01:00
Curtis Hard 767ecb0b62 Fix radial gradient userspaceonuse 2022-05-24 20:28:32 +01:00
Curtis Hard 2afae1516a Fixes patterns and masking 2022-05-24 19:58:46 +01:00
Curtis Hard 6f9412c3c0 Fixes preserveAspectRatio if there is a implicit size 2022-05-21 17:56:52 +01:00
Curtis Hard fac780b47a Possible fix for radial gradients objectBoundingBox 2022-05-19 10:54:53 +01:00
Curtis Hard 2f7c34cf68 Fixes linear gradient drawing with transform 2022-05-17 20:30:52 +01:00
Curtis Hard f2c50ec5a4 Few more fixes 2022-05-13 18:22:12 +01:00
Curtis Hard 3cc75701fc Fixes parsing of clippaths 2022-05-13 10:45:13 +01:00
Curtis Hard 5ba7e94d24 Adds better recursie def parsing (some people reference other elements that have yet to be parsed..) 2022-05-12 19:47:18 +01:00
Curtis Hard 4e53a2cfa9 Fixes switch statements in SVG’s 2022-05-12 18:44:50 +01:00
Curtis Hard a1eb04ab1d Fixes inherit crash 2022-05-12 17:08:06 +01:00
Curtis Hard 88d7bd048d Fixes various use things and dash patterns 2022-05-12 17:02:20 +01:00
Curtis Hard 0dd8e1755e Wrong class used for filter effects detection 2022-05-10 16:31:39 +01:00
Curtis Hard e34f28cbda oops, fixed! 2022-05-10 15:54:55 +01:00
Curtis Hard f7a566d078 Fixes use and transform 2022-05-10 15:39:26 +01:00
Curtis Hard 7ebfa75ccd Fixes viewbox transforms 2022-05-10 12:37:34 +01:00
Curtis Hard 84ade44557 Fixes default colour opacity 2022-05-10 12:29:16 +01:00
Curtis Hard 1f0d0b41dc Clip path and userSpaceOnUse fixes 2022-05-10 12:06:38 +01:00
Curtis Hard 4c280e9694 Filter fixes 2022-05-09 18:37:42 +01:00
Curtis Hard 240a62127c Fixes parsing crash 2022-05-09 17:51:51 +01:00
Curtis Hard 7eb2e12164 more parsing fixes and CA issues resolved 2022-05-09 09:19:27 +01:00
Curtis Hard 2224a2538d Fixes buffer with whitespace parsing issue
- adds more examples
2022-05-08 17:00:33 +01:00
Curtis Hard 7513fc92fd Gradients no longer need their NS counterpart 2022-05-04 11:49:34 +01:00
Curtis Hard 7a0390b377 Uses angle brackers instead of quotes for imports 2022-04-20 22:28:23 +01:00
Curtis Hard 1cefc6aeed More ARC fixes 2022-04-20 21:37:26 +01:00
Curtis Hard 824e87d69a More ARC things 2022-04-20 20:27:30 +01:00
Curtis Hard e80088fc71 Dont know.... 2022-04-20 18:07:01 +01:00
Curtis Hard 46ba1ddcbd Converted everything to ARC.. ARC ALL THINGS! 2022-04-20 18:06:53 +01:00
Curtis Hard 533c369eb8 Adds threadmanager in to deal with per thread memory 2022-04-20 12:14:59 +01:00
Curtis Hard 5ac8aa8760 Fixes inner/outer bounding box frames for masks and snapshots 2022-04-19 22:36:00 +01:00
Curtis Hard b6ebd598e7 Initial filters 2022-04-19 18:11:54 +01:00
186 changed files with 62148 additions and 4270 deletions
+130 -50
View File
@@ -7,49 +7,67 @@
objects = {
/* Begin PBXBuildFile section */
590AA08D280DDD90002BBE12 /* IJSVGFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 590AA08B280DDD90002BBE12 /* IJSVGFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
590AA08E280DDD90002BBE12 /* IJSVGFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 590AA08C280DDD90002BBE12 /* IJSVGFilter.m */; };
590AA091280DDDA3002BBE12 /* IJSVGFilterEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 590AA08F280DDDA3002BBE12 /* IJSVGFilterEffect.h */; settings = {ATTRIBUTES = (Public, ); }; };
590AA092280DDDA3002BBE12 /* IJSVGFilterEffect.m in Sources */ = {isa = PBXBuildFile; fileRef = 590AA090280DDDA3002BBE12 /* IJSVGFilterEffect.m */; };
590AA096280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.h in Headers */ = {isa = PBXBuildFile; fileRef = 590AA094280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.h */; settings = {ATTRIBUTES = (Public, ); }; };
590AA097280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.m in Sources */ = {isa = PBXBuildFile; fileRef = 590AA095280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.m */; };
590EB7A427F637EF0047CECF /* IJSVGTransformLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 590EB7A227F637EF0047CECF /* IJSVGTransformLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
590EB7A527F637EF0047CECF /* IJSVGTransformLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 590EB7A327F637EF0047CECF /* IJSVGTransformLayer.m */; };
5910A9A628427AD600BD1F03 /* IJSVGMask.h in Headers */ = {isa = PBXBuildFile; fileRef = 5910A9A428427AD600BD1F03 /* IJSVGMask.h */; settings = {ATTRIBUTES = (Public, ); }; };
5910A9A728427AD600BD1F03 /* IJSVGMask.m in Sources */ = {isa = PBXBuildFile; fileRef = 5910A9A528427AD600BD1F03 /* IJSVGMask.m */; };
5910A9AA284377D600BD1F03 /* IJSVGClipPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 5910A9A8284377D600BD1F03 /* IJSVGClipPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
5910A9AB284377D600BD1F03 /* IJSVGClipPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 5910A9A9284377D600BD1F03 /* IJSVGClipPath.m */; };
5919E65723F47FF60051873A /* IJSVGUnitRect.h in Headers */ = {isa = PBXBuildFile; fileRef = 5919E65523F47FF60051873A /* IJSVGUnitRect.h */; settings = {ATTRIBUTES = (Public, ); }; };
5919E65823F47FF60051873A /* IJSVGUnitRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 5919E65623F47FF60051873A /* IJSVGUnitRect.m */; };
5919E65B23F480330051873A /* IJSVGUnitPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 5919E65923F480330051873A /* IJSVGUnitPoint.h */; settings = {ATTRIBUTES = (Public, ); }; };
5919E65C23F480330051873A /* IJSVGUnitPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 5919E65A23F480330051873A /* IJSVGUnitPoint.m */; };
591A3E4D25CC91F800AD45B7 /* IJSVGParsing.h in Headers */ = {isa = PBXBuildFile; fileRef = 591A3E4B25CC91F800AD45B7 /* IJSVGParsing.h */; settings = {ATTRIBUTES = (Public, ); }; };
591A3E4E25CC91F800AD45B7 /* IJSVGParsing.m in Sources */ = {isa = PBXBuildFile; fileRef = 591A3E4C25CC91F800AD45B7 /* IJSVGParsing.m */; };
5926079F287D6C1000E93B09 /* IJSVGFeatureFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 5926079D287D6C1000E93B09 /* IJSVGFeatureFlags.h */; settings = {ATTRIBUTES = (Public, ); }; };
592607A0287D6C1000E93B09 /* IJSVGFeatureFlags.m in Sources */ = {isa = PBXBuildFile; fileRef = 5926079E287D6C1000E93B09 /* IJSVGFeatureFlags.m */; };
594A10DA248D7C90001A3181 /* NSImage+IJSVGAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 594A10D8248D7C90001A3181 /* NSImage+IJSVGAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
594A10DB248D7C90001A3181 /* NSImage+IJSVGAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 594A10D9248D7C90001A3181 /* NSImage+IJSVGAdditions.m */; };
594CF55F238FF462009B251B /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 594CF55E238FF462009B251B /* AppKit.framework */; };
594CF561238FF46C009B251B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 594CF560238FF46C009B251B /* Foundation.framework */; };
594CF563238FF473009B251B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 594CF562238FF473009B251B /* QuartzCore.framework */; };
5955731F286C643900156047 /* IJSVGTileLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 5955731D286C643900156047 /* IJSVGTileLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
59557320286C643900156047 /* IJSVGTileLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 5955731E286C643900156047 /* IJSVGTileLayer.m */; };
595BA91C280EB29B00AD1C89 /* IJSVGFilterLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 595BA91A280EB29B00AD1C89 /* IJSVGFilterLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
595BA91D280EB29B00AD1C89 /* IJSVGFilterLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 595BA91B280EB29B00AD1C89 /* IJSVGFilterLayer.m */; };
5978C46A280A241200D25296 /* IJSVGRootLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 5978C468280A241200D25296 /* IJSVGRootLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
5978C46B280A241200D25296 /* IJSVGRootLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 5978C469280A241200D25296 /* IJSVGRootLayer.m */; };
599EB4D3238FF570004CB6BC /* libobjc.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 599EB4D2238FF535004CB6BC /* libobjc.tbd */; };
59A24EBC23F480EA0090C374 /* IJSVGUnitSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 59A24EBA23F480EA0090C374 /* IJSVGUnitSize.h */; settings = {ATTRIBUTES = (Public, ); }; };
59A24EBD23F480EA0090C374 /* IJSVGUnitSize.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A24EBB23F480EA0090C374 /* IJSVGUnitSize.m */; };
59AC865A2810156B00CD5685 /* IJSVGThreadManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 59AC86582810156B00CD5685 /* IJSVGThreadManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
59AC865B2810156B00CD5685 /* IJSVGThreadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 59AC86592810156B00CD5685 /* IJSVGThreadManager.m */; };
59E6690D287D6C810085EDF5 /* IJSVGFeatureFlag.h in Headers */ = {isa = PBXBuildFile; fileRef = 59E6690B287D6C810085EDF5 /* IJSVGFeatureFlag.h */; settings = {ATTRIBUTES = (Public, ); }; };
59E6690E287D6C810085EDF5 /* IJSVGFeatureFlag.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E6690C287D6C810085EDF5 /* IJSVGFeatureFlag.m */; };
59E7CFAF23B148600077D599 /* IJSVGCommandParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 59E7CFAD23B148600077D599 /* IJSVGCommandParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
59E7CFB023B148600077D599 /* IJSVGCommandParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E7CFAE23B148600077D599 /* IJSVGCommandParser.m */; };
59EB75D623905F7300F5AE63 /* IJSVGLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756523905F6B00F5AE63 /* IJSVGLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75D723905F7300F5AE63 /* IJSVGGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756623905F6B00F5AE63 /* IJSVGGradientLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75D823905F7300F5AE63 /* IJSVGStyleSheetRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB756723905F6B00F5AE63 /* IJSVGStyleSheetRule.m */; };
59EB75D923905F7300F5AE63 /* IJSVGCommandLineTo.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756823905F6B00F5AE63 /* IJSVGCommandLineTo.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75DA23905F7300F5AE63 /* IJSVGDef.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB756923905F6B00F5AE63 /* IJSVGDef.m */; };
59EB75DB23905F7300F5AE63 /* IJSVG.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756A23905F6B00F5AE63 /* IJSVG.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75DC23905F7300F5AE63 /* IJSVGText.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756B23905F6B00F5AE63 /* IJSVGText.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75DD23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB756C23905F6B00F5AE63 /* IJSVGCommandQuadraticCurve.m */; };
59EB75DE23905F7300F5AE63 /* IJSVGCommandVerticalLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756D23905F6C00F5AE63 /* IJSVGCommandVerticalLine.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E023905F7300F5AE63 /* IJSVGStyleSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E123905F7300F5AE63 /* IJSVGCommandSmoothCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E223905F7300F5AE63 /* IJSVGColorList.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757123905F6C00F5AE63 /* IJSVGColorList.m */; };
59EB75E223905F7300F5AE63 /* IJSVGTraitedColorStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757123905F6C00F5AE63 /* IJSVGTraitedColorStorage.m */; };
59EB75E323905F7300F5AE63 /* IJSVGRadialGradient.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E423905F7300F5AE63 /* IJSVGGradientUnitLength.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757323905F6C00F5AE63 /* IJSVGGradientUnitLength.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E523905F7300F5AE63 /* IJSVGStrokeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757423905F6C00F5AE63 /* IJSVGStrokeLayer.m */; };
59EB75E623905F7300F5AE63 /* IJSVGStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757523905F6C00F5AE63 /* IJSVGStyle.m */; };
59EB75E623905F7300F5AE63 /* IJSVGStyleSheetStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757523905F6C00F5AE63 /* IJSVGStyleSheetStyle.m */; };
59EB75E723905F7300F5AE63 /* IJSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757623905F6C00F5AE63 /* IJSVGImage.m */; };
59EB75E823905F7300F5AE63 /* IJSVGUnitLength.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757723905F6C00F5AE63 /* IJSVGUnitLength.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E923905F7300F5AE63 /* IJSVGStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */; };
59EB75EA23905F7300F5AE63 /* IJSVGTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757923905F6C00F5AE63 /* IJSVGTransaction.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75EB23905F7300F5AE63 /* IJSVGShapeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */; };
59EB75EC23905F7300F5AE63 /* IJSVGLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */; };
59EB75ED23905F7300F5AE63 /* IJSVGFontConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */; };
59EB75EE23905F7300F5AE63 /* IJSVGImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */; };
59EB75EF23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757E23905F6C00F5AE63 /* IJSVGCommandQuadraticCurve.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75F023905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757F23905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -59,13 +77,11 @@
59EB75F423905F7300F5AE63 /* IJSVGColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758323905F6C00F5AE63 /* IJSVGColor.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75F523905F7300F5AE63 /* IJSVGError.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758423905F6C00F5AE63 /* IJSVGError.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75F623905F7300F5AE63 /* IJSVGColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758523905F6C00F5AE63 /* IJSVGColor.m */; };
59EB75F723905F7300F5AE63 /* IJSVGDef.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758623905F6C00F5AE63 /* IJSVGDef.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75F823905F7300F5AE63 /* IJSVGCommandHorizontalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758723905F6C00F5AE63 /* IJSVGCommandHorizontalLine.m */; };
59EB75F923905F7300F5AE63 /* IJSVGFontConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75FB23905F7300F5AE63 /* IJSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758A23905F6D00F5AE63 /* IJSVGPath.m */; };
59EB75FC23905F7300F5AE63 /* IJSVGGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75FD23905F7300F5AE63 /* IJSVGPatternLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */; };
59EB75FE23905F7300F5AE63 /* IJSVGRenderingStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */; };
59EB75FE23905F7300F5AE63 /* IJSVGStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758D23905F6D00F5AE63 /* IJSVGStyle.m */; };
59EB760023905F7300F5AE63 /* IJSVGGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758F23905F6D00F5AE63 /* IJSVGGradientLayer.m */; };
59EB760123905F7300F5AE63 /* IJSVGLayerTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */; };
59EB760223905F7300F5AE63 /* IJSVGCommandVerticalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759123905F6D00F5AE63 /* IJSVGCommandVerticalLine.m */; };
@@ -83,7 +99,7 @@
59EB760F23905F7300F5AE63 /* IJSVGCommandEllipticalArc.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759E23905F6E00F5AE63 /* IJSVGCommandEllipticalArc.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761023905F7300F5AE63 /* IJSVGLinearGradient.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761123905F7300F5AE63 /* IJSVGCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A023905F6E00F5AE63 /* IJSVGCommand.m */; };
59EB761223905F7300F5AE63 /* IJSVGRenderingStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A123905F6E00F5AE63 /* IJSVGRenderingStyle.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761223905F7300F5AE63 /* IJSVGStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A123905F6E00F5AE63 /* IJSVGStyle.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761323905F7300F5AE63 /* IJSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A223905F6E00F5AE63 /* IJSVG.m */; };
59EB761423905F7300F5AE63 /* IJSVGImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761523905F7300F5AE63 /* IJSVGStrokeLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -91,10 +107,10 @@
59EB761723905F7300F5AE63 /* IJSVGRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */; };
59EB761823905F7300F5AE63 /* IJSVGParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A723905F6F00F5AE63 /* IJSVGParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761923905F7300F5AE63 /* IJSVGCommandSmoothCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75A823905F6F00F5AE63 /* IJSVGCommandSmoothCurve.m */; };
59EB761A23905F7300F5AE63 /* IJSVGColorList.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761A23905F7300F5AE63 /* IJSVGTraitedColorStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75A923905F6F00F5AE63 /* IJSVGTraitedColorStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761B23905F7300F5AE63 /* IJSVGPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75AA23905F6F00F5AE63 /* IJSVGPattern.m */; };
59EB761C23905F7300F5AE63 /* IJSVGGradient.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AB23905F6F00F5AE63 /* IJSVGGradient.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761D23905F7300F5AE63 /* IJSVGStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AC23905F6F00F5AE63 /* IJSVGStyle.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761D23905F7300F5AE63 /* IJSVGStyleSheetStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AC23905F6F00F5AE63 /* IJSVGStyleSheetStyle.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761E23905F7300F5AE63 /* IJSVGGroupLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AD23905F6F00F5AE63 /* IJSVGGroupLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB761F23905F7300F5AE63 /* IJSVGCommandLineTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75AE23905F6F00F5AE63 /* IJSVGCommandLineTo.m */; };
59EB762023905F7300F5AE63 /* IJSVGCommandMove.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75AF23905F6F00F5AE63 /* IJSVGCommandMove.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -134,8 +150,10 @@
59EB764423905F7300F5AE63 /* IJSVGRendering.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75D323905F7300F5AE63 /* IJSVGRendering.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB764523905F7300F5AE63 /* IJSVGExporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75D423905F7300F5AE63 /* IJSVGExporter.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB764623905F7300F5AE63 /* IJSVGRendering.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75D523905F7300F5AE63 /* IJSVGRendering.m */; };
59F36508262F1ABB00BCE3FD /* IJSVGColorType.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F36506262F1ABB00BCE3FD /* IJSVGColorType.h */; settings = {ATTRIBUTES = (Public, ); }; };
59F36509262F1ABB00BCE3FD /* IJSVGColorType.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F36507262F1ABB00BCE3FD /* IJSVGColorType.m */; };
59F36508262F1ABB00BCE3FD /* IJSVGTraitedColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F36506262F1ABB00BCE3FD /* IJSVGTraitedColor.h */; settings = {ATTRIBUTES = (Public, ); }; };
59F36509262F1ABB00BCE3FD /* IJSVGTraitedColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F36507262F1ABB00BCE3FD /* IJSVGTraitedColor.m */; };
59F38A63280ED99200804FE4 /* IJSVGBasicLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F38A61280ED99200804FE4 /* IJSVGBasicLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
59F38A64280ED99200804FE4 /* IJSVGBasicLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F38A62280ED99200804FE4 /* IJSVGBasicLayer.m */; };
59F9EAF82808BB5F00188ACB /* IJSVGViewBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F9EAF62808BB5F00188ACB /* IJSVGViewBox.h */; settings = {ATTRIBUTES = (Public, ); }; };
59F9EAF92808BB5F00188ACB /* IJSVGViewBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F9EAF72808BB5F00188ACB /* IJSVGViewBox.m */; };
59FCC09427F2394D00BB924E /* IJSVGRootNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FCC09227F2394D00BB924E /* IJSVGRootNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -145,14 +163,26 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
590AA08B280DDD90002BBE12 /* IJSVGFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGFilter.h; sourceTree = "<group>"; };
590AA08C280DDD90002BBE12 /* IJSVGFilter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGFilter.m; sourceTree = "<group>"; };
590AA08F280DDDA3002BBE12 /* IJSVGFilterEffect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGFilterEffect.h; sourceTree = "<group>"; };
590AA090280DDDA3002BBE12 /* IJSVGFilterEffect.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGFilterEffect.m; sourceTree = "<group>"; };
590AA094280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGFilterEffectGaussianBlur.h; sourceTree = "<group>"; };
590AA095280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGFilterEffectGaussianBlur.m; sourceTree = "<group>"; };
590EB7A227F637EF0047CECF /* IJSVGTransformLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGTransformLayer.h; sourceTree = "<group>"; };
590EB7A327F637EF0047CECF /* IJSVGTransformLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGTransformLayer.m; sourceTree = "<group>"; };
5910A9A428427AD600BD1F03 /* IJSVGMask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGMask.h; sourceTree = "<group>"; };
5910A9A528427AD600BD1F03 /* IJSVGMask.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGMask.m; sourceTree = "<group>"; };
5910A9A8284377D600BD1F03 /* IJSVGClipPath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGClipPath.h; sourceTree = "<group>"; };
5910A9A9284377D600BD1F03 /* IJSVGClipPath.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGClipPath.m; sourceTree = "<group>"; };
5919E65523F47FF60051873A /* IJSVGUnitRect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitRect.h; sourceTree = "<group>"; };
5919E65623F47FF60051873A /* IJSVGUnitRect.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitRect.m; sourceTree = "<group>"; };
5919E65923F480330051873A /* IJSVGUnitPoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitPoint.h; sourceTree = "<group>"; };
5919E65A23F480330051873A /* IJSVGUnitPoint.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitPoint.m; sourceTree = "<group>"; };
591A3E4B25CC91F800AD45B7 /* IJSVGParsing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGParsing.h; sourceTree = "<group>"; };
591A3E4C25CC91F800AD45B7 /* IJSVGParsing.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGParsing.m; sourceTree = "<group>"; };
5926079D287D6C1000E93B09 /* IJSVGFeatureFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGFeatureFlags.h; sourceTree = "<group>"; };
5926079E287D6C1000E93B09 /* IJSVGFeatureFlags.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGFeatureFlags.m; sourceTree = "<group>"; };
594A10D8248D7C90001A3181 /* NSImage+IJSVGAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSImage+IJSVGAdditions.h"; sourceTree = "<group>"; };
594A10D9248D7C90001A3181 /* NSImage+IJSVGAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSImage+IJSVGAdditions.m"; sourceTree = "<group>"; };
594CF46F238FF38E009B251B /* IJSVG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IJSVG.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -160,36 +190,42 @@
594CF55E238FF462009B251B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
594CF560238FF46C009B251B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
594CF562238FF473009B251B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
5955731D286C643900156047 /* IJSVGTileLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGTileLayer.h; sourceTree = "<group>"; };
5955731E286C643900156047 /* IJSVGTileLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGTileLayer.m; sourceTree = "<group>"; };
595BA91A280EB29B00AD1C89 /* IJSVGFilterLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGFilterLayer.h; sourceTree = "<group>"; };
595BA91B280EB29B00AD1C89 /* IJSVGFilterLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGFilterLayer.m; sourceTree = "<group>"; };
5978C468280A241200D25296 /* IJSVGRootLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGRootLayer.h; sourceTree = "<group>"; };
5978C469280A241200D25296 /* IJSVGRootLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGRootLayer.m; sourceTree = "<group>"; };
599EB4D2238FF535004CB6BC /* libobjc.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libobjc.tbd; path = usr/lib/libobjc.tbd; sourceTree = SDKROOT; };
59A24EBA23F480EA0090C374 /* IJSVGUnitSize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitSize.h; sourceTree = "<group>"; };
59A24EBB23F480EA0090C374 /* IJSVGUnitSize.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitSize.m; sourceTree = "<group>"; };
59AC86582810156B00CD5685 /* IJSVGThreadManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGThreadManager.h; sourceTree = "<group>"; };
59AC86592810156B00CD5685 /* IJSVGThreadManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGThreadManager.m; sourceTree = "<group>"; };
59E6690B287D6C810085EDF5 /* IJSVGFeatureFlag.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGFeatureFlag.h; sourceTree = "<group>"; };
59E6690C287D6C810085EDF5 /* IJSVGFeatureFlag.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGFeatureFlag.m; sourceTree = "<group>"; };
59E7CFAD23B148600077D599 /* IJSVGCommandParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IJSVGCommandParser.h; path = IJSVG/Source/Parsing/IJSVGCommandParser.h; sourceTree = SOURCE_ROOT; };
59E7CFAE23B148600077D599 /* IJSVGCommandParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = IJSVGCommandParser.m; path = IJSVG/Source/Parsing/IJSVGCommandParser.m; sourceTree = SOURCE_ROOT; };
59EB756523905F6B00F5AE63 /* IJSVGLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLayer.h; sourceTree = "<group>"; };
59EB756623905F6B00F5AE63 /* IJSVGGradientLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradientLayer.h; sourceTree = "<group>"; };
59EB756723905F6B00F5AE63 /* IJSVGStyleSheetRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetRule.m; sourceTree = "<group>"; };
59EB756823905F6B00F5AE63 /* IJSVGCommandLineTo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandLineTo.h; sourceTree = "<group>"; };
59EB756923905F6B00F5AE63 /* IJSVGDef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGDef.m; sourceTree = "<group>"; };
59EB756A23905F6B00F5AE63 /* IJSVG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVG.h; sourceTree = "<group>"; };
59EB756B23905F6B00F5AE63 /* IJSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGText.h; sourceTree = "<group>"; };
59EB756C23905F6B00F5AE63 /* IJSVGCommandQuadraticCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandQuadraticCurve.m; sourceTree = "<group>"; };
59EB756D23905F6C00F5AE63 /* IJSVGCommandVerticalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandVerticalLine.h; sourceTree = "<group>"; };
59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheet.h; sourceTree = "<group>"; };
59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandSmoothCurve.h; sourceTree = "<group>"; };
59EB757123905F6C00F5AE63 /* IJSVGColorList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorList.m; sourceTree = "<group>"; };
59EB757123905F6C00F5AE63 /* IJSVGTraitedColorStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGTraitedColorStorage.m; sourceTree = "<group>"; };
59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRadialGradient.h; sourceTree = "<group>"; };
59EB757323905F6C00F5AE63 /* IJSVGGradientUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradientUnitLength.h; sourceTree = "<group>"; };
59EB757423905F6C00F5AE63 /* IJSVGStrokeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStrokeLayer.m; sourceTree = "<group>"; };
59EB757523905F6C00F5AE63 /* IJSVGStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyle.m; sourceTree = "<group>"; };
59EB757523905F6C00F5AE63 /* IJSVGStyleSheetStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetStyle.m; sourceTree = "<group>"; };
59EB757623905F6C00F5AE63 /* IJSVGImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImage.m; sourceTree = "<group>"; };
59EB757723905F6C00F5AE63 /* IJSVGUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitLength.h; sourceTree = "<group>"; };
59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStringAdditions.m; sourceTree = "<group>"; };
59EB757923905F6C00F5AE63 /* IJSVGTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGTransaction.h; sourceTree = "<group>"; };
59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGShapeLayer.m; sourceTree = "<group>"; };
59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLayer.m; sourceTree = "<group>"; };
59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGFontConverter.m; sourceTree = "<group>"; };
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImageRep.m; sourceTree = "<group>"; };
59EB757E23905F6C00F5AE63 /* IJSVGCommandQuadraticCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandQuadraticCurve.h; sourceTree = "<group>"; };
59EB757F23905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetSelectorRaw.h; sourceTree = "<group>"; };
@@ -199,13 +235,11 @@
59EB758323905F6C00F5AE63 /* IJSVGColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGColor.h; sourceTree = "<group>"; };
59EB758423905F6C00F5AE63 /* IJSVGError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGError.h; sourceTree = "<group>"; };
59EB758523905F6C00F5AE63 /* IJSVGColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGColor.m; sourceTree = "<group>"; };
59EB758623905F6C00F5AE63 /* IJSVGDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGDef.h; sourceTree = "<group>"; };
59EB758723905F6C00F5AE63 /* IJSVGCommandHorizontalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandHorizontalLine.m; sourceTree = "<group>"; };
59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGFontConverter.h; sourceTree = "<group>"; };
59EB758A23905F6D00F5AE63 /* IJSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPath.m; sourceTree = "<group>"; };
59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGroup.h; sourceTree = "<group>"; };
59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPatternLayer.m; sourceTree = "<group>"; };
59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRenderingStyle.m; sourceTree = "<group>"; };
59EB758D23905F6D00F5AE63 /* IJSVGStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyle.m; sourceTree = "<group>"; };
59EB758F23905F6D00F5AE63 /* IJSVGGradientLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGradientLayer.m; sourceTree = "<group>"; };
59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLayerTree.m; sourceTree = "<group>"; };
59EB759123905F6D00F5AE63 /* IJSVGCommandVerticalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandVerticalLine.m; sourceTree = "<group>"; };
@@ -223,7 +257,7 @@
59EB759E23905F6E00F5AE63 /* IJSVGCommandEllipticalArc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandEllipticalArc.h; sourceTree = "<group>"; };
59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLinearGradient.h; sourceTree = "<group>"; };
59EB75A023905F6E00F5AE63 /* IJSVGCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommand.m; sourceTree = "<group>"; };
59EB75A123905F6E00F5AE63 /* IJSVGRenderingStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRenderingStyle.h; sourceTree = "<group>"; };
59EB75A123905F6E00F5AE63 /* IJSVGStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyle.h; sourceTree = "<group>"; };
59EB75A223905F6E00F5AE63 /* IJSVG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVG.m; sourceTree = "<group>"; };
59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImageRep.h; sourceTree = "<group>"; };
59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStrokeLayer.h; sourceTree = "<group>"; };
@@ -231,10 +265,10 @@
59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRadialGradient.m; sourceTree = "<group>"; };
59EB75A723905F6F00F5AE63 /* IJSVGParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGParser.h; sourceTree = "<group>"; };
59EB75A823905F6F00F5AE63 /* IJSVGCommandSmoothCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandSmoothCurve.m; sourceTree = "<group>"; };
59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGColorList.h; sourceTree = "<group>"; };
59EB75A923905F6F00F5AE63 /* IJSVGTraitedColorStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGTraitedColorStorage.h; sourceTree = "<group>"; };
59EB75AA23905F6F00F5AE63 /* IJSVGPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPattern.m; sourceTree = "<group>"; };
59EB75AB23905F6F00F5AE63 /* IJSVGGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradient.h; sourceTree = "<group>"; };
59EB75AC23905F6F00F5AE63 /* IJSVGStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyle.h; sourceTree = "<group>"; };
59EB75AC23905F6F00F5AE63 /* IJSVGStyleSheetStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetStyle.h; sourceTree = "<group>"; };
59EB75AD23905F6F00F5AE63 /* IJSVGGroupLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGroupLayer.h; sourceTree = "<group>"; };
59EB75AE23905F6F00F5AE63 /* IJSVGCommandLineTo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandLineTo.m; sourceTree = "<group>"; };
59EB75AF23905F6F00F5AE63 /* IJSVGCommandMove.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandMove.h; sourceTree = "<group>"; };
@@ -274,8 +308,10 @@
59EB75D323905F7300F5AE63 /* IJSVGRendering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRendering.h; sourceTree = "<group>"; };
59EB75D423905F7300F5AE63 /* IJSVGExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporter.h; sourceTree = "<group>"; };
59EB75D523905F7300F5AE63 /* IJSVGRendering.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRendering.m; sourceTree = "<group>"; };
59F36506262F1ABB00BCE3FD /* IJSVGColorType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGColorType.h; sourceTree = "<group>"; };
59F36507262F1ABB00BCE3FD /* IJSVGColorType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorType.m; sourceTree = "<group>"; };
59F36506262F1ABB00BCE3FD /* IJSVGTraitedColor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGTraitedColor.h; sourceTree = "<group>"; };
59F36507262F1ABB00BCE3FD /* IJSVGTraitedColor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGTraitedColor.m; sourceTree = "<group>"; };
59F38A61280ED99200804FE4 /* IJSVGBasicLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGBasicLayer.h; sourceTree = "<group>"; };
59F38A62280ED99200804FE4 /* IJSVGBasicLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGBasicLayer.m; sourceTree = "<group>"; };
59F9EAF62808BB5F00188ACB /* IJSVGViewBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGViewBox.h; sourceTree = "<group>"; };
59F9EAF72808BB5F00188ACB /* IJSVGViewBox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGViewBox.m; sourceTree = "<group>"; };
59FCC09227F2394D00BB924E /* IJSVGRootNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGRootNode.h; sourceTree = "<group>"; };
@@ -299,6 +335,15 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
590AA093280DE648002BBE12 /* Filter Effects */ = {
isa = PBXGroup;
children = (
590AA094280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.h */,
590AA095280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.m */,
);
path = "Filter Effects";
sourceTree = "<group>";
};
592ABBE223979F9B00F44380 /* Commands */ = {
isa = PBXGroup;
children = (
@@ -331,8 +376,8 @@
592ABBE323979FBB00F44380 /* Stylesheets */ = {
isa = PBXGroup;
children = (
59EB75AC23905F6F00F5AE63 /* IJSVGStyle.h */,
59EB757523905F6C00F5AE63 /* IJSVGStyle.m */,
59EB75AC23905F6F00F5AE63 /* IJSVGStyleSheetStyle.h */,
59EB757523905F6C00F5AE63 /* IJSVGStyleSheetStyle.m */,
59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */,
59EB75D123905F7300F5AE63 /* IJSVGStyleSheet.m */,
59EB759B23905F6E00F5AE63 /* IJSVGStyleSheetRule.h */,
@@ -350,10 +395,10 @@
children = (
59EB758323905F6C00F5AE63 /* IJSVGColor.h */,
59EB758523905F6C00F5AE63 /* IJSVGColor.m */,
59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */,
59EB757123905F6C00F5AE63 /* IJSVGColorList.m */,
59F36506262F1ABB00BCE3FD /* IJSVGColorType.h */,
59F36507262F1ABB00BCE3FD /* IJSVGColorType.m */,
59EB75A923905F6F00F5AE63 /* IJSVGTraitedColorStorage.h */,
59EB757123905F6C00F5AE63 /* IJSVGTraitedColorStorage.m */,
59F36506262F1ABB00BCE3FD /* IJSVGTraitedColor.h */,
59F36507262F1ABB00BCE3FD /* IJSVGTraitedColor.m */,
);
path = Colors;
sourceTree = "<group>";
@@ -379,6 +424,12 @@
590EB7A327F637EF0047CECF /* IJSVGTransformLayer.m */,
5978C468280A241200D25296 /* IJSVGRootLayer.h */,
5978C469280A241200D25296 /* IJSVGRootLayer.m */,
595BA91A280EB29B00AD1C89 /* IJSVGFilterLayer.h */,
595BA91B280EB29B00AD1C89 /* IJSVGFilterLayer.m */,
59F38A61280ED99200804FE4 /* IJSVGBasicLayer.h */,
59F38A62280ED99200804FE4 /* IJSVGBasicLayer.m */,
5955731D286C643900156047 /* IJSVGTileLayer.h */,
5955731E286C643900156047 /* IJSVGTileLayer.m */,
);
path = Layers;
sourceTree = "<group>";
@@ -397,10 +448,9 @@
592ABBE72397A02900F44380 /* Nodes */ = {
isa = PBXGroup;
children = (
590AA093280DE648002BBE12 /* Filter Effects */,
59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */,
59EB75C923905F7200F5AE63 /* IJSVGForeignObject.m */,
59EB758623905F6C00F5AE63 /* IJSVGDef.h */,
59EB756923905F6B00F5AE63 /* IJSVGDef.m */,
59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */,
59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */,
59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */,
@@ -423,6 +473,14 @@
59FCC09327F2394D00BB924E /* IJSVGRootNode.m */,
59FDBEFE27F3454800AF7038 /* IJSVGColorNode.h */,
59FDBEFF27F3454800AF7038 /* IJSVGColorNode.m */,
590AA08B280DDD90002BBE12 /* IJSVGFilter.h */,
590AA08C280DDD90002BBE12 /* IJSVGFilter.m */,
590AA08F280DDDA3002BBE12 /* IJSVGFilterEffect.h */,
590AA090280DDDA3002BBE12 /* IJSVGFilterEffect.m */,
5910A9A428427AD600BD1F03 /* IJSVGMask.h */,
5910A9A528427AD600BD1F03 /* IJSVGMask.m */,
5910A9A8284377D600BD1F03 /* IJSVGClipPath.h */,
5910A9A9284377D600BD1F03 /* IJSVGClipPath.m */,
);
path = Nodes;
sourceTree = "<group>";
@@ -452,6 +510,12 @@
591A3E4C25CC91F800AD45B7 /* IJSVGParsing.m */,
59F9EAF62808BB5F00188ACB /* IJSVGViewBox.h */,
59F9EAF72808BB5F00188ACB /* IJSVGViewBox.m */,
59AC86582810156B00CD5685 /* IJSVGThreadManager.h */,
59AC86592810156B00CD5685 /* IJSVGThreadManager.m */,
5926079D287D6C1000E93B09 /* IJSVGFeatureFlags.h */,
5926079E287D6C1000E93B09 /* IJSVGFeatureFlags.m */,
59E6690B287D6C810085EDF5 /* IJSVGFeatureFlag.h */,
59E6690C287D6C810085EDF5 /* IJSVGFeatureFlag.m */,
);
path = Utils;
sourceTree = "<group>";
@@ -474,8 +538,8 @@
59EB759023905F6D00F5AE63 /* IJSVGLayerTree.m */,
59EB75D323905F7300F5AE63 /* IJSVGRendering.h */,
59EB75D523905F7300F5AE63 /* IJSVGRendering.m */,
59EB75A123905F6E00F5AE63 /* IJSVGRenderingStyle.h */,
59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */,
59EB75A123905F6E00F5AE63 /* IJSVGStyle.h */,
59EB758D23905F6D00F5AE63 /* IJSVGStyle.m */,
);
path = Rendering;
sourceTree = "<group>";
@@ -534,8 +598,6 @@
59EB756A23905F6B00F5AE63 /* IJSVG.h */,
59EB75A223905F6E00F5AE63 /* IJSVG.m */,
59EB758423905F6C00F5AE63 /* IJSVGError.h */,
59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */,
59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */,
59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */,
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */,
59EB75CD23905F7200F5AE63 /* IJSVGView.h */,
@@ -578,14 +640,13 @@
59EB764423905F7300F5AE63 /* IJSVGRendering.h in Headers */,
59EB75DC23905F7300F5AE63 /* IJSVGText.h in Headers */,
59EB761C23905F7300F5AE63 /* IJSVGGradient.h in Headers */,
59EB75F923905F7300F5AE63 /* IJSVGFontConverter.h in Headers */,
59EB75EF23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.h in Headers */,
59EB75FC23905F7300F5AE63 /* IJSVGGroup.h in Headers */,
59EB760323905F7300F5AE63 /* IJSVGNode.h in Headers */,
59EB762023905F7300F5AE63 /* IJSVGCommandMove.h in Headers */,
59EB762C23905F7300F5AE63 /* IJSVGPattern.h in Headers */,
59EB762923905F7300F5AE63 /* IJSVGStringAdditions.h in Headers */,
59EB761A23905F7300F5AE63 /* IJSVGColorList.h in Headers */,
59EB761A23905F7300F5AE63 /* IJSVGTraitedColorStorage.h in Headers */,
59EB762123905F7300F5AE63 /* IJSVGTransform.h in Headers */,
59EB763F23905F7300F5AE63 /* IJSVGForeignObject.h in Headers */,
59EB75F423905F7300F5AE63 /* IJSVGColor.h in Headers */,
@@ -602,11 +663,10 @@
59EB764123905F7300F5AE63 /* IJSVGImageLayer.h in Headers */,
59EB75E023905F7300F5AE63 /* IJSVGStyleSheet.h in Headers */,
59EB761423905F7300F5AE63 /* IJSVGImageRep.h in Headers */,
59EB761223905F7300F5AE63 /* IJSVGRenderingStyle.h in Headers */,
59EB761223905F7300F5AE63 /* IJSVGStyle.h in Headers */,
59EB760E23905F7300F5AE63 /* IJSVGPath.h in Headers */,
59EB75EA23905F7300F5AE63 /* IJSVGTransaction.h in Headers */,
59EB75D723905F7300F5AE63 /* IJSVGGradientLayer.h in Headers */,
59EB75F723905F7300F5AE63 /* IJSVGDef.h in Headers */,
59EB760623905F7300F5AE63 /* IJSVGCommandHorizontalLine.h in Headers */,
59EB762323905F7300F5AE63 /* IJSVGExporterPathInstruction.h in Headers */,
59EB761023905F7300F5AE63 /* IJSVGLinearGradient.h in Headers */,
@@ -617,13 +677,13 @@
59EB75F023905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.h in Headers */,
59EB761823905F7300F5AE63 /* IJSVGParser.h in Headers */,
59EB761E23905F7300F5AE63 /* IJSVGGroupLayer.h in Headers */,
59EB761D23905F7300F5AE63 /* IJSVGStyle.h in Headers */,
59EB761D23905F7300F5AE63 /* IJSVGStyleSheetStyle.h in Headers */,
5919E65723F47FF60051873A /* IJSVGUnitRect.h in Headers */,
5919E65B23F480330051873A /* IJSVGUnitPoint.h in Headers */,
591A3E4D25CC91F800AD45B7 /* IJSVGParsing.h in Headers */,
59A24EBC23F480EA0090C374 /* IJSVGUnitSize.h in Headers */,
59EB764523905F7300F5AE63 /* IJSVGExporter.h in Headers */,
59F36508262F1ABB00BCE3FD /* IJSVGColorType.h in Headers */,
59F36508262F1ABB00BCE3FD /* IJSVGTraitedColor.h in Headers */,
59E7CFAF23B148600077D599 /* IJSVGCommandParser.h in Headers */,
59EB762823905F7300F5AE63 /* IJSVGCommandClose.h in Headers */,
59EB75E423905F7300F5AE63 /* IJSVGGradientUnitLength.h in Headers */,
@@ -631,9 +691,20 @@
594A10DA248D7C90001A3181 /* NSImage+IJSVGAdditions.h in Headers */,
59EB762D23905F7300F5AE63 /* IJSVGLayerTree.h in Headers */,
59FDBF0027F3454800AF7038 /* IJSVGColorNode.h in Headers */,
590AA091280DDDA3002BBE12 /* IJSVGFilterEffect.h in Headers */,
590AA08D280DDD90002BBE12 /* IJSVGFilter.h in Headers */,
59F38A63280ED99200804FE4 /* IJSVGBasicLayer.h in Headers */,
595BA91C280EB29B00AD1C89 /* IJSVGFilterLayer.h in Headers */,
590AA096280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.h in Headers */,
590EB7A427F637EF0047CECF /* IJSVGTransformLayer.h in Headers */,
59AC865A2810156B00CD5685 /* IJSVGThreadManager.h in Headers */,
5978C46A280A241200D25296 /* IJSVGRootLayer.h in Headers */,
59F9EAF82808BB5F00188ACB /* IJSVGViewBox.h in Headers */,
5910A9AA284377D600BD1F03 /* IJSVGClipPath.h in Headers */,
5926079F287D6C1000E93B09 /* IJSVGFeatureFlags.h in Headers */,
59E6690D287D6C810085EDF5 /* IJSVGFeatureFlag.h in Headers */,
5910A9A628427AD600BD1F03 /* IJSVGMask.h in Headers */,
5955731F286C643900156047 /* IJSVGTileLayer.h in Headers */,
59EB760B23905F7300F5AE63 /* IJSVGStyleSheetSelector.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -706,16 +777,21 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
592607A0287D6C1000E93B09 /* IJSVGFeatureFlags.m in Sources */,
59EB763123905F7300F5AE63 /* IJSVGText.m in Sources */,
59A24EBD23F480EA0090C374 /* IJSVGUnitSize.m in Sources */,
59EB760223905F7300F5AE63 /* IJSVGCommandVerticalLine.m in Sources */,
59EB75FD23905F7300F5AE63 /* IJSVGPatternLayer.m in Sources */,
59EB763923905F7300F5AE63 /* IJSVGCommandSmoothQuadraticCurve.m in Sources */,
59EB75D823905F7300F5AE63 /* IJSVGStyleSheetRule.m in Sources */,
590AA092280DDDA3002BBE12 /* IJSVGFilterEffect.m in Sources */,
59AC865B2810156B00CD5685 /* IJSVGThreadManager.m in Sources */,
59EB75FB23905F7300F5AE63 /* IJSVGPath.m in Sources */,
59F36509262F1ABB00BCE3FD /* IJSVGColorType.m in Sources */,
590AA097280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.m in Sources */,
59F36509262F1ABB00BCE3FD /* IJSVGTraitedColor.m in Sources */,
59EB760123905F7300F5AE63 /* IJSVGLayerTree.m in Sources */,
59EB763A23905F7300F5AE63 /* IJSVGForeignObject.m in Sources */,
59E6690E287D6C810085EDF5 /* IJSVGFeatureFlag.m in Sources */,
59EB761123905F7300F5AE63 /* IJSVGCommand.m in Sources */,
59EB760923905F7300F5AE63 /* IJSVGCommandCurve.m in Sources */,
59EB763323905F7300F5AE63 /* IJSVGLinearGradient.m in Sources */,
@@ -727,21 +803,26 @@
59EB75E523905F7300F5AE63 /* IJSVGStrokeLayer.m in Sources */,
59EB763223905F7300F5AE63 /* IJSVGView.m in Sources */,
59EB763523905F7300F5AE63 /* IJSVGStyleSheetSelector.m in Sources */,
590AA08E280DDD90002BBE12 /* IJSVGFilter.m in Sources */,
59E7CFB023B148600077D599 /* IJSVGCommandParser.m in Sources */,
5910A9AB284377D600BD1F03 /* IJSVGClipPath.m in Sources */,
59EB760723905F7300F5AE63 /* IJSVGNode.m in Sources */,
5919E65C23F480330051873A /* IJSVGUnitPoint.m in Sources */,
59EB75E923905F7300F5AE63 /* IJSVGStringAdditions.m in Sources */,
59FDBF0127F3454800AF7038 /* IJSVGColorNode.m in Sources */,
59557320286C643900156047 /* IJSVGTileLayer.m in Sources */,
59EB761723905F7300F5AE63 /* IJSVGRadialGradient.m in Sources */,
59EB75E223905F7300F5AE63 /* IJSVGColorList.m in Sources */,
59EB75ED23905F7300F5AE63 /* IJSVGFontConverter.m in Sources */,
59EB75E223905F7300F5AE63 /* IJSVGTraitedColorStorage.m in Sources */,
595BA91D280EB29B00AD1C89 /* IJSVGFilterLayer.m in Sources */,
59EB763C23905F7300F5AE63 /* IJSVGCommandEllipticalArc.m in Sources */,
59EB75E723905F7300F5AE63 /* IJSVGImage.m in Sources */,
59EB75E623905F7300F5AE63 /* IJSVGStyle.m in Sources */,
59EB75E623905F7300F5AE63 /* IJSVGStyleSheetStyle.m in Sources */,
59F38A64280ED99200804FE4 /* IJSVGBasicLayer.m in Sources */,
59EB75EB23905F7300F5AE63 /* IJSVGShapeLayer.m in Sources */,
59EB75F623905F7300F5AE63 /* IJSVGColor.m in Sources */,
59EB75F323905F7300F5AE63 /* IJSVGGroupLayer.m in Sources */,
591A3E4E25CC91F800AD45B7 /* IJSVGParsing.m in Sources */,
5910A9A728427AD600BD1F03 /* IJSVGMask.m in Sources */,
5919E65823F47FF60051873A /* IJSVGUnitRect.m in Sources */,
5978C46B280A241200D25296 /* IJSVGRootLayer.m in Sources */,
59EB762523905F7300F5AE63 /* IJSVGTransform.m in Sources */,
@@ -753,14 +834,13 @@
59EB761623905F7300F5AE63 /* IJSVGParser.m in Sources */,
59EB75DD23905F7300F5AE63 /* IJSVGCommandQuadraticCurve.m in Sources */,
59EB762423905F7300F5AE63 /* IJSVGTransaction.m in Sources */,
59EB75DA23905F7300F5AE63 /* IJSVGDef.m in Sources */,
59EB763723905F7300F5AE63 /* IJSVGCommandClose.m in Sources */,
59F9EAF92808BB5F00188ACB /* IJSVGViewBox.m in Sources */,
59EB764323905F7300F5AE63 /* IJSVGGradient.m in Sources */,
59EB762A23905F7300F5AE63 /* IJSVGGradientUnitLength.m in Sources */,
59EB764223905F7300F5AE63 /* IJSVGStyleSheet.m in Sources */,
59EB764023905F7300F5AE63 /* IJSVGExporterPathInstruction.m in Sources */,
59EB75FE23905F7300F5AE63 /* IJSVGRenderingStyle.m in Sources */,
59EB75FE23905F7300F5AE63 /* IJSVGStyle.m in Sources */,
59EB75F223905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.m in Sources */,
590EB7A527F637EF0047CECF /* IJSVGTransformLayer.m in Sources */,
59EB75EE23905F7300F5AE63 /* IJSVGImageRep.m in Sources */,
@@ -899,7 +979,7 @@
594CF478238FF38E009B251B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CODE_SIGN_STYLE = Automatic;
@@ -927,7 +1007,7 @@
594CF479238FF38E009B251B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CODE_SIGN_STYLE = Automatic;
@@ -6,8 +6,8 @@
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGStringAdditions.h"
#import "IJSVGUtils.h"
#import <IJSVG/IJSVGStringAdditions.h>
#import <IJSVG/IJSVGUtils.h>
@implementation NSString (IJSVGAdditions)
@@ -18,7 +18,7 @@
return @[];
}
NSMutableArray<NSString*>* strings = nil;
strings = [[[NSMutableArray alloc] init] autorelease];
strings = [[NSMutableArray alloc] init];
char* copy = strdup(chars);
char* spt = NULL;
char* ptr = strtok_r(copy, aChar, &spt);
@@ -38,7 +38,7 @@
const char* buffer = self.UTF8String;
char currentChar;
while((currentChar = *buffer++) ) {
if (isalpha(currentChar)) {
if(isalpha(currentChar)) {
return YES;
}
}
@@ -50,7 +50,7 @@
const char* buffer = self.UTF8String;
char currentChar;
while((currentChar = *buffer++) ) {
if (!isnumber(currentChar)) {
if(!isnumber(currentChar)) {
return NO;
}
}
@@ -6,13 +6,13 @@
// Copyright © 2020 Curtis Hard. All rights reserved.
//
#import "IJSVGImageRep.h"
#import "NSImage+IJSVGAdditions.h"
#import <IJSVG/IJSVGImageRep.h>
#import <IJSVG/NSImage+IJSVGAdditions.h>
IJSVG* IJSVGGetFromNSImage(NSImage* image)
{
for (NSImageRep* rep in image.representations) {
if ([rep isKindOfClass:IJSVGImageRep.class]) {
if([rep isKindOfClass:IJSVGImageRep.class]) {
return ((IJSVGImageRep*)rep).SVG;
}
}
@@ -27,23 +27,23 @@ IJSVG* IJSVGGetFromNSImage(NSImage* image)
NSBundle* bundle = NSBundle.mainBundle;
NSString* str = nil;
NSString* ext = imageName.pathExtension;
if (ext == nil || ext.length == 0) {
if(ext == nil || ext.length == 0) {
ext = @"svg";
}
if ((str = [bundle pathForResource:imageName.stringByDeletingPathExtension
if((str = [bundle pathForResource:imageName.stringByDeletingPathExtension
ofType:ext])
!= nil) {
// work out if we can get the data
NSData* data = [[[NSData alloc] initWithContentsOfFile:str] autorelease];
if (data == nil) {
NSData* data = [[NSData alloc] initWithContentsOfFile:str];
if(data == nil) {
return nil;
}
// grab the image rep
IJSVGImageRep* rep = [[[IJSVGImageRep alloc] initWithData:data] autorelease];
NSImage* image = [[[NSImage alloc] init] autorelease];
IJSVGImageRep* rep = [[IJSVGImageRep alloc] initWithData:data];
NSImage* image = [[NSImage alloc] init];
[image addRepresentation:rep];
return image;
}
@@ -6,10 +6,11 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGColor.h"
#import "IJSVGUtils.h"
#import "IJSVGStringAdditions.h"
#import "IJSVGParsing.h"
#import <IJSVG/IJSVGColor.h>
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGStringAdditions.h>
#import <IJSVG/IJSVGParsing.h>
#import <IJSVG/IJSVGParser.h>
NSString* const IJSVGColorCurrentColorName = @"currentColor";
@@ -28,7 +29,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
CGFloat s = saturation * ((lightness < 1.f) ? lightness : (2.f - lightness));
CGFloat brightness = (lightness + s) * .5f;
if (s != 0.f) {
if(s != 0.f) {
s = (2.f * s) / (lightness + s);
}
CGFloat* floats = (CGFloat*)malloc(3 * sizeof(CGFloat));
@@ -51,7 +52,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
+ (NSColor*)computeColorSpace:(NSColor*)color
{
NSColorSpace* space = [self defaultColorSpace];
if (color.colorSpace != space) {
if(color.colorSpace != space) {
color = [color colorUsingColorSpace:space];
}
return color;
@@ -61,7 +62,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_colorTree = [@{
_colorTree = @{
@"aliceblue" : @(0xf0f8ff),
@"antiquewhite" : @(0xfaebd7),
@"aqua" : @(0x00ffff),
@@ -207,13 +208,13 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
@"whitesmoke" : @(0xf5f5f5),
@"yellow" : @(0xffff00),
@"yellowgreen" : @(0x9acd32)
} retain];
};
});
}
+ (NSColor*)computeColor:(id)colour
{
if ([colour isKindOfClass:[NSColor class]])
if([colour isKindOfClass:[NSColor class]])
return colour;
return nil;
}
@@ -263,13 +264,14 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
}
char* str = IJSVGTimmedCharBufferCreate(oString);
if (IJSVGCharBufferIsHEX(str) == YES) {
if(IJSVGCharBufferIsHEX(str) == YES) {
string = [NSString stringWithUTF8String:str];
(void)free(str), str = NULL;
return [self.class colorFromHEXString:string];
}
// is it RGB?
if (IJSVGCharBufferHasPrefix(str, "rgb") == YES) {
if(IJSVGCharBufferHasPrefix(str, "rgb") == YES) {
NSUInteger count = 0;
IJSVGParsingStringMethod** methods = NULL;
methods = IJSVGParsingMethodParseString(str, &count);
@@ -291,7 +293,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
NSString* parameters = [NSString stringWithUTF8String:method->parameters];
NSArray* parts = [parameters ijsvg_componentsSeparatedByChars:","];
NSString* alpha = @"100%";
if (parts.count == 4) {
if(parts.count == 4) {
alpha = parts[3];
}
@@ -304,12 +306,12 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
}
// is it HSL?
if (IJSVGCharBufferHasPrefix(str, "hsl")) {
if(IJSVGCharBufferHasPrefix(str, "hsl")) {
NSInteger count = 0;
CGFloat* params = [IJSVGUtils scanFloatsFromCString:str
size:&count];
CGFloat alpha = 1;
if (count == 4) {
if(count == 4) {
alpha = params[3];
}
@@ -330,7 +332,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
}
// is simply a clear color, dont fill
if (strcmp(str, "none") == 0 ||
if(strcmp(str, "none") == 0 ||
strcmp(str, "transparent") == 0) {
(void)free(str), str = NULL;
return nil;
@@ -345,7 +347,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
{
NSNumber* hex = nil;
name = [name.lowercaseString stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
if ((hex = _colorTree[name]) == nil) {
if((hex = _colorTree[name]) == nil) {
return nil;
}
return [self.class colorFromHEXInteger:hex.integerValue];
@@ -374,33 +376,33 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
BOOL allowRRGGBBAA = (options & IJSVGColorStringOptionAllowRRGGBBAA) != 0;
// jsut return none
if (alpha == 0 && forceHex == NO) {
return @"none";
if(alpha == 0 && forceHex == NO) {
return IJSVGStringNone;
}
// always return hex unless criteria is met
if (forceHex == YES || allowRRGGBBAA == YES || alpha == 100 || (red == 0 && green == 0 && blue == 0 && alpha == 0) || (red == 255 && green == 255 && blue == 255 && alpha == 100)) {
if(forceHex == YES || allowRRGGBBAA == YES || alpha == 100 || (red == 0 && green == 0 && blue == 0 && alpha == 0) || (red == 255 && green == 255 && blue == 255 && alpha == 100)) {
// we need to make sure the last 2 chars
// are the same or we cant enable shorthand
if (allowRRGGBBAA == YES) {
if(allowRRGGBBAA == YES) {
NSString* alphaHexString = [NSString stringWithFormat:@"%02X",
(int)(color.alphaComponent * 0xFF)];
if ([alphaHexString characterAtIndex:0] !=
if([alphaHexString characterAtIndex:0] !=
[alphaHexString characterAtIndex:1]) {
allowShortHand = NO;
}
}
if (allowShortHand == YES) {
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] &&
if([r characterAtIndex:0] == [r characterAtIndex:1] &&
[g characterAtIndex:0] == [g characterAtIndex:1] &&
[b characterAtIndex:0] == [b characterAtIndex:1]) {
// allow shorthand alpha
if (allowRRGGBBAA == YES && alpha != 100) {
if(allowRRGGBBAA == YES && alpha != 100) {
NSString* a = [NSString stringWithFormat:@"%02X",
(int)(color.alphaComponent * 0xFF)];
return [NSString stringWithFormat:@"#%c%c%c%c",
@@ -411,7 +413,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
[g characterAtIndex:0], [b characterAtIndex:0]];
}
}
if (allowRRGGBBAA == YES && alpha != 100) {
if(allowRRGGBBAA == YES && alpha != 100) {
return [NSString stringWithFormat:@"#%02X%02X%02X%02X", red, green,
blue, (int)(color.alphaComponent * 0xFF)];
}
@@ -761,7 +763,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
+ (NSColor*)colorFromHEXInteger:(NSInteger)hex
{
CGFloat alpha = 1.f;
if ([self HEXContainsAlphaComponent:hex] == YES) {
if([self HEXContainsAlphaComponent:hex] == YES) {
alpha = (hex & 0xFF) / 255.f;
hex = hex >> 8;
}
@@ -793,7 +795,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
char* str = (char*)string.UTF8String;
size_t length = strlen(str);
if (length == 0 || IJSVGCharBufferIsHEX(str) == NO) {
if(length == 0 || IJSVGCharBufferIsHEX(str) == NO) {
return nil;
}
@@ -806,7 +808,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
unsigned long hex;
// we need to work out if its shorthand
// if it is, the length needs to be length*2
if (length == 3 || length == 4) {
if(length == 3 || length == 4) {
char* chars = NULL;
chars = (char*)calloc(sizeof(char),length*2+1);
for(int i = 0; i < length; i++) {
@@ -819,7 +821,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
}
// now convert rest to hex
if (containsAlphaComponent != nil) {
if(containsAlphaComponent != nil) {
*containsAlphaComponent = [self HEXContainsAlphaComponent:hex];
}
return [self colorFromHEXInteger:hex];
@@ -1,35 +0,0 @@
//
// IJSVGColorList.h
// IconJar
//
// Created by Curtis Hard on 07/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGColor.h>
#import <IJSVG/IJSVGColorType.h>
#import <Foundation/Foundation.h>
@interface IJSVGColorList : NSObject <NSCopying> {
@private
NSMutableDictionary<NSColor*, NSColor*>* _replacementColorTree;
NSMutableSet<IJSVGColorType*>* _colors;
}
@property (nonatomic, assign, readonly) NSUInteger count;
- (NSColor*)proposedColorForColor:(NSColor*)color;
- (void)removeAllReplacementColors;
- (void)removeReplacementColor:(NSColor*)color;
- (void)setReplacementColor:(NSColor*)newColor
forColor:(NSColor*)color;
- (void)setReplacementColors:(NSDictionary<NSColor*, NSColor*>*)colors
clearExistingColors:(BOOL)clearExistingColors;
- (void)addColorsFromList:(IJSVGColorList*)sheet;
- (NSSet<IJSVGColorType*>*)colors;
- (void)addColor:(IJSVGColorType*)color;
- (NSDictionary<NSColor*, NSColor*>*)replacementColors;
@end
@@ -1,136 +0,0 @@
//
// IJSVGColorList.m
// IconJar
//
// Created by Curtis Hard on 07/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGColorList.h"
@implementation IJSVGColorList
- (void)dealloc
{
(void)([_replacementColorTree release]), _replacementColorTree = nil;
(void)([_colors release]), _colors = nil;
[super dealloc];
}
- (instancetype)init
{
if ((self = [super init]) != nil) {
_replacementColorTree = [[NSMutableDictionary alloc] init];
_colors = [[NSMutableSet alloc] init];
}
return self;
}
- (id)copyWithZone:(NSZone*)zone
{
IJSVGColorList* sheet = [[self.class alloc] init];
[sheet setReplacementColors:[_replacementColorTree.copy autorelease]
clearExistingColors:YES];
return sheet;
}
- (NSColor*)proposedColorForColor:(NSColor*)color
{
// nothing found, just return color
if (_replacementColorTree == nil || _replacementColorTree.count == 0) {
return color;
}
// check the mappings
NSColor* found = nil;
color = [IJSVGColor computeColorSpace:color];
if ((found = _replacementColorTree[color]) != nil) {
return found;
}
return color;
}
- (void)_invalidateColorTree
{
(void)([_replacementColorTree release]), _replacementColorTree = nil;
_replacementColorTree = [[NSMutableDictionary alloc] init];
}
- (void)removeAllReplacementColors
{
[self _invalidateColorTree];
}
- (void)removeReplacementColor:(NSColor*)color
{
if (_replacementColorTree == nil) {
return;
}
[_replacementColorTree removeObjectForKey:[IJSVGColor computeColorSpace:color]];
}
- (void)setReplacementColor:(NSColor*)newColor
forColor:(NSColor*)color
{
color = [IJSVGColor computeColorSpace:color];
newColor = [IJSVGColor computeColorSpace:newColor];
_replacementColorTree[color] = newColor;
}
- (void)setReplacementColors:(NSDictionary<NSColor*, NSColor*>*)colors
clearExistingColors:(BOOL)clearExistingColors
{
if (clearExistingColors == YES) {
[self _invalidateColorTree];
}
for (NSColor* oldColor in colors) {
[self setReplacementColor:colors[oldColor]
forColor:oldColor];
}
}
- (NSSet<IJSVGColorType*>*)colors
{
return [NSSet setWithSet:_colors];
}
- (void)addColorsFromList:(IJSVGColorList*)sheet
{
for(IJSVGColorType* color in sheet.colors) {
[self addColor:color];
}
}
- (void)addColor:(IJSVGColorType*)color
{
// we just need to update its bit mask
if([_colors containsObject:color] == YES) {
void (^handler)(IJSVGColorType * _Nonnull obj, BOOL * _Nonnull stop) =
^(IJSVGColorType * _Nonnull obj, BOOL * _Nonnull stop) {
if([obj isEqual:color] == YES) {
obj.flags |= color.flags;
*stop = YES;
}
};
[_colors enumerateObjectsUsingBlock:handler];
return;
}
[_colors addObject:color];
}
- (NSDictionary<NSColor*,NSColor*>*)replacementColors
{
return _replacementColorTree;
}
- (void)removeColor:(IJSVGColorType*)color
{
[_colors removeObject:color];
}
- (NSUInteger)count
{
return _colors.count;
}
@end
@@ -9,22 +9,24 @@
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
typedef NS_OPTIONS(NSInteger, IJSVGColorTypeFlags) {
IJSVGColorTypeNone = 0,
IJSVGColorTypeFlagUnknown = 1 << 0,
IJSVGColorTypeFlagFill = 1 << 1,
IJSVGColorTypeFlagStroke = 1 << 2,
IJSVGColorTypeFlagStop = 1 << 3
typedef NS_OPTIONS(NSInteger, IJSVGColorUsageTraits) {
IJSVGColorUsageTraitNone = 0,
IJSVGColorUsageTraitUnknown = 1 << 0,
IJSVGColorUsageTraitFill = 1 << 1,
IJSVGColorUsageTraitStroke = 1 << 2,
IJSVGColorUsageTraitGradientStop = 1 << 3,
IJSVGColorUsageTraitAll = IJSVGColorUsageTraitFill | IJSVGColorUsageTraitGradientStop |
IJSVGColorUsageTraitStroke
};
@interface IJSVGColorType : NSObject {
@interface IJSVGTraitedColor : NSObject {
}
@property (nonatomic, retain) NSColor* color;
@property (nonatomic, assign) IJSVGColorTypeFlags flags;
@property (nonatomic, strong) NSColor* color;
@property (nonatomic, assign) IJSVGColorUsageTraits traits;
+ (IJSVGColorType*)typeWithColor:(NSColor*)color
flags:(IJSVGColorTypeFlags)mask;
+ (IJSVGTraitedColor*)typeWithColor:(NSColor*)color
traits:(IJSVGColorUsageTraits)mask;
@end
@@ -1,41 +0,0 @@
//
// IJSVGColorType.m
// IJSVG
//
// Created by Curtis Hard on 20/04/2021.
// Copyright © 2021 Curtis Hard. All rights reserved.
//
#import "IJSVGColorType.h"
@implementation IJSVGColorType
- (void)dealloc
{
(void)[_color release], _color = nil;
[super dealloc];
}
+ (IJSVGColorType*)typeWithColor:(NSColor*)color
flags:(IJSVGColorTypeFlags)mask
{
IJSVGColorType* type = [[[self alloc] init] autorelease];
type.color = color;
type.flags = mask;
return type;
}
- (BOOL)isEqual:(id)object
{
if([object isKindOfClass:IJSVGColorType.class] == NO) {
return NO;
}
return [self.color isEqual:((IJSVGColorType*)object).color];
}
- (NSUInteger)hash
{
return self.color.hash;
}
@end
@@ -0,0 +1,36 @@
//
// IJSVGColorType.h
// IJSVG
//
// Created by Curtis Hard on 20/04/2021.
// Copyright © 2021 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
typedef NS_OPTIONS(NSInteger, IJSVGColorUsageTraits) {
IJSVGColorUsageTraitNone = 0,
IJSVGColorUsageTraitUnknown = 1 << 0,
IJSVGColorUsageTraitFill = 1 << 1,
IJSVGColorUsageTraitStroke = 1 << 2,
IJSVGColorUsageTraitGradientStop = 1 << 3,
IJSVGColorUsageTraitAll = IJSVGColorUsageTraitFill | IJSVGColorUsageTraitGradientStop |
IJSVGColorUsageTraitStroke
};
@interface IJSVGTraitedColor : NSObject {
}
@property (nonatomic, strong) NSColor* color;
@property (nonatomic, assign) IJSVGColorUsageTraits traits;
+ (IJSVGTraitedColor*)colorWithColor:(NSColor*)color
traits:(IJSVGColorUsageTraits)mask;
- (void)addTraits:(IJSVGColorUsageTraits)traits;
- (void)removeTraits:(IJSVGColorUsageTraits)traits;
- (BOOL)matchesTraits:(IJSVGColorUsageTraits)traits;
@end
@@ -0,0 +1,64 @@
//
// IJSVGColorType.m
// IJSVG
//
// Created by Curtis Hard on 20/04/2021.
// Copyright © 2021 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGTraitedColor.h>
#import <IJSVG/IJSVGColor.h>
@implementation IJSVGTraitedColor
+ (IJSVGTraitedColor*)colorWithColor:(NSColor*)color
traits:(IJSVGColorUsageTraits)traits
{
IJSVGTraitedColor* type = [[self alloc] init];
type.color = color;
type.traits = traits;
return type;
}
- (instancetype)init
{
if((self = [super init]) != nil) {
_traits = IJSVGColorUsageTraitNone;
}
return self;
}
- (BOOL)isEqual:(id)object
{
if([object isKindOfClass:IJSVGTraitedColor.class] == NO) {
return NO;
}
return [self.color isEqual:((IJSVGTraitedColor*)object).color];
}
- (void)setColor:(NSColor *)color
{
_color = [IJSVGColor computeColorSpace:color];
}
- (NSUInteger)hash
{
return self.color.hash;
}
- (void)addTraits:(IJSVGColorUsageTraits)traits
{
_traits |= traits;
}
- (void)removeTraits:(IJSVGColorUsageTraits)traits
{
_traits = _traits & ~traits;
}
- (BOOL)matchesTraits:(IJSVGColorUsageTraits)traits
{
return (self.traits & traits) == traits;
}
@end
@@ -0,0 +1,43 @@
//
// IJSVGColorList.h
// IconJar
//
// Created by Curtis Hard on 07/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGColor.h>
#import <IJSVG/IJSVGTraitedColor.h>
#import <Foundation/Foundation.h>
@interface IJSVGReplacementColor : IJSVGTraitedColor
@property (nonatomic, strong) NSColor* replacementColor;
@end
@interface IJSVGTraitedColorStorage : NSObject {
@private
NSMutableArray<IJSVGReplacementColor*>* _replacementColors;
NSMutableSet<IJSVGTraitedColor*>* _colors;
IJSVGColorUsageTraits _traits;
IJSVGColorUsageTraits _replacementTraits;
}
@property (nonatomic, readonly) NSUInteger count;
@property (nonatomic, readonly) NSSet<IJSVGTraitedColor*>* colors;
@property (nonatomic, readonly) NSUInteger replacedColorCount;
- (void)addTraits:(IJSVGColorUsageTraits)traits;
- (void)addColor:(IJSVGTraitedColor*)color;
- (void)replaceColor:(NSColor*)replaceColor
withColor:(NSColor*)withColor
traits:(IJSVGColorUsageTraits)traits;
- (void)unionColorStorage:(IJSVGTraitedColorStorage*)colorList;
- (NSColor*)colorForColor:(NSColor*)color
matchingTraits:(IJSVGColorUsageTraits)traits;
- (BOOL)matchesReplacementTraits:(IJSVGColorUsageTraits)traits;
- (BOOL)matchesTraits:(IJSVGColorUsageTraits)traits;
@end
@@ -0,0 +1,146 @@
//
// IJSVGColorList.m
// IconJar
//
// Created by Curtis Hard on 07/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGTraitedColorStorage.h>
@implementation IJSVGReplacementColor
- (void)setReplacementColor:(NSColor*)replacementColor
{
_replacementColor = [IJSVGColor computeColorSpace:replacementColor];
}
@end
@implementation IJSVGTraitedColorStorage
- (instancetype)init
{
if((self = [super init]) != nil) {
_replacementColors = [[NSMutableArray alloc] init];
_colors = [[NSMutableSet alloc] init];
_replacementTraits = IJSVGColorUsageTraitNone;
_traits = IJSVGColorUsageTraitNone;
}
return self;
}
- (void)addColor:(IJSVGTraitedColor*)color
{
if([_colors containsObject:color] == YES) {
void (^handler)(IJSVGTraitedColor * _Nonnull obj, BOOL * _Nonnull stop) =
^(IJSVGTraitedColor * _Nonnull obj, BOOL * _Nonnull stop) {
if([obj isEqual:color] == YES) {
[obj addTraits:color.traits];
*stop = YES;
}
};
[_colors enumerateObjectsUsingBlock:handler];
return;
}
_traits |= color.traits;
[_colors addObject:color];
}
- (void)addTraits:(IJSVGColorUsageTraits)traits
{
for(IJSVGTraitedColor* color in _colors) {
[color addTraits:traits];
}
}
- (void)replaceColor:(NSColor*)replaceColor
withColor:(NSColor*)withColor
traits:(IJSVGColorUsageTraits)traits
{
replaceColor = [IJSVGColor computeColorSpace:replaceColor];
withColor = [IJSVGColor computeColorSpace:withColor];
IJSVGReplacementColor* repColor = [self replacementColorForColor:replaceColor
withColor:withColor];
if(repColor == nil) {
repColor = [[IJSVGReplacementColor alloc] init];
repColor.color = replaceColor;
repColor.replacementColor = withColor;
[_replacementColors addObject:repColor];
}
_replacementTraits |= traits;
[repColor addTraits:traits];
}
- (IJSVGReplacementColor*)replacementColorForColor:(NSColor*)replacementColor
withColor:(NSColor*)withColor
{
for(IJSVGReplacementColor* color in _replacementColors) {
if([color.color isEqual:color] == YES &&
[color.replacementColor isEqual:withColor] == YES) {
return color;
}
}
return nil;
}
- (IJSVGReplacementColor*)replacementColorForColor:(NSColor*)color
matchingTraits:(IJSVGColorUsageTraits)traits
{
for(IJSVGReplacementColor* replacementColor in _replacementColors) {
if([replacementColor.color isEqual:color] &&
[replacementColor matchesTraits:traits] == YES) {
return replacementColor;
}
}
return nil;
}
- (NSColor*)colorForColor:(NSColor*)color
matchingTraits:(IJSVGColorUsageTraits)traits
{
if([self matchesReplacementTraits:traits] == NO) {
return nil;
}
color = [IJSVGColor computeColorSpace:color];
IJSVGReplacementColor* repColor = nil;
if((repColor = [self replacementColorForColor:color
matchingTraits:traits]) != nil) {
return repColor.replacementColor;
}
return nil;
}
- (void)unionColorStorage:(IJSVGTraitedColorStorage*)colorList
{
for(IJSVGTraitedColor* traitedColor in colorList.colors) {
[self addColor:traitedColor];
}
}
- (BOOL)matchesTraits:(IJSVGColorUsageTraits)traits
{
return (_traits & traits) == traits;
}
- (BOOL)matchesReplacementTraits:(IJSVGColorUsageTraits)traits
{
return (_replacementTraits & traits) == traits;
}
- (NSUInteger)replacedColorCount
{
return _replacementColors.count;
}
- (NSUInteger)count
{
return _colors.count;
}
- (NSSet<IJSVGTraitedColor*>*)colors
{
return _colors;
}
@end
@@ -26,7 +26,7 @@ typedef NS_ENUM(NSInteger, IJSVGCommandType) {
@property (nonatomic, assign) CGFloat* parameters;
@property (nonatomic, assign) NSInteger parameterCount;
@property (nonatomic, assign) IJSVGCommandType type;
@property (nonatomic, retain) NSArray<IJSVGCommand*>* subCommands;
@property (nonatomic, strong) NSArray<IJSVGCommand*>* subCommands;
@property (nonatomic, assign) IJSVGCommand* previousCommand;
@property (nonatomic, assign) BOOL isSubCommand;
@@ -6,19 +6,19 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import "IJSVGUtils.h"
#import "IJSVGCommandClose.h"
#import "IJSVGCommandCurve.h"
#import "IJSVGCommandEllipticalArc.h"
#import "IJSVGCommandHorizontalLine.h"
#import "IJSVGCommandLineTo.h"
#import "IJSVGCommandMove.h"
#import "IJSVGCommandQuadraticCurve.h"
#import "IJSVGCommandSmoothCurve.h"
#import "IJSVGCommandSmoothQuadraticCurve.h"
#import "IJSVGCommandVerticalLine.h"
#import <IJSVG/IJSVGCommand.h>
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGCommandClose.h>
#import <IJSVG/IJSVGCommandCurve.h>
#import <IJSVG/IJSVGCommandEllipticalArc.h>
#import <IJSVG/IJSVGCommandHorizontalLine.h>
#import <IJSVG/IJSVGCommandLineTo.h>
#import <IJSVG/IJSVGCommandMove.h>
#import <IJSVG/IJSVGCommandQuadraticCurve.h>
#import <IJSVG/IJSVGCommandSmoothCurve.h>
#import <IJSVG/IJSVGCommandSmoothQuadraticCurve.h>
#import <IJSVG/IJSVGCommandVerticalLine.h>
#import <IJSVG/IJSVGThreadManager.h>
@implementation IJSVGCommand
@@ -112,28 +112,34 @@
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer
{
IJSVGPathDataStream* stream = IJSVGPathDataStreamCreateDefault();
IJSVGThreadManager* manager = IJSVGThreadManager.currentManager;
NSArray<IJSVGCommand*>* commands = [self commandsForDataCharacters:buffer
dataStream:stream];
IJSVGPathDataStreamRelease(stream);
dataStream:manager.pathDataStream];
return commands;
}
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)unsafeBuffer
dataStream:(IJSVGPathDataStream*)dataStream
{
NSMutableArray<IJSVGCommand*>* commands = [[[NSMutableArray alloc] init] autorelease];
NSUInteger len = strlen(buffer);
NSMutableArray<IJSVGCommand*>* commands = [[NSMutableArray alloc] init];
NSUInteger len = strlen(unsafeBuffer);
NSUInteger lastIndex = len - 1;
// we need to trim the buffer first as any given string given to us
// could be unsafe and have random whitespace at the extremes.
size_t bufferLength = sizeof(char)*(len + 1);
char* buffer = (char*)malloc(bufferLength);
memcpy(buffer, unsafeBuffer, bufferLength);
IJSVGTrimCharBuffer(buffer);
// make sure we plus 1 for the null byte
char* charBuffer = (char*)malloc(sizeof(char)*(len + 1));
char* charBuffer = (char*)malloc(bufferLength);
NSInteger start = 0;
for (NSInteger i = 0; i < len; i++) {
for (NSInteger i = start; i < len; i++) {
char nextChar = buffer[i + 1];
BOOL atEnd = i == lastIndex;
BOOL isStartCommand = IJSVGIsLegalCommandCharacter(nextChar);
if (isStartCommand == YES || atEnd == YES) {
if(isStartCommand == YES || atEnd == YES) {
// copy memory from current buffer
NSInteger index = ((i + 1) - start);
@@ -151,17 +157,27 @@
// previous command is actual subcommand
Class commandClass = [IJSVGCommand commandClassForCommandChar:commandString[0]];
IJSVGCommand* command = nil;
command = (IJSVGCommand*)[[[commandClass alloc] initWithCommandStringBuffer:commandString
dataStream:dataStream] autorelease];
[commands addObject:command];
if(commandClass != nil) {
IJSVGCommand* command = nil;
command = (IJSVGCommand*)[[commandClass alloc] initWithCommandStringBuffer:commandString
dataStream:dataStream];
[commands addObject:command];
}
#if DEBUG
else {
// if we get here then the command buffer is invalid, nothing we can
// do about it, just invalid data.
NSLog(@"\"%s\" is not a valid command instruction set", commandString);
}
#endif
// free the memory as at this point, we are done with it
(void)free(commandString), commandString = NULL;
}
}
(void)free(charBuffer), charBuffer = NULL;
(void)free(buffer), buffer = NULL;
return commands;
}
@@ -170,7 +186,7 @@
bounds:(CGRect)bounds
{
NSMutableArray<IJSVGCommand*>* newCommands = nil;
newCommands = [[[NSMutableArray alloc] initWithCapacity:commands.count] autorelease];
newCommands = [[NSMutableArray alloc] initWithCapacity:commands.count];
for(IJSVGCommand* command in commands) {
IJSVGCommand* nCommand = [command commandByConvertingToUnits:unitType
boundingBox:bounds];
@@ -181,17 +197,15 @@
- (void)dealloc
{
(void)([_subCommands release]), _subCommands = nil;
if (_parameters) {
if(_parameters) {
(void)(free(_parameters)), _parameters = nil;
}
[super dealloc];
}
- (id)initWithCommandStringBuffer:(const char*)str
dataStream:(IJSVGPathDataStream*)dataStream
{
if ((self = [super init]) != nil) {
if((self = [super init]) != nil) {
// work out the basics
_currentIndex = 0;
_command = str[0];
@@ -202,15 +216,15 @@
_parameters = IJSVGParsePathDataStreamSequence(str, strlen(str),
dataStream, sequence, paramCount, &sets);
if (sets <= 1) {
if(sets <= 1) {
CGFloat* subParams = [self parametersFromIndexOffset:0];
IJSVGCommand* command = [self subcommandWithParameters:subParams
paramCount:paramCount
previousCommand:nil];
_subCommands = @[ command ].retain;
_subCommands = @[ command ];
} else {
NSMutableArray<IJSVGCommand*>* subCommandArray = nil;
subCommandArray = [[NSMutableArray alloc] initWithCapacity:sets].autorelease;
subCommandArray = [[NSMutableArray alloc] initWithCapacity:sets];
// interate over the sets
IJSVGCommand* lastCommand = nil;
@@ -239,8 +253,7 @@
- (void)setSubCommands:(NSArray<IJSVGCommand*>*)subCommands
{
(void)[_subCommands release], _subCommands = nil;
_subCommands = subCommands.retain;
_subCommands = subCommands;
}
- (id)copyWithZone:(NSZone *)zone
@@ -257,9 +270,9 @@
IJSVGCommand* lastCommand = nil;
NSMutableArray<IJSVGCommand*>* subcommands = nil;
subcommands = [[[NSMutableArray alloc] initWithCapacity:self.subCommands.count] autorelease];
subcommands = [[NSMutableArray alloc] initWithCapacity:self.subCommands.count];
for(IJSVGCommand* subcommand in self.subCommands) {
IJSVGCommand* subCopy = [[subcommand copy] autorelease];
IJSVGCommand* subCopy = subcommand.copy;
subCopy.previousCommand = lastCommand;
subCopy.isSubCommand = lastCommand != nil;
[subcommands addObject:subCopy];
@@ -272,7 +285,7 @@
{
CGFloat* subParams = 0;
NSInteger req = [self.class requiredParameterCount];
if (req != 0) {
if(req != 0) {
subParams = (CGFloat*)malloc(req * sizeof(CGFloat));
memcpy(subParams, &self.parameters[index * req], sizeof(CGFloat) * req);
}
@@ -284,7 +297,7 @@
previousCommand:(IJSVGCommand*)aPreviousCommand
{
// create a subcommand per set
IJSVGCommand* c = [[[self.class alloc] init] autorelease];
IJSVGCommand* c = [[self.class alloc] init];
c.parameterCount = paramCount;
c.parameters = subParams;
c.type = self.type;
@@ -330,9 +343,9 @@
- (NSString *)description
{
NSMutableString* str = [[[NSMutableString alloc] init] autorelease];
NSMutableString* str = [[NSMutableString alloc] init];
[str appendFormat:@"%c ",_command];
NSMutableArray* args = [[[NSMutableArray alloc] initWithCapacity:_parameterCount] autorelease];
NSMutableArray* args = [[NSMutableArray alloc] initWithCapacity:_parameterCount];
for(int i = 0; i < _parameterCount; i++) {
[args addObject:[NSString stringWithFormat:@"%f",_parameters[i]]];
}
@@ -346,7 +359,7 @@
IJSVGCommand* copy = self.copy;
[copy convertToUnits:unitType
boundingBox:boundingBox];
return [copy autorelease];
return copy;
}
@end
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandClose : IJSVGCommand
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandClose.h"
#import <IJSVG/IJSVGCommandClose.h>
@implementation IJSVGCommandClose
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandCurve : IJSVGCommand
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandCurve.h"
#import <IJSVG/IJSVGCommandCurve.h>
@implementation IJSVGCommandCurve
@@ -22,7 +22,7 @@
type:(IJSVGCommandType)type
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddCurveToPoint(path, NULL, params[0], params[1],
params[2], params[3],
params[4], params[5]);
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandEllipticalArc : IJSVGCommand
@@ -6,8 +6,8 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandEllipticalArc.h"
#import "IJSVGUtils.h"
#import <IJSVG/IJSVGCommandEllipticalArc.h>
#import <IJSVG/IJSVGUtils.h>
@implementation IJSVGCommandEllipticalArc
@@ -49,11 +49,11 @@ static IJSVGPathDataSequence* _sequence;
BOOL largeArcFlag = NO;
BOOL sweepFlag = NO;
radii = [currentCommand readPoint];
xAxisRotation = [currentCommand readFloat];
largeArcFlag = [currentCommand readBOOL];
sweepFlag = [currentCommand readBOOL];
arcEndPoint = [currentCommand readPoint];
radii = currentCommand.readPoint;
xAxisRotation = currentCommand.readFloat;
largeArcFlag = currentCommand.readBOOL;
sweepFlag = currentCommand.readBOOL;
arcEndPoint = currentCommand.readPoint;
CGFloat rx = fabs(radii.x);
CGFloat ry = fabs(radii.y);
@@ -61,7 +61,7 @@ static IJSVGPathDataSequence* _sequence;
xAxisRotation *= M_PI / 180.f;
xAxisRotation = fmod(xAxisRotation, 2.f * M_PI);
if (type == kIJSVGCommandTypeRelative) {
if(type == kIJSVGCommandTypeRelative) {
arcEndPoint.x += pathCurrentPoint.x;
arcEndPoint.y += pathCurrentPoint.y;
}
@@ -72,7 +72,7 @@ static IJSVGPathDataSequence* _sequence;
CGFloat x2 = arcEndPoint.x;
CGFloat y2 = arcEndPoint.y;
if (rx == 0.f || ry == 0.f) {
if(rx == 0.f || ry == 0.f) {
CGPathAddLineToPoint(path, NULL, x2, y2);
return;
}
@@ -90,7 +90,7 @@ static IJSVGPathDataSequence* _sequence;
CGFloat delta = xp_2 / rx_2 + yp_2 / ry_2;
if (delta > 1.f) {
if(delta > 1.f) {
rx *= sqrt(delta);
ry *= sqrt(delta);
rx_2 = rx * rx;
@@ -120,11 +120,11 @@ static IJSVGPathDataSequence* _sequence;
CGFloat angleDelta = endAngle - startAngle;;
if (sweepFlag == YES) {
if (angleDelta < 0.f) {
if(sweepFlag == YES) {
if(angleDelta < 0.f) {
angleDelta += 2.f * M_PI;
}
} else if (angleDelta > 0.f) {
} else if(angleDelta > 0.f) {
angleDelta = angleDelta - 2.f * M_PI;
}
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandHorizontalLine : IJSVGCommand
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandHorizontalLine.h"
#import <IJSVG/IJSVGCommandHorizontalLine.h>
@implementation IJSVGCommandHorizontalLine
@@ -22,7 +22,7 @@
type:(IJSVGCommandType)type
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, params[0], CGPathGetCurrentPoint(path).y);
return;
}
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandLineTo : IJSVGCommand
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandLineTo.h"
#import <IJSVG/IJSVGCommandLineTo.h>
@implementation IJSVGCommandLineTo
@@ -22,7 +22,7 @@
type:(IJSVGCommandType)type
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, params[0], params[1]);
return;
}
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandMove : IJSVGCommand
@@ -6,8 +6,8 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandLineTo.h"
#import "IJSVGCommandMove.h"
#import <IJSVG/IJSVGCommandLineTo.h>
#import <IJSVG/IJSVGCommandMove.h>
@implementation IJSVGCommandMove
@@ -25,7 +25,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.class == self.class && currentCommand.isSubCommand == YES) {
if(command.class == self.class && currentCommand.isSubCommand == YES) {
[IJSVGCommandLineTo runWithParams:params
paramCount:count
command:currentCommand
@@ -40,7 +40,7 @@
// relative but there is no previous command which means
// there is no current point. Asking for current point on an empty
// path will result in an exception being thrown
if (type == kIJSVGCommandTypeAbsolute || command == nil) {
if(type == kIJSVGCommandTypeAbsolute || command == nil) {
CGPathMoveToPoint(path, NULL,
params[0], params[1]);
return;
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandQuadraticCurve : IJSVGCommand
@@ -6,8 +6,8 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandQuadraticCurve.h"
#import "IJSVGUtils.h"
#import <IJSVG/IJSVGCommandQuadraticCurve.h>
#import <IJSVG/IJSVGUtils.h>
@implementation IJSVGCommandQuadraticCurve
@@ -23,7 +23,7 @@
type:(IJSVGCommandType)type
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddQuadCurveToPoint(path, NULL, params[0], params[1],
params[2], params[3]);
return;
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandSmoothCurve : IJSVGCommand
@@ -6,9 +6,9 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandCurve.h"
#import "IJSVGCommandSmoothCurve.h"
#import "IJSVGUtils.h"
#import <IJSVG/IJSVGCommandCurve.h>
#import <IJSVG/IJSVGCommandSmoothCurve.h>
#import <IJSVG/IJSVGUtils.h>
@implementation IJSVGCommandSmoothCurve
@@ -26,10 +26,10 @@
{
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPoint firstControl = CGPointMake(currentPoint.x, currentPoint.y);
if (command != nil) {
if (command.class == [IJSVGCommandCurve class] || command.class == self.class) {
if (command.class == [IJSVGCommandCurve class]) {
if (command.type == kIJSVGCommandTypeAbsolute) {
if(command != nil) {
if(command.class == [IJSVGCommandCurve class] || command.class == self.class) {
if(command.class == [IJSVGCommandCurve class]) {
if(command.type == kIJSVGCommandTypeAbsolute) {
firstControl = CGPointMake(-1 * command.parameters[2] + 2 * currentPoint.x,
-1 * command.parameters[3] + 2 * currentPoint.y);
} else {
@@ -39,7 +39,7 @@
-1 * (command.parameters[3] + oldPoint.y) + 2 * currentPoint.y);
}
} else {
if (command.type == kIJSVGCommandTypeAbsolute) {
if(command.type == kIJSVGCommandTypeAbsolute) {
firstControl = CGPointMake(-1 * command.parameters[0] + 2 * currentPoint.x,
-1 * command.parameters[1] + 2 * currentPoint.y);
} else {
@@ -51,7 +51,7 @@
}
}
}
if (type == kIJSVGCommandTypeAbsolute) {
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddCurveToPoint(path, NULL, firstControl.x, firstControl.y,
params[0], params[1], params[2], params[3]);
return;
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandSmoothQuadraticCurve : IJSVGCommand
@@ -6,9 +6,9 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandQuadraticCurve.h"
#import "IJSVGCommandSmoothQuadraticCurve.h"
#import "IJSVGUtils.h"
#import <IJSVG/IJSVGCommandQuadraticCurve.h>
#import <IJSVG/IJSVGCommandSmoothQuadraticCurve.h>
#import <IJSVG/IJSVGUtils.h>
@implementation IJSVGCommandSmoothQuadraticCurve
@@ -27,10 +27,10 @@
CGPoint lastControlPoint = IJSVGPathGetLastQuadraticCommandPoint(path);
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPoint commandPoint = CGPointMake(currentPoint.x, currentPoint.y);
if (command != nil) {
if (command.class == IJSVGCommandQuadraticCurve.class) {
if(command != nil) {
if(command.class == IJSVGCommandQuadraticCurve.class) {
// quadratic curve
if (command.type == kIJSVGCommandTypeAbsolute) {
if(command.type == kIJSVGCommandTypeAbsolute) {
commandPoint = NSMakePoint(-1 * command.parameters[0] + 2 * currentPoint.x,
-1 * command.parameters[1] + 2 * currentPoint.y);
} else {
@@ -39,14 +39,14 @@
commandPoint = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * (currentPoint.x),
-1 * (command.parameters[1] + oldPoint.y) + 2 * currentPoint.y);
}
} else if (command.class == self.class) {
} else if(command.class == self.class) {
// smooth quadratic curve
commandPoint = CGPointMake(-1 * (lastControlPoint.x) + 2 * (currentPoint.x),
-1 * (lastControlPoint.y) + 2 * currentPoint.y);
}
}
// path.lastControlPoint = commandPoint;
if (type == kIJSVGCommandTypeAbsolute) {
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddQuadCurveToPoint(path, NULL, commandPoint.x, commandPoint.y,
params[0], params[1]);
return;
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommand.h"
#import <IJSVG/IJSVGCommand.h>
#import <Foundation/Foundation.h>
@interface IJSVGCommandVerticalLine : IJSVGCommand
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandVerticalLine.h"
#import <IJSVG/IJSVGCommandVerticalLine.h>
@implementation IJSVGCommandVerticalLine
@@ -22,7 +22,7 @@
type:(IJSVGCommandType)type
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, CGPathGetCurrentPoint(path).x, params[0]);
return;
}
+60 -71
View File
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGColorList.h>
#import <IJSVG/IJSVGTraitedColorStorage.h>
#import <IJSVG/IJSVGRootNode.h>
#import <IJSVG/IJSVGExporter.h>
#import <IJSVG/IJSVGGradientLayer.h>
@@ -16,42 +16,20 @@
#import <IJSVG/IJSVGLayerTree.h>
#import <IJSVG/IJSVGParser.h>
#import <IJSVG/IJSVGRendering.h>
#import <IJSVG/IJSVGRenderingStyle.h>
#import <IJSVG/IJSVGStyle.h>
#import <IJSVG/IJSVGTransaction.h>
#import <Foundation/Foundation.h>
@class IJSVG;
typedef NS_OPTIONS(NSInteger, IJSVGMatchPropertiesMask) {
IJSVGMatchPropertyNone = 0,
IJSVGMatchPropertyContainsMaskedElement = 1 << 0,
IJSVGMatchPropertyContainsStrokedElement = 1 << 1
};
@protocol IJSVGDelegate <NSObject, IJSVGParserDelegate>
@optional
- (void)svg:(IJSVG*)svg
foundSubSVG:(IJSVG*)subSVG
withSVGString:(NSString*)subSVGString;
@end
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
@interface IJSVG : NSObject <NSPasteboardWriting> {
@private
IJSVGRootNode* _rootNode;
CGFloat _scale;
CGFloat _clipScale;
id<IJSVGDelegate> _delegate;
IJSVGLayerTree* _layerTree;
CGRect _viewBox;
CGFloat _backingScale;
NSMutableDictionary* _replacementColors;
struct {
unsigned int shouldHandleSubSVG : 1;
} _respondsTo;
IJSVGUnitSize* _intrinsicSize;
}
// set this to be called when the layer is about to draw, it will call this
@@ -63,37 +41,59 @@ withSVGString:(NSString*)subSVGString;
// global overwriting rules for when rendering an SVG, this will overide any
// fillColor, strokeColor, pattern and gradient fill
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) BOOL clipToViewport;
@property (nonatomic, retain) IJSVGRenderingStyle* renderingStyle;
@property (nonatomic, readonly) IJSVGUnitSize * intrinsicSize;
@property (nonatomic, strong) IJSVGStyle* style;
@property (nonatomic, copy) NSString* title;
@property (nonatomic, copy) NSString* desc;
@property (nonatomic, retain) IJSVGLayerTree* layerTree;
@property (nonatomic, retain) IJSVGRootLayer* rootLayer;
@property (nonatomic, strong) IJSVGLayerTree* layerTree;
@property (nonatomic, strong) IJSVGRootLayer* rootLayer;
@property (nonatomic, assign) BOOL ignoreIntrinsicSize;
@property (nonatomic, readonly) IJSVGTraitedColorStorage* colors;
// The size of the SVG either computed by its intrinsicSize of its viewBox
// If the size if % values, it will use the defaultSize
@property (nonatomic, readonly) CGSize size;
// Will return true if the intrinsic size is a % value
@property (nonatomic, readonly) BOOL hasDynamicSize;
// This is used when the intrinsic size is a % value, e.g. 100% x 100%
@property (nonatomic, assign) CGSize defaultSize;
// bitmask of which dimentions were implicitly set on the SVG
@property (nonatomic, readonly) IJSVGIntrinsicDimensions intrinsicDimensions;
- (void)prepForDrawingInView:(NSView*)view;
- (BOOL)isFont;
- (IJSVGGroup*)rootNode;
- (NSRect)viewBox;
- (NSArray<IJSVGPath*>*)glyphs;
- (IJSVGRootNode*)rootNode;
- (CGRect)viewBox;
- (CGSize)sizeWithDefaultSize:(CGSize)size;
- (NSString*)identifier;
- (NSArray<IJSVG*>*)subSVGs:(BOOL)recursive;
- (NSSet<IJSVG*>*)directDescendSVGs;
- (IJSVGExporter*)exporterWithSize:(CGSize)size
options:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
- (NSString*)SVGStringWithSize:(CGSize)size
options:(IJSVGExporterOptions)options;
- (NSString*)SVGStringWithSize:(CGSize)size
options:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options;
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
+ (id)svgNamed:(NSString*)string;
+ (id)svgNamed:(NSString*)string
delegate:(id<IJSVGDelegate>)delegate;
+ (id)SVGNamed:(NSString*)string;
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path;
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path
flipped:(BOOL)flipped;
- (id)initWithImage:(NSImage*)image;
- (id)initWithRootNode:(IJSVGRootNode*)rootNode;
- (id)initWithSVGLayer:(IJSVGGroupLayer*)group
viewBox:(NSRect)viewBox;
- (id)initWithSVGString:(NSString*)string
error:(NSError**)error
delegate:(id<IJSVGDelegate>)delegate;
viewBox:(CGRect)viewBox;
- (id)initWithSVGString:(NSString*)string;
- (id)initWithSVGString:(NSString*)string
@@ -106,19 +106,9 @@ withSVGString:(NSString*)subSVGString;
- (id)initWithFile:(NSString*)file;
- (id)initWithFile:(NSString*)file
error:(NSError**)error;
- (id)initWithFile:(NSString*)file
delegate:(id<IJSVGDelegate>)delegate;
- (id)initWithFile:(NSString*)file
error:(NSError**)error
delegate:(id<IJSVGDelegate>)delegate;
- (id)initWithFilePathURL:(NSURL*)aURL;
- (id)initWithFilePathURL:(NSURL*)aURL
error:(NSError**)error;
- (id)initWithFilePathURL:(NSURL*)aURL
delegate:(id<IJSVGDelegate>)delegate;
- (id)initWithFilePathURL:(NSURL*)aURL
error:(NSError**)error
delegate:(id<IJSVGDelegate>)delegate;
- (id)initWithDataAssetNamed:(NSDataAssetName)name
error:(NSError**)error;
@@ -126,45 +116,44 @@ withSVGString:(NSString*)subSVGString;
bundle:(NSBundle*)bundle
error:(NSError**)error;
- (NSImage*)imageWithSize:(NSSize)aSize;
- (NSImage*)imageWithSize:(NSSize)aSize
- (NSImage*)imageWithSize:(CGSize)aSize;
- (NSImage*)imageWithSize:(CGSize)aSize
error:(NSError**)error;
- (NSImage*)imageWithSize:(NSSize)aSize
- (NSImage*)imageWithSize:(CGSize)aSize
flipped:(BOOL)flipped;
- (NSImage*)imageWithSize:(NSSize)aSize
- (NSImage*)imageWithSize:(CGSize)aSize
flipped:(BOOL)flipped
error:(NSError**)error;
- (NSImage*)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
- (NSImage*)imageByMaintainingAspectRatioWithSize:(CGSize)aSize
flipped:(BOOL)flipped
error:(NSError**)error;
- (CGImageRef)newCGImageRefWithSize:(CGSize)size
flipped:(BOOL)flipped
error:(NSError**)error;
- (BOOL)drawAtPoint:(NSPoint)point
size:(NSSize)size;
- (BOOL)drawAtPoint:(NSPoint)point
size:(NSSize)aSize
- (BOOL)drawAtPoint:(CGPoint)point
size:(CGSize)size;
- (BOOL)drawAtPoint:(CGPoint)point
size:(CGSize)aSize
error:(NSError**)error;
- (BOOL)drawInRect:(NSRect)rect;
- (BOOL)drawInRect:(NSRect)rect
- (BOOL)drawInRect:(CGRect)rect;
- (BOOL)drawInRect:(CGRect)rect
error:(NSError**)error;
- (void)drawInRect:(NSRect)rect
- (void)drawInRect:(CGRect)rect
context:(CGContextRef)context;
- (NSData*)PDFData;
- (NSData*)PDFData:(NSError**)error;
- (NSData*)PDFDataWithRect:(NSRect)rect;
- (NSData*)PDFDataWithRect:(NSRect)rect
- (NSData*)PDFDataWithRect:(CGRect)rect;
- (NSData*)PDFDataWithRect:(CGRect)rect
error:(NSError**)error;
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize;
// call this to invalidate the render tree when you change the style
- (void)setNeedsDisplay;
// colors
- (IJSVGColorList*)colorList;
- (void)performBlock:(dispatch_block_t)block;
// matching
- (BOOL)matchesPropertiesWithMask:(IJSVGMatchPropertiesMask)mask;
- (BOOL)containsNodesMatchingTraits:(IJSVGNodeTraits)mask;
@end
File diff suppressed because it is too large Load Diff
@@ -1,29 +0,0 @@
//
// IJSVGFontConverter.h
// IJSVGExample
//
// Created by Curtis Hard on 21/05/2015.
// Copyright (c) 2015 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVG.h>
#import <Foundation/Foundation.h>
typedef void (^IJSVGFontConverterEnumerateBlock)(NSString* unicode, IJSVG* svg);
@interface IJSVGFontConverter : NSObject {
@private
NSURL* _url;
NSFont* _font;
NSMutableDictionary<NSString*, id>* _transformedPaths;
}
- (id)initWithFontAtFileURL:(NSURL*)url;
- (NSFont*)font;
- (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block;
+ (IJSVG*)convertIJSVGPathToSVG:(IJSVGPath*)path;
+ (IJSVG*)convertPathToSVG:(CGPathRef)path;
@end
@@ -1,127 +0,0 @@
//
// IJSVGFontConverter.m
// IJSVGExample
//
// Created by Curtis Hard on 21/05/2015.
// Copyright (c) 2015 Curtis Hard. All rights reserved.
//
#import "IJSVGFontConverter.h"
#import "IJSVGShapeLayer.h"
@implementation IJSVGFontConverter
- (void)dealloc
{
(void)([_transformedPaths release]), _transformedPaths = nil;
(void)([_url release]), _url = nil;
(void)([_font release]), _font = nil;
[super dealloc];
}
- (id)initWithFontAtFileURL:(NSURL*)url
{
if ((self = [super init]) != nil) {
_url = [url copy];
// load the font
CGDataProviderRef dataProvider = CGDataProviderCreateWithURL((CFURLRef)_url);
CGFontRef fontRef = CGFontCreateWithDataProvider(dataProvider);
CTFontRef font = CTFontCreateWithGraphicsFont(fontRef, 30.f, NULL, NULL);
// toll free bridge between NSFont at CTFont :)
_font = [(NSFont*)font copy];
CGFontRelease(fontRef);
CGDataProviderRelease(dataProvider);
CFRelease(font);
}
return self;
}
- (NSFont*)font
{
return _font;
}
- (NSArray*)allCharacters
{
NSCharacterSet* charSet = _font.coveredCharacterSet;
NSMutableArray* array = [[[NSMutableArray alloc] init] autorelease];
NSStringEncoding encoding = NSUTF32LittleEndianStringEncoding;
for (int plane = 0; plane <= 16; plane++) {
if ([charSet hasMemberInPlane:plane]) {
UTF32Char c;
for (c = plane << 16; c < (plane + 1) << 16; c++) {
if ([charSet longCharacterIsMember:c]) {
UTF32Char c1 = NSSwapHostIntToLittle(c);
[array addObject:[[[NSString alloc] initWithBytes:&c1
length:4
encoding:encoding] autorelease]];
}
}
}
}
return array;
}
- (void)generateMap
{
CTFontRef font = (CTFontRef)_font;
for (NSString* charString in [self allCharacters]) {
// get the characters in each char
NSUInteger count = charString.length;
unichar characters[count];
[charString getCharacters:characters
range:NSMakeRange(0, count)];
// get the glyphs
CGGlyph glyphs[count];
CTFontGetGlyphsForCharacters(font, characters, glyphs, count);
CGPathRef path = CTFontCreatePathForGlyph(font, glyphs[0], NULL);
if (path != NULL) {
// add SVG to the dictionary
NSString* key = [NSString stringWithFormat:@"%04x", [charString characterAtIndex:0]];
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:path];
_transformedPaths[key] = (id)flippedPath;
CGPathRelease(flippedPath);
}
CGPathRelease(path);
}
}
- (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block
{
if (_transformedPaths == nil) {
_transformedPaths = [[NSMutableDictionary alloc] init];
[self generateMap];
}
for (NSString* key in _transformedPaths.allKeys) {
block(key, [self.class convertPathToSVG:(CGPathRef)_transformedPaths[key]]);
}
}
+ (IJSVG*)convertIJSVGPathToSVG:(IJSVGPath*)path
{
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:path.path];
IJSVG* svg = [self convertPathToSVG:flippedPath];
CGPathRelease(flippedPath);
return svg;
}
+ (IJSVG*)convertPathToSVG:(CGPathRef)path
{
IJSVGBeginTransaction();
__block IJSVG* svg = nil;
IJSVGGroupLayer* layer = [[[IJSVGGroupLayer alloc] init] autorelease];
IJSVGShapeLayer* shape = [[[IJSVGShapeLayer alloc] init] autorelease];
[layer addSublayer:shape];
shape.path = path;
CGRect box = CGPathGetPathBoundingBox(path);
svg = [[IJSVG alloc] initWithSVGLayer:layer
viewBox:box];
IJSVGEndTransaction();
return [svg autorelease];
}
@end
@@ -6,7 +6,7 @@
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGParser.h"
#import <IJSVG/IJSVGParser.h>
#import <Cocoa/Cocoa.h>
@class IJSVG;
@@ -6,8 +6,8 @@
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVG.h"
#import "IJSVGImageRep.h"
#import <IJSVG/IJSVG.h>
#import <IJSVG/IJSVGImageRep.h>
@implementation IJSVGImageRep
@@ -23,7 +23,7 @@
+ (NSArray<NSString*>*)imageTypes
{
if (@available(macOS 10.10, *)) {
if(@available(macOS 10.10, *)) {
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
} else {
return @[ @"public.svg-image", @"svg" ];
@@ -32,7 +32,7 @@
+ (NSArray<NSString*>*)imageUnfilteredTypes
{
if (@available(macOS 10.10, *)) {
if(@available(macOS 10.10, *)) {
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
} else {
return @[ @"public.svg-image", @"svg" ];
@@ -42,7 +42,7 @@
+ (NSArray<NSImageRep*>*)imageRepsWithData:(NSData*)data
{
IJSVGImageRep* instance = [self imageRepWithData:data];
if (instance == nil) {
if(instance == nil) {
return @[];
}
return @[ instance ];
@@ -50,28 +50,21 @@
+ (instancetype)imageRepWithData:(NSData*)data
{
return [[[self alloc] initWithData:data] autorelease];
}
- (void)dealloc
{
(void)([_svg release]), _svg = nil;
[super dealloc];
return [[self alloc] initWithData:data];
}
- (instancetype)initWithData:(NSData*)data
{
if ((self = [super init]) != nil) {
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];
NSString* string = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
_svg = [[IJSVG alloc] initWithSVGString:string];
// no valid SVG, just return nil;
if (_svg == nil) {
[self release];
if(_svg == nil) {
return nil;
}
@@ -17,7 +17,7 @@ IB_DESIGNABLE
IJSVG* SVG;
}
@property (nonatomic, retain) IJSVG* SVG;
@property (nonatomic, strong) IJSVG* SVG;
+ (IJSVGView*)viewWithSVGNamed:(NSString*)name;
- (id)initWithSVG:(IJSVG*)anSvg;
+10 -16
View File
@@ -6,7 +6,7 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGView.h"
#import <IJSVG/IJSVGView.h>
@implementation IJSVGView
@@ -17,20 +17,17 @@
// make sure we call this, or block may get called for a view
// that doesnt exist
[SVG prepForDrawingInView:nil];
(void)([imageName release]), imageName = nil;
(void)([SVG release]), SVG = nil;
[super dealloc];
}
+ (IJSVGView*)viewWithSVGNamed:(NSString*)name
{
IJSVG* anSVG = [IJSVG svgNamed:name];
return [[[self alloc] initWithSVG:anSVG] autorelease];
IJSVG* anSVG = [IJSVG SVGNamed:name];
return [[self alloc] initWithSVG:anSVG];
}
- (id)initWithSVG:(IJSVG*)anSvg
{
if ((self = [super init]) != nil) {
if((self = [super init]) != nil) {
self.SVG = anSvg;
}
return self;
@@ -39,10 +36,10 @@
- (void)awakeFromNib
{
// image was set via IB
if (imageName != nil) {
IJSVG* anSVG = [IJSVG svgNamed:imageName];
if (tintColor != nil) {
anSVG.renderingStyle.fillColor = tintColor;
if(imageName != nil) {
IJSVG* anSVG = [IJSVG SVGNamed:imageName];
if(tintColor != nil) {
anSVG.style.fillColor = tintColor;
}
self.SVG = anSVG;
}
@@ -51,10 +48,7 @@
- (void)setSVG:(IJSVG*)anSVG
{
// memory clean
if (SVG != nil) {
(void)([SVG release]), SVG = nil;
}
SVG = [anSVG retain];
SVG = anSVG;
// redisplay ourself!
[SVG prepForDrawingInView:self];
@@ -69,7 +63,7 @@
- (void)drawRect:(NSRect)dirtyRect
{
// only draw if there is actually an SVG
if (self.SVG == nil) {
if(self.SVG == nil) {
return;
}
@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h>
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGColorType.h>
#import <IJSVG/IJSVGTraitedColor.h>
@class IJSVG;
@class IJSVGExporter;
@@ -32,10 +32,10 @@ typedef NS_OPTIONS(NSInteger, IJSVGExporterOptions) {
IJSVGExporterOptionCollapseGroups = 1 << 6,
IJSVGExporterOptionCleanupPaths = 1 << 7,
IJSVGExporterOptionRemoveHiddenElements = 1 << 8,
IJSVGExporterOptionScaleToSizeIfNecessary = 1 << 9,
IJSVGExporterOptionScaleToSizeIfNecessary DEPRECATED_ATTRIBUTE = 1 << 9,
IJSVGExporterOptionCompressOutput = 1 << 10,
IJSVGExporterOptionCollapseGradients = 1 << 11,
IJSVGExporterOptionCreateClasses = 1 << 12,
IJSVGExporterOptionCreateClasses DEPRECATED_ATTRIBUTE = 1 << 12,
IJSVGExporterOptionRemoveWidthHeightAttributes = 1 << 13,
IJSVGExporterOptionColorAllowRRGGBBAA = 1 << 14,
IJSVGExporterOptionRemoveComments = 1 << 15,
@@ -45,16 +45,17 @@ typedef NS_OPTIONS(NSInteger, IJSVGExporterOptions) {
IJSVGExporterOptionConvertShapesToPaths = 1 << 19,
IJSVGExporterOptionRoundTransforms = 1 << 20,
IJSVGExporterOptionRemoveDefaultValues = 1 << 21,
IJSVGExporterOptionConvertStrokesToPaths = 1 << 22,
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef | IJSVGExporterOptionRemoveUselessGroups |
IJSVGExporterOptionCreateUseForPaths | IJSVGExporterOptionMoveAttributesToGroup |
IJSVGExporterOptionSortAttributes | IJSVGExporterOptionCollapseGroups |
IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements |
IJSVGExporterOptionScaleToSizeIfNecessary | IJSVGExporterOptionCompressOutput |
IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements | IJSVGExporterOptionCompressOutput |
IJSVGExporterOptionCollapseGradients | IJSVGExporterOptionRemoveWidthHeightAttributes |
IJSVGExporterOptionColorAllowRRGGBBAA | IJSVGExporterOptionRemoveComments |
IJSVGExporterOptionCenterWithinViewBox | IJSVGExporterOptionRemoveXMLDeclaration |
IJSVGExporterOptionConvertArcs | IJSVGExporterOptionConvertShapesToPaths |
IJSVGExporterOptionRoundTransforms | IJSVGExporterOptionRemoveDefaultValues
IJSVGExporterOptionRoundTransforms | IJSVGExporterOptionRemoveDefaultValues |
IJSVGExporterOptionConvertStrokesToPaths
};
BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option);
@@ -72,7 +73,7 @@ const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes(void);
defaultID:(NSString* (^)(void))defaultID;
- (NSString* _Nullable)svgExporter:(IJSVGExporter*)exporter
stringForColor:(NSColor*)color
flags:(IJSVGColorTypeFlags)flag
flags:(IJSVGColorUsageTraits)flag
options:(IJSVGColorStringOptions)options;
File diff suppressed because it is too large Load Diff
@@ -10,15 +10,13 @@
NS_ASSUME_NONNULL_BEGIN
typedef struct {
char instruction;
NSArray<NSString*>* params;
} IJSVGExporterPathInstructionCommand;
@interface IJSVGExporterPathInstructionCommand : NSObject {
}
typedef struct {
CGPoint center;
CGFloat radius;
} IJSVGExporterPathInstructionCircle;
@property (nonatomic, assign) char instruction;
@property (nonatomic, strong) NSArray<NSString*>* params;
@end
@interface IJSVGExporterPathInstruction : NSObject {
@@ -33,8 +31,6 @@ typedef struct {
void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length, IJSVGFloatingPointOptions options);
CGFloat IJSVGExporterPathFloatToFixed(CGFloat number, int precision);
IJSVGExporterPathInstructionCommand* IJSVGExporterPathInstructionCommandCopy(IJSVGExporterPathInstructionCommand command);
void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand* _Nullable command);
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
@@ -6,37 +6,39 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGExporter.h"
#import "IJSVGExporterPathInstruction.h"
#import "IJSVGUtils.h"
#import <IJSVG/IJSVGExporter.h>
#import <IJSVG/IJSVGExporterPathInstruction.h>
#import <IJSVG/IJSVGUtils.h>
#import <math.h>
@implementation IJSVGExporterPathInstructionCommand
@end
@implementation IJSVGExporterPathInstruction
@synthesize instruction = _instruction;
- (void)dealloc
{
if (_data != NULL) {
if(_data != NULL) {
(void)free(_data), _data = NULL;
}
if (_base != NULL) {
if(_base != NULL) {
(void)free(_base), _base = NULL;
}
if (_coords != NULL) {
if(_coords != NULL) {
(void)free(_coords), _coords = NULL;
}
[super dealloc];
}
- (id)initWithInstruction:(char)instruction
dataCount:(NSInteger)floatCount
{
if ((self = [super init]) != nil) {
if((self = [super init]) != nil) {
_instruction = instruction;
// only allocate if not zero
if (floatCount != 0) {
if(floatCount != 0) {
_dataCount = floatCount;
_data = (CGFloat*)calloc(sizeof(CGFloat), floatCount);
}
@@ -68,36 +70,18 @@
return _coords;
}
IJSVGExporterPathInstructionCommand* IJSVGExporterPathInstructionCommandCopy(IJSVGExporterPathInstructionCommand command)
{
IJSVGExporterPathInstructionCommand* copy = NULL;
copy = (IJSVGExporterPathInstructionCommand*)malloc(sizeof(IJSVGExporterPathInstructionCommand));
copy->instruction = command.instruction;
copy->params = command.params;
return copy;
}
void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand* _Nullable command)
{
if (command != NULL) {
free(command);
}
}
+ (NSString*)pathStringWithInstructionSet:(NSArray<NSValue*>*)instructionSets
+ (NSString*)pathStringWithInstructionSet:(NSArray<IJSVGExporterPathInstructionCommand*>*)instructionSets
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
IJSVGExporterPathInstructionCommand* lastCommand = NULL;
NSMutableString* string = [[[NSMutableString alloc] init] autorelease];
for (NSValue* value in instructionSets) {
NSMutableString* string = [[NSMutableString alloc] init];
for (IJSVGExporterPathInstructionCommand* command in instructionSets) {
// read back the bytes
IJSVGExporterPathInstructionCommand command;
[value getValue:&command];
// add on the instruction character only if there is no current command
// or the last command is not the same as the current command
// if they both are the same, we still need to seperate them via a space
if (lastCommand == nil || (lastCommand != nil && lastCommand->instruction != command.instruction)) {
if(lastCommand == nil || (lastCommand != nil && lastCommand.instruction != command.instruction)) {
[string appendFormat:@"%c", command.instruction];
} else {
[string appendString:@" "];
@@ -108,18 +92,15 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
[string appendString:compressedFloats];
// store last command
IJSVGExporterPathInstructionCommandFree(lastCommand);
lastCommand = IJSVGExporterPathInstructionCommandCopy(command);
lastCommand = command;
}
IJSVGExporterPathInstructionCommandFree(lastCommand);
return string;
}
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
NSMutableArray* pathInstructions = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* pathInstructions = [[NSMutableArray alloc] init];
for (IJSVGExporterPathInstruction* instruction in instructions) {
CGFloat* data = instruction.data;
const char lowerInstruction = tolower(instruction.instruction);
@@ -186,14 +167,11 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
}
// wrap into the command and give to the array
IJSVGExporterPathInstructionCommand wrapper;
wrapper.instruction = instruction.instruction;
wrapper.params = set ?: @[];
// encode and store
NSValue* value = [NSValue valueWithBytes:&wrapper
objCType:@encode(IJSVGExporterPathInstructionCommand)];
[pathInstructions addObject:value];
IJSVGExporterPathInstructionCommand* wrapperCommand = nil;
wrapperCommand = [[IJSVGExporterPathInstructionCommand alloc] init];
wrapperCommand.instruction = instruction.instruction;
wrapperCommand.params = set ?: @[];
[pathInstructions addObject:wrapperCommand];
}
return [self pathStringWithInstructionSet:pathInstructions
floatingPointOptions:floatingPointOptions];
@@ -210,7 +188,7 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
for (NSInteger i = length; i-- > 0;) {
CGFloat d = data[i];
CGFloat proposed = IJSVGExporterPathFloatToFixed(d, options.precision);
if (proposed != d) {
if(proposed != d) {
CGFloat rounded = +IJSVGExporterPathFloatToFixed(d, options.precision - 1);
data[i] = IJSVGExporterPathFloatToFixed(+fabs(rounded - d), options.precision + 1)
>= kIJSVGExporterPathInstructionErrorThreshold
@@ -228,22 +206,22 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
char instructionChar = instruction.instruction;
NSInteger length = instruction.dataLength;
CGFloat* data = instruction.data;
if (strchr("mltqsc", instructionChar) != NULL) {
if(strchr("mltqsc", instructionChar) != NULL) {
for (NSInteger i = length; i--;) {
data[i] += instruction.base[i % 2] - relSubPoint[i % 2];
}
} else if (instructionChar == 'h') {
} else if(instructionChar == 'h') {
data[0] += instruction.base[0] - relSubPoint[0];
} else if (instructionChar == 'v') {
} else if(instructionChar == 'v') {
data[0] += instruction.base[1] - relSubPoint[1];
} else if (instructionChar == 'a') {
} else if(instructionChar == 'a') {
data[5] += instruction.base[0] - relSubPoint[0];
data[5] += instruction.base[1] - relSubPoint[1];
}
IJSVGExporterPathInstructionRoundData(data, length, floatingPointOptions);
if (instructionChar == 'h') {
if(instructionChar == 'h') {
relSubPoint[0] += data[0];
} else if (instructionChar == 'v') {
} else if(instructionChar == 'v') {
relSubPoint[1] += data[0];
} else {
relSubPoint[0] += data[length - 2];
@@ -258,7 +236,7 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
{
IJSVGExporterPathInstruction* prevInstruction = nil;
for (IJSVGExporterPathInstruction* instruction in instructions) {
if (prevInstruction == nil || instruction.dataLength == 0) {
if(prevInstruction == nil || instruction.dataLength == 0) {
prevInstruction = instruction;
continue;
}
@@ -269,15 +247,15 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
CGFloat* adata = (CGFloat*)malloc(sizeof(CGFloat) * length);
memcpy(adata, data, sizeof(CGFloat) * length);
if (strchr("mltqsc", instructionChar) != NULL) {
if(strchr("mltqsc", instructionChar) != NULL) {
for (NSInteger i = length; i--;) {
adata[i] += instruction.base[i % 2];
}
} else if (instructionChar == 'h') {
} else if(instructionChar == 'h') {
adata[0] += instruction.base[0];
} else if (instructionChar == 'v') {
} else if(instructionChar == 'v') {
adata[0] += instruction.base[1];
} else if (instructionChar == 'a') {
} else if(instructionChar == 'a') {
adata[5] += instruction.base[0];
adata[6] += instruction.base[1];
}
@@ -285,8 +263,8 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
IJSVGExporterPathInstructionRoundData(adata, length, floatingPointOptions);
IJSVGExporterPathInstruction* ainstruction = nil;
ainstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:instructionChar
dataCount:length] autorelease];
ainstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:instructionChar
dataCount:length];
memcpy(ainstruction.data, adata, sizeof(CGFloat) * length);
// run these through our default string runner
@@ -296,7 +274,11 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
NSString* comp = [self pathStringFromInstructions:@[ ainstruction ]
floatingPointOptions:floatingPointOptions];
if (comp.length < orig.length && !(instructionChar == prevInstruction.instruction && prevInstruction.instruction > 96 && comp.length == orig.length - 1 && data[0] < 0.f && fmod(prevInstruction.data[prevInstruction.dataLength - 1], 1) != 0.f)) {
if(comp.length < orig.length && !(instructionChar == prevInstruction.instruction &&
prevInstruction.instruction > 96 &&
comp.length == orig.length - 1 &&
data[0] < 0.f &&
fmod(prevInstruction.data[prevInstruction.dataLength - 1], 1) != 0.f)) {
instruction.instruction = toupper(instructionChar);
memcpy(data, adata, sizeof(CGFloat) * length);
}
@@ -319,39 +301,45 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
NSMutableArray<IJSVGExporterPathInstruction*>* nInstructions = nil;
nInstructions = [[[NSMutableArray alloc] initWithCapacity:instructions.count] autorelease];
nInstructions = [[NSMutableArray alloc] initWithCapacity:instructions.count];
IJSVGExporterPathInstruction* lastInstruction = nil;
for (IJSVGExporterPathInstruction* instruction in instructions) {
lastInstruction = nInstructions.lastObject;
if (lastInstruction == nil) {
if(lastInstruction == nil) {
[nInstructions addObject:instruction];
continue;
}
if (instruction.instruction == 'c') {
if (lastInstruction.instruction == 'c' && instruction.data[0] == -(lastInstruction.data[2] - lastInstruction.data[4]) && instruction.data[1] == -(lastInstruction.data[3] - lastInstruction.data[5])) {
if(instruction.instruction == 'c') {
if(lastInstruction.instruction == 'c' &&
instruction.data[0] == -(lastInstruction.data[2] - lastInstruction.data[4]) &&
instruction.data[1] == -(lastInstruction.data[3] - lastInstruction.data[5])) {
IJSVGExporterPathInstruction* nInstruction = nil;
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
dataCount:4] autorelease];
nInstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
dataCount:4];
nInstruction.data[0] = instruction.data[2];
nInstruction.data[1] = instruction.data[3];
nInstruction.data[2] = instruction.data[4];
nInstruction.data[3] = instruction.data[5];
[nInstructions addObject:nInstruction];
continue;
} else if (lastInstruction.instruction == 's' && instruction.data[0] == -(lastInstruction.data[0] - lastInstruction.data[2]) && instruction.data[1] == -(lastInstruction.data[1] - lastInstruction.data[3])) {
} else if(lastInstruction.instruction == 's' &&
instruction.data[0] == -(lastInstruction.data[0] - lastInstruction.data[2]) &&
instruction.data[1] == -(lastInstruction.data[1] - lastInstruction.data[3])) {
IJSVGExporterPathInstruction* nInstruction = nil;
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
dataCount:4] autorelease];
nInstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
dataCount:4];
nInstruction.data[0] = instruction.data[2];
nInstruction.data[1] = instruction.data[3];
nInstruction.data[2] = instruction.data[4];
nInstruction.data[3] = instruction.data[5];
[nInstructions addObject:nInstruction];
continue;
} else if (lastInstruction.instruction != 'c' && lastInstruction.instruction != 's' && instruction.data[0] == 0.f && instruction.data[1] == 0.f) {
} else if(lastInstruction.instruction != 'c' &&
lastInstruction.instruction != 's' &&
instruction.data[0] == 0.f && instruction.data[1] == 0.f) {
IJSVGExporterPathInstruction* nInstruction = nil;
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
dataCount:4] autorelease];
nInstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'s'
dataCount:4];
nInstruction.data[0] = instruction.data[2];
nInstruction.data[1] = instruction.data[3];
nInstruction.data[2] = instruction.data[4];
@@ -359,19 +347,23 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
[nInstructions addObject:nInstruction];
continue;
}
} else if (instruction.instruction == 'q') {
if (lastInstruction.instruction == 'q' && instruction.data[0] == (lastInstruction.data[2] - lastInstruction.data[0]) && instruction.data[1] == (lastInstruction.data[3] - lastInstruction.data[1])) {
} else if(instruction.instruction == 'q') {
if(lastInstruction.instruction == 'q' &&
instruction.data[0] == (lastInstruction.data[2] - lastInstruction.data[0]) &&
instruction.data[1] == (lastInstruction.data[3] - lastInstruction.data[1])) {
IJSVGExporterPathInstruction* nInstruction = nil;
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
dataCount:2] autorelease];
nInstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
dataCount:2];
nInstruction.data[0] = instruction.data[2];
nInstruction.data[1] = instruction.data[3];
[nInstructions addObject:nInstruction];
continue;
} else if (lastInstruction.instruction == 't' && instruction.data[2] == lastInstruction.data[0] && instruction.data[3] == lastInstruction.data[1]) {
} else if(lastInstruction.instruction == 't' &&
instruction.data[2] == lastInstruction.data[0] &&
instruction.data[3] == lastInstruction.data[1]) {
IJSVGExporterPathInstruction* nInstruction = nil;
nInstruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
dataCount:2] autorelease];
nInstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
dataCount:2];
nInstruction.data[0] = instruction.data[2];
nInstruction.data[1] = instruction.data[3];
[nInstructions addObject:nInstruction];
@@ -386,128 +378,159 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
+ (void)convertInstructionsToRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
CGFloat point[2] = { 0, 0 };
CGFloat subpathPoint[2] = { 0, 0 };
IJSVGExporterPathInstruction* baseInstruction = nil;
IJSVGExporterPathInstruction* prevInstruction = nil;
CGFloat start[2] = {0, 0};
CGFloat cursor[2] = {0, 0};
CGFloat prevCoords[2] = {0, 0};
NSInteger index = 0;
for (IJSVGExporterPathInstruction* anInstruction in instructions) {
char instruction = anInstruction.instruction;
CGFloat* data = anInstruction.data;
NSInteger length = anInstruction.dataLength;
if (data != NULL) {
// already relative
if (instruction == 'm' || instruction == 'c' || instruction == 's' || instruction == 'l' || instruction == 'q' || instruction == 't' || instruction == 'a') {
point[0] += data[length - 2];
point[1] += data[length - 1];
if (instruction == 'm') {
subpathPoint[0] = point[0];
subpathPoint[1] = point[1];
baseInstruction = anInstruction;
}
} else if (instruction == 'h') {
point[0] += data[0];
} else if (instruction == 'v') {
point[1] += data[0];
CGFloat* base = anInstruction.base;
CGFloat* coords = anInstruction.coords;
switch(instruction) {
case 'm': {
cursor[0] += data[0];
cursor[1] += data[1];
start[0] = cursor[0];
start[1] = cursor[1];
break;
}
// convert absolute to relative
if (instruction == 'M') {
if (index > 0) {
case 'M': {
if(index != 0) {
instruction = 'm';
}
data[0] -= point[0];
data[1] -= point[1];
subpathPoint[0] = point[0] += data[0];
subpathPoint[1] = point[1] += data[1];
baseInstruction = anInstruction;
} else if (instruction == 'L' || instruction == 'T') {
instruction = tolower(instruction);
data[0] -= point[0];
data[1] -= point[1];
point[0] += data[0];
point[1] += data[1];
} else if (instruction == 'C') {
instruction = 'c';
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
data[4] -= point[0];
data[5] -= point[1];
point[0] += data[4];
point[1] += data[5];
} else if (instruction == 'S' || instruction == 'Q') {
instruction = tolower(instruction);
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
point[0] += data[2];
point[1] += data[3];
} else if (instruction == 'A') {
instruction = 'a';
data[5] -= point[0];
data[6] -= point[1];
point[0] += data[5];
point[1] += data[6];
} else if (instruction == 'H') {
data[0] -= cursor[0];
data[1] -= cursor[1];
cursor[0] += data[0];
cursor[1] += data[1];
start[0] = cursor[0];
start[1] = cursor[1];
break;
}
case 'l': {
cursor[0] += data[0];
cursor[1] += data[1];
break;
}
case 'L': {
instruction = 'l';
data[0] -= cursor[0];
data[1] -= cursor[1];
cursor[0] += data[0];
cursor[1] += data[1];
break;
}
case 'h': {
cursor[0] += data[0];
break;
}
case 'H': {
instruction = 'h';
data[0] -= point[0];
point[0] += data[0];
} else if (instruction == 'V') {
data[0] -= cursor[0];
cursor[0] += data[0];
break;
}
case 'v': {
cursor[1] += data[0];
break;
}
case 'V': {
instruction = 'v';
data[0] -= point[1];
point[1] += data[0];
data[0] -= cursor[1];
cursor[1] += data[0];
break;
}
// reset the instruction
anInstruction.instruction = instruction;
CGFloat* coords = anInstruction.coords;
coords[0] = point[0];
coords[1] = point[1];
} else if (instruction == 'Z' || instruction == 'z') {
if (baseInstruction != nil) {
CGFloat* coords = anInstruction.coords;
coords[0] = baseInstruction.coords[0];
coords[1] = baseInstruction.coords[1];
case 'c': {
cursor[0] += data[4];
cursor[1] += data[5];
break;
}
case 'C': {
instruction = 'c';
data[0] -= cursor[0];
data[1] -= cursor[1];
data[2] -= cursor[0];
data[3] -= cursor[1];
data[4] -= cursor[0];
data[5] -= cursor[1];
cursor[0] += data[4];
cursor[1] += data[5];
break;
}
case 's': {
cursor[0] += data[2];
cursor[1] += data[3];
break;
}
case 'S': {
instruction = 's';
data[0] -= cursor[0];
data[1] -= cursor[1];
data[2] -= cursor[0];
data[3] -= cursor[1];
cursor[0] += data[2];
cursor[1] += data[3];
break;
}
case 'q': {
cursor[0] += data[2];
cursor[1] += data[3];
break;
}
case 'Q': {
instruction = 'q';
data[0] -= cursor[0];
data[1] -= cursor[1];
data[2] -= cursor[0];
data[3] -= cursor[1];
cursor[0] += data[2];
cursor[1] += data[3];
break;
}
case 't': {
cursor[0] += data[0];
cursor[1] += data[1];
break;
}
case 'T': {
instruction = 't';
data[0] -= cursor[0];
data[1] -= cursor[1];
cursor[0] += data[0];
cursor[1] += data[1];
break;
}
case 'a': {
cursor[0] += data[5];
cursor[1] += data[6];
break;
}
case 'A': {
instruction = 'a';
data[5] -= cursor[0];
data[6] -= cursor[1];
cursor[0] += data[5];
cursor[1] += data[6];
break;
}
case 'Z':
case 'z': {
cursor[0] = start[0];
cursor[1] = start[1];
break;
}
point[0] = subpathPoint[0];
point[1] = subpathPoint[1];
}
CGFloat* base = anInstruction.base;
if (prevInstruction != nil) {
base[0] = prevInstruction.coords[0];
base[1] = prevInstruction.coords[1];
} else {
base[0] = 0.f;
base[1] = 0.f;
}
// increment index
prevInstruction = anInstruction;
// set the instruction back
anInstruction.instruction = instruction;
base[0] = prevCoords[0];
base[1] = prevCoords[1];
coords[0] = cursor[0];
coords[1] = cursor[1];
prevCoords[0] = cursor[0];
prevCoords[1] = cursor[1];
index++;
}
}
@@ -518,7 +541,7 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
// keep track of the current point
__block CGPoint currentPoint = CGPointZero;
NSMutableArray* instructions = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* instructions = [[NSMutableArray alloc] init];
// create the path callback
IJSVGCGPathHandler callback = ^(const CGPathElement* pathElement) {
@@ -528,8 +551,8 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
case kCGPathElementMoveToPoint: {
// move to command
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'M'
dataCount:2] autorelease];
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'M'
dataCount:2];
CGPoint point = pathElement->points[0];
instruction.data[0] = point.x;
instruction.data[1] = point.y;
@@ -542,17 +565,17 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
case kCGPathElementAddLineToPoint: {
// line to command
CGPoint point = pathElement->points[0];
if (point.x == currentPoint.x) {
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'V'
dataCount:1] autorelease];
if(point.x == currentPoint.x) {
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'V'
dataCount:1];
instruction.data[0] = point.y;
} else if (point.y == currentPoint.y) {
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'H'
dataCount:1] autorelease];
} else if(point.y == currentPoint.y) {
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'H'
dataCount:1];
instruction.data[0] = point.x;
} else {
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'L'
dataCount:2] autorelease];
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'L'
dataCount:2];
instruction.data[0] = point.x;
instruction.data[1] = point.y;
}
@@ -566,8 +589,8 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
// quad curve to command
CGPoint controlPoint = pathElement->points[0];
CGPoint point = pathElement->points[1];
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Q'
dataCount:4] autorelease];
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'Q'
dataCount:4];
instruction.data[0] = controlPoint.x;
instruction.data[1] = controlPoint.y;
instruction.data[2] = point.x;
@@ -585,8 +608,8 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
CGPoint point = pathElement->points[2];
currentPoint = point;
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'C'
dataCount:6] autorelease];
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'C'
dataCount:6];
instruction.data[0] = controlPoint1.x;
instruction.data[1] = controlPoint1.y;
instruction.data[2] = controlPoint2.x;
@@ -600,8 +623,8 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
case kCGPathElementCloseSubpath: {
// close command
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z'
dataCount:0] autorelease];
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z'
dataCount:0];
[instructions addObject:instruction];
break;
}
@@ -613,11 +636,11 @@ void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
// remove last instruction if it was Z -> M
IJSVGExporterPathInstruction* lastInstruction = instructions.lastObject;
if (lastInstruction.instruction == 'M' || lastInstruction.instruction == 'm') {
if (instructions.count >= 2) {
if(lastInstruction.instruction == 'M' || lastInstruction.instruction == 'm') {
if(instructions.count >= 2) {
NSInteger index = [instructions indexOfObject:lastInstruction] - 1;
IJSVGExporterPathInstruction* prevInstruction = instructions[index];
if (prevInstruction.instruction == 'z' || prevInstruction.instruction == 'Z') {
if(prevInstruction.instruction == 'z' || prevInstruction.instruction == 'Z') {
[instructions removeLastObject];
}
}
@@ -0,0 +1,14 @@
//
// IJSVGBasicLayer.h
// IJSVG
//
// Created by Curtis Hard on 19/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import <IJSVG/IJSVGLayer.h>
@interface IJSVGBasicLayer : CALayer <IJSVGBasicLayer>
@end
@@ -0,0 +1,30 @@
//
// IJSVGBasicLayer.m
// IJSVG
//
// Created by Curtis Hard on 19/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGBasicLayer.h>
@implementation IJSVGBasicLayer
@synthesize backingScaleFactor;
@synthesize requiresBackingScale;
@synthesize renderQuality;
@synthesize debugLayers;
- (id<CAAction>)actionForKey:(NSString*)event
{
return nil;
}
- (void)performRenderInContext:(CGContextRef)ctx
{
}
@end
@@ -0,0 +1,23 @@
//
// IJSVGFilterLayer.h
// IJSVG
//
// Created by Curtis Hard on 19/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGFilter.h>
#import <IJSVG/IJSVGBasicLayer.h>
@interface IJSVGFilterLayer : IJSVGLayer {
@private
IJSVGBasicLayer* _hostingLayer;
CGImageRef _image;
}
@property (nonatomic, strong) CALayer<IJSVGDrawableLayer>* sublayer;
@end
@@ -0,0 +1,73 @@
//
// IJSVGFilterLayer.m
// IJSVG
//
// Created by Curtis Hard on 19/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGFilterLayer.h>
#import <IJSVG/IJSVGTransform.h>
@implementation IJSVGFilterLayer
- (void)dealloc
{
(void)CGImageRelease(_image), _image = nil;
}
- (instancetype)init
{
if((self = [super init]) != nil) {
_hostingLayer = [IJSVGBasicLayer layer];
[self addSublayer:_hostingLayer];
}
return self;
}
- (BOOL)requiresBackingScale
{
return YES;
}
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
// we are responsible for recursively calling the sublayer
// with the new backing scale factor
[IJSVGLayer setBackingScaleFactor:backingScaleFactor
renderQuality:self.renderQuality
recursivelyToLayer:_sublayer];
BOOL needsChange = self.backingScaleFactor != backingScaleFactor;
[super setBackingScaleFactor:backingScaleFactor];
if(needsChange == YES) {
[self updateImage];
}
}
- (void)updateImage
{
if(_image != nil) {
(void)CGImageRelease(_image), _image = nil;
}
_image = [self.filter newImageByApplyFilterToLayer:_sublayer
scale:1.f];
}
- (void)layoutSublayers
{
CGFloat width = CGImageGetWidth(_image);
CGFloat height = CGImageGetHeight(_image);
CGRect frame = _sublayer.innerBoundingBox;
_hostingLayer.frame = CGRectMake(frame.origin.x + (frame.size.width / 2.f - width / 2.f),
frame.origin.y + (frame.size.height / 2.f - height / 2.f),
width, height);
_hostingLayer.contents = (__bridge id)_image;
}
- (NSArray<CALayer<IJSVGBasicLayer>*>*)debugLayers
{
return @[_sublayer];
}
@end
@@ -14,7 +14,7 @@
@interface IJSVGGradientLayer : IJSVGLayer {
}
@property (nonatomic, retain) IJSVGGradient* gradient;
@property (nonatomic, strong) IJSVGGradient* gradient;
@property (nonatomic, assign) CGRect viewBox;
@end
@@ -6,38 +6,24 @@
// Copyright © 2016 Curtis Hard. All rights reserved.
//
#import "IJSVGGradientLayer.h"
#import <IJSVG/IJSVGGradientLayer.h>
#import <IJSVG/IJSVGRootLayer.h>
@implementation IJSVGGradientLayer
- (void)dealloc
{
(void)([_gradient release]), _gradient = nil;
[super dealloc];
}
- (BOOL)requiresBackingScaleHelp
- (BOOL)requiresBackingScale
{
return YES;
}
- (void)setGradient:(IJSVGGradient*)newGradient
{
if (_gradient != nil) {
(void)([_gradient release]), _gradient = nil;
}
_gradient = [newGradient retain];
_gradient = newGradient;
// 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) {
for (NSColor* color in newGradient.colors) {
if(color.alphaComponent != 1.f) {
hasAlphaChannel = YES;
break;
}
@@ -47,7 +33,7 @@
- (void)setOpacity:(float)opacity
{
if (opacity != 1.f) {
if(opacity != 1.f) {
self.opaque = NO;
}
[super setOpacity:opacity];
@@ -56,17 +42,17 @@
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
switch (self.renderQuality) {
case kIJSVGRenderQualityOptimized: {
backingScaleFactor = (backingScaleFactor * .35f);
break;
}
case kIJSVGRenderQualityLow: {
backingScaleFactor = (backingScaleFactor * .05f);
break;
}
default: {
break;
}
case kIJSVGRenderQualityOptimized: {
backingScaleFactor = (backingScaleFactor * .35f);
break;
}
case kIJSVGRenderQualityLow: {
backingScaleFactor = (backingScaleFactor * .05f);
break;
}
default: {
break;
}
}
[super setBackingScaleFactor:backingScaleFactor];
}
@@ -81,28 +67,41 @@
[super drawInContext:ctx];
// nothing to do :(
if (self.gradient == nil) {
if(self.gradient == nil) {
return;
}
// draw the gradient
// perform the draw
CGRect bounds = CGRectZero;
CGAffineTransform transform = CGAffineTransformIdentity;
CALayer<IJSVGDrawableLayer>* layer = (CALayer<IJSVGDrawableLayer>*)self.referencingLayer;
CGRect objectRect = layer.boundingBox;
CGRect objectFrame = layer.frame;
CGAffineTransform affine = [IJSVGLayer absoluteTransformForLayer:layer];
affine = CGAffineTransformTranslate(affine,
-CGRectGetMinX(objectFrame),
-CGRectGetMinY(objectFrame));
CGContextSaveGState(ctx);
if(self.gradient.units == IJSVGUnitUserSpaceOnUse) {
IJSVGRootLayer* rootNode = (IJSVGRootLayer*)[IJSVGLayer rootLayerForLayer:self];
bounds = [rootNode.viewBox computeValue:CGSizeZero];
transform = [IJSVGLayer userSpaceTransformForLayer:layer];
} else {
bounds = IJSVGLayerGetBoundingBoxBounds(layer);
}
IJSVGRootLayer* rootNode = (IJSVGRootLayer*)[IJSVGLayer rootLayerForLayer:self];
CGRect bounds = [rootNode.viewBox computeValue:CGSizeZero];
// its possible that this layer is shifted inwards due to a stroke on the
// parent layer
transform = CGAffineTransformConcat(transform, [IJSVGLayer userSpaceTransformForLayer:self]);
[self.gradient drawInContextRef:ctx
objectRect:objectRect
absoluteTransform:affine
viewPort:bounds];
CGContextRestoreGState(ctx);
bounds:bounds
transform:transform];
}
- (IJSVGTraitedColorStorage*)colors
{
IJSVGTraitedColorStorage* list = [[IJSVGTraitedColorStorage alloc] init];
for(NSColor* color in self.gradient.colors) {
IJSVGTraitedColor* traited = nil;
traited = [IJSVGTraitedColor colorWithColor:color
traits:IJSVGColorUsageTraitNone];
[list addColor:traited];
}
return list;
}
@end
@@ -8,13 +8,15 @@
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGShapeLayer.h>
#import <IJSVG/IJSVGUnitRect.h>
#import <QuartzCore/QuartzCore.h>
@interface IJSVGGroupLayer : IJSVGLayer {
@interface IJSVGGroupLayer : IJSVGLayer <IJSVGMaskingLayer> {
}
@property (nonatomic, retain) IJSVGUnitRect* viewBox;
@property (nonatomic, strong) IJSVGUnitSize* intrinsicSize;
@property (nonatomic, strong) IJSVGUnitRect* viewBox;
@property (nonatomic, assign) IJSVGViewBoxAlignment viewBoxAlignment;
@property (nonatomic, assign) IJSVGViewBoxMeetOrSlice viewBoxMeetOrSlice;
@@ -6,17 +6,16 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGGroupLayer.h"
#import "IJSVGViewBox.h"
#import "IJSVGUnitRect.h"
#import "IJSVGLayer.h"
#import <IJSVG/IJSVGGroupLayer.h>
#import <IJSVG/IJSVGViewBox.h>
#import <IJSVG/IJSVGUnitRect.h>
#import <IJSVG/IJSVGLayer.h>
@implementation IJSVGGroupLayer
- (void)dealloc
- (CGRect)innerBoundingBox
{
(void)[_viewBox release], _viewBox = nil;
[super dealloc];
return self.outerBoundingBox;
}
@end
@@ -9,16 +9,15 @@
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGImage.h>
#import <IJSVG/IJSVGTransformLayer.h>
#import <IJSVG/IJSVGTileLayer.h>
#import <IJSVG/IJSVGBasicLayer.h>
#import <AppKit/AppKit.h>
#import <QuartzCore/QuartzCore.h>
@interface IJSVGImageLayer : IJSVGLayer {
@private
IJSVGLayer* _imageLayer;
@interface IJSVGImageLayer : IJSVGTileLayer {
}
@property (nonatomic, retain) IJSVGImage* image;
@property (nonatomic, strong) IJSVGImage* image;
- (id)initWithImage:(IJSVGImage*)image;
@@ -6,48 +6,43 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGImageLayer.h"
#import <IJSVG/IJSVGImageLayer.h>
@implementation IJSVGImageLayer
- (void)dealloc
{
(void)[_image release], _image = nil;
(void)[_imageLayer release], _imageLayer = nil;
[super dealloc];
}
- (id)initWithImage:(IJSVGImage*)image
{
if((self = [super init]) != nil) {
_image = image.retain;
self.image = image;
}
return self;
}
- (BOOL)requiresBackingScaleHelp
- (BOOL)requiresBackingScale
{
return YES;
}
- (void)layoutSublayers
- (void)setImage:(IJSVGImage *)image
{
[super layoutSublayers];
[self reloadContent];
_image = image;
[self setNeedsDisplay];
}
- (void)reloadContent
- (void)drawInContext:(CGContextRef)ctx
{
if(_imageLayer == nil) {
_imageLayer = [IJSVGLayer layer].retain;
_imageLayer.contentsGravity = kCAGravityResize;
_imageLayer.affineTransform = CGAffineTransformMakeScale(1.f, -1.f);
_imageLayer.contents = (id)_image.CGImage;
[self addSublayer:_imageLayer];
}
_imageLayer.frame = self.bounds;
CGImageRef image = _image.CGImage;
CGRect imageDrawRect = _image.bounds;
CGRect currentBounds = self.bounds;
IJSVGViewBoxDrawingBlock drawBlock = ^(CGFloat scale[]) {
// image will be upside down, so just translate it back on itself
CGContextConcatCTM(ctx, CGAffineTransformMakeScale(1.f, -1.f));
CGContextTranslateCTM(ctx, 0.f, -CGRectGetHeight(imageDrawRect));
CGContextDrawImage(ctx, imageDrawRect, image);
};
IJSVGContextDrawViewBox(ctx, imageDrawRect, currentBounds,
_image.viewBoxAlignment,
_image.viewBoxMeetOrSlice, drawBlock);
}
@end
+110 -54
View File
@@ -16,6 +16,19 @@
@class IJSVGStrokeLayer;
@class IJSVGGroupLayer;
@class IJSVGLayer;
@class IJSVGFilter;
@class IJSVGTraitedColorStorage;
typedef NS_OPTIONS(NSUInteger, IJSVGLayerTraits) {
IJSVGLayerTraitNone = 0,
IJSVGLayerTraitFilled = 1 << 1,
IJSVGLayerTraitStroked = 1 << 2
};
typedef NS_OPTIONS(NSUInteger, IJSVGLayerDrawingOptions) {
IJSVGLayerDrawingOptionNone = 0,
IJSVGLayerDrawingOptionIgnoreClipping = 1 << 1
};
typedef NS_ENUM(NSUInteger, IJSVGLayerFillType) {
IJSVGLayerFillTypeColor,
@@ -24,8 +37,14 @@ typedef NS_ENUM(NSUInteger, IJSVGLayerFillType) {
IJSVGLayerFillTypeUnknown
};
typedef NS_OPTIONS(NSUInteger, IJSVGLayerTraits) {
IJSVGLayerTraitGroup
typedef NS_ENUM(NSUInteger, IJSVGLayerUsageType) {
IJSVGLayerUsageTypeFillGeneric,
IJSVGLayerUsageTypeFillPattern,
IJSVGLayerUsageTypeFillGradient,
IJSVGLayerUsageTypeStrokeGeneric,
IJSVGLayerUsageTypeStrokePattern,
IJSVGLayerUsageTypeStrokeGradient,
IJSVGLayerUsageTypeStroke
};
@protocol IJSVGPathableLayer <NSObject>
@@ -35,92 +54,126 @@ typedef NS_OPTIONS(NSUInteger, IJSVGLayerTraits) {
@end
@protocol IJSVGDrawableLayer <NSObject>
@protocol IJSVGBasicLayer <NSObject>
@required
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* maskLayer;
@property (nonatomic, copy) CAShapeLayerFillRule clipRule;
@property (nonatomic, copy) CAShapeLayerFillRule fillRule;
@property (nonatomic, readonly) CGPoint absoluteOrigin;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, readonly) BOOL requiresBackingScaleHelp;
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* rootLayer;
@property (nonatomic, readonly) CGRect absoluteFrame;
@property (nonatomic, assign) CGRect boundingBox;
@property (nonatomic, readonly) CGRect strokeBoundingBox;
@property (nonatomic, readonly) CGRect boundingBoxBounds;
@property (nonatomic, assign) CGRect outerBoundingBox;
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
@property (nonatomic, readonly) NSArray<CALayer<IJSVGDrawableLayer>*>* debugLayers;
- (void)performRenderInContext:(CGContextRef)ctx;
@property (nonatomic, readonly) BOOL requiresBackingScale;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, readonly) NSArray<CALayer<IJSVGBasicLayer>*>* debugLayers;
@end
@interface IJSVGLayer : CALayer <IJSVGDrawableLayer> {
@protocol IJSVGMaskingLayer <NSObject>
@required
@property (nonatomic, assign) CGRect maskingBoundingBox;
@property (nonatomic, assign) CGRect maskingClippingRect;
@end
@protocol IJSVGClippingLayer <NSObject>
@required
@property (nonatomic, assign) CGRect clippingBoundingBox;
@property (nonatomic, assign) CGAffineTransform clippingTransform;
@property (nonatomic, assign) CGPathRef clipPath;
@property (nonatomic, assign) CGAffineTransform clipPathTransform;
@end
@protocol IJSVGDrawableLayer <NSObject, IJSVGBasicLayer, IJSVGMaskingLayer, IJSVGClippingLayer>
@required
@property (nonatomic, readonly) BOOL treatImplicitOriginAsTransform;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, strong) NSArray<CALayer<IJSVGDrawableLayer>*>* clipLayers;
@property (nonatomic, strong) CALayer<IJSVGDrawableLayer>* maskLayer;
@property (nonatomic, copy) CAShapeLayerFillRule clipRule;
@property (nonatomic, copy) CAShapeLayerFillRule fillRule;
@property (nonatomic, readonly) CGPoint absoluteOrigin;
@property (nonatomic, readonly) CGRect absoluteFrame;
@property (nonatomic, assign) CGRect boundingBox;
@property (nonatomic, assign) CGRect outerBoundingBox;
@property (nonatomic, readonly) CGRect innerBoundingBox;
@property (nonatomic, weak) CALayer<IJSVGDrawableLayer>* referencingLayer;
@property (nonatomic, strong) IJSVGFilter* filter;
@property (nonatomic, readonly) IJSVGLayerTraits layerTraits;
@property (nonatomic, readonly) NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* layerUsageMapTable;
@property (nonatomic, readonly) IJSVGTraitedColorStorage* colors;
- (void)performRenderInContext:(CGContextRef)ctx;
- (void)setLayer:(CALayer<IJSVGDrawableLayer>*)layer
forUsageType:(IJSVGLayerUsageType)type;
- (CALayer<IJSVGDrawableLayer>*)layerForUsageType:(IJSVGLayerUsageType)type;
- (CALayer<IJSVGDrawableLayer>*)strokeLayer:(IJSVGLayerUsageType*)usageType;
- (void)addTraits:(IJSVGLayerTraits)traits;
- (void)removeTraits:(IJSVGLayerTraits)traits;
- (BOOL)matchesTraits:(IJSVGLayerTraits)traits;
- (CALayer<IJSVGDrawableLayer>*)firstSublayerOfClass:(Class)aClass;
@end
CGRect IJSVGLayerGetBoundingBoxBounds(CALayer<IJSVGDrawableLayer>* drawableLayer);
NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* IJSVGLayerDefaultUsageMapTable(void);
@interface IJSVGLayer : CALayer <IJSVGDrawableLayer, IJSVGMaskingLayer> {
@private
IJSVGLayer* _maskingLayer;
NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* _layerUsageMapTable;
}
@property (nonatomic, assign) IJSVGGradientLayer* gradientFillLayer;
@property (nonatomic, assign) IJSVGPatternLayer* patternFillLayer;
@property (nonatomic, assign) IJSVGStrokeLayer* strokeLayer;
@property (nonatomic, assign) IJSVGGradientLayer* gradientStrokeLayer;
@property (nonatomic, assign) IJSVGPatternLayer* patternStrokeLayer;
@property (nonatomic, readonly) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
@property (nonatomic, copy) CAShapeLayerFillRule clipRule;
@property (nonatomic, copy) CAShapeLayerFillRule fillRule;
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* maskLayer;
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* rootLayer;
@property (nonatomic, readonly) CGRect absoluteFrame;
@property (nonatomic, assign) CGRect boundingBox;
@property (nonatomic, readonly) CGRect boundingBoxBounds;
@property (nonatomic, readonly) CGRect strokeBoundingBox;
@property (nonatomic, assign) CGRect outerBoundingBox;
@property (nonatomic, readonly) CGRect outerBoundingBoxBounds;
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
+ (IJSVGLayerFillType)fillTypeForFill:(id)fill;
+ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer;
+ (void)recursivelyWalkLayer:(CALayer<IJSVGDrawableLayer>*)layer
withBlock:(void (^)(CALayer<IJSVGDrawableLayer>* layer, BOOL* stop))block;
+ (void)recursivelyWalkLayer:(CALayer<IJSVGBasicLayer>*)layer
withBlock:(void (^)(CALayer<IJSVGBasicLayer>* layer, BOOL* stop))block;
+ (CALayer<IJSVGDrawableLayer>*)firstSublayerOfClass:(Class)aClass
fromLayer:(CALayer<IJSVGDrawableLayer>*)layer;
+ (void)setBackingScaleFactor:(CGFloat)scale
renderQuality:(IJSVGRenderQuality)quality
recursivelyToLayer:(CALayer<IJSVGDrawableLayer>*)layer;
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer*)sublayer
withOffset:(CGPoint)offset;
+ (CGImageRef)newMaskImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
options:(IJSVGLayerDrawingOptions)options
scale:(CGFloat)scale;
+ (CGImageRef)newImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
options:(IJSVGLayerDrawingOptions)options
colorSpace:(CGColorSpaceRef)colorSpace
bitmapInfo:(uint32_t)bitmapInfo
scale:(CGFloat)scale;
+ (CGImageRef)newImageWithSize:(CGSize)size
drawBlock:(void (^)(CGContextRef context))drawBlock
colorSpace:(CGColorSpaceRef)colorSpace
bitmapInfo:(uint32_t)bitmapInfo
scale:(CGFloat)scale;
+ (void)renderLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx;
inContext:(CGContextRef)ctx
options:(IJSVGLayerDrawingOptions)options;
+ (void)applyBlendingMode:(CGBlendMode)blendMode
toContext:(CGContextRef)ctx
drawingBlock:(dispatch_block_t)drawingBlock;
+ (void)clipContextWithClip:(CALayer<IJSVGDrawableLayer>*)clipLayer
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
drawingBlock:(dispatch_block_t)drawingBlock;
+ (void)clipContextWithClipLayers:(NSArray<CALayer<IJSVGDrawableLayer>*>*)clipLayers
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
drawingBlock:(dispatch_block_t)drawingBlock;
+ (void)clipContextWithMask:(CALayer<IJSVGDrawableLayer>*)maskLayer
+ (void)clipContextWithMask:(CALayer<IJSVGMaskingLayer>*)maskLayer
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)context
drawingBlock:(dispatch_block_t)drawingBlock;
@@ -129,6 +182,9 @@ typedef NS_OPTIONS(NSUInteger, IJSVGLayerTraits) {
+ (CGAffineTransform)absoluteTransformForLayer:(CALayer*)layer;
+ (CGRect)absoluteFrameForLayer:(CALayer<IJSVGDrawableLayer>*)layer;
+ (CGRect)calculateFrameForSublayers:(NSArray<CALayer<IJSVGDrawableLayer>*>*)layers;
+ (CGAffineTransform)userSpaceTransformForLayer:(CALayer<IJSVGDrawableLayer>*)layer;
+ (void)transformLayer:(CALayer<IJSVGDrawableLayer>*)layer
intoUserSpaceUnitsFrom:(CALayer<IJSVGDrawableLayer>*)fromLayer;
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer;
+414 -144
View File
@@ -6,23 +6,59 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVG.h"
#import "IJSVGGroupLayer.h"
#import "IJSVGLayer.h"
#import "IJSVGShapeLayer.h"
#import "IJSVGTransformLayer.h"
#import "IJSVGRootLayer.h"
#import <IJSVG/IJSVG.h>
#import <IJSVG/IJSVGGroupLayer.h>
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGShapeLayer.h>
#import <IJSVG/IJSVGTransformLayer.h>
#import <IJSVG/IJSVGRootLayer.h>
CGRect IJSVGLayerGetBoundingBoxBounds(CALayer<IJSVGDrawableLayer>* drawableLayer)
{
return (CGRect) {
.origin = CGPointZero,
.size = drawableLayer.boundingBox.size
};
}
NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* IJSVGLayerDefaultUsageMapTable(void)
{
return [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
valueOptions:NSPointerFunctionsWeakMemory
capacity:3];
}
@implementation IJSVGLayer
@synthesize backingScaleFactor = _backingScaleFactor;
@synthesize requiresBackingScale;
@synthesize renderQuality;
@synthesize blendingMode;
@synthesize absoluteOrigin;
@synthesize clipPath = _clipPath;
@synthesize clipRule = _clipRule;
@synthesize clipLayers = _clipLayers;
@synthesize clippingTransform;
@synthesize clippingBoundingBox;
@synthesize maskingClippingRect;
@synthesize clipPathTransform;
@synthesize colors;
@synthesize boundingBox = _boundingBox;
@synthesize layerTraits = _layerTraits;
@synthesize maskingBoundingBox;
@synthesize filter;
@synthesize referencingLayer = _referencingLayer;
@synthesize outerBoundingBox = _outerBoundingBox;
@synthesize maskLayer = _maskLayer;
@synthesize treatImplicitOriginAsTransform;
@synthesize fillRule;
- (void)dealloc
{
(void)([_clipLayer release]), _clipLayer = nil;
(void)([_maskLayer release]), _maskLayer = nil;
(void)([_clipRule release]), _clipRule = nil;
(void)([_fillRule release]), _fillRule = nil;
(void)([_maskingLayer release]), _maskingLayer = nil;
[super dealloc];
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
}
- (instancetype)init
@@ -34,6 +70,11 @@
return self;
}
- (id<CAAction>)actionForKey:(NSString*)event
{
return nil;
}
- (CAShapeLayerFillRule)fillRule
{
return kCAFillRuleNonZero;
@@ -61,6 +102,33 @@
return IJSVGLayerFillTypeUnknown;
}
+ (CALayer<IJSVGDrawableLayer>*)firstSublayerOfClass:(Class)aClass
fromLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
for(CALayer<IJSVGDrawableLayer>* sublayer in layer.sublayers) {
if(sublayer.class == aClass) {
return sublayer;
}
}
return nil;
}
+ (void)applyAbsoluteTransformForLayer:(CALayer<IJSVGDrawableLayer>*)layer
toContext:(CGContextRef)ctx
{
CALayer<IJSVGDrawableLayer>* parentLayer = layer;
while((parentLayer = parentLayer.referencingLayer) != nil) {
CGContextConcatCTM(ctx, parentLayer.affineTransform);
// only go up until we find a root layer, at that point, we know
// we can stop looking
if([parentLayer isKindOfClass:IJSVGRootLayer.class] == YES) {
break;
}
}
CGContextConcatCTM(ctx, layer.affineTransform);
}
+ (CGAffineTransform)absoluteTransformForLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
CGAffineTransform identity = CGAffineTransformIdentity;
@@ -73,11 +141,26 @@
if([parentLayer isKindOfClass:IJSVGRootLayer.class] == YES) {
break;
}
}
return CGAffineTransformConcat(identity, layer.affineTransform);
}
+ (void)transformLayer:(CALayer<IJSVGDrawableLayer>*)layer
intoUserSpaceUnitsFrom:(CALayer<IJSVGDrawableLayer>*)fromLayer
{
CGAffineTransform transform = layer.affineTransform;
CGAffineTransform userSpaceTransform = [IJSVGLayer userSpaceTransformForLayer:fromLayer];
layer.affineTransform = CGAffineTransformConcat(transform, userSpaceTransform);
}
+ (CGAffineTransform)userSpaceTransformForLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
CGRect absolutePosition = layer.outerBoundingBox;
return CGAffineTransformTranslate(CGAffineTransformIdentity,
-CGRectGetMinX(absolutePosition),
-CGRectGetMinY(absolutePosition));
}
+ (CALayer<IJSVGDrawableLayer>*)rootLayerForLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
CALayer<IJSVGDrawableLayer>* parentLayer = (CALayer<IJSVGDrawableLayer>*)layer.referencingLayer;
@@ -88,106 +171,206 @@
return parentLayer;
}
+ (void)renderLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
+ (void)clipContext:(CGContextRef)ctx
path:(CGPathRef)path
rule:(CAShapeLayerFillRule)rule
drawingBlock:(dispatch_block_t)block
{
CGContextSaveGState(ctx);
CGContextAddPath(ctx, path);
if([rule isEqualToString:kCAFillRuleEvenOdd] == YES) {
CGContextEOClip(ctx);
} else {
CGContextClip(ctx);
}
block();
CGContextRestoreGState(ctx);
}
+ (void)performBasicRenderOfLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
options:(IJSVGLayerDrawingOptions)options
{
dispatch_block_t drawingBlock = ^{
if(layer.clipPath != NULL) {
[self clipContext:ctx
path:layer.clipPath
rule:layer.clipRule
drawingBlock:^{
[layer performRenderInContext:ctx];
}];
return;
}
[layer performRenderInContext:ctx];
};
[self applyBlendingMode:layer.blendingMode
toContext:ctx
drawingBlock:^{
// we need to clip first
if(layer.clipLayer == nil) {
IJSVGLayerDrawingOptions opt = IJSVGLayerDrawingOptionIgnoreClipping;
BOOL ignoreClipping = (options & opt) == opt;
if(ignoreClipping == YES || layer.clipLayers == nil) {
drawingBlock();
return;
}
[self clipContextWithClip:layer.clipLayer
toLayer:layer
inContext:ctx
drawingBlock:drawingBlock];
[self clipContextWithClipLayers:layer.clipLayers
toLayer:layer
inContext:ctx
drawingBlock:drawingBlock];
}];
}
+ (void)renderLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
options:(IJSVGLayerDrawingOptions)options
{
[self performBasicRenderOfLayer:layer
inContext:ctx
options:options];
}
+ (void)applyBlendingMode:(CGBlendMode)blendMode
toContext:(CGContextRef)ctx
drawingBlock:(dispatch_block_t)drawingBlock
{
if (blendMode != kCGBlendModeNormal) {
CGContextSaveGState(ctx);
CGContextSetBlendMode(ctx, blendMode);
if(blendMode == kCGBlendModeNormal) {
drawingBlock();
CGContextRestoreGState(ctx);
return;
}
CGContextSaveGState(ctx);
CGContextSetBlendMode(ctx, blendMode);
drawingBlock();
CGContextRestoreGState(ctx);
}
/// Shape layers are the only thing we can clip, as they contain a path, however
/// the layer passed to us from a clip could have groups contained with in it that
/// have transforms on them, so simply recursively iterate over them and concat
/// their transforms down to the path and clip at the end with the path.
+ (void)recursivelyClip:(CALayer<IJSVGDrawableLayer>*)layer
transform:(CGAffineTransform)transform
inContext:(CGContextRef)ctx
///// Shape layers are the only thing we can clip, as they contain a path, however
///// the layer passed to us from a clip could have groups contained with in it that
///// have transforms on them, so simply recursively iterate over them and concat
///// their transforms down to the path and clip at the end with the path.
//+ (void)recursivelyClip:(CALayer<IJSVGDrawableLayer>*)layer
// transform:(CGAffineTransform)transform
// inContext:(CGContextRef)ctx
//{
// if([layer isKindOfClass:IJSVGShapeLayer.class]) {
// [self clipContextWithShapeLayer:(IJSVGShapeLayer*)layer
// transform:transform
// inContext:ctx];
// return;
// }
//
// for(CALayer<IJSVGDrawableLayer>* drawableLayer in layer.sublayers) {
// CGAffineTransform drawTransform = CGAffineTransformConcat(transform,
// drawableLayer.affineTransform);
//
// // If its not a shape layer, just go down the tree until we find one
// if([drawableLayer isKindOfClass:IJSVGShapeLayer.class] == NO) {
// [self recursivelyClip:drawableLayer
// transform:drawTransform
// inContext:ctx];
// continue;
// }
// IJSVGShapeLayer* shapeLayer = (IJSVGShapeLayer*)drawableLayer;
// [self clipContextWithShapeLayer:shapeLayer
// transform:transform
// inContext:ctx];
// }
//}
//
//+ (void)clipContextWithShapeLayer:(IJSVGShapeLayer*)shapeLayer
// transform:(CGAffineTransform)transform
// inContext:(CGContextRef)ctx
//{
// CGAffineTransform drawTransform = CGAffineTransformConcat(transform,
// shapeLayer.affineTransform);
// // Shape layers paths are reset back to 0,0 origin, so in order to be
// // correct path, we need to shift it back to where it belongs.
// drawTransform = CGAffineTransformTranslate(transform,
// shapeLayer.frame.origin.x,
// shapeLayer.frame.origin.y);
// CGPathRef path = CGPathCreateCopyByTransformingPath(shapeLayer.path,
// &drawTransform);
// CGContextAddPath(ctx, path);
// CGPathRelease(path);
//}
//
//+ (void)clipContextWithClip:(CALayer<IJSVGDrawableLayer>*)clipLayer
// toLayer:(CALayer<IJSVGDrawableLayer>*)layer
// inContext:(CGContextRef)ctx
// drawingBlock:(dispatch_block_t)drawingBlock
//{
// CGContextSaveGState(ctx);
// [self recursivelyClip:clipLayer
// transform:clipLayer.affineTransform
// inContext:ctx];
// if([layer.clipRule isEqualToString:kCAFillRuleEvenOdd]) {
// CGContextEOClip(ctx);
// } else {
// CGContextClip(ctx);
// }
// drawingBlock();
// CGContextRestoreGState(ctx);
//}
+ (void)clipContextWithClipLayers:(NSArray<CALayer<IJSVGDrawableLayer>*>*)clipLayers
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
drawingBlock:(dispatch_block_t)drawingBlock
{
if([layer isKindOfClass:IJSVGShapeLayer.class]) {
[self clipContextWithShapeLayer:(IJSVGShapeLayer*)layer
transform:transform
inContext:ctx];
CGContextSaveGState(ctx);
const CGFloat maskTolerance = .5f;
const CGFloat scale = layer.backingScaleFactor;
CGRect rect = layer.clippingBoundingBox;
// weed out the no empty clipPaths
if(CGRectEqualToRect(rect, CGRectZero) == YES) {
drawingBlock();
return;
}
for(CALayer<IJSVGDrawableLayer>* drawableLayer in layer.sublayers) {
CGAffineTransform drawTransform = CGAffineTransformConcat(transform,
drawableLayer.affineTransform);
// If its not a shape layer, just go down the tree until we find one
if([drawableLayer isKindOfClass:IJSVGShapeLayer.class] == NO) {
[self recursivelyClip:drawableLayer
transform:drawTransform
inContext:ctx];
continue;
CGSize size = CGSizeMake(CGRectGetWidth(rect),
CGRectGetHeight(rect));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
void (^drawBlock)(CGContextRef maskCtx) = ^(CGContextRef maskCtx) {
CGImageRef maskImage = NULL;
for(CALayer<IJSVGDrawableLayer>* clipLayer in clipLayers) {
CGContextSaveGState(maskCtx);
CGRect layerRect = clipLayer.outerBoundingBox;
layerRect = CGRectApplyAffineTransform(layerRect, layer.clippingTransform);
CGImageRef layerMask = [self newMaskImageForLayer:clipLayer
options:IJSVGLayerDrawingOptionIgnoreClipping
scale:scale];
if(maskImage != NULL) {
CGRect maskRect = CGRectInset(rect, -maskTolerance, -maskTolerance);
CGContextClipToMask(maskCtx, maskRect, maskImage);
}
CGContextDrawImage(maskCtx, layerRect, layerMask);
CGImageRelease(layerMask);
if(maskImage != NULL) {
CGImageRelease(maskImage);
}
maskImage = CGBitmapContextCreateImage(maskCtx);
CGContextRestoreGState(maskCtx);
}
IJSVGShapeLayer* shapeLayer = (IJSVGShapeLayer*)drawableLayer;
[self clipContextWithShapeLayer:shapeLayer
transform:transform
inContext:ctx];
}
}
+ (void)clipContextWithShapeLayer:(IJSVGShapeLayer*)shapeLayer
transform:(CGAffineTransform)transform
inContext:(CGContextRef)ctx
{
CGAffineTransform drawTransform = CGAffineTransformConcat(transform,
shapeLayer.affineTransform);
// Shape layers paths are reset back to 0,0 origin, so in order to be
// correct path, we need to shift it back to where it belongs.
drawTransform = CGAffineTransformTranslate(transform,
shapeLayer.frame.origin.x,
shapeLayer.frame.origin.y);
CGPathRef path = CGPathCreateCopyByTransformingPath(shapeLayer.path,
&drawTransform);
CGContextAddPath(ctx, path);
CGPathRelease(path);
}
+ (void)clipContextWithClip:(CALayer<IJSVGDrawableLayer>*)clipLayer
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
drawingBlock:(dispatch_block_t)drawingBlock
{
CGContextSaveGState(ctx);
[self recursivelyClip:clipLayer
transform:CGAffineTransformIdentity
inContext:ctx];
if([layer.clipRule isEqualToString:kCAFillRuleEvenOdd]) {
CGContextEOClip(ctx);
} else {
CGContextClip(ctx);
}
CGImageRelease(maskImage);
};
CGImageRef image = [self newImageWithSize:size
drawBlock:drawBlock
colorSpace:colorSpace
bitmapInfo:kCGImageAlphaNone
scale:scale];
// we need to transform the mask rect back based on the inner bounding
// box of the layer, as this could be a group layer that inner box is
// not at 0,0.
CGRect layerRect = layer.innerBoundingBox;
CGAffineTransform transform = CGAffineTransformMakeTranslation(CGRectGetMinX(layerRect),
CGRectGetMinY(layerRect));
rect = CGRectApplyAffineTransform(rect, transform);
CGContextClipToMask(ctx, rect, image);
drawingBlock();
CGImageRelease(image);
CGColorSpaceRelease(colorSpace);
CGContextRestoreGState(ctx);
}
@@ -197,21 +380,24 @@
drawingBlock:(dispatch_block_t)drawingBlock
{
CGContextSaveGState(ctx);
CGRect bounds = layer.outerBoundingBox;
CGFloat scale = layer.backingScaleFactor;
CGImageRef maskImage = [self newMaskImageForLayer:maskLayer
options:IJSVGLayerDrawingOptionNone
scale:scale];
CGContextClipToMask(ctx, bounds, maskImage);
CGContextClipToRect(ctx, maskLayer.maskingClippingRect);
CGContextClipToMask(ctx, maskLayer.maskingBoundingBox, maskImage);
drawingBlock();
CGImageRelease(maskImage);
CGContextRestoreGState(ctx);
}
+ (CGImageRef)newMaskImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
options:(IJSVGLayerDrawingOptions)options
scale:(CGFloat)scale
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGImageRef ref = [self newImageForLayer:layer
options:options
colorSpace:colorSpace
bitmapInfo:kCGImageAlphaNone
scale:scale];
@@ -219,21 +405,41 @@
return ref;
}
+ (CGImageRef)newImageWithSize:(CGSize)size
drawBlock:(void (^)(CGContextRef context))drawBlock
colorSpace:(CGColorSpaceRef)colorSpace
bitmapInfo:(uint32_t)bitmapInfo
scale:(CGFloat)scale
{
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
ceilf(size.width*scale),
ceilf(size.height*scale),
8, 0, colorSpace, bitmapInfo);
CGContextScaleCTM(offscreenContext, scale, scale);
drawBlock(offscreenContext);
CGImageRef image = CGBitmapContextCreateImage(offscreenContext);
CGContextRelease(offscreenContext);
return image;
}
+ (CGImageRef)newImageForLayer:(CALayer<IJSVGDrawableLayer>*)layer
options:(IJSVGLayerDrawingOptions)options
colorSpace:(CGColorSpaceRef)colorSpace
bitmapInfo:(uint32_t)bitmapInfo
scale:(CGFloat)scale
{
CGRect frame = layer.outerBoundingBox;
CGRect bounds = layer.innerBoundingBox;
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
ceilf(frame.size.width * scale),
ceilf(frame.size.height * scale),
ceilf(frame.size.width*scale),
ceilf(frame.size.height*scale),
8, 0, colorSpace, bitmapInfo);
CGContextSaveGState(offscreenContext);
CGContextScaleCTM(offscreenContext, scale, scale);
CGContextTranslateCTM(offscreenContext, -frame.origin.x, -frame.origin.y);
[layer renderInContext:offscreenContext];
CGContextConcatCTM(offscreenContext, CGAffineTransformMakeTranslation(-bounds.origin.x,
-bounds.origin.y));
[IJSVGLayer renderLayer:layer
inContext:offscreenContext
options:options];
CGImageRef image = CGBitmapContextCreateImage(offscreenContext);
CGContextRelease(offscreenContext);
return image;
@@ -261,9 +467,9 @@
+ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer
{
NSMutableArray* arr = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* arr = [[NSMutableArray alloc] init];
for (CALayer* subLayer in layer.sublayers) {
if (subLayer.sublayers.count != 0) {
if(subLayer.sublayers.count != 0) {
NSArray* moreLayers = [self deepestSublayersOfLayer:(IJSVGLayer*)subLayer];
[arr addObjectsFromArray:moreLayers];
} else {
@@ -273,8 +479,8 @@
return arr;
}
+ (void)recursivelyWalkLayer:(CALayer<IJSVGDrawableLayer>*)layer
withBlock:(void (^)(CALayer<IJSVGDrawableLayer>* layer, BOOL* stop))block
+ (void)recursivelyWalkLayer:(CALayer<IJSVGBasicLayer>*)layer
withBlock:(void (^)(CALayer<IJSVGBasicLayer>* layer, BOOL* stop))block
{
// call for layer and mask if there is one
BOOL stop = NO;
@@ -284,12 +490,25 @@
}
// sublayers!!
for (CALayer<IJSVGDrawableLayer>* aLayer in layer.sublayers) {
for (CALayer<IJSVGBasicLayer>* aLayer in layer.sublayers) {
[self recursivelyWalkLayer:aLayer
withBlock:block];
}
}
+ (void)setBackingScaleFactor:(CGFloat)scale
renderQuality:(IJSVGRenderQuality)quality
recursivelyToLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
[self recursivelyWalkLayer:layer
withBlock:^(CALayer<IJSVGDrawableLayer>*sublayer, BOOL *stop) {
if(sublayer.requiresBackingScale == YES) {
sublayer.backingScaleFactor = scale;
}
sublayer.renderQuality = quality;
}];
}
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
[self logLayer:layer
@@ -333,7 +552,7 @@
- (void)setBackingScaleFactor:(CGFloat)newFactor
{
if (_backingScaleFactor == newFactor) {
if(_backingScaleFactor == newFactor) {
return;
}
@@ -343,9 +562,9 @@
// make sure its applied to any mask or clipPath
_maskLayer.backingScaleFactor = newFactor;
_clipLayer.backingScaleFactor = newFactor;
[self setNeedsDisplay];
for(CALayer<IJSVGDrawableLayer>* clipLayer in _clipLayers) {
clipLayer.backingScaleFactor = newFactor;
}
}
- (void)performRenderInContext:(CGContextRef)ctx
@@ -362,24 +581,6 @@
[super renderInContext:ctx];
}
- (void)setConvertMasksToPaths:(BOOL)flag
{
if (_convertMasksToPaths == flag) {
return;
}
_convertMasksToPaths = flag;
if (flag == YES) {
if (_maskingLayer != nil) {
(void)([_maskingLayer release]), _maskingLayer = nil;
}
_maskingLayer = [(IJSVGLayer*)self.mask retain];
self.mask = nil;
} else {
self.mask = _maskingLayer;
(void)([_maskingLayer release]), _maskingLayer = nil;
}
}
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer*)sublayer
withOffset:(CGPoint)offset
@@ -391,7 +592,7 @@
// walk up the superlayer chain
CALayer* superlayer = self.superlayer;
if (IJSVGIsSVGLayer(superlayer) == YES) {
if(IJSVGIsSVGLayer(superlayer) == YES) {
[(IJSVGLayer*)superlayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer*)self
withOffset:layerOffset];
@@ -402,14 +603,14 @@
// if its a group we need to get the lowest level children
// and walk up the chain again
if ([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
if([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
NSArray* subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer];
for (IJSVGLayer* subLayer in subs) {
[subLayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer*)self
withOffset:layerOffset];
}
} else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
} else if([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
// is a shape, go for it!
CGPathRef maskPath = maskingLayer.path;
CGContextTranslateCTM(context, -layerOffset.x, -layerOffset.y);
@@ -420,19 +621,14 @@
CGContextConcatCTM(context, sublayerTransform);
}
- (CALayer<IJSVGDrawableLayer>*)rootLayer
{
return [self.class rootLayerForLayer:self];
}
- (CGAffineTransform)absoluteTransform
{
return [IJSVGLayer absoluteTransformForLayer:self];
}
- (BOOL)requiresBackingScaleHelp
- (BOOL)requiresBackingScale
{
return _maskLayer != nil || _clipLayer != nil;
return _maskLayer != nil || (_clipLayers != nil && _clipLayers.count != 0);
}
- (IJSVGShapeLayer*)maskingLayer
@@ -443,12 +639,8 @@
- (void)renderInContext:(CGContextRef)ctx
{
[IJSVGLayer renderLayer:self
inContext:ctx];
}
- (id<CAAction>)actionForKey:(NSString*)event
{
return nil;
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
}
- (CGRect)absoluteFrame
@@ -466,14 +658,6 @@
return CGRectIsNull(_outerBoundingBox) == NO ? _outerBoundingBox : self.frame;
}
- (CGRect)outerBoundingBoxBounds
{
return (CGRect) {
.origin = CGPointZero,
.size = self.outerBoundingBox.size
};
}
- (CGRect)boundingBoxBounds
{
return (CGRect) {
@@ -482,9 +666,12 @@
};
}
- (CGRect)strokeBoundingBox
- (CGRect)innerBoundingBox
{
return self.boundingBox;
return (CGRect) {
.origin = CGPointZero,
.size = self.outerBoundingBox.size
};
}
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
@@ -497,4 +684,87 @@
return self.sublayers;
}
- (void)setClipPath:(CGPathRef)clipPath
{
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
_clipPath = CGPathRetain(clipPath);
}
- (NSMapTable<NSNumber*,CALayer<IJSVGDrawableLayer>*>*)layerUsageMapTable
{
if(_layerUsageMapTable == nil) {
_layerUsageMapTable = IJSVGLayerDefaultUsageMapTable();
}
return _layerUsageMapTable;
}
- (void)setLayer:(CALayer<IJSVGDrawableLayer>*)layer
forUsageType:(IJSVGLayerUsageType)type
{
[self.layerUsageMapTable setObject:layer
forKey:@(type)];
}
- (CALayer<IJSVGDrawableLayer>*)layerForUsageType:(IJSVGLayerUsageType)type
{
return [self.layerUsageMapTable objectForKey:@(type)];
}
- (CALayer<IJSVGDrawableLayer>*)strokeLayer:(IJSVGLayerUsageType*)usageType
{
CALayer<IJSVGDrawableLayer>* layer = nil;
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGeneric]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGeneric;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGradient]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGradient;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokePattern]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokePattern;
return layer;
}
return nil;
}
- (void)addTraits:(IJSVGLayerTraits)traits
{
_layerTraits |= traits;
}
- (void)removeTraits:(IJSVGLayerTraits)traits
{
_layerTraits = _layerTraits & ~traits;
}
- (BOOL)matchesTraits:(IJSVGLayerTraits)traits
{
return (_layerTraits & traits) == traits;
}
- (BOOL)treatImplicitOriginAsTransform
{
return YES;
}
- (IJSVGTraitedColorStorage*)colors
{
IJSVGTraitedColorStorage* colorList = [[IJSVGTraitedColorStorage alloc] init];
for(CALayer<IJSVGDrawableLayer>* layer in self.sublayers) {
[colorList unionColorStorage:layer.colors];
}
return colorList;
}
- (CALayer<IJSVGDrawableLayer>*)firstSublayerOfClass:(Class)aClass
{
return [self.class firstSublayerOfClass:aClass
fromLayer:self];
}
@end
@@ -6,13 +6,17 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGLayer.h"
#import "IJSVGPattern.h"
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGPattern.h>
#import <QuartzCore/QuartzCore.h>
@interface IJSVGPatternLayer : IJSVGLayer
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* pattern;
@property (nonatomic, retain) IJSVGPattern* patternNode;
@property (nonatomic, strong) CALayer<IJSVGDrawableLayer>* pattern;
@property (nonatomic, strong) IJSVGPattern* patternNode;
- (void)computeCellSize:(CGSize*)cellSize
viewBox:(CGRect*)viewBox
origin:(CGPoint*)origin;
@end
@@ -20,22 +20,23 @@
@implementation IJSVGPatternLayer
- (void)dealloc
{
(void)([_pattern release]), _pattern = nil;
(void)([_patternNode release]), _patternNode = nil;
[super dealloc];
}
- (BOOL)requiresBackingScaleHelp
- (BOOL)requiresBackingScale
{
return YES;
}
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
[super setBackingScaleFactor:backingScaleFactor];
[IJSVGLayer setBackingScaleFactor:backingScaleFactor
renderQuality:self.renderQuality
recursivelyToLayer:self.pattern];
}
void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
{
// reassign the layer
IJSVGPatternLayer* layer = (IJSVGPatternLayer*)info;
IJSVGPatternLayer* layer = (__bridge IJSVGPatternLayer*)info;
CGSize size = layer.cellSize;
CGContextSaveGState(ctx);
CGRect rect = CGRectMake(0.f, 0.f, size.width, size.height);
@@ -44,15 +45,13 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
IJSVGViewBoxAlignment alignment = layer.patternNode.viewBoxAlignment;
IJSVGViewBoxMeetOrSlice meetOrSlice = layer.patternNode.viewBoxMeetOrSlice;
CGRect viewBox = layer.viewBox;
[IJSVGViewBox drawViewBox:viewBox
inRect:rect
alignment:alignment
meetOrSlice:meetOrSlice
inContext:ctx
drawingBlock:^(CGSize size) {
[layer.pattern renderInContext:ctx];
}];
IJSVGViewBoxDrawingBlock drawBlock = ^(CGFloat scale[]) {
[IJSVGLayer renderLayer:layer.pattern
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
};
IJSVGContextDrawViewBox(ctx, viewBox, rect, alignment, meetOrSlice,
drawBlock);
CGContextSaveGState(ctx);
};
@@ -61,6 +60,49 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
return [super referencingLayer] ?: self.superlayer;
}
- (void)computeCellSize:(CGSize*)cellSize
viewBox:(CGRect*)viewBox
origin:(CGPoint*)origin
{
CALayer<IJSVGDrawableLayer>* layer = (CALayer<IJSVGDrawableLayer>*)self.referencingLayer;
CGRect rect = IJSVGLayerGetBoundingBoxBounds(layer);
// get the bounds, we need these as when we render we might need to swap
// the coordinates over to objectBoundingBox
IJSVGUnitLength* xLength = _patternNode.x;
IJSVGUnitLength* yLength = _patternNode.y;
IJSVGUnitLength* wLength = _patternNode.width;
IJSVGUnitLength* hLength = _patternNode.height;
// actually do the swap if required
if(_patternNode.units == IJSVGUnitObjectBoundingBox) {
wLength = wLength.lengthByMatchingPercentage;
hLength = hLength.lengthByMatchingPercentage;
xLength = xLength.lengthByMatchingPercentage;
yLength = yLength.lengthByMatchingPercentage;
}
*origin = CGPointMake([xLength computeValue:rect.size.width],
[yLength computeValue:rect.size.height]);
CGFloat width = [wLength computeValue:rect.size.width];
CGFloat height = [hLength computeValue:rect.size.height];
*cellSize = CGSizeMake(width, height);
// who knew that patterns have viewBoxes? Not me, but here is an implementation
// of it anyway
if(_patternNode.viewBox != nil && _patternNode.viewBox.isZeroRect == NO) {
IJSVGUnitRect* nViewBox = _patternNode.viewBox;
if(_patternNode.contentUnits == IJSVGUnitObjectBoundingBox) {
nViewBox = [nViewBox copyByConvertingToUnitsLengthType:IJSVGUnitLengthTypePercentage];
}
*viewBox = [nViewBox computeValue:rect.size];
} else {
// no viewbox is assigned, so just map it 1:1 with its cellSize
*viewBox = CGRectMake(0.f, 0.f, cellSize->width, cellSize->height);
}
}
- (void)drawInContext:(CGContextRef)ctx
{
// holder for callback
@@ -71,53 +113,31 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
CGContextSetFillColorSpace(ctx, patternSpace);
CGColorSpaceRelease(patternSpace);
CGRect rect = self.referencingLayer.boundingBoxBounds;
IJSVGUnitLength* wLength = _patternNode.width;
IJSVGUnitLength* hLength = _patternNode.height;
if(self.patternNode.units == IJSVGUnitObjectBoundingBox ||
self.patternNode.contentUnits == IJSVGUnitObjectBoundingBox) {
wLength = wLength.lengthByMatchingPercentage;
hLength = hLength.lengthByMatchingPercentage;
}
CGFloat width = [wLength computeValue:rect.size.width];
CGFloat height = [hLength computeValue:rect.size.height];
_cellSize = CGSizeMake(width, height);
CALayer<IJSVGDrawableLayer>* layer = (CALayer<IJSVGDrawableLayer>*)self.referencingLayer;
// transform us back into the correct space
CGAffineTransform transform = CGAffineTransformIdentity;
if (self.patternNode.units == IJSVGUnitUserSpaceOnUse) {
CGRect frame = layer.boundingBox;
transform = [IJSVGLayer absoluteTransformForLayer:layer];
transform = CGAffineTransformTranslate(transform,
-CGRectGetMinX(frame),
-CGRectGetMinY(frame));
if(_patternNode.units == IJSVGUnitUserSpaceOnUse) {
transform = [IJSVGLayer userSpaceTransformForLayer:layer];
}
transform = CGAffineTransformConcat(transform, IJSVGConcatTransforms(self.patternNode.transforms));
// transform the X and Y shift
transform = CGAffineTransformTranslate(transform,
[_patternNode.x computeValue:rect.size.width],
[_patternNode.y computeValue:rect.size.height]);
// who knew that patterns have viewBoxes? Not me, but here is an implementation
// of it anyway
if(_patternNode.viewBox != nil && _patternNode.viewBox.isZeroRect == NO) {
if(_patternNode.units == IJSVGUnitObjectBoundingBox) {
IJSVGUnitRect* viewBox = nil;
viewBox = [[_patternNode.viewBox copyByConvertingToUnitsLengthType:IJSVGUnitLengthTypePercentage] autorelease];
_viewBox = [viewBox computeValue:rect.size];
}
}
CGPoint origin = CGPointZero;
[self computeCellSize:&_cellSize
viewBox:&_viewBox
origin:&origin];
// transform the X and Y shift
transform = CGAffineTransformConcat(transform, IJSVGConcatTransforms(self.patternNode.transforms));
transform = CGAffineTransformTranslate(transform, origin.x, origin.y);
// its possible that this layer is shifted inwards due to a stroke on the
// parent layer
transform = CGAffineTransformConcat(transform, [IJSVGLayer userSpaceTransformForLayer:self]);
// create the pattern
CGRect selfBounds = self.boundingBoxBounds;
CGRect selfBounds = IJSVGLayerGetBoundingBoxBounds(self);
CGPatternRef ref = CGPatternCreate((void*)self, selfBounds,
transform, width, height,
transform, _cellSize.width, _cellSize.height,
kCGPatternTilingConstantSpacing,
true, &callbacks);
@@ -135,4 +155,9 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
return @[self.pattern];
}
- (IJSVGTraitedColorStorage*)colors
{
return _pattern.colors;
}
@end
@@ -18,6 +18,7 @@
- (void)renderInContext:(CGContextRef)ctx
viewPort:(CGRect)viewPort
backingScale:(CGFloat)backingScale
quality:(IJSVGRenderQuality)quality;
quality:(IJSVGRenderQuality)quality
ignoreIntrinsicSize:(BOOL)ignoreIntrinsicSize;
@end
@@ -6,7 +6,7 @@
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import "IJSVGRootLayer.h"
#import <IJSVG/IJSVGRootLayer.h>
@implementation IJSVGRootLayer
@@ -14,19 +14,23 @@
{
if(self.viewBox != nil) {
CGRect viewBox = [self.viewBox computeValue:CGSizeZero];
__block IJSVGRootLayer* weakSelf = self;
IJSVGViewBoxDrawingBlock drawingBlock = ^(CGSize size) {
__weak IJSVGRootLayer* weakSelf = self;
IJSVGViewBoxDrawingBlock drawingBlock = ^(CGFloat scale[]) {
CGContextSaveGState(ctx);
// we have to make sure we set the backing scale factor once
// we know how scale this will be drawn at
weakSelf.backingScaleFactor *= MAX(size.width, size.height);
CGFloat nScale = MIN(scale[0], scale[1]);
nScale += weakSelf.backingScaleFactor;
weakSelf.backingScaleFactor = nScale;
// perform the actual render now we have computed backing scale
[super performRenderInContext:ctx];
CGContextRestoreGState(ctx);
};
[IJSVGViewBox drawViewBox:viewBox
inRect:self.boundingBoxBounds
alignment:self.viewBoxAlignment
meetOrSlice:self.viewBoxMeetOrSlice
inContext:ctx
drawingBlock:drawingBlock];
IJSVGContextDrawViewBox(ctx, viewBox, IJSVGLayerGetBoundingBoxBounds(self),
self.viewBoxAlignment,
self.viewBoxMeetOrSlice, drawingBlock);
return;
}
[super performRenderInContext:ctx];
@@ -34,6 +38,8 @@
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
// get nearest .5f
backingScaleFactor = MAX(round(backingScaleFactor * 2.f) / 2.f, .5f);
[super setBackingScaleFactor:backingScaleFactor];
if(_disableBackingScalePropagation == YES) {
return;
@@ -43,13 +49,10 @@
- (void)propagateBackingScalePropertiesToSublayers
{
__block IJSVGRootLayer* weakSelf = self;
for(CALayer<IJSVGDrawableLayer>* layer in self.sublayers) {
[IJSVGLayer recursivelyWalkLayer:layer
withBlock:^(CALayer<IJSVGDrawableLayer>* propLayer, BOOL *stop) {
propLayer.renderQuality = weakSelf.renderQuality;
propLayer.backingScaleFactor = weakSelf.backingScaleFactor;
}];
[IJSVGLayer setBackingScaleFactor:self.backingScaleFactor
renderQuality:self.renderQuality
recursivelyToLayer:layer];
}
}
@@ -57,15 +60,34 @@
viewPort:(CGRect)viewPort
backingScale:(CGFloat)backingScale
quality:(IJSVGRenderQuality)quality
ignoreIntrinsicSize:(BOOL)ignoreIntrinsicSize
{
CGRect frame = viewPort;
IJSVGUnitSize* size = nil;
// The SVG might have an intrinsic size against it, if so, we need to use
// that instead of the viewPort size to make sure we obey the render correctly.
if(ignoreIntrinsicSize == NO && (size = self.intrinsicSize) != nil) {
CGFloat width = 0.f;
CGFloat height = 0.f;
if((width = [size.width computeValue:frame.size.width]) != 0.f) {
frame.size.width = width;
}
if((height = [size.height computeValue:frame.size.height]) != 0.f) {
frame.size.height = height;
}
}
self.frame = frame;
_disableBackingScalePropagation = YES;
self.backingScaleFactor = backingScale;
self.renderQuality = quality;
_disableBackingScalePropagation = NO;
[self propagateBackingScalePropertiesToSublayers];
[self renderInContext:ctx];
}
- (BOOL)treatImplicitOriginAsTransform
{
return NO;
}
@end
@@ -14,32 +14,10 @@
@private
IJSVGLayer* _maskingLayer;
NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* _layerUsageMapTable;
}
@property (nonatomic, assign) IJSVGGradientLayer* gradientFillLayer;
@property (nonatomic, assign) IJSVGPatternLayer* patternFillLayer;
@property (nonatomic, assign) IJSVGStrokeLayer* strokeLayer;
@property (nonatomic, assign) IJSVGGradientLayer* gradientStrokeLayer;
@property (nonatomic, assign) IJSVGPatternLayer* patternStrokeLayer;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, readonly) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) CGPoint originalPathOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
@property (nonatomic, assign) IJSVGPrimitivePathType primitiveType;
@property (nonatomic, readonly) CGRect computedFrame;
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* maskLayer;
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* rootLayer;
@property (nonatomic, readonly) CGRect absoluteFrame;
@property (nonatomic, assign) CGRect boundingBox;
@property (nonatomic, assign) CGRect outerBoundingBox;
@property (nonatomic, readonly) CGRect boundingBoxBounds;
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
@property (nonatomic, assign) CGRect strokeBoundingBox;
@property (nonatomic, copy) CAShapeLayerFillRule clipRule;
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer*)sublayer
@@ -6,23 +6,47 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGGroupLayer.h"
#import "IJSVGShapeLayer.h"
#import <IJSVG/IJSVGGroupLayer.h>
#import <IJSVG/IJSVGShapeLayer.h>
#import <IJSVG/IJSVGStrokeLayer.h>
#import <IJSVG/IJSVGGradientLayer.h>
#import <IJSVG/IJSVGTraitedColorStorage.h>
#import <IJSVG/IJSVGPatternLayer.h>
@implementation IJSVGShapeLayer
@synthesize backingScaleFactor = _backingScaleFactor;
@synthesize requiresBackingScale;
@synthesize renderQuality;
@synthesize blendingMode;
@synthesize absoluteOrigin;
@synthesize clipPath = _clipPath;
@synthesize clipRule;
@synthesize clipLayers = _clipLayers;
@synthesize clippingTransform;
@synthesize clippingBoundingBox;
@synthesize maskingClippingRect;
@synthesize clipPathTransform;
@synthesize colors;
@synthesize boundingBox;
@synthesize layerTraits = _layerTraits;
@synthesize maskingBoundingBox;
@synthesize filter;
@synthesize referencingLayer = _referencingLayer;
@synthesize outerBoundingBox;
@synthesize maskLayer = _maskLayer;
@synthesize treatImplicitOriginAsTransform;
- (void)dealloc
{
(void)([_clipLayer release]), _clipLayer = nil;
(void)([_maskLayer release]), _maskLayer = nil;
(void)([_maskingLayer release]), _maskingLayer = nil;
(void)([_clipRule release]), _clipRule = nil;
[super dealloc];
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
}
- (CALayer<IJSVGDrawableLayer> *)rootLayer
- (id<CAAction>)actionForKey:(NSString*)event
{
return [IJSVGLayer rootLayerForLayer:self];
return nil;
}
- (CGRect)absoluteFrame
@@ -48,14 +72,27 @@
};
}
- (BOOL)requiresBackingScaleHelp
- (CGRect)innerBoundingBox
{
return _maskLayer != nil || _clipLayer != nil;
return self.bounds;
}
- (BOOL)requiresBackingScale
{
return _maskLayer != nil || (_clipLayers != nil && _clipLayers.count != 0);
}
- (void)setClipPath:(CGPathRef)clipPath
{
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
_clipPath = CGPathRetain(clipPath);
}
- (void)setBackingScaleFactor:(CGFloat)newFactor
{
if (_backingScaleFactor == newFactor) {
if(_backingScaleFactor == newFactor) {
return;
}
@@ -65,7 +102,10 @@
// make sure its applied to any mask or clipPath
_maskLayer.backingScaleFactor = newFactor;
_clipLayer.backingScaleFactor = newFactor;
for(CALayer<IJSVGDrawableLayer>* clipLayer in _clipLayers) {
clipLayer.backingScaleFactor = newFactor;
}
[self setNeedsDisplay];
}
@@ -84,24 +124,6 @@
[super renderInContext:ctx];
}
- (void)setConvertMasksToPaths:(BOOL)flag
{
if (_convertMasksToPaths == flag) {
return;
}
_convertMasksToPaths = flag;
if (flag == YES) {
if (_maskingLayer != nil) {
(void)([_maskingLayer release]), _maskingLayer = nil;
}
_maskingLayer = [(IJSVGLayer*)self.mask retain];
self.mask = nil;
} else {
self.mask = _maskingLayer;
(void)([_maskingLayer release]), _maskingLayer = nil;
}
}
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer*)sublayer
withOffset:(CGPoint)offset
@@ -113,7 +135,7 @@
// walk up the superlayer chain
CALayer* superlayer = self.superlayer;
if (IJSVGIsSVGLayer(superlayer) == YES) {
if(IJSVGIsSVGLayer(superlayer) == YES) {
[(IJSVGLayer*)superlayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer*)self
withOffset:layerOffset];
@@ -124,14 +146,14 @@
// if its a group we need to get the lowest level children
// and walk up the chain again
if ([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
if([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
NSArray* subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer];
for (IJSVGLayer* subLayer in subs) {
[subLayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer*)self
withOffset:layerOffset];
}
} else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
} else if([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
// is a shape, go for it!
CGPathRef maskPath = maskingLayer.path;
CGContextTranslateCTM(context, -layerOffset.x, -layerOffset.y);
@@ -150,11 +172,47 @@
- (void)renderInContext:(CGContextRef)ctx
{
[IJSVGLayer renderLayer:(IJSVGLayer*)self
inContext:ctx];
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
}
- (id<CAAction>)actionForKey:(NSString*)event
- (NSMapTable<NSNumber*,CALayer<IJSVGDrawableLayer>*>*)layerUsageMapTable
{
if(_layerUsageMapTable == nil) {
_layerUsageMapTable = IJSVGLayerDefaultUsageMapTable();
}
return _layerUsageMapTable;
}
- (void)setLayer:(CALayer<IJSVGDrawableLayer>*)layer
forUsageType:(IJSVGLayerUsageType)type
{
[self.layerUsageMapTable setObject:layer
forKey:@(type)];
}
- (CALayer<IJSVGDrawableLayer>*)layerForUsageType:(IJSVGLayerUsageType)type
{
return [self.layerUsageMapTable objectForKey:@(type)];
}
- (CALayer<IJSVGDrawableLayer>*)strokeLayer:(IJSVGLayerUsageType*)usageType
{
CALayer<IJSVGDrawableLayer>* layer = nil;
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGeneric]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGeneric;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGradient]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGradient;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokePattern]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokePattern;
return layer;
}
return nil;
}
@@ -163,4 +221,92 @@
return self.sublayers;
}
- (BOOL)treatImplicitOriginAsTransform
{
return YES;
}
- (void)addTraits:(IJSVGLayerTraits)traits
{
_layerTraits |= traits;
}
- (void)removeTraits:(IJSVGLayerTraits)traits
{
_layerTraits = _layerTraits & ~traits;
}
- (BOOL)matchesTraits:(IJSVGLayerTraits)traits
{
return (_layerTraits & traits) == traits;
}
- (CALayer<IJSVGDrawableLayer>*)firstSublayerOfClass:(Class)aClass
{
return [IJSVGLayer firstSublayerOfClass:aClass
fromLayer:self];
}
- (IJSVGTraitedColorStorage*)colors
{
IJSVGTraitedColorStorage* list = [[IJSVGTraitedColorStorage alloc] init];
// we have a fill color
if([self matchesTraits:IJSVGLayerTraitFilled] == YES) {
IJSVGShapeLayer* fillLayer = nil;
if((fillLayer = (IJSVGShapeLayer*)[self layerForUsageType:IJSVGLayerUsageTypeFillGeneric]) != nil) {
CGColorRef colorRef = NULL;
if((colorRef = fillLayer.fillColor) != NULL) {
NSColor* nsColor = [NSColor colorWithCGColor:colorRef];
IJSVGTraitedColor* color = [IJSVGTraitedColor colorWithColor:nsColor
traits:IJSVGColorUsageTraitFill];
[list addColor:color];
}
}
// patterns
if((fillLayer = (IJSVGShapeLayer*)[self layerForUsageType:IJSVGLayerUsageTypeFillPattern]) != nil) {
IJSVGTraitedColorStorage* storage = fillLayer.colors;
[storage addTraits:IJSVGColorUsageTraitFill];
[list unionColorStorage:storage];
}
// gradients
if((fillLayer = (IJSVGShapeLayer*)[self layerForUsageType:IJSVGLayerUsageTypeFillGradient]) != nil) {
IJSVGTraitedColorStorage* storage = fillLayer.colors;
[storage addTraits:IJSVGColorUsageTraitGradientStop];
[list unionColorStorage:storage];
}
}
// we have a stroke color
if([self matchesTraits:IJSVGLayerTraitStroked] == YES) {
IJSVGStrokeLayer* strokeLayer = nil;
if((strokeLayer = (IJSVGStrokeLayer*)[self layerForUsageType:IJSVGLayerUsageTypeStrokeGeneric]) != nil) {
CGColorRef colorRef = NULL;
if((colorRef = strokeLayer.strokeColor) != NULL) {
NSColor* nsColor = [NSColor colorWithCGColor:colorRef];
IJSVGTraitedColor* color = [IJSVGTraitedColor colorWithColor:nsColor
traits:IJSVGColorUsageTraitStroke];
[list addColor:color];
}
}
// patterns
if((strokeLayer = (IJSVGStrokeLayer*)[self layerForUsageType:IJSVGLayerUsageTypeStrokePattern]) != nil) {
IJSVGTraitedColorStorage* storage = strokeLayer.colors;
[storage addTraits:IJSVGColorUsageTraitFill];
[list unionColorStorage:storage];
}
// gradients
if((strokeLayer = (IJSVGStrokeLayer*)[self layerForUsageType:IJSVGLayerUsageTypeStrokeGradient]) != nil) {
IJSVGTraitedColorStorage* storage = strokeLayer.colors;
[storage addTraits:IJSVGColorUsageTraitGradientStop];
[list unionColorStorage:storage];
}
}
return list;
}
@end
@@ -6,7 +6,7 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGShapeLayer.h"
#import <IJSVG/IJSVGShapeLayer.h>
@interface IJSVGStrokeLayer : IJSVGShapeLayer
@@ -6,15 +6,8 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGStrokeLayer.h"
#import <IJSVG/IJSVGStrokeLayer.h>
@implementation IJSVGStrokeLayer
- (CGRect)outerBoundingBox
{
return CGRectMake(-self.lineWidth / 2.f, -self.lineWidth / 2.f,
self.boundingBox.size.width + self.lineWidth,
self.boundingBox.size.height + self.lineWidth);
}
@end
@@ -0,0 +1,17 @@
//
// IJSVGTileLayer.h
// IJSVG
//
// Created by Curtis Hard on 29/06/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import <IJSVG/IJSVGLayer.h>
@interface IJSVGTileLayer : CATiledLayer <IJSVGDrawableLayer> {
@private
NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* _layerUsageMapTable;
}
@end
@@ -0,0 +1,150 @@
//
// IJSVGTileLayer.m
// IJSVG
//
// Created by Curtis Hard on 29/06/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import "IJSVGTileLayer.h"
@implementation IJSVGTileLayer
@synthesize clipLayers;
@synthesize backingScaleFactor;
@synthesize renderQuality;
@synthesize requiresBackingScale;
@synthesize maskLayer = _maskLayer;
@synthesize fillRule = _fillRule;
@synthesize clipRule = _clipRule;
@synthesize absoluteFrame;
@synthesize boundingBox;
@synthesize outerBoundingBox;
@synthesize filter = _filter;
@synthesize innerBoundingBox;
@synthesize maskingBoundingBox;
@synthesize maskingClippingRect;
@synthesize clippingBoundingBox;
@synthesize clippingTransform;
@synthesize layerTraits = _layerTraits;
@synthesize clipPath = _clipPath;
@synthesize clipPathTransform;
@synthesize referencingLayer = _referencingLayer;
@synthesize absoluteOrigin;
@synthesize blendingMode;
@synthesize colors;
- (void)dealloc
{
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
}
- (id<CAAction>)actionForKey:(NSString*)event
{
return nil;
}
- (CALayer<IJSVGDrawableLayer> *)referencedLayer
{
return self.sublayers.firstObject;
}
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
{
return _referencingLayer ?: self.superlayer;
}
- (void)renderInContext:(CGContextRef)ctx
{
[IJSVGLayer renderLayer:self
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
}
- (void)performRenderInContext:(CGContextRef)ctx
{
[super renderInContext:ctx];
}
- (NSArray<CALayer<IJSVGDrawableLayer>*>*)debugLayers
{
return self.sublayers;
}
- (void)setClipPath:(CGPathRef)clipPath
{
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
_clipPath = CGPathRetain(clipPath);
}
- (NSMapTable<NSNumber*,CALayer<IJSVGDrawableLayer>*>*)layerUsageMapTable
{
if(_layerUsageMapTable == nil) {
_layerUsageMapTable = IJSVGLayerDefaultUsageMapTable();
}
return _layerUsageMapTable;
}
- (CALayer<IJSVGDrawableLayer>*)layerForUsageType:(IJSVGLayerUsageType)type
{
return [self.layerUsageMapTable objectForKey:@(type)];
}
- (CALayer<IJSVGDrawableLayer>*)strokeLayer:(IJSVGLayerUsageType*)usageType
{
CALayer<IJSVGDrawableLayer>* layer = nil;
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGeneric]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGeneric;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGradient]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGradient;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokePattern]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokePattern;
return layer;
}
return nil;
}
- (void)setLayer:(CALayer<IJSVGDrawableLayer>*)layer
forUsageType:(IJSVGLayerUsageType)type
{
[self.layerUsageMapTable setObject:layer
forKey:@(type)];
}
- (void)addTraits:(IJSVGLayerTraits)traits
{
_layerTraits |= traits;
}
- (void)removeTraits:(IJSVGLayerTraits)traits
{
_layerTraits = _layerTraits & ~traits;
}
- (BOOL)matchesTraits:(IJSVGLayerTraits)traits
{
return (_layerTraits & traits) == traits;
}
- (BOOL)treatImplicitOriginAsTransform
{
return YES;
}
- (CALayer<IJSVGDrawableLayer>*)firstSublayerOfClass:(Class)aClass
{
return [IJSVGLayer firstSublayerOfClass:aClass
fromLayer:self];
}
@end
@@ -9,13 +9,9 @@
#import <QuartzCore/QuartzCore.h>
#import <IJSVG/IJSVGLayer.h>
@interface IJSVGTransformLayer : CATransformLayer <IJSVGDrawableLayer>
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, retain) CALayer<IJSVGDrawableLayer>* clipLayer;
@property (nonatomic, readonly) CGPoint absoluteOrigin;
@property (nonatomic, readonly) CGRect computedFrame;
@property (nonatomic, readonly) CALayer<IJSVGDrawableLayer>* referencedLayer;
@property (nonatomic, assign) CALayer<IJSVGDrawableLayer>* referencingLayer;
@interface IJSVGTransformLayer : CATransformLayer <IJSVGDrawableLayer> {
@private
NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* _layerUsageMapTable;
}
@end
@@ -6,29 +6,45 @@
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import "IJSVGTransformLayer.h"
#import <IJSVG/IJSVGTransformLayer.h>
#import <IJSVG/IJSVGTraitedColorStorage.h>
@implementation IJSVGTransformLayer
@synthesize clipLayers;
@synthesize backingScaleFactor;
@synthesize renderQuality;
@synthesize requiresBackingScaleHelp;
@synthesize requiresBackingScale;
@synthesize maskLayer = _maskLayer;
@synthesize fillRule = _fillRule;
@synthesize clipRule = _clipRule;
@synthesize absoluteFrame;
@synthesize boundingBox;
@synthesize boundingBoxBounds;
@synthesize strokeBoundingBox;
@synthesize outerBoundingBox;
@synthesize filter = _filter;
@synthesize innerBoundingBox;
@synthesize maskingBoundingBox;
@synthesize maskingClippingRect;
@synthesize clippingBoundingBox;
@synthesize clippingTransform;
@synthesize layerTraits = _layerTraits;
@synthesize clipPath = _clipPath;
@synthesize clipPathTransform;
@synthesize colors;
@synthesize absoluteOrigin;
@synthesize blendingMode;
@synthesize referencingLayer = _referencingLayer;
- (void)dealloc
{
(void)[_maskLayer release], _maskLayer = nil;
(void)[_fillRule release], _fillRule = nil;
(void)[_clipRule release], _clipRule = nil;
(void)[_clipLayer release], _clipLayer = nil;
[super dealloc];
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
}
- (id<CAAction>)actionForKey:(NSString*)event
{
return nil;
}
- (CALayer<IJSVGDrawableLayer> *)referencedLayer
@@ -36,24 +52,16 @@
return self.sublayers.firstObject;
}
- (CALayer<IJSVGDrawableLayer> *)referencingLayer {
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
{
return _referencingLayer ?: self.superlayer;
}
- (CALayer<IJSVGDrawableLayer>*)rootLayer
{
return [IJSVGLayer rootLayerForLayer:self];
}
- (BOOL)requiresBackingScaleHelp
{
return YES;
}
- (void)renderInContext:(CGContextRef)ctx
{
[IJSVGLayer renderLayer:self
inContext:ctx];
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
}
- (void)performRenderInContext:(CGContextRef)ctx
@@ -66,4 +74,87 @@
return self.sublayers;
}
- (void)setClipPath:(CGPathRef)clipPath
{
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
_clipPath = CGPathRetain(clipPath);
}
- (NSMapTable<NSNumber*,CALayer<IJSVGDrawableLayer>*>*)layerUsageMapTable
{
if(_layerUsageMapTable == nil) {
_layerUsageMapTable = IJSVGLayerDefaultUsageMapTable();
}
return _layerUsageMapTable;
}
- (CALayer<IJSVGDrawableLayer>*)layerForUsageType:(IJSVGLayerUsageType)type
{
return [self.layerUsageMapTable objectForKey:@(type)];
}
- (CALayer<IJSVGDrawableLayer>*)strokeLayer:(IJSVGLayerUsageType*)usageType
{
CALayer<IJSVGDrawableLayer>* layer = nil;
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGeneric]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGeneric;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokeGradient]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokeGradient;
return layer;
}
if((layer = [self layerForUsageType:IJSVGLayerUsageTypeStrokePattern]) != nil) {
*usageType = IJSVGLayerUsageTypeStrokePattern;
return layer;
}
return nil;
}
- (void)setLayer:(CALayer<IJSVGDrawableLayer>*)layer
forUsageType:(IJSVGLayerUsageType)type
{
[self.layerUsageMapTable setObject:layer
forKey:@(type)];
}
- (void)addTraits:(IJSVGLayerTraits)traits
{
_layerTraits |= traits;
}
- (void)removeTraits:(IJSVGLayerTraits)traits
{
_layerTraits = _layerTraits & ~traits;
}
- (BOOL)matchesTraits:(IJSVGLayerTraits)traits
{
return (_layerTraits & traits) == traits;
}
- (BOOL)treatImplicitOriginAsTransform
{
return YES;
}
- (CALayer<IJSVGDrawableLayer>*)firstSublayerOfClass:(Class)aClass
{
return [IJSVGLayer firstSublayerOfClass:aClass
fromLayer:self];
}
- (IJSVGTraitedColorStorage*)colors
{
IJSVGTraitedColorStorage* colorList = [[IJSVGTraitedColorStorage alloc] init];
for(CALayer<IJSVGDrawableLayer>* layer in self.sublayers) {
[colorList unionColorStorage:layer.colors];
}
return colorList;
}
@end
@@ -0,0 +1,13 @@
//
// IJSVGFilterEffectGaussianBlur.h
// IJSVG
//
// Created by Curtis Hard on 18/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGFilterEffect.h>
@interface IJSVGFilterEffectGaussianBlur : IJSVGFilterEffect
@end
@@ -0,0 +1,36 @@
//
// IJSVGFilterEffectGaussianBlur.m
// IJSVG
//
// Created by Curtis Hard on 18/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGFilterEffectGaussianBlur.h>
#import <IJSVG/IJSVGThreadManager.h>
@implementation IJSVGFilterEffectGaussianBlur
+ (CIFilter*)sharedFilter
{
IJSVGThreadManager* manager = IJSVGThreadManager.currentManager;
NSString* key = @"CIFilterGaussianBlur";
CIFilter* filter = nil;
if((filter = [manager userInfoObjectForKey:key]) == nil) {
filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[manager setUserInfoObject:filter
forKey:key];
}
return filter;
}
- (CIImage*)processImage:(CIImage*)image
{
CIFilter* filter = [self.class sharedFilter];
[filter setDefaults];
[filter setValue:image forKey:kCIInputImageKey];
[filter setValue:@(self.stdDeviation.value) forKey:kCIInputRadiusKey];
return [filter valueForKey:kCIOutputImageKey];
}
@end
@@ -0,0 +1,16 @@
//
// IJSVGClipPath.h
// IJSVG
//
// Created by Curtis Hard on 29/05/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGGroup.h>
@interface IJSVGClipPath : IJSVGGroup {
}
@property (nonatomic, readonly) IJSVGWindingRule computedClipRule;
@end
@@ -0,0 +1,75 @@
//
// IJSVGClipPath.m
// IJSVG
//
// Created by Curtis Hard on 29/05/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGClipPath.h>
#import <IJSVG/IJSVGRootNode.h>
@implementation IJSVGClipPath
- (void)setDefaults
{
self.units = IJSVGUnitObjectBoundingBox;
self.contentUnits = IJSVGUnitUserSpaceOnUse;
self.windingRule = IJSVGWindingRuleNonZero;
self.overflowVisibility = IJSVGOverflowVisibilityHidden;
self.fill = [IJSVGColorNode colorNodeWithColor:NSColor.whiteColor];
}
- (IJSVGUnitType)contentUnitsWithReferencingNodeBounds:(CGRect*)bounds
{
IJSVGNode* node = nil;
IJSVGUnitType units = [self contentUnitsWithReferencingNode:&node];
if(units == IJSVGUnitUserSpaceOnUse) {
*bounds = node.rootNode.bounds;
} else {
*bounds = node.parentNode.bounds;
}
return units;
}
- (void)postProcess
{
// clip paths only allow shapes in them, nothing else, we can simply
// check the node types for the trait of pathed
IJSVGNodeTraits childTraits = IJSVGNodeTraitPathed;
for(IJSVGNode* childNode in self.children.copy) {
if([childNode matchesTraits:childTraits] == NO) {
BOOL remove = YES;
IJSVGNodeType type = childNode.type;
if(type == IJSVGNodeTypeUse) {
remove = [(IJSVGGroup*)childNode childrenMatchTraits:childTraits] == NO;
}
if(remove == YES) {
[self removeChild:childNode];
}
}
}
}
- (IJSVGWindingRule)computedClipRule
{
// find the first use of a clipRule that is useful
__block IJSVGWindingRule rule = IJSVGWindingRuleInherit;
__weak IJSVGClipPath* weakSelf = self;
IJSVGNodeWalkHandler handler = ^(IJSVGNode *node, BOOL *allowChildNodes,
BOOL *stop) {
if(node == weakSelf) {
return;
}
IJSVGWindingRule clipRule = node.clipRule;
if(clipRule != IJSVGWindingRuleInherit) {
rule = clipRule;
*stop = YES;
}
};
[IJSVGNode walkNodeTree:self
handler:handler];
return rule;
}
@end
@@ -12,7 +12,8 @@
}
@property (nonatomic, retain) NSColor* color;
@property (nonatomic, strong) NSColor* color;
@property (nonatomic, assign) BOOL isNoneOrTransparent;
+ (IJSVGNode*)colorNodeWithColor:(NSColor*)color;
@@ -6,19 +6,13 @@
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import "IJSVGColorNode.h"
#import <IJSVG/IJSVGColorNode.h>
@implementation IJSVGColorNode
- (void)dealloc
{
(void)[_color release], _color = nil;
[super dealloc];
}
+ (IJSVGNode*)colorNodeWithColor:(NSColor *)color
{
return [[[self alloc] initWithColor:color] autorelease];
return [[self alloc] initWithColor:color];
}
- (id)initWithColor:(NSColor*)color {
@@ -1,21 +0,0 @@
//
// IJSVGDef.h
// IJSVGExample
//
// Created by Curtis Hard on 03/09/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGNode.h>
#import <Foundation/Foundation.h>
@interface IJSVGDef : NSObject {
@private
NSMutableDictionary* _dict;
}
- (void)addDef:(IJSVGNode*)aDef;
- (IJSVGDef*)defForID:(NSString*)anID;
@end
@@ -1,40 +0,0 @@
//
// IJSVGDef.m
// IJSVGExample
//
// Created by Curtis Hard on 03/09/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGDef.h"
@implementation IJSVGDef
- (void)dealloc
{
(void)([_dict release]), _dict = nil;
[super dealloc];
}
- (id)init
{
if ((self = [super init]) != nil) {
_dict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)addDef:(IJSVGNode*)aDef
{
if (aDef.identifier == nil) {
return;
}
_dict[aDef.identifier] = aDef;
}
- (IJSVGDef*)defForID:(NSString*)anID
{
return _dict[anID];
}
@end
@@ -0,0 +1,19 @@
//
// IJSVGFilter.h
// IJSVG
//
// Created by Curtis Hard on 18/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGGroup.h>
#import <IJSVG/IJSVGLayer.h>
@interface IJSVGFilter : IJSVGGroup
- (CGImageRef)newImageByApplyFilterToLayer:(CALayer<IJSVGDrawableLayer>*)layer
scale:(CGFloat)scale;
@property (nonatomic, readonly) BOOL valid;
@end
@@ -0,0 +1,57 @@
//
// IJSVGFilter.m
// IJSVG
//
// Created by Curtis Hard on 18/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGFilter.h>
#import <IJSVG/IJSVGFilterEffect.h>
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGThreadManager.h>
@implementation IJSVGFilter
- (BOOL)valid
{
return self.children.count != 0;
}
- (CGImageRef)newImageByApplyFilterToLayer:(CALayer<IJSVGDrawableLayer>*)layer
scale:(CGFloat)scale
{
IJSVGFilter* filter = layer.filter;
layer.filter = nil;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
uint32_t info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little;
CGImageRef originalImage = [IJSVGLayer newImageForLayer:layer
options:IJSVGLayerDrawingOptionNone
colorSpace:colorSpace
bitmapInfo:info
scale:scale];
CIImage* image = [CIImage imageWithCGImage:originalImage];
CGColorSpaceRelease(colorSpace);
CGImageRelease(originalImage);
for(IJSVGFilterEffect* effect in self.children) {
image = [effect processImage:image];
}
IJSVGThreadManager* manager = IJSVGThreadManager.currentManager;
CIContext* context = manager.CIContext;
CGImageRef outputImage = [context createCGImage:image
fromRect:image.extent];
layer.filter = filter;
return outputImage;
}
- (void)addChild:(IJSVGNode*)child
{
if([child isKindOfClass:IJSVGFilterEffect.class] == NO) {
return;
}
[super addChild:child];
}
@end
@@ -0,0 +1,40 @@
//
// IJSVGFilterEffect.h
// IJSVG
//
// Created by Curtis Hard on 18/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGGroup.h>
typedef NS_ENUM(NSInteger, IJSVGFilterEffectSource) {
IJSVGFilterEffectSourceGraphic,
IJSVGFilterEffectSourceAlpha,
IJSVGFilterEffectSourceBackgroundImage,
IJSVGFilterEffectSourceBackgroundAlpha,
IJSVGFilterEffectSourceFillPaint,
IJSVGFilterEffectSourceStrokePaint,
IJSVGFilterEffectSourcePrimitiveReference,
};
typedef NS_ENUM(NSInteger, IJSVGFilterEffectEdgeMode) {
IJSVGFilterEffectEdgeModeNone,
IJSVGFilterEffectEdgeModeWrap,
IJSVGFilterEffectEdgeModeDuplicate,
};
@interface IJSVGFilterEffect : IJSVGGroup
@property (nonatomic, assign) IJSVGFilterEffectSource source;
@property (nonatomic, strong) IJSVGUnitLength* stdDeviation;
@property (nonatomic, assign) IJSVGFilterEffectEdgeMode edgeMode;
@property (nonatomic, copy) NSString* primitiveReference;
+ (Class)effectClassForElementName:(NSString*)name;
+ (IJSVGFilterEffectSource)sourceForString:(NSString*)string;
+ (IJSVGFilterEffectEdgeMode)edgeModeForString:(NSString*)string;
- (CIImage*)processImage:(CIImage*)image;
@end
@@ -0,0 +1,79 @@
//
// IJSVGFilterEffect.m
// IJSVG
//
// Created by Curtis Hard on 18/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGFilterEffect.h>
#import <IJSVG/IJSVGFilterEffectGaussianBlur.h>
@implementation IJSVGFilterEffect
static NSDictionary<NSString*, Class>* _elementClassMap = nil;
+ (void)load
{
_elementClassMap = @{
@"fegaussianblur": IJSVGFilterEffectGaussianBlur.class
};
}
+ (Class)effectClassForElementName:(NSString*)name
{
NSString* key = name.lowercaseString;
return _elementClassMap[key] ?: IJSVGFilterEffect.class;
}
+ (IJSVGFilterEffectSource)sourceForString:(NSString*)string
{
const char* name = string.lowercaseString.UTF8String;
if(name == NULL) {
return IJSVGFilterEffectSourceGraphic;
}
if(strcmp(name, "sourcegraphic") == 0) {
return IJSVGFilterEffectSourceGraphic;
}
if(strcmp(name, "sourcealpha") == 0) {
return IJSVGFilterEffectSourceAlpha;
}
if(strcmp(name, "backgroundimage") == 0) {
return IJSVGFilterEffectSourceBackgroundImage;
}
if(strcmp(name, "backgroundalpha") == 0) {
return IJSVGFilterEffectSourceBackgroundAlpha;
}
if(strcmp(name, "fillpaint") == 0) {
return IJSVGFilterEffectSourceFillPaint;
}
if(strcmp(name, "strokepain") == 0) {
return IJSVGFilterEffectSourceStrokePaint;
}
return IJSVGFilterEffectSourcePrimitiveReference;
}
+ (IJSVGFilterEffectEdgeMode)edgeModeForString:(NSString*)string
{
const char* name = string.lowercaseString.UTF8String;
if(name == NULL) {
return IJSVGFilterEffectEdgeModeNone;
}
if(strcmp(name, "none") == 0) {
return IJSVGFilterEffectEdgeModeNone;
}
if(strcmp(name, "wrap") == 0) {
return IJSVGFilterEffectEdgeModeWrap;
}
if(strcmp(name, "duplicate") == 0) {
return IJSVGFilterEffectEdgeModeDuplicate;
}
return IJSVGFilterEffectEdgeModeNone;
}
- (CIImage*)processImage:(CIImage*)image
{
return image;
}
@end
@@ -6,14 +6,8 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGForeignObject.h"
#import <IJSVG/IJSVGForeignObject.h>
@implementation IJSVGForeignObject
- (void)dealloc
{
(void)([_requiredExtension release]), _requiredExtension = nil;
[super dealloc];
}
@end
@@ -7,35 +7,27 @@
//
#import <Foundation/Foundation.h>
#import <IJSVG/IJSVGColorList.h>
#import <IJSVG/IJSVGDef.h>
#import <IJSVG/IJSVGTraitedColorStorage.h>
#import <IJSVG/IJSVGTransform.h>
#import <IJSVG/IJSVGGroup.h>
@interface IJSVGGradient : IJSVGGroup
@property (nonatomic, retain) NSGradient* gradient;
@property (nonatomic, strong) NSArray<NSColor*>* colors;
@property (nonatomic, assign) CGFloat* locations;
@property (nonatomic, assign) NSUInteger numberOfStops;
@property (nonatomic, assign) CGGradientRef CGGradient;
@property (nonatomic, retain) IJSVGUnitLength* x1;
@property (nonatomic, retain) IJSVGUnitLength* x2;
@property (nonatomic, retain) IJSVGUnitLength* y1;
@property (nonatomic, retain) IJSVGUnitLength* y2;
@property (nonatomic, retain) IJSVGColorList* colorList;
@property (nonatomic, strong) IJSVGUnitLength* x1;
@property (nonatomic, strong) IJSVGUnitLength* x2;
@property (nonatomic, strong) IJSVGUnitLength* y1;
@property (nonatomic, strong) IJSVGUnitLength* y2;
+ (CGFloat*)computeColorStops:(IJSVGGradient*)gradient
colors:(NSArray**)someColors;
- (CGGradientRef)CGGradient;
- (void)drawInContextRef:(CGContextRef)ctx
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox;
- (void)_debugStart:(CGPoint)startPoint
end:(CGPoint)endPoint
context:(CGContextRef)ctx;
- (IJSVGColorList*)colorList;
- (IJSVGColorList*)computedColorList;
bounds:(NSRect)objectRect
transform:(CGAffineTransform)absoluteTransform;
@end
@@ -6,49 +6,55 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGGradient.h"
#import "IJSVGParser.h"
#import <IJSVG/IJSVGGradient.h>
#import <IJSVG/IJSVGParser.h>
@implementation IJSVGGradient
@synthesize colorList = _privateColorList;
- (void)dealloc
{
(void)([_x1 release]), _x1 = nil;
(void)([_x2 release]), _x2 = nil;
(void)([_y1 release]), _y1 = nil;
(void)([_y2 release]), _y2 = nil;
(void)([_gradient release]), _gradient = nil;
(void)([_privateColorList release]), _privateColorList = nil;
if (_CGGradient != nil) {
CGGradientRelease(_CGGradient);
if(_locations != NULL) {
(void)free(_locations), _locations = NULL;
}
if(_CGGradient != NULL) {
(void)CGGradientRelease(_CGGradient), _CGGradient = NULL;
}
[super dealloc];
}
- (id)copyWithZone:(NSZone*)zone
{
IJSVGGradient* clone = [super copyWithZone:zone];
clone.gradient = [[self.gradient copy] autorelease];
IJSVGGradient* clone = [[self.class alloc] init];
[clone applyPropertiesFromNode:self];
return clone;
}
- (void)setColorList:(IJSVGColorList*)list
- (void)applyPropertiesFromNode:(IJSVGGradient*)node
{
(void)([_privateColorList release]), _privateColorList = nil;
_privateColorList = list.retain;
if (_CGGradient != nil) {
CGGradientRelease(_CGGradient);
_CGGradient = nil;
}
[super applyPropertiesFromNode:node];
self.numberOfStops = node.numberOfStops;
self.colors = node.colors.copy;
size_t length = sizeof(CGFloat)*node.numberOfStops;
self.locations = (CGFloat*)malloc(length);
memcpy(self.locations, node.locations, length);
self.x1 = node.x1.copy;
self.x2 = node.x2.copy;
self.y1 = node.y1.copy;
self.y2 = node.y2.copy;
}
+ (CGFloat *)computeColorStops:(IJSVGGradient*)gradient
colors:(NSArray**)someColors
- (void)setLocations:(CGFloat*)locations
{
if(_locations != NULL) {
(void)free(_locations), _locations = NULL;
}
_locations = locations;
}
+ (CGFloat*)computeColorStops:(IJSVGGradient*)gradient
colors:(NSArray**)someColors
{
NSArray<IJSVGNode*>* stops = gradient.children;
NSMutableArray* colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease];
NSMutableArray* colors = [[NSMutableArray alloc] initWithCapacity:stops.count];
CGFloat* stopsParams = (CGFloat*)malloc(stops.count * sizeof(CGFloat));
NSInteger i = 0;
@@ -70,73 +76,30 @@
return stopsParams;
}
- (IJSVGColorList*)colorList
{
IJSVGColorList* sheet = [[[IJSVGColorList alloc] init] autorelease];
NSInteger num = self.gradient.numberOfColorStops;
for (NSInteger i = 0; i < num; i++) {
NSColor* color;
[self.gradient getColor:&color
location:nil
atIndex:i];
IJSVGColorType* type = [IJSVGColorType typeWithColor:color
flags:IJSVGColorTypeFlagStop];
[sheet addColor:type];
}
return sheet;
}
- (IJSVGColorList*)computedColorList
{
return _privateColorList;
}
- (CGGradientRef)CGGradient
{
// store it in the cache
if (_CGGradient != nil) {
if(_CGGradient != nil) {
return _CGGradient;
}
// actually create the gradient
NSInteger num = self.gradient.numberOfColorStops;
CGFloat* locations = (CGFloat*)malloc(sizeof(CGFloat) * num);
NSInteger num = self.numberOfStops;
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num,
&kCFTypeArrayCallBacks);
for (NSInteger i = 0; i < num; i++) {
NSColor* color;
[self.gradient getColor:&color
location:&locations[i]
atIndex:i];
if (_privateColorList != nil) {
color = [_privateColorList proposedColorForColor:color];
}
for (NSColor* color in _colors) {
CFArrayAppendValue(colors, color.CGColor);
}
CGGradientRef result = CGGradientCreateWithColors(_gradient.colorSpace.CGColorSpace,
colors, locations);
CGGradientRef result = CGGradientCreateWithColors(IJSVGColor.defaultColorSpace.CGColorSpace,
colors, _locations);
CFRelease(colors);
free(locations);
return _CGGradient = result;
}
- (void)drawInContextRef:(CGContextRef)ctx
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
bounds:(NSRect)objectRect
transform:(CGAffineTransform)absoluteTransform
{
}
- (void)_debugStart:(CGPoint)startPoint
end:(CGPoint)endPoint
context:(CGContextRef)ctx
{
CGContextSaveGState(ctx);
CGContextSetStrokeColorWithColor(ctx, NSColor.blackColor.CGColor);
CGContextSetLineWidth(ctx, 1.f);
CGContextMoveToPoint(ctx, startPoint.x, startPoint.y);
CGContextAddLineToPoint(ctx, endPoint.x, endPoint.y);
CGContextStrokePath(ctx);
}
@end
@@ -16,8 +16,15 @@
NSMutableArray<IJSVGNode*>* _children;
}
@property (nonatomic, readonly) NSArray<IJSVGNode*>* children;
@property (weak, nonatomic, readonly) NSArray<IJSVGNode*>* children;
- (void)addChild:(IJSVGNode*)child;
- (void)addChildren:(NSArray<IJSVGNode*>*)children;
- (void)removeChild:(IJSVGNode*)child;
- (void)removeChildren:(NSArray<IJSVGNode*>*)children;
- (BOOL)childrenMatchTraits:(IJSVGNodeTraits)traits;
- (BOOL)containsNodesMatchingTraits:(IJSVGNodeTraits)traits;
- (NSArray<IJSVGNode*>*)nodesMatchingTraits:(IJSVGNodeTraits)traits;
- (NSSet<IJSVGNode*>*)childrenOfType:(IJSVGNodeType)type;
@end
+60 -14
View File
@@ -6,19 +6,13 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGGroup.h"
#import <IJSVG/IJSVGGroup.h>
@implementation IJSVGGroup
- (void)dealloc
{
(void)([_children release]), _children = nil;
[super dealloc];
}
- (id)init
{
if ((self = [super init]) != nil) {
if((self = [super init]) != nil) {
_children = [[NSMutableArray alloc] init];
}
return self;
@@ -27,7 +21,7 @@
- (void)prepareFromCopy
{
if(_children != nil) {
(void)[_children release], _children = nil;
(void)_children, _children = nil;
}
_children = [[NSMutableArray alloc] init];
}
@@ -37,8 +31,8 @@
IJSVGGroup* node = [super copyWithZone:zone];
[node prepareFromCopy];
for (IJSVGNode* childNode in _children) {
childNode = [[childNode copy] autorelease];
for (__strong IJSVGNode* childNode in _children) {
childNode = childNode.copy;
childNode.parentNode = node;
[node addChild:childNode];
}
@@ -47,7 +41,8 @@
- (void)addChild:(IJSVGNode*)child
{
if(child == nil || (child.parentNode == self && [_children containsObject:child])) {
if(child == nil || child == self ||
(child.parentNode == self && [_children containsObject:child])) {
return;
}
child.parentNode = self;
@@ -62,11 +57,62 @@
[_children removeObject:child];
}
- (void)addChildren:(NSArray<IJSVGNode*>*)children
{
for(IJSVGNode* node in children) {
[self addChild:node];
}
}
- (void)removeChildren:(NSArray<IJSVGNode*>*)children
{
for(IJSVGNode* node in children) {
[self removeChild:node];
}
}
- (BOOL)childrenMatchTraits:(IJSVGNodeTraits)traits
{
for(IJSVGNode* node in _children) {
if([node matchesTraits:traits] == NO) {
return NO;
}
}
return YES;
}
- (NSSet<IJSVGNode*>*)childrenOfType:(IJSVGNodeType)type
{
NSMutableSet<IJSVGNode*>* nodes = [[NSMutableSet alloc] init];
for(IJSVGNode* node in self.children) {
if(node.type == type) {
[nodes addObject:node];
}
}
return nodes;
}
- (BOOL)containsNodesMatchingTraits:(IJSVGNodeTraits)traits
{
return [self.class node:self
containsNodesMatchingTraits:traits];
}
- (NSArray<IJSVGNode*>*)nodesMatchingTraits:(IJSVGNodeTraits)traits
{
return [self.class node:self
nodesMatchingTraits:traits];
}
- (CGRect)bounds
{
CGRect rect = CGRectZero;
CGRect rect = CGRectNull;
for(IJSVGNode* node in self.children) {
rect = CGRectUnion(rect, node.bounds);
if(CGRectIsNull(rect)) {
rect = node.bounds;
} else {
rect = CGRectUnion(rect, node.bounds);
}
}
return rect;
}
@@ -17,8 +17,7 @@
@property (nonatomic, readonly) CGSize intrinsicSize;
@property (nonatomic, readonly) CGRect intrinsicBounds;
@property (nonatomic, readonly) CGAffineTransform intrinsicTransform;
@property (nonatomic, retain) NSImage* image;
@property (nonatomic, strong) NSImage* image;
- (CGImageRef)CGImage;
- (void)loadFromString:(NSString*)encodedString;
+18 -21
View File
@@ -6,22 +6,27 @@
// Copyright © 2016 Curtis Hard. All rights reserved.
//
#import "IJSVGImage.h"
#import "IJSVGPath.h"
#import "IJSVGTransform.h"
#import <IJSVG/IJSVGImage.h>
#import <IJSVG/IJSVGPath.h>
#import <IJSVG/IJSVGTransform.h>
@implementation IJSVGImage
- (void)dealloc
{
(void)(CGImageRelease(CGImage)), CGImage = nil;
(void)([_image release]), _image = nil;
[super dealloc];
}
- (void)setDefaults
{
[super setDefaults];
self.viewBoxAlignment = IJSVGViewBoxAlignmentXMidYMid;
self.viewBoxMeetOrSlice = IJSVGViewBoxMeetOrSliceMeet;
}
- (void)loadFromString:(NSString*)encodedString
{
if ([encodedString hasPrefix:@"data:"]) {
if([encodedString hasPrefix:@"data:"]) {
encodedString = [encodedString stringByReplacingOccurrencesOfString:@"\\s+"
withString:@""
options:NSRegularExpressionSearch
@@ -38,29 +43,28 @@
NSData* data = [NSData dataWithContentsOfURL:aURL];
// no data, just ignore...invalid probably
if (data == nil) {
if(data == nil) {
return;
}
// set the image against the container
NSImage* anImage = [[[NSImage alloc] initWithData:data] autorelease];
NSImage* anImage = [[NSImage alloc] initWithData:data];
[self setImage:anImage];
}
- (void)setImage:(NSImage*)anImage
{
if (_image != nil) {
(void)([_image release]), _image = nil;
}
_image = [anImage retain];
_image = anImage;
_intrinsicSize = (CGSize)_image.size;
if (CGImage != nil) {
if(CGImage != nil) {
CGImageRelease(CGImage);
CGImage = nil;
}
NSRect rect = NSMakeRect(0.f, 0.f, _intrinsicSize.width, _intrinsicSize.height);
CGRect rect = CGRectMake(0.f, 0.f,
_intrinsicSize.width,
_intrinsicSize.height);
CGImage = [_image CGImageForProposedRect:&rect
context:nil
hints:nil];
@@ -81,13 +85,6 @@
return rect;
}
- (CGAffineTransform)intrinsicTransform
{
CGFloat widthRatio = self.width.value / _intrinsicSize.width;
CGFloat heightRatio = self.height.value / _intrinsicSize.height;
return CGAffineTransformMakeScale(widthRatio, heightRatio);
}
- (CGRect)bounds
{
return CGRectMake(0.f, 0.f,
@@ -11,7 +11,7 @@
@interface IJSVGLinearGradient : IJSVGGradient
+ (NSGradient*)parseGradient:(NSXMLElement*)element
gradient:(IJSVGLinearGradient*)aGradient;
+ (void)parseGradient:(NSXMLElement*)element
gradient:(IJSVGLinearGradient*)aGradient;
@end
@@ -6,14 +6,14 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGLinearGradient.h"
#import "IJSVGUtils.h"
#import "IJSVGParser.h"
#import <IJSVG/IJSVGLinearGradient.h>
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGParser.h>
@implementation IJSVGLinearGradient
+ (NSGradient*)parseGradient:(NSXMLElement*)element
gradient:(IJSVGLinearGradient*)aGradient
+ (void)parseGradient:(NSXMLElement*)element
gradient:(IJSVGLinearGradient*)aGradient
{
// just ask unit for the value
NSString* x1 = ([element attributeForName:IJSVGAttributeX1].stringValue ?: @"0");
@@ -29,57 +29,49 @@
NSArray* colors = nil;
CGFloat* stopsParams = [self.class computeColorStops:aGradient
colors:&colors];
// create the gradient with the colours
NSGradient* grad = [[NSGradient alloc] initWithColors:colors
atLocations:stopsParams
colorSpace:IJSVGColor.defaultColorSpace];
free(stopsParams);
return [grad autorelease];
aGradient.colors = colors;
aGradient.locations = stopsParams;
aGradient.numberOfStops = colors.count;
}
- (void)drawInContextRef:(CGContextRef)ctx
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
bounds:(NSRect)objectRect
transform:(CGAffineTransform)absoluteTransform
{
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
CGRect boundingBox = objectRect;
// make sure we apply the absolute position to
// transform us back into the correct space
if (inUserSpace == YES) {
CGContextConcatCTM(ctx, absoluteTransform);
}
CGFloat width = CGRectGetWidth(boundingBox);
CGFloat height = CGRectGetHeight(boundingBox);
gradientStartPoint = CGPointMake([self.x1 computeValue:width],
[self.y1 computeValue:height]);
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
[self.y2 computeValue:height]);
// transform the context
if(inUserSpace == YES) {
CGContextConcatCTM(ctx, absoluteTransform);
} else {
width = 1.f;
height = 1.f;
CGContextConcatCTM(ctx, CGAffineTransformMakeScale(boundingBox.size.width,
boundingBox.size.height));
}
gradientStartPoint = CGPointMake([self.x1 computeValue:width],
[self.y1 computeValue:height]);
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
[self.y2 computeValue:height]);
// apply the gradient transform if there is one
CGContextConcatCTM(ctx, selfTransform);
// draw the gradient
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(ctx, self.CGGradient, gradientStartPoint,
gradientEndPoint, options);
#ifdef IJSVG_DEBUG
[self _debugStart:gradientStartPoint
end:gradientEndPoint
context:ctx];
#endif
}
@end
@@ -0,0 +1,13 @@
//
// IJSVGMask.h
// IJSVG
//
// Created by Curtis Hard on 28/05/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGGroup.h>
@interface IJSVGMask : IJSVGGroup
@end
@@ -0,0 +1,38 @@
//
// IJSVGMask.m
// IJSVG
//
// Created by Curtis Hard on 28/05/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGMask.h>
#import <IJSVG/IJSVGRootNode.h>
@implementation IJSVGMask
- (void)setDefaults
{
[super setDefaults];
self.x = [IJSVGUnitLength unitWithPercentageFloat:-.2f];
self.y = [IJSVGUnitLength unitWithPercentageFloat:-.2f];
self.width = [IJSVGUnitLength unitWithPercentageFloat:1.2f];
self.height = [IJSVGUnitLength unitWithPercentageFloat:1.2f];
self.units = IJSVGUnitObjectBoundingBox;
self.contentUnits = IJSVGUnitUserSpaceOnUse;
self.overflowVisibility = IJSVGOverflowVisibilityHidden;
}
- (IJSVGUnitType)contentUnitsWithReferencingNodeBounds:(CGRect *)bounds
{
IJSVGNode* node = nil;
IJSVGUnitType units = [self contentUnitsWithReferencingNode:&node];
if(units == IJSVGUnitUserSpaceOnUse) {
*bounds = node.rootNode.bounds;
} else {
*bounds = node.parentNode.bounds;
}
return units;
}
@end
+62 -23
View File
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGStyle.h>
#import <IJSVG/IJSVGStyleSheetStyle.h>
#import <IJSVG/IJSVGUnitLength.h>
#import <IJSVG/IJSVGViewBox.h>
#import <AppKit/AppKit.h>
@@ -21,16 +21,28 @@
@class IJSVGTransform;
@class IJSVGRootNode;
@class IJSVGUnitRect;
@class IJSVGFilter;
@class IJSVGMask;
@class IJSVGClipPath;
typedef void (^IJSVGNodeWalkHandler)(IJSVGNode* node, BOOL* allowChildNodes, BOOL* stop);
typedef NS_OPTIONS(NSInteger, IJSVGIntrinsicDimensions) {
IJSVGIntrinsicDimensionNone = 0,
IJSVGIntrinsicDimensionWidth = 1 << 1,
IJSVGIntrinsicDimensionHeight = 1 << 2,
IJSVGIntrinsicDimensionBoth = IJSVGIntrinsicDimensionWidth | IJSVGIntrinsicDimensionHeight
};
typedef NS_OPTIONS(NSInteger, IJSVGNodeTraits) {
IJSVGNodeTraitNone = 0,
IJSVGNodeTraitStroked = 1 << 0,
IJSVGNodeTraitPaintable = 1 << 1
IJSVGNodeTraitPaintable = 1 << 1,
IJSVGNodeTraitPathed = 1 << 2
};
typedef NS_ENUM(NSInteger, IJSVGNodeType) {
IJSVGNodeTypeUnknown = 0,
IJSVGNodeTypeGroup,
IJSVGNodeTypePath,
IJSVGNodeTypeDef,
@@ -58,7 +70,9 @@ typedef NS_ENUM(NSInteger, IJSVGNodeType) {
IJSVGNodeTypeDesc,
IJSVGNodeTypeStop,
IJSVGNodeTypeNotFound,
IJSVGNodeTypeUnknown,
IJSVGNodeTypeFilter,
IJSVGNodeTypeFilterEffect,
IJSVGNodeTypeForeignObject
};
typedef NS_ENUM(NSInteger, IJSVGWindingRule) {
@@ -114,14 +128,18 @@ typedef NS_ENUM(NSInteger, IJSVGOverflowVisibility) {
};
static CGFloat IJSVGInheritedFloatValue = -99.9999991;
static CGFloat IJSVGInheritedIntegerValue = INT_MIN;
@interface IJSVGNode : NSObject <NSCopying>
@interface IJSVGNode : NSObject <NSCopying> {
@private
BOOL _computedTraits;
}
void IJSVGAssertPaintableObject(id object);
@property (nonatomic, assign) IJSVGNodeTraits traits;
@property (nonatomic, assign, readonly) CGRect bounds;
@property (nonatomic, retain) IJSVGUnitRect* viewBox;
@property (nonatomic, strong) IJSVGUnitRect* viewBox;
@property (nonatomic, assign) IJSVGViewBoxAlignment viewBoxAlignment;
@property (nonatomic, assign) IJSVGViewBoxMeetOrSlice viewBoxMeetOrSlice;
@property (nonatomic, copy) NSString* title;
@@ -129,44 +147,59 @@ void IJSVGAssertPaintableObject(id object);
@property (nonatomic, assign) IJSVGNodeType type;
@property (nonatomic, copy) NSString* name;
@property (nonatomic, copy) NSString* className;
@property (nonatomic, retain) NSArray* classNameList;
@property (nonatomic, strong) NSSet<NSString*>* classNameList;
@property (nonatomic, copy) NSString* unicode;
@property (nonatomic, assign) BOOL shouldRender;
@property (nonatomic, retain) IJSVGUnitLength* x;
@property (nonatomic, retain) IJSVGUnitLength* y;
@property (nonatomic, retain) IJSVGUnitLength* width;
@property (nonatomic, retain) IJSVGUnitLength* height;
@property (nonatomic, retain) IJSVGUnitLength* opacity;
@property (nonatomic, retain) IJSVGUnitLength* fillOpacity;
@property (nonatomic, retain) IJSVGUnitLength* strokeOpacity;
@property (nonatomic, retain) IJSVGUnitLength* strokeWidth;
@property (nonatomic, retain) IJSVGUnitLength* offset;
@property (nonatomic, retain) IJSVGNode* fill;
@property (nonatomic, retain) IJSVGNode* stroke;
@property (nonatomic, strong) IJSVGUnitLength* x;
@property (nonatomic, strong) IJSVGUnitLength* y;
@property (nonatomic, strong) IJSVGUnitLength* width;
@property (nonatomic, strong) IJSVGUnitLength* height;
@property (nonatomic, strong) IJSVGUnitLength* opacity;
@property (nonatomic, strong) IJSVGUnitLength* fillOpacity;
@property (nonatomic, strong) IJSVGUnitLength* strokeOpacity;
@property (nonatomic, strong) IJSVGUnitLength* strokeWidth;
@property (nonatomic, strong) IJSVGUnitLength* offset;
@property (nonatomic, strong) IJSVGNode* fill;
@property (nonatomic, strong) IJSVGNode* stroke;
@property (nonatomic, copy) NSString* identifier;
@property (nonatomic, assign) IJSVGNode* parentNode;
@property (nonatomic, retain) IJSVGGroup* clipPath;
@property (nonatomic, retain) IJSVGGroup* mask;
@property (nonatomic, strong) IJSVGClipPath* clipPath;
@property (nonatomic, strong) IJSVGMask* mask;
@property (nonatomic, assign) IJSVGWindingRule windingRule;
@property (nonatomic, assign) IJSVGWindingRule clipRule;
@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle;
@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle;
@property (nonatomic, retain) NSArray<IJSVGTransform*>* transforms;
@property (nonatomic, strong) IJSVGUnitLength* strokeMiterLimit;
@property (nonatomic, strong) NSArray<IJSVGTransform*>* transforms;
@property (nonatomic, strong) IJSVGFilter* filter;
@property (nonatomic, assign) CGFloat* strokeDashArray;
@property (nonatomic, assign) NSInteger strokeDashArrayCount;
@property (nonatomic, readonly) NSArray<NSNumber*>* lineDashPattern;
@property (nonatomic, retain) IJSVGUnitLength* strokeDashOffset;
@property (nonatomic, retain) IJSVG* svg;
@property (nonatomic, strong) IJSVGUnitLength* strokeDashOffset;
@property (nonatomic, strong) IJSVG* svg;
@property (nonatomic, assign) IJSVGUnitType contentUnits;
@property (nonatomic, assign) IJSVGUnitType units;
@property (nonatomic, assign) IJSVGBlendMode blendMode;
@property (nonatomic, assign) IJSVGOverflowVisibility overflowVisibility;
@property (nonatomic, readonly) BOOL detachedFromParentNode;
@property (nonatomic, readonly) IJSVGRootNode* rootNode;
+ (void)walkNodeTree:(IJSVGNode*)node
handler:(IJSVGNodeWalkHandler)handler;
handler:(IJSVGNodeWalkHandler)handler;
+ (NSArray<IJSVGNode*>*)node:(IJSVGNode*)node
nodesMatchingTraits:(IJSVGNodeTraits)traits;
+ (BOOL)node:(IJSVGNode*)node
containsNodesMatchingTraits:(IJSVGNodeTraits)traits;
+ (IJSVGNodeType)typeForString:(NSString*)string
kind:(NSXMLNodeKind)kind;
+ (BOOL)typeIsPathable:(IJSVGNodeType)type;
- (void)setDefaults;
- (void)postProcess;
- (void)applyPropertiesFromNode:(IJSVGNode*)node;
- (IJSVGUnitType)contentUnitsWithReferencingNodeBounds:(CGRect*)bounds;
@@ -178,5 +211,11 @@ void IJSVGAssertPaintableObject(id object);
- (void)removeTraits:(IJSVGNodeTraits)traits;
- (BOOL)matchesTraits:(IJSVGNodeTraits)traits;
- (void)computeTraits;
- (void)normalizeWithOffset:(CGPoint)offset;
- (NSSet<IJSVGNode*>*)nodesMatchingTypes:(NSIndexSet*)types;
- (instancetype)parentNodeMatchingClass:(Class)class;
- (instancetype)rootNodeMatchingClass:(Class)class;
@end
+263 -69
View File
@@ -6,10 +6,10 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGDef.h>
#import <IJSVG/IJSVGNode.h>
#import <IJSVG/IJSVGGroup.h>
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGRootNode.h>
@implementation IJSVGNode
@@ -19,38 +19,13 @@
- (void)dealloc
{
(void)free(_strokeDashArray), _strokeDashArray = NULL;
(void)([_x release]), _x = nil;
(void)([_y release]), _y = nil;
(void)([_width release]), _width = nil;
(void)([_height release]), _height = nil;
(void)([_opacity release]), _opacity = nil;
(void)([_offset release]), _offset = nil;
(void)([_fillOpacity release]), _fillOpacity = nil;
(void)([_strokeOpacity release]), _strokeOpacity = nil;
(void)([_strokeWidth release]), _strokeWidth = nil;
(void)([_strokeDashOffset release]), _strokeDashOffset = nil;
(void)([_unicode release]), _unicode = nil;
(void)([_fill release]), _fill = nil;
(void)([_stroke release]), _stroke = nil;
(void)([_transforms release]), _transforms = nil;
(void)([_identifier release]), _identifier = nil;
(void)([_name release]), _name = nil;
(void)([_title release]), _title = nil;
(void)([_desc release]), _desc = nil;
(void)([_className release]), _className = nil;
(void)([_classNameList release]), _classNameList = nil;
(void)([_clipPath release]), _clipPath = nil;
(void)([_svg release]), _svg = nil;
(void)([_mask release]), _mask = nil;
(void)([_viewBox release]), _viewBox = nil;
[super dealloc];
}
+ (IJSVGNodeType)typeForString:(NSString*)string
kind:(NSXMLNodeKind)kind
{
// possible fix for older os's that complain
if(string == nil || kind == NSXMLCommentKind) {
if(string == nil || kind != NSXMLElementKind) {
return IJSVGNodeTypeNotFound;
}
@@ -58,76 +33,76 @@
if(name == NULL) {
return IJSVGNodeTypeNotFound;
}
if (strcmp(name, "style") == 0) {
if(strcmp(name, "style") == 0) {
return IJSVGNodeTypeStyle;
}
if (strcmp(name, "switch") == 0) {
if(strcmp(name, "switch") == 0) {
return IJSVGNodeTypeSwitch;
}
if (strcmp(name, "defs") == 0) {
if(strcmp(name, "defs") == 0) {
return IJSVGNodeTypeDef;
}
if (strcmp(name, "g") == 0) {
if(strcmp(name, "g") == 0) {
return IJSVGNodeTypeGroup;
}
if (strcmp(name, "path") == 0) {
if(strcmp(name, "path") == 0) {
return IJSVGNodeTypePath;
}
if (strcmp(name, "polygon") == 0) {
if(strcmp(name, "polygon") == 0) {
return IJSVGNodeTypePolygon;
}
if (strcmp(name, "polyline") == 0) {
if(strcmp(name, "polyline") == 0) {
return IJSVGNodeTypePolyline;
}
if (strcmp(name, "rect") == 0) {
if(strcmp(name, "rect") == 0) {
return IJSVGNodeTypeRect;
}
if (strcmp(name, "line") == 0) {
if(strcmp(name, "line") == 0) {
return IJSVGNodeTypeLine;
}
if (strcmp(name, "circle") == 0) {
if(strcmp(name, "circle") == 0) {
return IJSVGNodeTypeCircle;
}
if (strcmp(name, "ellipse") == 0) {
if(strcmp(name, "ellipse") == 0) {
return IJSVGNodeTypeEllipse;
}
if (strcmp(name, "use") == 0) {
if(strcmp(name, "use") == 0) {
return IJSVGNodeTypeUse;
}
if (strcmp(name, "lineargradient") == 0) {
if(strcmp(name, "lineargradient") == 0) {
return IJSVGNodeTypeLinearGradient;
}
if (strcmp(name, "radialgradient") == 0) {
if(strcmp(name, "radialgradient") == 0) {
return IJSVGNodeTypeRadialGradient;
}
if(strcmp(name, "stop") == 0) {
return IJSVGNodeTypeStop;
}
if (strcmp(name, "glyph") == 0) {
if(strcmp(name, "glyph") == 0) {
return IJSVGNodeTypeGlyph;
}
if (strcmp(name, "font") == 0) {
if(strcmp(name, "font") == 0) {
return IJSVGNodeTypeFont;
}
if (strcmp(name, "clippath") == 0) {
if(strcmp(name, "clippath") == 0) {
return IJSVGNodeTypeClipPath;
}
if (strcmp(name, "mask") == 0) {
if(strcmp(name, "mask") == 0) {
return IJSVGNodeTypeMask;
}
if (strcmp(name, "image") == 0) {
if(strcmp(name, "image") == 0) {
return IJSVGNodeTypeImage;
}
if (strcmp(name, "pattern") == 0) {
if(strcmp(name, "pattern") == 0) {
return IJSVGNodeTypePattern;
}
if (strcmp(name, "svg") == 0) {
if(strcmp(name, "svg") == 0) {
return IJSVGNodeTypeSVG;
}
if (strcmp(name, "text") == 0) {
if(strcmp(name, "text") == 0) {
return IJSVGNodeTypeText;
}
if (strcmp(name, "tspan") == 0 || kind == NSXMLTextKind) {
if(strcmp(name, "tspan") == 0 || kind == NSXMLTextKind) {
return IJSVGNodeTypeTextSpan;
}
if(strcmp(name, "title") == 0) {
@@ -136,9 +111,26 @@
if(strcmp(name, "desc") == 0) {
return IJSVGNodeTypeDesc;
}
if(strcmp(name, "foreignobject") == 0) {
return IJSVGNodeTypeForeignObject;
}
if(strcmp(name, "filter") == 0) {
return IJSVGNodeTypeFilter;
}
if(strcmp(name, "fegaussianblur") == 0) {
return IJSVGNodeTypeFilterEffect;
}
return IJSVGNodeTypeUnknown;
}
+ (BOOL)typeIsPathable:(IJSVGNodeType)type
{
return type == IJSVGNodeTypePath || type == IJSVGNodeTypeRect ||
type == IJSVGNodeTypeCircle || type == IJSVGNodeTypeEllipse ||
type == IJSVGNodeTypePolygon || type == IJSVGNodeTypePolyline ||
type == IJSVGNodeTypeLine;
}
+ (void)walkNodeTree:(IJSVGNode*)node
handler:(IJSVGNodeWalkHandler)handler
{
@@ -183,13 +175,80 @@
}
}
+ (NSArray<IJSVGNode*>*)node:(IJSVGNode*)node
nodesMatchingTraits:(IJSVGNodeTraits)traits
{
NSMutableArray<IJSVGNode*>* nodes = [[NSMutableArray alloc] init];
IJSVGNodeWalkHandler handler = ^(IJSVGNode* node,
BOOL* allowChildNodes,
BOOL* stop) {
// dont compute nodes that are not designed
// to be rendered
if(node.shouldRender == NO) {
*allowChildNodes = NO;
return;
}
if([node matchesTraits:traits] == YES) {
[nodes addObject:node];
}
};
[IJSVGNode walkNodeTree:node
handler:handler];
return nodes;
}
+ (BOOL)node:(IJSVGNode*)node
containsNodesMatchingTraits:(IJSVGNodeTraits)traits
{
__block IJSVGNodeTraits matchedTraits = IJSVGNodeTraitNone;
IJSVGNodeWalkHandler handler = ^(IJSVGNode* node,
BOOL* allowChildNodes,
BOOL* stop) {
// dont compute nodes that are not designed
// to be rendered
if(node.shouldRender == NO) {
*allowChildNodes = NO;
return;
}
// check for stroke
if((traits & IJSVGNodeTraitStroked) == IJSVGNodeTraitStroked &&
[node matchesTraits:IJSVGNodeTraitStroked] == YES) {
matchedTraits |= IJSVGNodeTraitStroked;
}
// check for pathed
if((traits & IJSVGNodeTraitPathed) == IJSVGNodeTraitPathed &&
[node matchesTraits:IJSVGNodeTraitPathed] == YES) {
matchedTraits |= IJSVGNodeTraitPathed;
}
// check for paintable
if((traits & IJSVGNodeTraitPaintable) == IJSVGNodeTraitPaintable &&
[node matchesTraits:IJSVGNodeTraitPaintable] == YES) {
matchedTraits |= IJSVGNodeTraitPaintable;
}
// simply check if masks equal, if they are, stop this loop
// and return the evaluation
if(matchedTraits == traits) {
*stop = YES;
}
};
[IJSVGNode walkNodeTree:node
handler:handler];
return matchedTraits == traits;
}
- (id)init
{
if ((self = [super init]) != nil) {
if((self = [super init]) != nil) {
self.opacity = [IJSVGUnitLength unitWithFloat:1.f];
self.fillOpacity = [IJSVGUnitLength unitWithFloat:1.f];
self.fillOpacity.inherit = YES;
self.strokeDashArrayCount = IJSVGInheritedIntegerValue;
self.strokeDashOffset = [IJSVGUnitLength unitWithFloat:0.f];
self.shouldRender = YES;
@@ -200,6 +259,7 @@
self.strokeWidth.inherit = YES;
self.windingRule = IJSVGWindingRuleInherit;
self.clipRule = IJSVGWindingRuleInherit;
self.lineCapStyle = IJSVGLineCapStyleInherit;
self.lineJoinStyle = IJSVGLineJoinStyleInherit;
self.units = IJSVGUnitInherit;
@@ -207,6 +267,9 @@
self.blendMode = IJSVGBlendModeNormal;
self.overflowVisibility = IJSVGOverflowVisibilityVisible;
// peform basic init
[self setDefaults];
}
return self;
}
@@ -243,11 +306,13 @@
self.strokeWidth = node.strokeWidth;
self.fillOpacity = node.fillOpacity;
self.strokeOpacity = node.strokeOpacity;
self.strokeMiterLimit = node.strokeMiterLimit;
self.identifier = node.identifier;
self.transforms = node.transforms;
self.windingRule = node.windingRule;
self.clipRule = node.clipRule;
self.lineCapStyle = node.lineCapStyle;
self.lineJoinStyle = node.lineJoinStyle;
self.parentNode = node.parentNode;
@@ -271,33 +336,43 @@
return node;
}
- (void)postProcess
{
}
- (void)setFill:(IJSVGNode*)fill
{
NSAssert([fill matchesTraits:IJSVGNodeTraitPaintable] || fill == nil, @"Fill must a paintable node.");
(void)[_fill release], _fill = nil;
_fill = [fill retain];
_fill = fill;
}
- (void)setStroke:(IJSVGNode*)stroke
{
NSAssert([stroke matchesTraits:IJSVGNodeTraitPaintable]|| stroke == nil, @"Stroke must be a paintable node.");
(void)[_stroke release], _stroke = nil;
_stroke = [stroke retain];
_stroke = stroke;
}
// winding rule can inherit..
- (IJSVGWindingRule)windingRule
{
if (_windingRule == IJSVGWindingRuleInherit && _parentNode != nil) {
if(_windingRule == IJSVGWindingRuleInherit && _parentNode != nil) {
return _parentNode.windingRule;
}
return _windingRule;
}
- (IJSVGWindingRule)clipRule
{
if(_clipRule == IJSVGWindingRuleInherit && _parentNode != nil) {
return _parentNode.clipRule;
}
return _clipRule;
}
- (IJSVGLineCapStyle)lineCapStyle
{
if (_lineCapStyle == IJSVGLineCapStyleInherit) {
if (_parentNode != nil) {
if(_lineCapStyle == IJSVGLineCapStyleInherit) {
if(_parentNode != nil) {
return _parentNode.lineCapStyle;
}
}
@@ -306,8 +381,8 @@
- (IJSVGLineJoinStyle)lineJoinStyle
{
if (_lineJoinStyle == IJSVGLineJoinStyleInherit) {
if (_parentNode != nil) {
if(_lineJoinStyle == IJSVGLineJoinStyleInherit) {
if(_parentNode != nil) {
return _parentNode.lineJoinStyle;
}
}
@@ -318,7 +393,7 @@
// if they dont exist on this specific node
- (IJSVGUnitLength*)opacity
{
if (_opacity.inherit && _parentNode != nil) {
if(_opacity.inherit && _parentNode != nil) {
return _parentNode.opacity;
}
return _opacity;
@@ -328,7 +403,7 @@
// if they dont exist on this specific node
- (IJSVGUnitLength*)fillOpacity
{
if (_fillOpacity.inherit && _parentNode != nil) {
if(_fillOpacity.inherit && _parentNode != nil) {
return _parentNode.fillOpacity;
}
return _fillOpacity;
@@ -338,7 +413,7 @@
// if they dont exist on this specific node
- (IJSVGUnitLength*)strokeWidth
{
if (_strokeWidth.inherit && _parentNode != nil) {
if(_strokeWidth.inherit && _parentNode != nil) {
return _parentNode.strokeWidth;
}
return _strokeWidth;
@@ -346,7 +421,7 @@
- (NSArray<NSNumber*>*)lineDashPattern
{
NSMutableArray* arr = [[[NSMutableArray alloc] initWithCapacity:self.strokeDashArrayCount] autorelease];
NSMutableArray* arr = [[NSMutableArray alloc] initWithCapacity:self.strokeDashArrayCount];
for (NSInteger i = 0; i < self.strokeDashArrayCount; i++) {
[arr addObject:@((CGFloat)self.strokeDashArray[i])];
}
@@ -357,15 +432,39 @@
// if they dont exist on this specific node
- (IJSVGNode*)stroke
{
if (_stroke == nil && _parentNode != nil) {
if(_stroke == nil && _parentNode != nil) {
return _parentNode.stroke;
}
return _stroke;
}
- (CGFloat*)strokeDashArray
{
if(_strokeDashArray == NULL && _parentNode != nil) {
return _parentNode.strokeDashArray;
}
return _strokeDashArray;
}
- (NSInteger)strokeDashArrayCount
{
if(_strokeDashArrayCount == IJSVGInheritedIntegerValue && _parentNode != nil) {
return _parentNode.strokeDashArrayCount;
}
return _strokeDashArrayCount;
}
- (IJSVGUnitLength *)strokeDashOffset
{
if(_strokeDashOffset == nil && _parentNode != nil) {
return _parentNode.strokeDashOffset;
}
return _strokeDashOffset;
}
- (IJSVGUnitLength*)strokeOpacity
{
if (_strokeOpacity.inherit && _parentNode != nil) {
if(_strokeOpacity.inherit && _parentNode != nil) {
return _parentNode.strokeOpacity;
}
return _strokeOpacity;
@@ -375,7 +474,7 @@
// must be on the path, it can also be on the
- (IJSVGNode*)fill
{
if (_fill == nil && _parentNode != nil) {
if(_fill == nil && _parentNode != nil) {
return _parentNode.fill;
}
return _fill;
@@ -397,6 +496,14 @@
return _contentUnits;
}
- (IJSVGUnitLength*)strokeMiterLimit
{
if(_strokeMiterLimit == nil && _parentNode != nil) {
return _parentNode.strokeMiterLimit;
}
return _strokeMiterLimit;
}
- (IJSVGUnitType)contentUnitsWithReferencingNodeBounds:(CGRect*)bounds
{
IJSVGNode* node = nil;
@@ -414,6 +521,15 @@
return _contentUnits;
}
- (IJSVGNodeTraits)traits
{
if(_computedTraits == NO) {
_computedTraits = YES;
[self computeTraits];
}
return _traits;
}
- (void)addTraits:(IJSVGNodeTraits)traits
{
_traits |= traits;
@@ -426,7 +542,7 @@
- (BOOL)matchesTraits:(IJSVGNodeTraits)traits
{
return (_traits & traits) == traits;
return (self.traits & traits) == traits;
}
- (void)computeTraits
@@ -434,6 +550,10 @@
// by default this does nothing
}
- (void)setDefaults
{
}
- (instancetype)detach
{
self.parentNode = nil;
@@ -442,7 +562,81 @@
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ %@ %@",self.name,self.classNameList,self.identifier];
return [NSString stringWithFormat:@"%@ %@ %@ %@",NSStringFromClass(self.class),
self.name,self.classNameList,self.identifier];
}
- (BOOL)detachedFromParentNode
{
return self.type == IJSVGNodeTypeClipPath ||
self.type == IJSVGNodeTypeMask;
}
- (IJSVGRootNode*)rootNode
{
IJSVGNode* parent = self;
while([parent isKindOfClass:IJSVGRootNode.class] == NO) {
parent = parent.parentNode;
if(parent == nil) {
return nil;
}
}
return (IJSVGRootNode*)parent;
}
- (NSSet<IJSVGNode*>*)nodesMatchingTypes:(NSIndexSet*)types
{
NSMutableSet<IJSVGNode*>* nodes = [[NSMutableSet alloc] init];
IJSVGNodeWalkHandler handler = ^(IJSVGNode* node,
BOOL* allowChildNodes,
BOOL* stop) {
if([types containsIndex:node.type] == YES) {
[nodes addObject:node];
}
};
[self.class walkNodeTree:self
handler:handler];
return nodes.copy;
}
- (instancetype)parentNodeMatchingClass:(Class)class
{
IJSVGNode* parent = self.parentNode;
if([parent isKindOfClass:class] == YES) {
return parent;
}
return [parent parentNodeMatchingClass:class];
}
- (instancetype)rootNodeMatchingClass:(Class)class
{
IJSVGRootNode* rootNode = self.rootNode;
IJSVGNode* parentNode = self.parentNode;
IJSVGNode* foundNode = nil;
while(parentNode != nil) {
// break on root node or if its matching
if(parentNode == rootNode || parentNode == nil) {
break;
}
if([parentNode isKindOfClass:class] == YES) {
foundNode = parentNode;
}
parentNode = parentNode.parentNode;
}
return foundNode;
}
- (void)normalizeWithOffset:(CGPoint)offset
{
// if an SVG has been asked to normalize, its root will give us an offset
// to transform by to shift everything based on the viewBox's origin, we can
// simply just create a translate transform and stick at first position.
NSMutableArray* transforms = self.transforms ?
self.transforms.mutableCopy : [[NSMutableArray alloc] init];
IJSVGTransform* transform = [IJSVGTransform transformByTranslatingX:-offset.x
y:-offset.y];
[transforms insertObject:transform atIndex:0];
self.transforms = transforms;
}
@end
@@ -31,6 +31,10 @@ typedef NS_ENUM(NSInteger, IJSVGPrimitivePathType) {
@property (nonatomic, readonly) CGRect controlPointBoundingBox;
@property (nonatomic, readonly) CGRect pathBoundingBox;
+ (void)recursivelyAddPathedNodesPaths:(NSArray<IJSVGNode*>*)nodes
transform:(CGAffineTransform)transform
toPath:(CGMutablePathRef)mutPath;
- (void)close;
- (NSPoint)currentPoint;
+32 -5
View File
@@ -7,26 +7,52 @@
//
#import <IJSVG/IJSVGPath.h>
#import <IJSVG/IJSVGGroup.h>
@implementation IJSVGPath
+ (void)recursivelyAddPathedNodesPaths:(NSArray<IJSVGNode*>*)nodes
transform:(CGAffineTransform)transform
toPath:(CGMutablePathRef)mutPath
{
for(IJSVGPath* pathNode in nodes) {
// just a pathed node
if([pathNode matchesTraits:IJSVGNodeTraitPathed] == YES) {
CGPathAddPath(mutPath, &transform, pathNode.path);
continue;
}
// could be a use group
if([pathNode isKindOfClass:IJSVGGroup.class] == YES) {
IJSVGGroup* useGroup = (IJSVGGroup*)pathNode;
[self recursivelyAddPathedNodesPaths:useGroup.children
transform:transform
toPath:mutPath];
}
}
}
- (void)dealloc
{
if(_path != NULL) {
(void)CGPathRelease(_path), _path = NULL;
}
[super dealloc];
}
- (id)init
{
if ((self = [super init]) != nil) {
if((self = [super init]) != nil) {
_primitiveType = kIJSVGPrimitivePathTypePath;
_path = CGPathCreateMutable();
}
return self;
}
- (void)setDefaults
{
[self addTraits:IJSVGNodeTraitPathed];
}
- (CGRect)bounds
{
return self.pathBoundingBox;
@@ -51,12 +77,12 @@
- (CGRect)pathBoundingBox
{
return CGPathGetPathBoundingBox(_path);
return CGPathGetBoundingBox(_path);
}
- (CGRect)controlPointBoundingBox
{
return CGPathGetBoundingBox(_path);
return CGPathGetPathBoundingBox(_path);
}
- (NSPoint)currentPoint
@@ -81,7 +107,8 @@
// component to then remove the trait if its 0.f
if([self.stroke isKindOfClass:IJSVGColorNode.class] == YES) {
IJSVGColorNode* strokeColor = (IJSVGColorNode*)self.stroke;
if(strokeColor.color.alphaComponent == 0.f) {
if(strokeColor.color.alphaComponent == 0.f ||
strokeColor.isNoneOrTransparent == YES) {
[self removeTraits:IJSVGNodeTraitStroked];
}
}
@@ -6,8 +6,9 @@
// Copyright © 2016 Curtis Hard. All rights reserved.
//
#import "IJSVGPattern.h"
#import "IJSVGUnitRect.h"
#import <IJSVG/IJSVGPattern.h>
#import <IJSVG/IJSVGUnitRect.h>
#import <IJSVG/IJSVGRootNode.h>
@implementation IJSVGPattern
@@ -21,5 +22,22 @@
return self;
}
- (IJSVGUnitType)contentUnitsWithReferencingNodeBounds:(CGRect*)bounds
{
// as far as I can tell, units are inherited, so we need to go to the root
// level pattern if there is one (we could be nested) and if so, return those
// units as the actual units, but the bounds are based on the units of current
// units defined on this node... wtf?!
IJSVGNode* node = nil;
IJSVGPattern* parentPattern = [self rootNodeMatchingClass:self.class];
IJSVGUnitType units = [self contentUnitsWithReferencingNode:&node];
if(units == IJSVGUnitUserSpaceOnUse) {
*bounds = node.rootNode.bounds;
} else {
*bounds = node.parentNode.bounds;
}
return parentPattern ? [parentPattern contentUnitsWithReferencingNode:&node] : units;
}
@end
@@ -11,14 +11,14 @@
@interface IJSVGRadialGradient : IJSVGGradient
@property (nonatomic, retain) IJSVGUnitLength* cx;
@property (nonatomic, retain) IJSVGUnitLength* cy;
@property (nonatomic, retain) IJSVGUnitLength* fx;
@property (nonatomic, retain) IJSVGUnitLength* fy;
@property (nonatomic, retain) IJSVGUnitLength* fr;
@property (nonatomic, retain) IJSVGUnitLength* r;
@property (nonatomic, strong) IJSVGUnitLength* cx;
@property (nonatomic, strong) IJSVGUnitLength* cy;
@property (nonatomic, strong) IJSVGUnitLength* fx;
@property (nonatomic, strong) IJSVGUnitLength* fy;
@property (nonatomic, strong) IJSVGUnitLength* fr;
@property (nonatomic, strong) IJSVGUnitLength* r;
+ (NSGradient*)parseGradient:(NSXMLElement*)element
gradient:(IJSVGRadialGradient*)gradient;
+ (void)parseGradient:(NSXMLElement*)element
gradient:(IJSVGRadialGradient*)gradient;
@end
@@ -11,17 +11,6 @@
@implementation IJSVGRadialGradient
- (void)dealloc
{
(void)([_cx release]), _cx = nil;
(void)([_cy release]), _cy = nil;
(void)([_fx release]), _fx = nil;
(void)([_fy release]), _fy = nil;
(void)([_fr release]), _fr = nil;
(void)([_r release]), _r = nil;
[super dealloc];
}
- (id)copyWithZone:(NSZone*)zone
{
IJSVGRadialGradient* grad = [super copyWithZone:zone];
@@ -34,8 +23,8 @@
return grad;
}
+ (NSGradient*)parseGradient:(NSXMLElement*)element
gradient:(IJSVGRadialGradient*)gradient
+ (void)parseGradient:(NSXMLElement*)element
gradient:(IJSVGRadialGradient*)gradient
{
// cx defaults to 50% if not specified
NSDictionary* kv = @{
@@ -46,7 +35,7 @@
for (NSString* key in kv.allKeys) {
NSString* str = [element attributeForName:key].stringValue;
IJSVGUnitLength* unit = nil;
if (str != nil) {
if(str != nil) {
unit = [IJSVGUnitLength unitWithString:str
fromUnitType:gradient.units];
} else {
@@ -72,52 +61,52 @@
// needs fixing
NSString* fx = [element attributeForName:IJSVGAttributeFX].stringValue;
if (fx != nil) {
if(fx != nil) {
gradient.fx = [IJSVGUnitLength unitWithString:fx
fromUnitType:gradient.units];
}
NSString* fy = [element attributeForName:IJSVGAttributeFY].stringValue;
if (fy != nil) {
if(fy != nil) {
gradient.fy = [IJSVGUnitLength unitWithString:fy
fromUnitType:gradient.units];
}
if (gradient.gradient != nil) {
return nil;
}
NSArray* colors = nil;
CGFloat* colorStops = [self.class computeColorStops:gradient
colors:&colors];
NSGradient* ret = [[[NSGradient alloc] initWithColors:colors
atLocations:colorStops
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
free(colorStops);
return ret;
gradient.locations = colorStops;
gradient.colors = colors;
gradient.numberOfStops = colors.count;
}
- (void)drawInContextRef:(CGContextRef)ctx
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
bounds:(NSRect)objectRect
transform:(CGAffineTransform)absoluteTransform
{
CGContextSaveGState(ctx);
CGContextSetInterpolationQuality(ctx, kCGInterpolationLow);
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGFloat radius = 0.f;
CGPoint startPoint = CGPointZero;
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
CGRect boundingBox = objectRect;
// transforms
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
// compute size based on percentages
CGFloat width = CGRectGetWidth(boundingBox);
CGFloat height = CGRectGetHeight(boundingBox);
CGFloat width = 0.f;
CGFloat height = 0.f;
if(inUserSpace == YES) {
width = CGRectGetWidth(boundingBox);
height = CGRectGetHeight(boundingBox);
} else {
width = 1.f;
height = 1.f;
}
CGFloat cx = [_cx computeValue:width];
CGFloat cy = [_cy computeValue:height];
startPoint = CGPointMake(cx, cy);
@@ -136,35 +125,13 @@
if(inUserSpace == YES) {
CGFloat rad = 2.f * radius;
CGRect rect = CGRectMake(startPoint.x, startPoint.y, rad, rad);
rect = CGRectApplyAffineTransform(rect, selfTransform);
rect = CGRectApplyAffineTransform(rect, absoluteTransform);
radius = CGRectGetHeight(rect) / 2.f;
CGContextConcatCTM(ctx, absoluteTransform);
} else if(width != height) {
CGAffineTransform transform = CGAffineTransformIdentity;
CGAffineTransform invert = CGAffineTransformIdentity;
CGPoint invPoint = CGPointZero;
CGFloat* radiusScale;
if(width > height) {
transform = CGAffineTransformMakeScale(1.f, height / width);
radiusScale = &invPoint.y;
} else {
transform = CGAffineTransformMakeScale(width / height, 1.f);
radiusScale = &invPoint.x;
}
invert = CGAffineTransformInvert(transform);
invPoint.x = invert.a;
invPoint.y = invert.d;
gradientStartPoint.x *= invPoint.x;
gradientStartPoint.y *= invPoint.y;
gradientEndPoint.x *= invPoint.x;
gradientEndPoint.y *= invPoint.y;
radius *= *radiusScale;
focalRadius *= *radiusScale;
selfTransform = CGAffineTransformConcat(transform, selfTransform);
} else {
CGContextConcatCTM(ctx, CGAffineTransformMakeScale(CGRectGetWidth(boundingBox),
CGRectGetHeight(boundingBox)));
}
// transform the context
CGContextConcatCTM(ctx, selfTransform);
// draw the gradient
@@ -174,12 +141,6 @@
gradientStartPoint,
radius, options);
CGContextRestoreGState(ctx);
//#ifdef IJSVG_DEBUG_GRADIENTS
// [self _debugStart:gradientStartPoint
// end:gradientEndPoint
// context:ctx];
//#endif
}
@end

Some files were not shown because too many files have changed in this diff Show More