Compare commits

..

267 Commits

Author SHA1 Message Date
Curtis Hard 27c4638fa7 Add the inner transforms 2024-07-16 18:48:13 +01:00
Curtis Hard 7c8bfa937e Fixes crash when large whitespace string is used 2024-07-03 17:11:38 +01:00
Curtis Hard fdc30123a4 be sure to copy children 2024-06-27 16:45:04 +01:00
Curtis Hard 80ef3790d2 Update Xcode settings 2024-02-11 19:26:26 +00:00
Curtis Hard ded0c9b839 updated proj 2024-02-06 19:24:47 +00:00
Curtis Hard 6585501f5d Merge branch 'fixes/masking-offsets' 2023-12-20 23:10:05 +00:00
Curtis Hard 846f0fe27c Fix memory leak 2023-11-09 21:59:22 +00:00
Curtis Hard 0c64626e3e Fix for colours using weird methods 2023-10-30 22:47:27 +00:00
Curtis Hard 9ea09ebeee Typo 2023-10-30 20:03:17 +00:00
Curtis Hard 0c04202ad1 Possible masking alpha channel fixes 2023-10-30 20:02:29 +00:00
Curtis Hard e66ee5e5a1 Possible fix for masking offsets 2023-10-30 15:59:11 +00:00
Curtis Hard a97272252d Merge branch 'fixes/masking-units' into enhancements/parsing 2023-10-20 20:53:34 +01:00
Curtis Hard a95a046c64 FIx for transforms being applied to root nodes 2023-10-20 20:28:19 +01:00
Curtis Hard d4d8fcfe78 Fix color parsing with CSS attributes 2023-10-20 20:09:36 +01:00
Curtis Hard e75d862430 Adds display attribute into base list for passing 2023-10-20 19:50:15 +01:00
Curtis Hard 44358cc00a Move all child layers within a mask if they are userSpaceOnUse 2023-10-18 20:42:19 +01:00
Curtis Hard c7e490fcba Fixes for new Xcode 2023-07-23 13:02:24 +01:00
Curtis Hard 63d682f5d9 Remove lock + fix for threading issue 2023-06-27 21:32:44 +01:00
Curtis Hard 13a7fb5431 Fixes clipping issue when maintaining ratio 2023-04-22 13:42:13 +01:00
Curtis Hard f52ee76e2d Possible threadinf fix 2023-04-20 21:47:20 +01:00
Curtis Hard 9c1ad0b44b Threading issue (only apparently from Swift) 2023-04-20 19:42:46 +01:00
Curtis Hard c608d01fa4 Adds umbrella header + changes to module map 2023-04-16 17:24:19 +01:00
Curtis Hard bb8b3f915b Deletes the old file 2023-01-30 19:42:10 +00:00
Curtis Hard ad78aa6598 Adds module map file in 2023-01-30 19:42:01 +00:00
Curtis Hard d558f90932 Adds really fast attribute checking and parsing 2022-09-08 21:29:12 +01:00
Curtis Hard e7716dbd7b fixes header missing 2022-09-06 21:46:40 +01:00
Curtis Hard 1d0fce8f2a Vast performance increases to parser when parsing attributes 2022-09-05 13:49:45 +01:00
Curtis Hard 24825d867d Further parsing performance increases 2022-09-04 22:22:14 +01:00
Curtis Hard 3b63e225c3 Odd commit 2022-09-04 19:24:10 +01:00
Curtis Hard 1f852e0cf9 Further performance enhancements 2022-09-04 19:13:10 +01:00
Curtis Hard 2547f47126 Memory fixes 2022-09-04 12:23:59 +01:00
Curtis Hard 4769ebeac7 Performance optimisations 2022-09-01 18:25:07 +01:00
Curtis Hard fe51568c83 Only parse filters if flag is enabled for them 2022-08-20 21:39:26 +01:00
Curtis Hard b91235323b Make sure we calculate the outerBoundingBox for masks that have transforms 2022-08-20 13:30:27 +01:00
Curtis Hard cefc304e6e Fixes gradient exports with transforms 2022-08-20 11:36:58 +01:00
Curtis Hard a23425c9b6 Fixes gradient rendering
- concat gradients and applying a single one does not work for some reason, however, applying each one individually into the context works
2022-08-20 11:26:26 +01:00
Curtis Hard 2f2c61e559 Added a comment 2022-08-17 13:31:32 +01:00
Curtis Hard 061a5fb52c Removal of useless code 2022-08-14 14:37:53 +01:00
Curtis Hard 8598bea11e Added IJSVGPerformTransactionBlock 2022-08-14 11:41:12 +01:00
Curtis Hard faac432117 Fixes a leak that can occur when the framework is used by code that involved ARC 2022-08-13 19:29:45 +01:00
Curtis Hard 29a5c5e533 - adds sizeByMaintainingAspectRatioWithSize: 2022-08-12 20:48:31 +01:00
Curtis Hard f286f4e993 Fixes a crash that could occur when the intrinsicSize is dynamic
- size should be calculated instead of static
2022-08-12 20:35:08 +01:00
Curtis Hard 6bbd213eb0 Delete _config.yml 2022-08-10 21:09:25 +01:00
Curtis Hard c82db3469e Update README.md 2022-08-09 21:57:04 +01:00
Curtis Hard 8269727063 Update README.md 2022-08-09 21:56:38 +01:00
Curtis Hard a3d2c6dca9 Update README.md 2022-08-09 20:58:22 +01:00
Curtis Hard 1c61ab18e4 Update README.md 2022-08-09 20:56:13 +01:00
Curtis Hard 64588b6e6d Update README.md 2022-08-08 18:21:27 +01:00
Curtis Hard 3c81cd6634 Merge branch 'features/filters' 2022-08-08 18:00:39 +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
Curtis Hard 050df84672 Adds isNoneOrTransparent to COlor 2022-04-19 18:11:02 +01:00
Curtis Hard ac61d3d6d6 Adds image generation to IJSVGLayer 2022-04-18 17:32:20 +01:00
Curtis Hard fdde1fd5f6 Fixes transforms and masking 2022-04-18 14:45:24 +01:00
Curtis Hard fe179076cc More fixes 2022-04-18 11:45:04 +01:00
Curtis Hard 01dd0d25d2 Make sure the node actually exists 2022-04-17 17:57:52 +01:00
Curtis Hard 799593d7d8 Removed log 2022-04-17 17:57:09 +01:00
Curtis Hard 0c7cfd776c Fixes stylesheets 2022-04-17 17:57:01 +01:00
Curtis Hard 757c4317d3 Adds better rendering calls into SVG 2022-04-17 12:45:44 +01:00
Curtis Hard 1727505968 Removed IJSVG_DRAWABLE_LAYER 2022-04-17 11:58:49 +01:00
Curtis Hard 775c28e91a Updated example and added better support for ratios 2022-04-16 17:50:57 +01:00
Curtis Hard ec539a12b3 More alignment stuff 2022-04-16 13:51:33 +01:00
Curtis Hard 43210c018e Fixes strokes with layer of constant fill color
- started to out viewboxes
2022-04-15 21:10:48 +01:00
Curtis Hard 3773e10f44 Fixes strokes, some patterns, changes how we parse commands ready for units 2022-04-13 21:20:53 +01:00
Curtis Hard 51fb9cc871 added referencing layers into layer tree 2022-04-12 20:00:58 +01:00
Curtis Hard be08ada5da Fixes gradients 2022-04-11 10:14:08 +01:00
Curtis Hard a3a6ee5a05 Fixes absolute transform and gradients 2022-04-08 21:56:03 +01:00
Curtis Hard cccfc0db68 Various fixes 2022-04-07 15:36:33 +01:00
Curtis Hard 19db898bdd More gradient things that dont work 2022-04-03 20:05:58 +01:00
Curtis Hard 8abbdf390a Continue of refactor 2022-04-02 13:51:47 +01:00
Curtis Hard 6e98e2cfed Removes useless properties 2022-03-31 13:36:53 +01:00
Curtis Hard 2c536a8962 Adds .children and improvements to addChild/removeChild 2022-03-30 19:52:30 +01:00
Curtis Hard 65a8c0a691 Proper clip path 2022-03-30 15:26:32 +01:00
Curtis Hard 2942cc0a58 Added IJSVGColorNode and traits 2022-03-29 20:12:53 +01:00
Curtis Hard ba7a05553e Adds frame calculations onto group 2022-03-29 11:37:28 +01:00
Curtis Hard c9a7788d98 Added correctly nested detached nodes 2022-03-29 09:34:08 +01:00
Curtis Hard 774ff48074 Refactor, IJSVGParser is not the root anymore, there is a new IJSVGRootNode as the root of the node tree 2022-03-28 20:31:27 +01:00
Curtis Hard 2eb629cd21 Overhaul of parser 2022-03-28 19:14:46 +01:00
Curtis Hard 137e34623f hacky things! 2022-03-27 22:05:19 +01:00
Curtis Hard 39b0b5bbb4 More image fixes 2022-03-27 20:45:31 +01:00
Curtis Hard 820fca2679 Merge branch 'features/patterns' of https://github.com/curthard89/IJSVG into features/patterns 2022-03-27 15:38:09 +01:00
Curtis Hard 2e5819183d More pattern things 2022-03-27 15:36:33 +01:00
Curtis Hard eff56d3c60 More pattern things, this is not fun 2022-03-27 15:35:51 +01:00
Curtis Hard 7a4fd35a64 initial pattern fixes 2022-03-25 13:21:59 +00:00
Curtis Hard 964dc3005d Merge branch 'fixes/const-memory-alloc-issues' of https://github.com/curthard89/IJSVG 2022-03-23 18:27:54 +00:00
Curtis Hard 1a8d44ec95 Fixes masking for gradients 2022-03-23 18:27:41 +00:00
Curtis Hard 717198457b Adds new method to create a trimmed string
- adds `const` in various places
- uses the new trimmed string method
- adds various memory releases in
2022-01-24 14:33:54 +00:00
Curtis Hard e2991ab8b0 Fixes smooth quad / curves having incorrect path data on export 2022-01-04 14:04:23 +00:00
Curtis Hard dda3e5ed8c Merge branch 'feature/ijsvgcolorsub' 2022-01-04 11:17:38 +00:00
Curtis Hard c3a0fb5b91 Fixes 10.9 issue with const 2022-01-04 11:17:15 +00:00
Curtis Hard 7ce4520a56 Adds currentColor as a predefined constant 2021-12-29 16:25:52 +00:00
Curtis Hard 368d19ea81 Nullable types 2021-12-28 22:33:12 +00:00
Curtis Hard d26c2f489f Adds delegate methods for color and ID 2021-12-28 19:28:32 +00:00
Curtis Hard 75b0d55b63 #oops, wrong list being used 2021-12-26 18:50:51 +00:00
Curtis Hard 310308cd8a Fixes stroke colorList stop colors not being identified correctly 2021-12-26 18:11:30 +00:00
Curtis Hard 278f405a41 Possible fix for older OS's 2021-12-15 15:16:59 +00:00
Curtis Hard 7addd97d0c Fixes issue with clipPath not using correct units
- adds support for overflow attribute
2021-11-24 15:15:54 +00:00
Curtis Hard d01ca0f3bb Fixes issue with wrong colors being used 2021-10-19 20:49:57 +01:00
Curtis Hard 6d7ad17e2a Fixes threading race condition 2021-05-11 22:06:56 +01:00
Curtis Hard deb09eaf04 Merge branch 'feature/color-stroke-checking' 2021-04-27 09:45:29 +01:00
Curtis Hard 1e7b8b38a5 Fixes the double quotes being used instead of angled brackets 2021-04-26 13:45:32 +01:00
Curtis Hard 58e1a8c45d fixes tempalte void things 2021-04-26 10:35:08 +01:00
Curtis Hard a525e4351a Fixes computeColorList for gradient export 2021-04-24 13:41:05 +01:00
Curtis Hard c87716b311 Code style 2021-04-21 20:18:07 +01:00
Curtis Hard 583a930bf7 Fixes multithread issue with strtok 2021-04-21 15:24:51 +01:00
Curtis Hard ec2473d450 Adds transaction to fix memory issue 2021-04-21 13:39:31 +01:00
Curtis Hard 3cc477955a Fixes enums and options 2021-04-20 20:36:37 +01:00
Curtis Hard 1f0ff52dff Adds color types 2021-04-20 16:31:52 +01:00
Curtis Hard e96bfa54b0 Make sure to check it has alpha 2021-04-20 12:15:23 +01:00
Curtis Hard cd3b540274 Initial commit 2021-04-20 09:31:10 +01:00
Curtis Hard 1cfbaf14e4 added utils for converting CGLineCap and Joi nto IJSVG counterparts 2021-04-11 17:13:45 +01:00
Curtis Hard 5a389f88d3 Added initWithDataAssetNamed:bundle:error:
Added support for loading SVG’s from the data asset catalogue
2021-04-07 21:42:00 +01:00
Curtis Hard 9f43832ff3 Fixes elliptical arc 2021-02-17 21:32:13 +00:00
Curtis Hard 65623ec552 Fixes colour forced from a style 2021-02-16 21:11:26 +00:00
Curtis Hard 5192520b7c Fixes memory crash 2021-02-16 09:37:22 +00:00
Curtis Hard 5123ee7308 Fixes crash 2021-02-11 21:39:31 +00:00
Curtis Hard c886a6a80d trolled by CGPath not being identical to bezierpath 2021-02-10 22:21:13 +00:00
Curtis Hard 4cd2895703 Seems to improve performance 2021-02-10 19:27:08 +00:00
Curtis Hard a98d84f209 Removed bezier path additions as its now useless
- more perfromance increases
2021-02-08 20:56:08 +00:00
Curtis Hard 8faab28823 Performance increases 2021-02-08 17:23:43 +00:00
Curtis Hard cca5524a11 Converts all bezier path storage over to CGPath
There was no need to use NSBezierPath, we only used to to convert to CGPath eventually, so swapped it all overm much faster
2021-02-06 18:33:23 +00:00
Curtis Hard c14e2367a0 Formatting 2021-02-06 13:21:46 +00:00
Curtis Hard db4b0e9a18 Fixes crash if string is nil 2021-02-06 12:25:16 +00:00
Curtis Hard 93d6a868a9 reformat and use of strtok - did not realise it was already built into C 2021-02-05 21:28:48 +00:00
Curtis Hard 60fa627d99 Perf 2021-02-05 15:51:15 +00:00
Curtis Hard ccaa350190 Fixes issue with mem crash when no width or height is specified as a fallback 2021-02-03 22:03:38 +00:00
Curtis Hard 727f8a2dea Modern Object-C refactor
This refactors most of the old style synthesized properties and lets the compiler do it for us.

This also changes how unit lengths works (now does correct parsing and using cstrings instead of nsstring where applicable)
2021-01-30 18:40:29 +00:00
Curtis Hard 972812b3f6 Fixes arc commands 2021-01-26 08:56:04 +00:00
Curtis Hard ad8f440c72 Merge branch 'feature/cm-mm-units' 2021-01-25 19:32:47 +00:00
Curtis Hard 68393b296b Faster low level parsing for paths 2021-01-25 19:29:53 +00:00
Curtis Hard 1cfcb596d9 Much faster command parsing
tl;dr, stops converting between char*/unichar* and NSString*, the low level code for passing commands wants char* so no point of converting it to a higher level NSString* just to convert it back again, waste of time.
2021-01-24 22:18:07 +00:00
Curtis Hard 69077e49cf Faster parsing for very large SVGs 2021-01-24 19:16:10 +00:00
Curtis Hard 3bdf2151ca Rewrote how we parse transforms (its much faster)
Also much faster arc transform processsing
2021-01-23 18:58:39 +00:00
Curtis Hard f7e28a2962 Added originalType for future reference 2021-01-20 21:39:10 +00:00
Curtis Hard 2c07cfabdd Added more units and neatened up methods 2021-01-20 21:19:28 +00:00
Curtis Hard 3e356b3fdc Possible fix for CM and MM units 2021-01-20 21:00:15 +00:00
Curtis Hard 49f759edc0 Added extra header in 2021-01-10 16:55:28 +00:00
Curtis Hard 38e314eb99 Cant use description as its already a thing on NSObject. #oops 2020-11-22 18:50:09 +00:00
Curtis Hard d0eb015cf1 Added title and desc parsing into the IJSVGNode 2020-11-22 18:14:04 +00:00
Curtis Hard 080626a022 Removed warning 2020-11-14 16:44:13 +00:00
Curtis Hard 36c20bc55c Updated clang warning 2020-11-13 20:01:37 +00:00
Curtis Hard 4d89631e9a Brace in the wrong place! #oops 2020-09-21 20:16:53 +01:00
Curtis Hard 65f62007f3 Fixes exception being thrown and lower cased move command 2020-09-21 19:55:31 +01:00
Curtis Hard af5f16288d Updated opyright 2020-09-21 09:58:38 +01:00
Curtis Hard 08e0f9288d Adds support to remove default attributes from exported files 2020-09-16 18:40:05 +01:00
Curtis Hard 7650f6205c More improvements to exporting data 2020-09-13 20:36:29 +01:00
Curtis Hard 263768af5b Initial compression changes 2020-09-12 22:59:54 +01:00
Curtis Hard 4b1be17f9a Reduces exported data by a fair amount on larger SVGs by using NSXMLNodeCompactEmptyElement to self close tags
- also added option to get back an IJSVG object from the current export string
2020-09-08 18:57:20 +01:00
Curtis Hard 6b0d6b1452 This adds in floating point export options
- aswell as an option to round matrix values
2020-09-03 19:37:37 +01:00
Curtis Hard f80d4145bb Default rounds numbers, but not for transforms 2020-08-14 20:48:33 +01:00
Curtis Hard f68c83285b Fixes issuew here stroke-opacity was not exported 2020-08-14 20:13:53 +01:00
Curtis Hard 1f4bd989d8 Fixes RX and RY on rect 2020-08-13 12:10:49 +01:00
Curtis Hard 5b5d0b738b Added instruction passing for c -> s + t 2020-08-04 20:58:05 +01:00
Curtis Hard bd82c5d81b Only add the xlink namespace attribute on if required 2020-07-31 18:27:16 +01:00
Curtis Hard 145bbb17f8 Adds xml declaration removal to options 2020-07-29 20:13:01 +01:00
Curtis Hard d9f40551a4 Added ijsvg_isHexString for faster hex comparison 2020-07-27 12:06:03 +01:00
Curtis Hard 4448f6aeaf Small perf increase 2020-07-12 14:36:12 +01:00
Curtis Hard 6834abba19 Typo fix 2020-07-11 11:56:42 +01:00
Curtis Hard a86b4e80ba Refacator name 2020-07-09 16:32:20 +01:00
Curtis Hard 2e8d039599 Memory reductions 2020-06-27 19:00:38 +01:00
Curtis Hard 4ba6bb776d Xcode stuff 2020-06-27 12:28:35 +01:00
Curtis Hard 9c80412e88 Various image additions 2020-06-15 09:25:53 +01:00
Curtis Hard 509f0e0b0a Only allow removal of 0 if the float contains a floating point 2020-06-05 13:34:44 +01:00
Curtis Hard ce30877a26 Xcode stuff 2020-05-25 19:58:48 +01:00
Curtis Hard 122271bf36 Fixes for layer tree masking 2020-04-18 17:16:29 +01:00
Curtis Hard 28b4c6b85c Fixes issue with intrinsicSize size and dom being discarded 2020-03-01 18:19:38 +00:00
Curtis Hard 4b308d3a3e Wrong unit used 2020-02-27 08:33:16 +00:00
Curtis Hard d3ee05d8ac #oops 2020-02-25 08:29:59 +00:00
Curtis Hard 204b516e77 Fixes width and height not working correctly 2020-02-12 22:32:52 +00:00
Curtis Hard a832a986fd Swaps back to CATransaction 2020-01-16 20:37:48 +00:00
Curtis Hard f875714609 FOrmatting 2020-01-14 21:12:38 +00:00
Curtis Hard b8f166f4c1 Uses NSAnimationContext over CATransaction for safety 2020-01-14 21:12:33 +00:00
Curtis Hard 7901c9eafe Possible fixes for main thread 2020-01-14 20:41:59 +00:00
Curtis Hard 5de88cb1d7 #oopsie 2020-01-14 16:38:08 +00:00
Curtis Hard 6216b61c19 Fixes compat for 10.13 with CGPath block applying 2020-01-14 16:34:52 +00:00
Curtis Hard e05f5a0884 Fixes compatibility issues for 10.9 2020-01-14 15:51:15 +00:00
222 changed files with 69065 additions and 21691 deletions
+1
View File
@@ -0,0 +1 @@
.DS_Store
+5
View File
@@ -0,0 +1,5 @@
framework module IJSVG {
umbrella header "IJSVGUmbrella.h"
export *
module * { export * }
}
+273 -66
View File
@@ -3,40 +3,76 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 54;
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 */; };
5919111E28C7F1160047791B /* IJSVGBitFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 5919111C28C7F1160047791B /* IJSVGBitFlags.h */; settings = {ATTRIBUTES = (Public, ); }; };
5919111F28C7F1160047791B /* IJSVGBitFlags.m in Sources */ = {isa = PBXBuildFile; fileRef = 5919111D28C7F1160047791B /* IJSVGBitFlags.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 */; };
595FD12F29EC56BA00666897 /* IJSVGUmbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 595FD12E29EC56BA00666897 /* IJSVGUmbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
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 */; };
59DB84E028C9F70000A9696A /* IJSVGBitFlags64.h in Headers */ = {isa = PBXBuildFile; fileRef = 59DB84DE28C9F70000A9696A /* IJSVGBitFlags64.h */; settings = {ATTRIBUTES = (Public, ); }; };
59DB84E128C9F70000A9696A /* IJSVGBitFlags64.m in Sources */ = {isa = PBXBuildFile; fileRef = 59DB84DF28C9F70000A9696A /* IJSVGBitFlags64.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, ); }; };
59EB75DF23905F7300F5AE63 /* IJSVGWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E023905F7300F5AE63 /* IJSVGStyleSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E123905F7300F5AE63 /* IJSVGCommandSmoothCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75E223905F7300F5AE63 /* IJSVGColorList.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB757123905F6C00F5AE63 /* IJSVGColorList.m */; };
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, ); }; };
@@ -46,15 +82,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, ); }; };
59EB75FA23905F7300F5AE63 /* IJSVGWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758923905F6D00F5AE63 /* IJSVGWriter.m */; };
59EB75FB23905F7300F5AE63 /* IJSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758A23905F6D00F5AE63 /* IJSVGPath.m */; };
59EB75FC23905F7300F5AE63 /* IJSVGGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB75FD23905F7300F5AE63 /* IJSVGPatternLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */; };
59EB75FE23905F7300F5AE63 /* IJSVGRenderingStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */; };
59EB75FF23905F7300F5AE63 /* IJSVGBezierPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */; };
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 */; };
@@ -72,7 +104,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, ); }; };
@@ -80,10 +112,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, ); }; };
@@ -105,7 +137,6 @@
59EB763123905F7300F5AE63 /* IJSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C023905F7100F5AE63 /* IJSVGText.m */; };
59EB763223905F7300F5AE63 /* IJSVGView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C123905F7100F5AE63 /* IJSVGView.m */; };
59EB763323905F7300F5AE63 /* IJSVGLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */; };
59EB763423905F7300F5AE63 /* IJSVGBezierPathAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB763523905F7300F5AE63 /* IJSVGStyleSheetSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C423905F7100F5AE63 /* IJSVGStyleSheetSelector.m */; };
59EB763623905F7300F5AE63 /* IJSVGImageLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C523905F7100F5AE63 /* IJSVGImageLayer.m */; };
59EB763723905F7300F5AE63 /* IJSVGCommandClose.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75C623905F7100F5AE63 /* IJSVGCommandClose.m */; };
@@ -124,41 +155,90 @@
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 /* 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, ); }; };
59FCC09527F2394D00BB924E /* IJSVGRootNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 59FCC09327F2394D00BB924E /* IJSVGRootNode.m */; };
59FDBF0027F3454800AF7038 /* IJSVGColorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FDBEFE27F3454800AF7038 /* IJSVGColorNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
59FDBF0127F3454800AF7038 /* IJSVGColorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 59FDBEFF27F3454800AF7038 /* IJSVGColorNode.m */; };
59FE8E4328C7E70800AB38B3 /* IJSVGStop.m in Sources */ = {isa = PBXBuildFile; fileRef = 59FE8E4128C7E70800AB38B3 /* IJSVGStop.m */; };
59FE8E4428C7E70800AB38B3 /* IJSVGStop.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FE8E4228C7E70800AB38B3 /* IJSVGStop.h */; settings = {ATTRIBUTES = (Public, ); }; };
/* 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>"; };
5919111C28C7F1160047791B /* IJSVGBitFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGBitFlags.h; sourceTree = "<group>"; };
5919111D28C7F1160047791B /* IJSVGBitFlags.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGBitFlags.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; };
594CF473238FF38E009B251B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
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>"; };
595FD12E29EC56BA00666897 /* IJSVGUmbrella.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGUmbrella.h; sourceTree = "<group>"; };
596AB830298854270013110A /* IJSVG.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = IJSVG.modulemap; sourceTree = SOURCE_ROOT; };
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>"; };
59DB84DE28C9F70000A9696A /* IJSVGBitFlags64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGBitFlags64.h; sourceTree = "<group>"; };
59DB84DF28C9F70000A9696A /* IJSVGBitFlags64.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGBitFlags64.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>"; };
59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGWriter.h; sourceTree = "<group>"; };
59EB756F23905F6C00F5AE63 /* IJSVGStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheet.h; sourceTree = "<group>"; };
59EB757023905F6C00F5AE63 /* IJSVGCommandSmoothCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandSmoothCurve.h; sourceTree = "<group>"; };
59EB757123905F6C00F5AE63 /* IJSVGColorList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorList.m; sourceTree = "<group>"; };
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>"; };
@@ -168,15 +248,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>"; };
59EB758923905F6D00F5AE63 /* IJSVGWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGWriter.m; sourceTree = "<group>"; };
59EB758A23905F6D00F5AE63 /* IJSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPath.m; sourceTree = "<group>"; };
59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGroup.h; sourceTree = "<group>"; };
59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGPatternLayer.m; sourceTree = "<group>"; };
59EB758D23905F6D00F5AE63 /* IJSVGRenderingStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRenderingStyle.m; sourceTree = "<group>"; };
59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGBezierPathAdditions.m; sourceTree = "<group>"; };
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>"; };
@@ -194,7 +270,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>"; };
@@ -202,10 +278,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>"; };
@@ -227,7 +303,6 @@
59EB75C023905F7100F5AE63 /* IJSVGText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGText.m; sourceTree = "<group>"; };
59EB75C123905F7100F5AE63 /* IJSVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGView.m; sourceTree = "<group>"; };
59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGLinearGradient.m; sourceTree = "<group>"; };
59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGBezierPathAdditions.h; sourceTree = "<group>"; };
59EB75C423905F7100F5AE63 /* IJSVGStyleSheetSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetSelector.m; sourceTree = "<group>"; };
59EB75C523905F7100F5AE63 /* IJSVGImageLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImageLayer.m; sourceTree = "<group>"; };
59EB75C623905F7100F5AE63 /* IJSVGCommandClose.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandClose.m; sourceTree = "<group>"; };
@@ -246,6 +321,18 @@
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 /* 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>"; };
59FCC09327F2394D00BB924E /* IJSVGRootNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGRootNode.m; sourceTree = "<group>"; };
59FDBEFE27F3454800AF7038 /* IJSVGColorNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGColorNode.h; sourceTree = "<group>"; };
59FDBEFF27F3454800AF7038 /* IJSVGColorNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGColorNode.m; sourceTree = "<group>"; };
59FE8E4128C7E70800AB38B3 /* IJSVGStop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStop.m; sourceTree = "<group>"; };
59FE8E4228C7E70800AB38B3 /* IJSVGStop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStop.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -263,6 +350,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 = (
@@ -295,8 +391,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 */,
@@ -314,8 +410,10 @@
children = (
59EB758323905F6C00F5AE63 /* IJSVGColor.h */,
59EB758523905F6C00F5AE63 /* IJSVGColor.m */,
59EB75A923905F6F00F5AE63 /* IJSVGColorList.h */,
59EB757123905F6C00F5AE63 /* IJSVGColorList.m */,
59EB75A923905F6F00F5AE63 /* IJSVGTraitedColorStorage.h */,
59EB757123905F6C00F5AE63 /* IJSVGTraitedColorStorage.m */,
59F36506262F1ABB00BCE3FD /* IJSVGTraitedColor.h */,
59F36507262F1ABB00BCE3FD /* IJSVGTraitedColor.m */,
);
path = Colors;
sourceTree = "<group>";
@@ -333,12 +431,20 @@
59EB757B23905F6C00F5AE63 /* IJSVGLayer.m */,
59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */,
59EB758C23905F6D00F5AE63 /* IJSVGPatternLayer.m */,
59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */,
59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */,
59EB759723905F6D00F5AE63 /* IJSVGShapeLayer.h */,
59EB757A23905F6C00F5AE63 /* IJSVGShapeLayer.m */,
59EB75A423905F6E00F5AE63 /* IJSVGStrokeLayer.h */,
59EB757423905F6C00F5AE63 /* IJSVGStrokeLayer.m */,
590EB7A227F637EF0047CECF /* IJSVGTransformLayer.h */,
590EB7A327F637EF0047CECF /* IJSVGTransformLayer.m */,
5978C468280A241200D25296 /* IJSVGRootLayer.h */,
5978C469280A241200D25296 /* IJSVGRootLayer.m */,
595BA91A280EB29B00AD1C89 /* IJSVGFilterLayer.h */,
595BA91B280EB29B00AD1C89 /* IJSVGFilterLayer.m */,
59F38A61280ED99200804FE4 /* IJSVGBasicLayer.h */,
59F38A62280ED99200804FE4 /* IJSVGBasicLayer.m */,
5955731D286C643900156047 /* IJSVGTileLayer.h */,
5955731E286C643900156047 /* IJSVGTileLayer.m */,
);
path = Layers;
sourceTree = "<group>";
@@ -357,12 +463,15 @@
592ABBE72397A02900F44380 /* Nodes */ = {
isa = PBXGroup;
children = (
590AA093280DE648002BBE12 /* Filter Effects */,
59FE8E4228C7E70800AB38B3 /* IJSVGStop.h */,
59FE8E4128C7E70800AB38B3 /* IJSVGStop.m */,
59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */,
59EB75C923905F7200F5AE63 /* IJSVGForeignObject.m */,
59EB758623905F6C00F5AE63 /* IJSVGDef.h */,
59EB756923905F6B00F5AE63 /* IJSVGDef.m */,
59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */,
59EB75C223905F7100F5AE63 /* IJSVGLinearGradient.m */,
59EB757223905F6C00F5AE63 /* IJSVGRadialGradient.h */,
59EB75A623905F6F00F5AE63 /* IJSVGRadialGradient.m */,
59EB75AB23905F6F00F5AE63 /* IJSVGGradient.h */,
59EB75D223905F7300F5AE63 /* IJSVGGradient.m */,
59EB758B23905F6D00F5AE63 /* IJSVGGroup.h */,
@@ -377,6 +486,18 @@
59EB75AA23905F6F00F5AE63 /* IJSVGPattern.m */,
59EB756B23905F6B00F5AE63 /* IJSVGText.h */,
59EB75C023905F7100F5AE63 /* IJSVGText.m */,
59FCC09227F2394D00BB924E /* IJSVGRootNode.h */,
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>";
@@ -396,6 +517,26 @@
59EB75BA23905F7000F5AE63 /* IJSVGUnitLength.m */,
59EB759423905F6D00F5AE63 /* IJSVGUtils.h */,
59EB758023905F6C00F5AE63 /* IJSVGUtils.m */,
5919E65523F47FF60051873A /* IJSVGUnitRect.h */,
5919E65623F47FF60051873A /* IJSVGUnitRect.m */,
5919E65923F480330051873A /* IJSVGUnitPoint.h */,
5919E65A23F480330051873A /* IJSVGUnitPoint.m */,
59A24EBA23F480EA0090C374 /* IJSVGUnitSize.h */,
59A24EBB23F480EA0090C374 /* IJSVGUnitSize.m */,
591A3E4B25CC91F800AD45B7 /* IJSVGParsing.h */,
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 */,
5919111C28C7F1160047791B /* IJSVGBitFlags.h */,
5919111D28C7F1160047791B /* IJSVGBitFlags.m */,
59DB84DE28C9F70000A9696A /* IJSVGBitFlags64.h */,
59DB84DF28C9F70000A9696A /* IJSVGBitFlags64.m */,
);
path = Utils;
sourceTree = "<group>";
@@ -418,8 +559,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>";
@@ -427,10 +568,10 @@
592ABBEB2397A11800F44380 /* Additions */ = {
isa = PBXGroup;
children = (
59EB75C323905F7100F5AE63 /* IJSVGBezierPathAdditions.h */,
59EB758E23905F6D00F5AE63 /* IJSVGBezierPathAdditions.m */,
59EB75B823905F7000F5AE63 /* IJSVGStringAdditions.h */,
59EB757823905F6C00F5AE63 /* IJSVGStringAdditions.m */,
594A10D8248D7C90001A3181 /* NSImage+IJSVGAdditions.h */,
594A10D9248D7C90001A3181 /* NSImage+IJSVGAdditions.m */,
);
path = Additions;
sourceTree = "<group>";
@@ -455,6 +596,7 @@
594CF471238FF38E009B251B /* IJSVG */ = {
isa = PBXGroup;
children = (
596AB830298854270013110A /* IJSVG.modulemap */,
59EB756423905F3100F5AE63 /* Source */,
594CF473238FF38E009B251B /* Info.plist */,
);
@@ -478,14 +620,11 @@
59EB756A23905F6B00F5AE63 /* IJSVG.h */,
59EB75A223905F6E00F5AE63 /* IJSVG.m */,
59EB758423905F6C00F5AE63 /* IJSVGError.h */,
59EB758823905F6D00F5AE63 /* IJSVGFontConverter.h */,
59EB757C23905F6C00F5AE63 /* IJSVGFontConverter.m */,
59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */,
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */,
59EB75CD23905F7200F5AE63 /* IJSVGView.h */,
59EB75C123905F7100F5AE63 /* IJSVGView.m */,
59EB756E23905F6C00F5AE63 /* IJSVGWriter.h */,
59EB758923905F6D00F5AE63 /* IJSVGWriter.m */,
595FD12E29EC56BA00666897 /* IJSVGUmbrella.h */,
);
path = Core;
sourceTree = "<group>";
@@ -517,7 +656,6 @@
files = (
59EB762623905F7300F5AE63 /* IJSVGImage.h in Headers */,
59EB760823905F7300F5AE63 /* IJSVGShapeLayer.h in Headers */,
59EB75DF23905F7300F5AE63 /* IJSVGWriter.h in Headers */,
59EB760F23905F7300F5AE63 /* IJSVGCommandEllipticalArc.h in Headers */,
59EB75F523905F7300F5AE63 /* IJSVGError.h in Headers */,
59EB763E23905F7300F5AE63 /* IJSVGView.h in Headers */,
@@ -525,14 +663,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 */,
@@ -549,11 +686,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 */,
@@ -562,15 +698,40 @@
59EB75D623905F7300F5AE63 /* IJSVGLayer.h in Headers */,
59EB763023905F7300F5AE63 /* IJSVGPatternLayer.h in Headers */,
59EB75F023905F7300F5AE63 /* IJSVGStyleSheetSelectorRaw.h in Headers */,
59EB763423905F7300F5AE63 /* IJSVGBezierPathAdditions.h in Headers */,
59EB761823905F7300F5AE63 /* IJSVGParser.h in Headers */,
59EB761E23905F7300F5AE63 /* IJSVGGroupLayer.h in Headers */,
59EB761D23905F7300F5AE63 /* IJSVGStyle.h in Headers */,
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 */,
595FD12F29EC56BA00666897 /* IJSVGUmbrella.h in Headers */,
59F36508262F1ABB00BCE3FD /* IJSVGTraitedColor.h in Headers */,
59E7CFAF23B148600077D599 /* IJSVGCommandParser.h in Headers */,
59EB762823905F7300F5AE63 /* IJSVGCommandClose.h in Headers */,
59EB75E423905F7300F5AE63 /* IJSVGGradientUnitLength.h in Headers */,
59FCC09427F2394D00BB924E /* IJSVGRootNode.h in Headers */,
594A10DA248D7C90001A3181 /* NSImage+IJSVGAdditions.h in Headers */,
59EB762D23905F7300F5AE63 /* IJSVGLayerTree.h in Headers */,
59FDBF0027F3454800AF7038 /* IJSVGColorNode.h in Headers */,
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 */,
5919111E28C7F1160047791B /* IJSVGBitFlags.h in Headers */,
59FE8E4428C7E70800AB38B3 /* IJSVGStop.h in Headers */,
5955731F286C643900156047 /* IJSVGTileLayer.h in Headers */,
59DB84E028C9F70000A9696A /* IJSVGBitFlags64.h in Headers */,
59EB760B23905F7300F5AE63 /* IJSVGStyleSheetSelector.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -602,7 +763,8 @@
594CF466238FF38E009B251B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1100;
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1520;
ORGANIZATIONNAME = "Curtis Hard";
TargetAttributes = {
594CF46E238FF38E009B251B = {
@@ -643,17 +805,27 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
592607A0287D6C1000E93B09 /* IJSVGFeatureFlags.m in Sources */,
59FE8E4328C7E70800AB38B3 /* IJSVGStop.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 */,
590AA097280DE668002BBE12 /* IJSVGFilterEffectGaussianBlur.m in Sources */,
59F36509262F1ABB00BCE3FD /* IJSVGTraitedColor.m in Sources */,
59EB760123905F7300F5AE63 /* IJSVGLayerTree.m in Sources */,
59DB84E128C9F70000A9696A /* IJSVGBitFlags64.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 */,
594A10DB248D7C90001A3181 /* NSImage+IJSVGAdditions.m in Sources */,
59EB761923905F7300F5AE63 /* IJSVGCommandSmoothCurve.m in Sources */,
59EB761323905F7300F5AE63 /* IJSVG.m in Sources */,
59EB763623905F7300F5AE63 /* IJSVGImageLayer.m in Sources */,
@@ -661,39 +833,50 @@
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 */,
5919111F28C7F1160047791B /* IJSVGBitFlags.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 */,
59EB75FF23905F7300F5AE63 /* IJSVGBezierPathAdditions.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 */,
59EB760023905F7300F5AE63 /* IJSVGGradientLayer.m in Sources */,
59EB762B23905F7300F5AE63 /* IJSVGUnitLength.m in Sources */,
59EB75F823905F7300F5AE63 /* IJSVGCommandHorizontalLine.m in Sources */,
59EB75FA23905F7300F5AE63 /* IJSVGWriter.m in Sources */,
59EB764623905F7300F5AE63 /* IJSVGRendering.m in Sources */,
59EB762E23905F7300F5AE63 /* IJSVGExporter.m in Sources */,
59EB761623905F7300F5AE63 /* IJSVGParser.m in Sources */,
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 */,
59EB762223905F7300F5AE63 /* IJSVGMath.m in Sources */,
59FCC09527F2394D00BB924E /* IJSVGRootNode.m in Sources */,
59EB763D23905F7300F5AE63 /* IJSVGGroup.m in Sources */,
59EB761F23905F7300F5AE63 /* IJSVGCommandLineTo.m in Sources */,
59EB75F123905F7300F5AE63 /* IJSVGUtils.m in Sources */,
@@ -731,6 +914,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -739,13 +923,18 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
ENABLE_MODULE_VERIFIER = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREFIX_HEADER = "";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
@@ -756,10 +945,14 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MODULEMAP_FILE = IJSVG.modulemap;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_MODULE_NAME = IJSVG;
SDKROOT = macosx;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -792,6 +985,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -800,20 +994,29 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
ENABLE_MODULE_VERIFIER = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREFIX_HEADER = "";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MODULEMAP_FILE = IJSVG.modulemap;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_MODULE_NAME = IJSVG;
SDKROOT = macosx;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -823,13 +1026,14 @@
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_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = NO;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 9KTR4W9XX6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -841,6 +1045,7 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
@@ -851,13 +1056,14 @@
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_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = NO;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 9KTR4W9XX6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -869,6 +1075,7 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1130"
LastUpgradeVersion = "1520"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -15,7 +15,7 @@
<key>594CF46E238FF38E009B251B</key>
<dict>
<key>primary</key>
<true/>
<true />
</dict>
</dict>
</dict>
+1 -1
View File
@@ -19,6 +19,6 @@
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 Curtis Hard. All rights reserved.</string>
<string>Copyright © 2020 Curtis Hard. All rights reserved.</string>
</dict>
</plist>
@@ -1,19 +0,0 @@
//
// IJSVGBezierPathAdditions.h
// IconJar
//
// Created by Curtis Hard on 30/08/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
@interface NSBezierPath (IJSVGAdditions)
- (void)addQuadCurveToPoint:(NSPoint)aPoint
controlPoint:(NSPoint)cp;
- (CGPathRef)newCGPathRef:(BOOL)autoClose;
@end
@@ -1,87 +0,0 @@
//
// IJSVGBezierPathAdditions.m
// IconJar
//
// Created by Curtis Hard on 30/08/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGBezierPathAdditions.h"
@implementation NSBezierPath (IJSVGAdditions)
- (void)addQuadCurveToPoint:(CGPoint)QP2
controlPoint:(CGPoint)QP1
{
CGPoint QP0 = [self currentPoint];
CGPoint CP3 = QP2;
CGPoint CP1 = CGPointMake(QP0.x + ((2.0 / 3.0) * (QP1.x - QP0.x)), QP0.y + ((2.0 / 3.0) * (QP1.y - QP0.y)));
CGPoint CP2 = CGPointMake(QP2.x + (2.0 / 3.0) * (QP1.x - QP2.x), QP2.y + (2.0 / 3.0) * (QP1.y - QP2.y));
[self curveToPoint:CP3
controlPoint1:CP1
controlPoint2:CP2];
}
- (CGPathRef)newCGPathRef:(BOOL)autoClose
{
NSInteger i = 0;
NSInteger numElements = self.elementCount;
NSBezierPath* bezPath = self;
// nothing to return
if (numElements == 0) {
return NULL;
}
CGMutablePathRef aPath = CGPathCreateMutable();
NSPoint points[3];
BOOL didClosePath = YES;
for (i = 0; i < numElements; i++) {
switch ([bezPath elementAtIndex:i associatedPoints:points]) {
// move
case NSMoveToBezierPathElement: {
CGPathMoveToPoint(aPath, NULL, points[0].x, points[0].y);
break;
}
// line
case NSLineToBezierPathElement: {
CGPathAddLineToPoint(aPath, NULL, points[0].x, points[0].y);
didClosePath = NO;
break;
}
// curve
case NSCurveToBezierPathElement: {
CGPathAddCurveToPoint(aPath, NULL, points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
didClosePath = NO;
break;
}
// close
case NSClosePathBezierPathElement: {
CGPathCloseSubpath(aPath);
didClosePath = YES;
break;
}
}
}
if (!didClosePath && autoClose) {
CGPathCloseSubpath(aPath);
}
// create immutable and release
CGPathRef pathToReturn = CGPathCreateCopy(aPath);
CGPathRelease(aPath);
return pathToReturn;
}
@end
@@ -14,5 +14,6 @@
- (BOOL)ijsvg_isNumeric;
- (BOOL)ijsvg_containsAlpha;
- (NSArray*)ijsvg_componentsSplitByWhiteSpace;
- (BOOL)ijsvg_isHexString;
@end
@@ -6,52 +6,39 @@
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGStringAdditions.h"
#import <IJSVG/IJSVGStringAdditions.h>
#import <IJSVG/IJSVGUtils.h>
@implementation NSString (IJSVGAdditions)
- (NSArray<NSString*>*)ijsvg_componentsSeparatedByChars:(const char*)aChar
{
NSMutableArray* comp = [[[NSMutableArray alloc] init] autorelease];
NSInteger length = self.length;
unichar* chars = (unichar*)calloc(sizeof(unichar), self.length);
NSInteger ind = 0;
BOOL startedString = NO;
const char* buffer = self.UTF8String;
for (NSInteger i = 0; i < length; i++) {
unichar theChar = buffer[i];
// start the buffer
BOOL isEqualToChar = strchr(aChar, theChar) != NULL;
if (isEqualToChar == NO) {
startedString = YES;
chars[ind++] = theChar;
}
// has started and char is the search char, or its at end
if ((startedString == YES && isEqualToChar) || (i == (length - 1) && startedString == YES)) {
startedString = NO;
// append the comp
[comp addObject:[NSString stringWithCharacters:chars length:ind]];
// restart and realloc the memory
ind = 0;
chars = memset(chars, '\0', sizeof(unichar) * ind);
}
char* chars = (char*)self.UTF8String;
if(chars == NULL || strlen(chars) == 0) {
return @[];
}
free(chars);
return comp;
NSMutableArray<NSString*>* strings = nil;
strings = [[NSMutableArray alloc] init];
char* copy = strdup(chars);
char* spt = NULL;
char* ptr = strtok_r(copy, aChar, &spt);
while(ptr != NULL) {
NSString* possibleString = nil;
if((possibleString = [NSString stringWithUTF8String:ptr]) != nil) {
[strings addObject:possibleString];
}
ptr = strtok_r(NULL, aChar, &spt);
}
(void)free(copy), copy = NULL;
return strings;
}
- (BOOL)ijsvg_containsAlpha
{
const char* buffer = self.UTF8String;
unsigned long length = strlen(buffer);
for (int i = 0; i < length; i++) {
if (isalpha(buffer[i])) {
char currentChar;
while((currentChar = *buffer++) ) {
if(isalpha(currentChar)) {
return YES;
}
}
@@ -61,9 +48,9 @@
- (BOOL)ijsvg_isNumeric
{
const char* buffer = self.UTF8String;
unsigned long length = strlen(buffer);
for (int i = 0; i < length; i++) {
if (!isnumber(buffer[i])) {
char currentChar;
while((currentChar = *buffer++) ) {
if(!isnumber(currentChar)) {
return NO;
}
}
@@ -75,4 +62,10 @@
return [self ijsvg_componentsSeparatedByChars:"\t\n\r "];
}
- (BOOL)ijsvg_isHexString
{
const char* chars = self.UTF8String;
return IJSVGCharBufferIsHEX((char*)chars);
}
@end
@@ -0,0 +1,18 @@
//
// NSImage+IJSVGAdditions.h
// IJSVG
//
// Created by Curtis Hard on 07/06/2020.
// Copyright © 2020 Curtis Hard. All rights reserved.
//
#import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>
IJSVG* IJSVGGetFromNSImage(NSImage* image);
@interface NSImage (IJSVGAdditions)
+ (NSImage*)SVGImageNamed:(NSString*)imageName;
@end
@@ -0,0 +1,53 @@
//
// NSImage+IJSVGAdditions.m
// IJSVG
//
// Created by Curtis Hard on 07/06/2020.
// Copyright © 2020 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGImageRep.h>
#import <IJSVG/NSImage+IJSVGAdditions.h>
IJSVG* IJSVGGetFromNSImage(NSImage* image)
{
for (NSImageRep* rep in image.representations) {
if([rep isKindOfClass:IJSVGImageRep.class]) {
return ((IJSVGImageRep*)rep).SVG;
}
}
return nil;
}
@implementation NSImage (IJSVGAdditions)
+ (NSImage*)SVGImageNamed:(NSString*)imageName
{
// find the image
NSBundle* bundle = NSBundle.mainBundle;
NSString* str = nil;
NSString* ext = imageName.pathExtension;
if(ext == nil || ext.length == 0) {
ext = @"svg";
}
if((str = [bundle pathForResource:imageName.stringByDeletingPathExtension
ofType:ext])
!= nil) {
// work out if we can get the data
NSData* data = [[NSData alloc] initWithContentsOfFile:str];
if(data == nil) {
return nil;
}
// grab the image rep
IJSVGImageRep* rep = [[IJSVGImageRep alloc] initWithData:data];
NSImage* image = [[NSImage alloc] init];
[image addRepresentation:rep];
return image;
}
return nil;
}
@end
@@ -167,6 +167,8 @@ typedef NS_ENUM(NSInteger, IJSVGPredefinedColor) {
IJSVGColorYellowgreen
};
extern NSString* const IJSVGColorCurrentColorName;
@interface IJSVGColor : NSObject
CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness);
@@ -179,6 +181,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
+ (NSString*)colorStringFromColor:(NSColor*)color;
+ (NSColor*)colorFromHEXInteger:(NSInteger)hex;
+ (NSColor*)computeColor:(id)colour;
+ (BOOL)isNoneOrTransparent:(NSString*)string;
+ (NSColor*)colorFromString:(NSString*)string;
+ (NSColor*)colorFromHEXString:(NSString*)string;
+ (NSColor*)colorFromHEXString:(NSString*)string
+126 -76
View File
@@ -6,13 +6,19 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGColor.h"
#import "IJSVGUtils.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";
@implementation IJSVGColor
static NSDictionary* _colorTree = nil;
CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness)
{
hue *= (1.f / 360.f);
@@ -23,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));
@@ -46,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;
@@ -56,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),
@@ -202,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;
}
@@ -239,39 +245,71 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
alpha:a]];
}
+ (BOOL)isNoneOrTransparent:(NSString*)string
{
const char* str = string.UTF8String;
return IJSVGCharBufferCaseInsensitiveCompare(str, "none") == YES ||
IJSVGCharBufferCaseInsensitiveCompare(str, "transparent") == YES;
}
+ (NSColor*)colorFromString:(NSString*)string
{
NSCharacterSet* set = NSCharacterSet.whitespaceAndNewlineCharacterSet;
string = [string stringByTrimmingCharactersInSet:set];
if ([string length] < 3) {
// swap over to C for performance
if(string == nil) {
return nil;
}
NSColor* color = nil;
string = [string lowercaseString];
if ([self.class isHex:string] == NO) {
color = [self.class colorFromPredefinedColorName:string];
if (color != nil) {
return color;
}
const char* oString = string.UTF8String;
if(strlen(oString) == 0) {
return nil;
}
// is simply a clear color, dont fill
if ([string.lowercaseString isEqualToString:@"none"] ||
[string.lowercaseString isEqualToString:@"transparent"]) {
return [self computeColorSpace:NSColor.clearColor];
char* str = IJSVGTimmedCharBufferCreate(oString);
if(IJSVGCharBufferIsHEX(str) == YES) {
string = [NSString stringWithUTF8String:str];
(void)free(str), str = NULL;
return [self.class colorFromHEXString:string];
}
// is it RGB?
if ([string hasPrefix:@"rgb"] == YES) {
NSRange range = [IJSVGUtils rangeOfParentheses:string];
NSString* rgbString = [string substringWithRange:range];
NSArray* parts = [rgbString ijsvg_componentsSeparatedByChars:","];
if(IJSVGCharBufferHasPrefix(str, "rgb") == YES) {
NSUInteger count = 0;
IJSVGParsingStringMethod** methods = NULL;
methods = IJSVGParsingMethodParseString(str, &count);
IJSVGParsingStringMethod* method = methods[0];
// memory clean for the string
(void)free(str), str = NULL;
// nothing to return, just mem clean and get out of here
if(count == 0 || methods == NULL) {
if(methods != NULL) {
IJSVGParsingStringMethodsRelease(methods, count);
methods = NULL;
}
return nil;
}
// Make sure we have actual floats within the parameters
NSInteger floatCount = 0;
CGFloat *params = [IJSVGUtils scanFloatsFromCString:method->parameters
size:&floatCount];
(void)free(params), params = NULL;
if(floatCount < 3) {
return [self computeColorSpace:NSColor.blackColor];
}
// Make sure the floats are not negative
// parse the parameters
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];
}
IJSVGParsingStringMethodsRelease(methods, count);
methods = NULL;
return [self colorFromRString:parts[0]
gString:parts[1]
bString:parts[2]
@@ -279,39 +317,48 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
}
// is it HSL?
if ([string hasPrefix:@"hsl"]) {
if(IJSVGCharBufferHasPrefix(str, "hsl")) {
NSInteger count = 0;
CGFloat* params = [IJSVGUtils commandParameters:string
count:&count];
CGFloat* params = [IJSVGUtils scanFloatsFromCString:str
size:&count];
CGFloat alpha = 1;
if (count == 4) {
if(count == 4) {
alpha = params[3];
}
// convert HSL to HSB
CGFloat* hsb = IJSVGColorCSSHSLToHSB(params[0], params[1], params[2]);
color = [NSColor colorWithDeviceHue:hsb[0]
saturation:hsb[1]
brightness:hsb[2]
alpha:alpha];
NSColor* color = [NSColor colorWithDeviceHue:hsb[0]
saturation:hsb[1]
brightness:hsb[2]
alpha:alpha];
color = [self computeColorSpace:color];
// memory clean!
free(hsb);
free(params);
(void)free(str), str = NULL;
(void)free(hsb), hsb = NULL;
(void)free(params), params = NULL;
return color;
}
color = [self.class colorFromHEXString:string];
return color;
// is simply a clear color, dont fill
if(IJSVGCharBufferCompare(str, "none") == YES ||
IJSVGCharBufferCompare(str, "transparent") == YES) {
(void)free(str), str = NULL;
return nil;
}
// could return nil
(void)free(str), str = NULL;
return [self.class colorFromPredefinedColorName:string];
}
+ (NSColor*)colorFromPredefinedColorName:(NSString*)name
{
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];
@@ -340,33 +387,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",
@@ -377,7 +424,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)];
}
@@ -707,14 +754,7 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
+ (BOOL)isHex:(NSString*)string
{
const char* validList = "0123456789ABCDEFabcdef#";
for (NSInteger i = 0; i < string.length; i++) {
char c = [string characterAtIndex:i];
if (strchr(validList, c) == NULL) {
return NO;
}
}
return YES;
return string.ijsvg_isHexString;
}
+ (unsigned long)lengthOfHEXInteger:(NSUInteger)hex
@@ -734,7 +774,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;
}
@@ -760,29 +800,39 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
containsAlphaComponent:(BOOL*)containsAlphaComponent
{
// absolutely no string
if (string == nil || string.length == 0 || ![self.class isHex:string]) {
if(string == nil) {
return nil;
}
char* str = (char*)string.UTF8String;
size_t length = strlen(str);
if(length == 0 || IJSVGCharBufferIsHEX(str) == NO) {
return nil;
}
if ([string hasPrefix:@"#"] == YES) {
string = [string substringFromIndex:1];
// remove the hash from the front of the string
if(str[0] == '#') {
length--;
str++;
}
// whats the length?
NSUInteger length = string.length;
if (length == 3 || length == 4) {
// shorthand...
NSMutableString* str = [[[NSMutableString alloc] init] autorelease];
for (NSInteger i = 0; i < length; i++) {
NSString* sub = [string substringWithRange:NSMakeRange(i, 1)];
[str appendFormat:@"%@%@", sub, sub];
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) {
char* chars = NULL;
chars = (char*)calloc(sizeof(char),length*2+1);
for(int i = 0; i < length; i++) {
chars[i*2] = chars[i*2+1] = str[i];
}
string = str;
hex = strtoul(chars, NULL, 16);
(void)free(chars), chars = NULL;
} else {
hex = strtoul(str, NULL, 16);
}
// now convert rest to hex
unsigned long hex = [self HEXFromArbitraryHexString:string];
if (containsAlphaComponent != nil) {
if(containsAlphaComponent != nil) {
*containsAlphaComponent = [self HEXContainsAlphaComponent:hex];
}
return [self colorFromHEXInteger:hex];
@@ -1,31 +0,0 @@
//
// IJSVGColorList.h
// IconJar
//
// Created by Curtis Hard on 07/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGColor.h"
#import <Foundation/Foundation.h>
@interface IJSVGColorList : NSObject <NSCopying> {
@private
NSMutableDictionary<NSColor*, NSColor*>* _replacementColorTree;
NSMutableSet<NSColor*>* _colors;
}
- (NSColor*)proposedColorForColor:(NSColor*)color;
- (void)removeAllReplacementColors;
- (void)removeReplacementColor:(NSColor*)color;
- (void)setReplacementColor:(NSColor*)newColor
forColor:(NSColor*)color;
- (void)setReplacementColors:(NSDictionary<NSColor*, NSColor*>*)colors
clearExistingColors:(BOOL)clearExistingColors;
- (void)addColorsFromList:(IJSVGColorList*)sheet;
- (NSSet<NSColor*>*)colors;
- (void)addColor:(NSColor*)color;
@end
@@ -1,112 +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<NSColor*>*)colors
{
return [NSSet setWithSet:_colors];
}
- (void)addColorsFromList:(IJSVGColorList*)sheet
{
[_colors addObjectsFromArray:sheet.colors.allObjects];
}
- (void)addColor:(NSColor*)color
{
[_colors addObject:[IJSVGColor computeColorSpace:color]];
}
- (void)removeColor:(NSColor*)color
{
[_colors removeObject:[IJSVGColor computeColorSpace:color]];
}
@end
@@ -0,0 +1,32 @@
//
// 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*)typeWithColor:(NSColor*)color
traits:(IJSVGColorUsageTraits)mask;
@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
@@ -6,8 +6,8 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandParser.h"
#import "IJSVGPath.h"
#import <IJSVG/IJSVGCommandParser.h>
#import <IJSVG/IJSVGPath.h>
#import <Foundation/Foundation.h>
static const NSInteger IJSVGCustomVariableParameterCount = NSNotFound;
@@ -17,25 +17,16 @@ typedef NS_ENUM(NSInteger, IJSVGCommandType) {
kIJSVGCommandTypeRelative
};
@interface IJSVGCommand : NSObject {
NSString* commandString;
char command;
CGFloat* parameters;
NSInteger parameterCount;
NSArray<IJSVGCommand*>* subCommands;
NSInteger requiredParameters;
IJSVGCommandType type;
IJSVGCommand* previousCommand;
@interface IJSVGCommand : NSObject <NSCopying> {
@private
NSInteger _currentIndex;
BOOL isSubCommand;
}
@property (nonatomic, copy) NSString* commandString;
@property (nonatomic, assign) char command;
@property (nonatomic, assign) CGFloat* parameters;
@property (nonatomic, assign) NSInteger parameterCount;
@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;
@@ -49,17 +40,30 @@ typedef NS_ENUM(NSInteger, IJSVGCommandType) {
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path;
path:(CGMutablePathRef)path;
+ (void)parseParams:(CGFloat*)params
paramCount:(NSInteger)paramCount
intoArray:(NSMutableArray<IJSVGCommand*>*)commands
parentCommand:(IJSVGCommand*)parentCommand;
- (id)initWithCommandString:(NSString*)str
dataStream:(IJSVGPathDataStream*)dataStream;
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer;
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer
dataStream:(IJSVGPathDataStream*)dataStream;
+ (CGMutablePathRef)newPathForCommandsArray:(NSArray<IJSVGCommand*>*)commands;
+ (NSArray<IJSVGCommand*>*)convertCommands:(NSArray<IJSVGCommand*>*)commands
toUnits:(IJSVGUnitType)unitType
bounds:(CGRect)bounds;
- (id)initWithCommandStringBuffer:(const char*)str
dataStream:(IJSVGPathDataStream*)dataStream;
- (IJSVGCommand*)subcommandWithParameters:(CGFloat*)subParams
paramCount:(NSInteger)paramCount
previousCommand:(IJSVGCommand*)command;
- (void)convertToUnits:(IJSVGUnitType)units
boundingBox:(CGRect)boundingBox;
- (IJSVGCommand*)commandByConvertingToUnits:(IJSVGUnitType)unitType
boundingBox:(CGRect)boundingBox;
- (CGFloat)readFloat;
- (NSPoint)readPoint;
@@ -6,31 +6,22 @@
// 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
@synthesize commandString;
@synthesize command;
@synthesize parameterCount;
@synthesize parameters;
@synthesize subCommands;
@synthesize type;
@synthesize previousCommand;
@synthesize isSubCommand;
+ (BOOL)requiresCustomParameterParsing
{
return NO;
@@ -51,7 +42,7 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
}
@@ -101,39 +92,139 @@
return nil;
}
- (void)dealloc
+ (CGMutablePathRef)newPathForCommandsArray:(NSArray<IJSVGCommand*>*)commands
{
(void)([commandString release]), commandString = nil;
(void)([subCommands release]), subCommands = nil;
if (parameters) {
(void)(free(parameters)), parameters = nil;
CGMutablePathRef path = CGPathCreateMutable();
IJSVGCommand* preCommand = nil;
for(IJSVGCommand* command in commands) {
for (IJSVGCommand* subCommand in command.subCommands) {
[command.class runWithParams:subCommand.parameters
paramCount:subCommand.parameterCount
command:subCommand
previousCommand:preCommand
type:subCommand.type
path:path];
preCommand = subCommand;
}
}
[super dealloc];
return path;
}
- (id)initWithCommandString:(NSString*)str
dataStream:(IJSVGPathDataStream*)dataStream
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)buffer
{
if ((self = [super init]) != nil) {
IJSVGThreadManager* manager = IJSVGThreadManager.currentManager;
NSArray<IJSVGCommand*>* commands = [self commandsForDataCharacters:buffer
dataStream:manager.pathDataStream];
return commands;
}
+ (NSArray<IJSVGCommand*>*)commandsForDataCharacters:(const char*)unsafeBuffer
dataStream:(IJSVGPathDataStream*)dataStream
{
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(bufferLength);
NSInteger start = 0;
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) {
// copy memory from current buffer
NSInteger index = ((i + 1) - start);
memcpy(&charBuffer[0], &buffer[start], sizeof(char)*index);
charBuffer[index] = '\0';
// create the command from the substring
unsigned long length = index + 1;
size_t mlength = sizeof(char)*length;
char* commandString = (char*)malloc(mlength);
memcpy(commandString, &charBuffer[0], mlength);
// reset start position
start = (i + 1);
// previous command is actual subcommand
Class commandClass = [IJSVGCommand commandClassForCommandChar:commandString[0]];
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;
}
+ (NSArray<IJSVGCommand*>*)convertCommands:(NSArray<IJSVGCommand*>*)commands
toUnits:(IJSVGUnitType)unitType
bounds:(CGRect)bounds
{
NSMutableArray<IJSVGCommand*>* newCommands = nil;
newCommands = [[NSMutableArray alloc] initWithCapacity:commands.count];
for(IJSVGCommand* command in commands) {
IJSVGCommand* nCommand = [command commandByConvertingToUnits:unitType
boundingBox:bounds];
[newCommands addObject:nCommand];
}
return newCommands;
}
- (void)dealloc
{
if(_parameters) {
(void)(free(_parameters)), _parameters = nil;
}
}
- (id)initWithCommandStringBuffer:(const char*)str
dataStream:(IJSVGPathDataStream*)dataStream
{
if((self = [super init]) != nil) {
// work out the basics
_currentIndex = 0;
command = [str characterAtIndex:0];
type = [IJSVGUtils typeForCommandChar:command];
_command = str[0];
_type = [IJSVGUtils typeForCommandChar:_command];
NSInteger sets = 0;
NSInteger paramCount = [self.class requiredParameterCount];
IJSVGPathDataSequence* sequence = [self.class pathDataSequence];
parameters = IJSVGParsePathDataStreamSequence(str.UTF8String, str.length,
dataStream, sequence, [self.class requiredParameterCount], &sets);
_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;
@@ -154,17 +245,47 @@
}
// store the retained value
subCommands = subCommandArray.copy;
_subCommands = subCommandArray.copy;
}
}
return self;
}
- (void)setSubCommands:(NSArray<IJSVGCommand*>*)subCommands
{
_subCommands = subCommands;
}
- (id)copyWithZone:(NSZone *)zone
{
IJSVGCommand* command = [[self.class alloc] init];
command.type = self.type;
command.command = self.command;
command.isSubCommand = self.isSubCommand;
command.parameterCount = self.parameterCount;
size_t memsize = sizeof(CGFloat)*self.parameterCount;
command.parameters = (CGFloat*)malloc(memsize);
memcpy(command.parameters, self.parameters, memsize);
IJSVGCommand* lastCommand = nil;
NSMutableArray<IJSVGCommand*>* subcommands = nil;
subcommands = [[NSMutableArray alloc] initWithCapacity:self.subCommands.count];
for(IJSVGCommand* subcommand in self.subCommands) {
IJSVGCommand* subCopy = subcommand.copy;
subCopy.previousCommand = lastCommand;
subCopy.isSubCommand = lastCommand != nil;
[subcommands addObject:subCopy];
}
command.subCommands = subcommands;
return command;
}
- (CGFloat*)parametersFromIndexOffset:(NSInteger)index
{
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);
}
@@ -176,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;
@@ -188,15 +309,15 @@
- (CGFloat)readFloat
{
CGFloat f = parameters[_currentIndex];
CGFloat f = _parameters[_currentIndex];
_currentIndex++;
return f;
}
- (NSPoint)readPoint
{
CGFloat x = parameters[_currentIndex];
CGFloat y = parameters[_currentIndex + 1];
CGFloat x = _parameters[_currentIndex];
CGFloat y = _parameters[_currentIndex + 1];
_currentIndex += 2;
return NSMakePoint(x, y);
}
@@ -211,4 +332,34 @@
_currentIndex = 0;
}
- (void)convertToUnits:(IJSVGUnitType)units
boundingBox:(CGRect)boundingBox
{
for(IJSVGCommand* command in _subCommands) {
[command convertToUnits:units
boundingBox:boundingBox];
}
}
- (NSString *)description
{
NSMutableString* str = [[NSMutableString alloc] init];
[str appendFormat:@"%c ",_command];
NSMutableArray* args = [[NSMutableArray alloc] initWithCapacity:_parameterCount];
for(int i = 0; i < _parameterCount; i++) {
[args addObject:[NSString stringWithFormat:@"%f",_parameters[i]]];
}
[str appendString:[args componentsJoinedByString:@", "]];
return str;
}
- (IJSVGCommand*)commandByConvertingToUnits:(IJSVGUnitType)unitType
boundingBox:(CGRect)boundingBox
{
IJSVGCommand* copy = self.copy;
[copy convertToUnits:unitType
boundingBox:boundingBox];
return copy;
}
@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
@@ -20,9 +20,9 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
[path close];
CGPathCloseSubpath(path);
}
@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 IJSVGCommandCurve : IJSVGCommand
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandCurve.h"
#import <IJSVG/IJSVGCommandCurve.h>
@implementation IJSVGCommandCurve
@@ -20,17 +20,19 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
[path.path curveToPoint:NSMakePoint(params[4], params[5])
controlPoint1:NSMakePoint(params[0], params[1])
controlPoint2:NSMakePoint(params[2], params[3])];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddCurveToPoint(path, NULL, params[0], params[1],
params[2], params[3],
params[4], params[5]);
return;
}
[path.path relativeCurveToPoint:NSMakePoint(params[4], params[5])
controlPoint1:NSMakePoint(params[0], params[1])
controlPoint2:NSMakePoint(params[2], params[3])];
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPathAddCurveToPoint(path, NULL,
currentPoint.x + params[0], currentPoint.y + params[1],
currentPoint.x + params[2], currentPoint.y + params[3],
currentPoint.x + params[4], currentPoint.y + params[5]);
}
@end
@@ -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
@@ -20,7 +20,8 @@ static IJSVGPathDataSequence* _sequence;
+ (IJSVGPathDataSequence*)pathDataSequence
{
if(_sequence == NULL) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sequence = (IJSVGPathDataSequence*)malloc(sizeof(IJSVGPathDataSequence) * 7);
_sequence[0] = kIJSVGPathDataSequenceTypeFloat;
_sequence[1] = kIJSVGPathDataSequenceTypeFloat;
@@ -29,96 +30,110 @@ static IJSVGPathDataSequence* _sequence;
_sequence[4] = kIJSVGPathDataSequenceTypeFlag;
_sequence[5] = kIJSVGPathDataSequenceTypeFloat;
_sequence[6] = kIJSVGPathDataSequenceTypeFloat;
}
});
return _sequence;
}
// modified from https://github.com/SVGKit/SVGKit/blob/880c94a5b77b6f22beb491a7a7e02ace220c32af/Source/Parsers/SVGKPointsAndPathsParser.m
+ (void)runWithParams:(CGFloat*)params
paramCount:(NSInteger)count
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
CGPoint radii = CGPointZero;
CGPoint arcEndPoint = CGPointZero;
CGPoint arcStartPoint = path.currentPoint;
CGFloat xAxisRotation = 0;
BOOL largeArcFlag = 0;
BOOL sweepFlag = 0;
radii = [currentCommand readPoint];
xAxisRotation = [currentCommand readFloat];
largeArcFlag = [currentCommand readBOOL];
sweepFlag = [currentCommand readBOOL];
arcEndPoint = [currentCommand readPoint];
if (type == kIJSVGCommandTypeRelative) {
arcEndPoint.x += path.currentPoint.x;
arcEndPoint.y += path.currentPoint.y;
}
CGPoint pathCurrentPoint = CGPathGetCurrentPoint(path);
CGFloat xAxisRotation = 0.f;
BOOL largeArcFlag = NO;
BOOL sweepFlag = NO;
radii = currentCommand.readPoint;
xAxisRotation = currentCommand.readFloat;
largeArcFlag = currentCommand.readBOOL;
sweepFlag = currentCommand.readBOOL;
arcEndPoint = currentCommand.readPoint;
CGFloat rx = fabs(radii.x);
CGFloat ry = fabs(radii.y);
xAxisRotation *= M_PI / 180.f;
CGPoint currentPoint = CGPointMake(cos(xAxisRotation) * (arcStartPoint.x - arcEndPoint.x) / 2.0 + sin(xAxisRotation) * (arcStartPoint.y - arcEndPoint.y) / 2.0, -sin(xAxisRotation) * (arcStartPoint.x - arcEndPoint.x) / 2.0 + cos(xAxisRotation) * (arcStartPoint.y - arcEndPoint.y) / 2.0);
xAxisRotation = fmod(xAxisRotation, 2.f * M_PI);
CGFloat radiiAdjustment = pow(currentPoint.x, 2) / pow(radii.x, 2) + pow(currentPoint.y, 2) / pow(radii.y, 2);
radii.x *= (radiiAdjustment > 1) ? sqrt(radiiAdjustment) : 1;
radii.y *= (radiiAdjustment > 1) ? sqrt(radiiAdjustment) : 1;
CGFloat sweep = (largeArcFlag == sweepFlag ? -1 : 1) * sqrt(((pow(radii.x, 2) * pow(radii.y, 2)) - (pow(radii.x, 2) * pow(currentPoint.y, 2)) - (pow(radii.y, 2) * pow(currentPoint.x, 2))) / (pow(radii.x, 2) * pow(currentPoint.y, 2) + pow(radii.y, 2) * pow(currentPoint.x, 2)));
sweep = (sweep != sweep) ? 0 : sweep;
CGPoint preCenterPoint = CGPointMake(sweep * radii.x * currentPoint.y / radii.y, sweep * -radii.y * currentPoint.x / radii.x);
CGPoint centerPoint = CGPointMake((arcStartPoint.x + arcEndPoint.x) / 2.0 + cos(xAxisRotation) * preCenterPoint.x - sin(xAxisRotation) * preCenterPoint.y, (arcStartPoint.y + arcEndPoint.y) / 2.0 + sin(xAxisRotation) * preCenterPoint.x + cos(xAxisRotation) * preCenterPoint.y);
CGFloat startAngle = angle(CGPointMake(1, 0), CGPointMake((currentPoint.x - preCenterPoint.x) / radii.x, (currentPoint.y - preCenterPoint.y) / radii.y));
CGPoint deltaU = CGPointMake((currentPoint.x - preCenterPoint.x) / radii.x,
(currentPoint.y - preCenterPoint.y) / radii.y);
CGPoint deltaV = CGPointMake((-currentPoint.x - preCenterPoint.x) / radii.x,
(-currentPoint.y - preCenterPoint.y) / radii.y);
CGFloat angleDelta = (deltaU.x * deltaV.y < deltaU.y * deltaV.x ? -1 : 1) * acos(ratio(deltaU, deltaV));
angleDelta = (ratio(deltaU, deltaV) <= -1) ? M_PI : (ratio(deltaU, deltaV) >= 1) ? 0 : angleDelta;
// check for actually numbers, if this is not valid
// kill it, blame WWDC 2017 SVG background for this...
if (isnan(startAngle) || isnan(angleDelta)) {
if(type == kIJSVGCommandTypeRelative) {
arcEndPoint.x += pathCurrentPoint.x;
arcEndPoint.y += pathCurrentPoint.y;
}
CGFloat x1 = pathCurrentPoint.x;
CGFloat y1 = pathCurrentPoint.y;
CGFloat x2 = arcEndPoint.x;
CGFloat y2 = arcEndPoint.y;
if(rx == 0.f || ry == 0.f) {
CGPathAddLineToPoint(path, NULL, x2, y2);
return;
}
CGFloat cosPhi = cos(xAxisRotation);
CGFloat sinPhi = sin(xAxisRotation);
CGFloat x1p = cosPhi * (x1 - x2) / 2.f + sinPhi * (y1 - y2) / 2.f;
CGFloat y1p = -sinPhi * (x1 - x2) / 2.f + cosPhi * (y1 - y2) / 2.f;
CGFloat rx_2 = rx * rx;
CGFloat ry_2 = ry * ry;
CGFloat xp_2 = x1p * x1p;
CGFloat yp_2 = y1p * y1p;
CGFloat radius = MAX(radii.x, radii.y);
CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) : CGPointMake(radii.x / radii.y, 1);
CGFloat delta = xp_2 / rx_2 + yp_2 / ry_2;
if(delta > 1.f) {
rx *= sqrt(delta);
ry *= sqrt(delta);
rx_2 = rx * rx;
ry_2 = ry * ry;
}
CGFloat sign = (largeArcFlag == sweepFlag) ? -1.f : 1.f;
CGFloat numerator = MAX(0.f, rx_2 * ry_2 - rx_2 * yp_2 - ry_2 * xp_2);
CGFloat denom = rx_2 * yp_2 + ry_2 * xp_2;
CGFloat lhs = denom == 0.f ? 0.f : sign * sqrt(numerator / denom);
CGFloat cxp = lhs * (rx * y1p) / ry;
CGFloat cyp = lhs * -((ry * x1p) / rx);
CGFloat cx = cosPhi * cxp + -sinPhi * cyp + (x1 + x2) / 2.f;
CGFloat cy = cxp * sinPhi + cyp * cosPhi + (y1 + y2) / 2.f;
NSAffineTransform* trans = NSAffineTransform.transform;
[trans translateXBy:-centerPoint.x yBy:-centerPoint.y];
[path.path transformUsingAffineTransform:trans];
CGAffineTransform transform = CGAffineTransformMakeScale(1.f / rx, 1.f / ry);
transform = CGAffineTransformRotate(transform, -xAxisRotation);
transform = CGAffineTransformTranslate(transform, -cx, -cy);
CGPoint arcPt1 = CGPointApplyAffineTransform(CGPointMake(x1, y1), transform);
CGPoint arcPt2 = CGPointApplyAffineTransform(CGPointMake(x2, y2), transform);
CGFloat startAngle = atan2(arcPt1.y, arcPt1.x);
CGFloat endAngle = atan2(arcPt2.y, arcPt2.x);
CGFloat angleDelta = endAngle - startAngle;;
if(sweepFlag == YES) {
if(angleDelta < 0.f) {
angleDelta += 2.f * M_PI;
}
} else if(angleDelta > 0.f) {
angleDelta = angleDelta - 2.f * M_PI;
}
transform = CGAffineTransformMakeTranslation(cx, cy);
transform = CGAffineTransformRotate(transform, xAxisRotation);
transform = CGAffineTransformScale(transform, rx, ry);
trans = NSAffineTransform.transform;
[trans rotateByRadians:-xAxisRotation];
[path.path transformUsingAffineTransform:trans];
trans = NSAffineTransform.transform;
[trans scaleXBy:(1 / scale.x) yBy:(1 / scale.y)];
[path.path transformUsingAffineTransform:trans];
[path.path appendBezierPathWithArcWithCenter:NSZeroPoint
radius:radius
startAngle:radians_to_degrees(startAngle)
endAngle:radians_to_degrees(startAngle + angleDelta)
clockwise:!sweepFlag];
trans = NSAffineTransform.transform;
[trans scaleXBy:scale.x yBy:scale.y];
[path.path transformUsingAffineTransform:trans];
trans = NSAffineTransform.transform;
[trans rotateByRadians:xAxisRotation];
[path.path transformUsingAffineTransform:trans];
trans = NSAffineTransform.transform;
[trans translateXBy:centerPoint.x yBy:centerPoint.y];
[path.path transformUsingAffineTransform:trans];
CGPathAddRelativeArc(path, &transform, 0.f, 0.f, 1.f,
startAngle, angleDelta);
}
@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 IJSVGCommandHorizontalLine : IJSVGCommand
@@ -6,7 +6,7 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGCommandHorizontalLine.h"
#import <IJSVG/IJSVGCommandHorizontalLine.h>
@implementation IJSVGCommandHorizontalLine
@@ -20,13 +20,15 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
[path.path lineToPoint:NSMakePoint(params[0], path.currentPoint.y)];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, params[0], CGPathGetCurrentPoint(path).y);
return;
}
[path.path relativeLineToPoint:NSMakePoint(params[0], 0.f)];
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPathAddLineToPoint(path, NULL, currentPoint.x + params[0],
currentPoint.y);
}
@end
@@ -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
@@ -20,15 +20,26 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
[path.path lineToPoint:NSMakePoint(params[0], params[1])];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, params[0], params[1]);
return;
}
NSPoint point = NSMakePoint(path.currentPoint.x + params[0],
path.currentPoint.y + params[1]);
[path.path lineToPoint:point];
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPathAddLineToPoint(path, NULL, currentPoint.x + params[0],
currentPoint.y + params[1]);
}
- (void)convertToUnits:(IJSVGUnitType)units
boundingBox:(CGRect)boundingBox
{
if(units == IJSVGUnitObjectBoundingBox) {
self.parameters[0] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[0]] computeValue:boundingBox.size.width];
self.parameters[1] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[1]] computeValue:boundingBox.size.height];
}
[super convertToUnits:units
boundingBox:boundingBox];
}
@end
@@ -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
@@ -21,11 +21,11 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
// move to's allow more then one move to, but if there are more then one,
// we need to run the line to instead...who knew!
if (command.class == self.class && currentCommand.isSubCommand == YES) {
if(command.class == self.class && currentCommand.isSubCommand == YES) {
[IJSVGCommandLineTo runWithParams:params
paramCount:count
command:currentCommand
@@ -35,17 +35,31 @@
return;
}
// actual move to command
if (type == kIJSVGCommandTypeAbsolute) {
[path.path moveToPoint:NSMakePoint(params[0], params[1])];
// actual move to command - do a moveToPoint only
// if the type is absolute, or its possible the type is
// 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) {
CGPathMoveToPoint(path, NULL,
params[0], params[1]);
return;
}
@try {
[path.path relativeMoveToPoint:NSMakePoint(params[0], params[1])];
}
@catch (NSException* exception) {
[path.path moveToPoint:NSMakePoint(params[0], params[1])];
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPathMoveToPoint(path, NULL,
currentPoint.x + params[0],
currentPoint.y + params[1]);
}
- (void)convertToUnits:(IJSVGUnitType)units
boundingBox:(CGRect)boundingBox
{
if(units == IJSVGUnitObjectBoundingBox) {
self.parameters[0] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[0]] computeValue:boundingBox.size.width];
self.parameters[1] = [[IJSVGUnitLength unitWithPercentageFloat:self.parameters[1]] computeValue:boundingBox.size.height];
}
[super convertToUnits:units
boundingBox:boundingBox];
}
@end
@@ -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
@@ -21,15 +21,17 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
[path.path addQuadCurveToPoint:NSMakePoint(params[2], params[3])
controlPoint:NSMakePoint(params[0], params[1])];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddQuadCurveToPoint(path, NULL, params[0], params[1],
params[2], params[3]);
return;
}
[path.path addQuadCurveToPoint:NSMakePoint(path.currentPoint.x + params[2], path.currentPoint.y + params[3])
controlPoint:NSMakePoint(path.currentPoint.x + params[0], path.currentPoint.y + params[1])];
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPathAddQuadCurveToPoint(path, NULL,
currentPoint.x + params[0], currentPoint.y + params[1],
currentPoint.x + params[2], currentPoint.y + params[3]);
}
@end
@@ -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
@@ -22,43 +22,43 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
NSPoint firstControl = NSMakePoint(path.currentPoint.x, path.currentPoint.y);
if (command != nil) {
if (command.class == [IJSVGCommandCurve class] || command.class == self.class) {
if (command.class == [IJSVGCommandCurve class]) {
if (command.type == kIJSVGCommandTypeAbsolute) {
firstControl = NSMakePoint(-1 * command.parameters[2] + 2 * path.currentPoint.x,
-1 * command.parameters[3] + 2 * path.currentPoint.y);
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPoint firstControl = CGPointMake(currentPoint.x, currentPoint.y);
if(command != nil) {
if(command.class == [IJSVGCommandCurve class] || command.class == self.class) {
if(command.class == [IJSVGCommandCurve class]) {
if(command.type == kIJSVGCommandTypeAbsolute) {
firstControl = CGPointMake(-1 * command.parameters[2] + 2 * currentPoint.x,
-1 * command.parameters[3] + 2 * currentPoint.y);
} else {
NSPoint oldPoint = NSMakePoint(path.currentPoint.x - command.parameters[4],
path.currentPoint.y - command.parameters[5]);
firstControl = NSMakePoint(-1 * (command.parameters[2] + oldPoint.x) + 2 * path.currentPoint.x,
-1 * (command.parameters[3] + oldPoint.y) + 2 * path.currentPoint.y);
NSPoint oldPoint = CGPointMake(currentPoint.x - command.parameters[4],
currentPoint.y - command.parameters[5]);
firstControl = CGPointMake(-1 * (command.parameters[2] + oldPoint.x) + 2 * currentPoint.x,
-1 * (command.parameters[3] + oldPoint.y) + 2 * currentPoint.y);
}
} else {
if (command.type == kIJSVGCommandTypeAbsolute) {
firstControl = NSMakePoint(-1 * command.parameters[0] + 2 * path.currentPoint.x,
-1 * command.parameters[1] + 2 * path.currentPoint.y);
if(command.type == kIJSVGCommandTypeAbsolute) {
firstControl = CGPointMake(-1 * command.parameters[0] + 2 * currentPoint.x,
-1 * command.parameters[1] + 2 * currentPoint.y);
} else {
NSPoint oldPoint = NSMakePoint(path.currentPoint.x - command.parameters[2],
path.currentPoint.y - command.parameters[3]);
firstControl = NSMakePoint(-1 * (command.parameters[0] + oldPoint.x) + 2 * path.currentPoint.x,
-1 * (command.parameters[1] + oldPoint.y) + 2 * path.currentPoint.y);
NSPoint oldPoint = CGPointMake(currentPoint.x - command.parameters[2],
currentPoint.y - command.parameters[3]);
firstControl = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * currentPoint.x,
-1 * (command.parameters[1] + oldPoint.y) + 2 * currentPoint.y);
}
}
}
}
if (type == kIJSVGCommandTypeAbsolute) {
[path.path curveToPoint:NSMakePoint(params[2], params[3])
controlPoint1:NSMakePoint(firstControl.x, firstControl.y)
controlPoint2:NSMakePoint(params[0], params[1])];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddCurveToPoint(path, NULL, firstControl.x, firstControl.y,
params[0], params[1], params[2], params[3]);
return;
}
[path.path curveToPoint:NSMakePoint(path.currentPoint.x + params[2], path.currentPoint.y + params[3])
controlPoint1:NSMakePoint(firstControl.x, firstControl.y)
controlPoint2:NSMakePoint(path.currentPoint.x + params[0], path.currentPoint.y + params[1])];
CGPathAddCurveToPoint(path, NULL, firstControl.x, firstControl.y,
currentPoint.x + params[0], currentPoint.y + params[1],
currentPoint.x + params[2], currentPoint.y + params[3]);
}
@end
@@ -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
@@ -22,35 +22,37 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
NSPoint commandPoint = NSMakePoint(path.currentPoint.x, path.currentPoint.y);
if (command != nil) {
if (command.class == IJSVGCommandQuadraticCurve.class) {
CGPoint lastControlPoint = IJSVGPathGetLastQuadraticCommandPoint(path);
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPoint commandPoint = CGPointMake(currentPoint.x, currentPoint.y);
if(command != nil) {
if(command.class == IJSVGCommandQuadraticCurve.class) {
// quadratic curve
if (command.type == kIJSVGCommandTypeAbsolute) {
commandPoint = NSMakePoint(-1 * command.parameters[0] + 2 * path.currentPoint.x,
-1 * command.parameters[1] + 2 * path.currentPoint.y);
if(command.type == kIJSVGCommandTypeAbsolute) {
commandPoint = NSMakePoint(-1 * command.parameters[0] + 2 * currentPoint.x,
-1 * command.parameters[1] + 2 * currentPoint.y);
} else {
NSPoint oldPoint = CGPointMake(path.currentPoint.x - command.parameters[2],
path.currentPoint.y - command.parameters[3]);
commandPoint = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * (path.currentPoint.x),
-1 * (command.parameters[1] + oldPoint.y) + 2 * path.currentPoint.y);
CGPoint oldPoint = CGPointMake(currentPoint.x - command.parameters[2],
currentPoint.y - command.parameters[3]);
commandPoint = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * (currentPoint.x),
-1 * (command.parameters[1] + oldPoint.y) + 2 * currentPoint.y);
}
} else if (command.class == self.class) {
} else if(command.class == self.class) {
// smooth quadratic curve
commandPoint = CGPointMake(-1 * (path.lastControlPoint.x) + 2 * (path.currentPoint.x),
-1 * (path.lastControlPoint.y) + 2 * path.currentPoint.y);
commandPoint = CGPointMake(-1 * (lastControlPoint.x) + 2 * (currentPoint.x),
-1 * (lastControlPoint.y) + 2 * currentPoint.y);
}
}
path.lastControlPoint = commandPoint;
if (type == kIJSVGCommandTypeAbsolute) {
[path.path addQuadCurveToPoint:NSMakePoint(params[0], params[1])
controlPoint:commandPoint];
// path.lastControlPoint = commandPoint;
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddQuadCurveToPoint(path, NULL, commandPoint.x, commandPoint.y,
params[0], params[1]);
return;
}
[path.path addQuadCurveToPoint:NSMakePoint(path.currentPoint.x + params[0], path.currentPoint.y + params[1])
controlPoint:commandPoint];
CGPathAddQuadCurveToPoint(path, NULL, commandPoint.x, commandPoint.y,
currentPoint.x + params[0], currentPoint.y + params[1]);
}
@end
@@ -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
@@ -20,13 +20,14 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
if (type == kIJSVGCommandTypeAbsolute) {
[path.path lineToPoint:NSMakePoint(path.currentPoint.x, params[0])];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, CGPathGetCurrentPoint(path).x, params[0]);
return;
}
[path.path relativeLineToPoint:NSMakePoint(0.f, params[0])];
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPathAddLineToPoint(path, NULL, currentPoint.x, currentPoint.y + params[0]);
}
@end
+92 -89
View File
@@ -6,56 +6,30 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGBezierPathAdditions.h"
#import "IJSVGColorList.h"
#import "IJSVGExporter.h"
#import "IJSVGGradientLayer.h"
#import "IJSVGGroupLayer.h"
#import "IJSVGImageLayer.h"
#import "IJSVGLayerTree.h"
#import "IJSVGParser.h"
#import "IJSVGRendering.h"
#import "IJSVGRenderingStyle.h"
#import "IJSVGTransaction.h"
#import <IJSVG/IJSVGTraitedColorStorage.h>
#import <IJSVG/IJSVGRootNode.h>
#import <IJSVG/IJSVGExporter.h>
#import <IJSVG/IJSVGGradientLayer.h>
#import <IJSVG/IJSVGGroupLayer.h>
#import <IJSVG/IJSVGRootLayer.h>
#import <IJSVG/IJSVGImageLayer.h>
#import <IJSVG/IJSVGLayerTree.h>
#import <IJSVG/IJSVGParser.h>
#import <IJSVG/IJSVGRendering.h>
#import <IJSVG/IJSVGStyle.h>
#import <IJSVG/IJSVGTransaction.h>
#import <Foundation/Foundation.h>
@class IJSVG;
@protocol IJSVGDelegate <NSObject, IJSVGParserDelegate>
@optional
- (BOOL)svg:(IJSVG*)svg
shouldHandleForeignObject:(IJSVGForeignObject*)foreignObject;
- (void)svg:(IJSVG*)svg
handleForeignObject:(IJSVGForeignObject*)foreignObject
document:(NSXMLDocument*)document;
- (void)svg:(IJSVG*)svg
foundSubSVG:(IJSVG*)subSVG
withSVGString:(NSString*)subSVGString;
@end
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
@interface IJSVG : NSObject <NSPasteboardWriting> {
@private
IJSVGParser* _group;
CGFloat _scale;
CGFloat _clipScale;
id<IJSVGDelegate> _delegate;
IJSVGLayer* _layerTree;
IJSVGRootNode* _rootNode;
IJSVGLayerTree* _layerTree;
CGRect _viewBox;
CGSize _proposedViewSize;
CGFloat _backingScaleFactor;
CGFloat _lastProposedBackingScale;
IJSVGRenderQuality _lastProposedRenderQuality;
CGFloat _backingScale;
NSMutableDictionary* _replacementColors;
struct {
unsigned int shouldHandleForeignObject : 1;
unsigned int handleForeignObject : 1;
unsigned int shouldHandleSubSVG : 1;
} _respondsTo;
IJSVGUnitSize* _intrinsicSize;
}
// set this to be called when the layer is about to draw, it will call this
@@ -67,91 +41,120 @@
// 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* style;
@property (nonatomic, strong) IJSVGStyle* style;
@property (nonatomic, copy) NSString* title;
@property (nonatomic, copy) NSString* desc;
@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;
- (CGSize)sizeByMaintainingAspectRatioWithSize:(CGSize)aSize;
- (NSString*)identifier;
- (IJSVGLayer*)layer;
- (IJSVGLayer*)layerWithTree:(IJSVGLayerTree*)tree;
- (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;
- (CGFloat)computeBackingScale:(CGFloat)scale;
- (void)discardDOM;
+ (id)SVGNamed:(NSString*)string;
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path;
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path
flipped:(BOOL)flipped;
+ (id)svgNamed:(NSString*)string;
+ (id)svgNamed:(NSString*)string
delegate:(id<IJSVGDelegate>)delegate;
- (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
error:(NSError**)error;
- (id)initWithSVGData:(NSData*)data;
- (id)initWithSVGData:(NSData*)data
error:(NSError**)error;
- (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;
- (NSImage*)imageWithSize:(NSSize)aSize;
- (NSImage*)imageWithSize:(NSSize)aSize
- (id)initWithDataAssetNamed:(NSDataAssetName)name
error:(NSError**)error;
- (id)initWithDataAssetNamed:(NSDataAssetName)name
bundle:(NSBundle*)bundle
error:(NSError**)error;
- (NSImage*)imageWithSize:(CGSize)aSize;
- (NSImage*)imageWithSize:(CGSize)aSize
error:(NSError**)error;
- (NSImage*)imageWithSize:(NSSize)aSize
- (NSImage*)imageWithSize:(CGSize)aSize
flipped:(BOOL)flipped;
- (NSImage*)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
- (NSImage*)imageWithSize:(CGSize)aSize
flipped:(BOOL)flipped
error:(NSError**)error;
- (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;
- (void)beginVectorDraw;
- (void)endVectorDraw;
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize;
// call this to invalidate the render tree when you change the style
- (void)setNeedsDisplay;
// colors
- (IJSVGColorList*)computedColorList:(BOOL*)hasPatternFills;
- (void)performBlock:(dispatch_block_t)block;
// matching
- (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.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,128 +0,0 @@
//
// IJSVGFontConverter.m
// IJSVGExample
//
// Created by Curtis Hard on 21/05/2015.
// Copyright (c) 2015 Curtis Hard. All rights reserved.
//
#import "IJSVGBezierPathAdditions.h"
#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 cgPath = [path.path newCGPathRef:NO];
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:cgPath];
IJSVG* svg = [self convertPathToSVG:flippedPath];
CGPathRelease(flippedPath);
CGPathRelease(cgPath);
return svg;
}
+ (IJSVG*)convertPathToSVG:(CGPathRef)path
{
__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];
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;
@@ -17,6 +17,9 @@
IJSVG* _svg;
}
- (instancetype)initWithData:(NSData*)data;
@property (nonatomic, readonly) CGRect viewBox;
@property (nonatomic, readonly) IJSVG* SVG;
@end
@@ -6,13 +6,11 @@
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVG.h"
#import "IJSVGImageRep.h"
#import <IJSVG/IJSVG.h>
#import <IJSVG/IJSVGImageRep.h>
@implementation IJSVGImageRep
@synthesize viewBox = _viewBox;
+ (void)load
{
[NSBitmapImageRep registerImageRepClass:self];
@@ -25,18 +23,26 @@
+ (NSArray<NSString*>*)imageTypes
{
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
if(@available(macOS 10.10, *)) {
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
} else {
return @[ @"public.svg-image", @"svg" ];
}
}
+ (NSArray<NSString*>*)imageUnfilteredTypes
{
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
if(@available(macOS 10.10, *)) {
return @[ (NSString*)kUTTypeScalableVectorGraphics, @"svg" ];
} else {
return @[ @"public.svg-image", @"svg" ];
}
}
+ (NSArray<NSImageRep*>*)imageRepsWithData:(NSData*)data
{
IJSVGImageRep* instance = [self imageRepWithData:data];
if (instance == nil) {
if(instance == nil) {
return @[];
}
return @[ instance ];
@@ -44,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;
}
@@ -101,4 +100,9 @@
return _svg.viewBox;
}
- (IJSVG*)SVG
{
return _svg;
}
@end
@@ -0,0 +1,37 @@
//
// IJSVGUmbrella.h
// IJSVG
//
// Created by Curtis Hard on 16/04/2023.
// Copyright © 2023 Curtis Hard. All rights reserved.
//
#ifndef IJSVGUmbrella_h
#define IJSVGUmbrella_h
#import <IJSVG/IJSVG.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/IJSVGCommandSmoothQuadraticCurve.h>
#import <IJSVG/IJSVGCommandSmoothCurve.h>
#import <IJSVG/IJSVGCommandVerticalLine.h>
#import <IJSVG/IJSVGExporterPathInstruction.h>
#import <IJSVG/IJSVGFeatureFlag.h>
#import <IJSVG/IJSVGFeatureFlags.h>
#import <IJSVG/IJSVGFilterEffectGaussianBlur.h>
#import <IJSVG/IJSVGFilterLayer.h>
#import <IJSVG/IJSVGImageRep.h>
#import <IJSVG/IJSVGMath.h>
#import <IJSVG/IJSVGParsing.h>
#import <IJSVG/IJSVGPatternLayer.h>
#import <IJSVG/IJSVGStrokeLayer.h>
#import <IJSVG/IJSVGThreadManager.h>
#import <IJSVG/IJSVGView.h>
#import <IJSVG/NSImage+IJSVGAdditions.h>
#endif /* IJSVGUmbrella_h */
@@ -6,7 +6,7 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVG.h"
#import <IJSVG/IJSVG.h>
#import <Cocoa/Cocoa.h>
IB_DESIGNABLE
@@ -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;
+9 -15
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,9 +36,9 @@
- (void)awakeFromNib
{
// image was set via IB
if (imageName != nil) {
IJSVG* anSVG = [IJSVG svgNamed:imageName];
if (tintColor != nil) {
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;
}
@@ -1,19 +0,0 @@
//
// IJSVGWriter.h
// IJSVGExample
//
// Created by Curtis Hard on 21/05/2015.
// Copyright (c) 2015 Curtis Hard. All rights reserved.
//
#import "IJSVGPath.h"
#import <Foundation/Foundation.h>
@interface IJSVGWriter : NSObject {
}
+ (NSString*)SVGDocumentStringForSVGGlyph:(IJSVGPath*)node;
+ (NSString*)SVGDocumentStringForBezierPath:(NSBezierPath*)path;
+ (NSXMLDocument*)SVGDocumentForBezierPath:(NSBezierPath*)path;
@end
@@ -1,115 +0,0 @@
//
// IJSVGWriter.m
// IJSVGExample
//
// Created by Curtis Hard on 21/05/2015.
// Copyright (c) 2015 Curtis Hard. All rights reserved.
//
#import "IJSVGWriter.h"
@implementation IJSVGWriter
+ (NSString*)SVGDocumentStringForSVGGlyph:(IJSVGPath*)node
{
NSBezierPath* path = [node path];
// we need to flip it
NSAffineTransform* trans = NSAffineTransform.transform;
[trans scaleXBy:1.f yBy:-1.f];
[trans translateXBy:0.f yBy:path.controlPointBounds.size.height];
path = [trans transformBezierPath:path];
return [self.class SVGDocumentStringForBezierPath:path];
}
+ (NSString*)SVGDocumentStringForBezierPath:(NSBezierPath*)path
{
return [self.class SVGDocumentForBezierPath:path].XMLString;
}
+ (NSXMLDocument*)SVGDocumentForBezierPath:(NSBezierPath*)path
{
NSXMLElement* root = [self.class rootElementForPath:path];
// create the path data
NSXMLElement* p = [[[NSXMLElement alloc] initWithName:@"path"] autorelease];
// add the drawing command
NSXMLNode* n = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
[n setName:@"d"];
[n setStringValue:[self.class SVGPathStringForBezierPath:path]];
[p addAttribute:n];
// add the drawing path to the root
[root addChild:p];
return [[[NSXMLDocument alloc] initWithRootElement:root] autorelease];
}
+ (NSXMLElement*)rootElementForPath:(NSBezierPath*)path
{
NSXMLElement* element = [[[NSXMLElement alloc] initWithName:@"svg"] autorelease];
NSRect bounds = path.controlPointBounds;
// width
NSXMLNode* att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
[att setName:@"width"];
[att setStringValue:[NSString stringWithFormat:@"%f", bounds.size.width]];
[element addAttribute:att];
// height
att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
[att setName:@"height"];
[att setStringValue:[NSString stringWithFormat:@"%f", bounds.size.height]];
[element addAttribute:att];
// viewbox
att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
[att setName:@"viewBox"];
[att setStringValue:[NSString stringWithFormat:@"%f %f %f %f", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height]];
[element addAttribute:att];
// namespace
att = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
[att setName:@"xmlns"];
[att setStringValue:@"http://www.w3.org/2000/svg"];
[element addAttribute:att];
return element;
}
+ (NSString*)SVGPathStringForBezierPath:(NSBezierPath*)path
{
NSMutableString* str = [[[NSMutableString alloc] init] autorelease];
for (NSInteger i = 0; i < path.elementCount; i++) {
NSBezierPathElement element = [path elementAtIndex:i];
switch (element) {
// move
case NSMoveToBezierPathElement: {
NSPoint points[1];
[path elementAtIndex:i associatedPoints:points];
[str appendFormat:@"M%f %f", points[0].x, points[0].y];
break;
}
// line
case NSLineToBezierPathElement: {
NSPoint points[1];
[path elementAtIndex:i associatedPoints:points];
[str appendFormat:@"L%f %f", points[0].x, points[0].y];
break;
}
// curve
case NSCurveToBezierPathElement: {
NSPoint points[3];
[path elementAtIndex:i associatedPoints:points];
[str appendFormat:@"C%f %f %f %f %f %f", points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y];
break;
}
// close
case NSClosePathBezierPathElement: {
[str appendFormat:@"Z"];
break;
}
}
}
return str;
}
@end
@@ -7,8 +7,15 @@
//
#import <Foundation/Foundation.h>
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGTraitedColor.h>
@class IJSVG;
@class IJSVGExporter;
@class IJSVGLayer;
@class IJSVGNode;
NS_ASSUME_NONNULL_BEGIN
typedef void (^IJSVGCGPathHandler)(const CGPathElement* pathElement);
typedef void (^IJSVGPathElementEnumerationBlock)(const CGPathElement* pathElement, CGPoint currentPoint);
@@ -25,20 +32,52 @@ 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,
IJSVGExporterOptionCenterWithinViewBox = 1 << 16,
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef | IJSVGExporterOptionRemoveUselessGroups | IJSVGExporterOptionCreateUseForPaths | IJSVGExporterOptionMoveAttributesToGroup | IJSVGExporterOptionSortAttributes | IJSVGExporterOptionCollapseGroups | IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements | IJSVGExporterOptionScaleToSizeIfNecessary | IJSVGExporterOptionCompressOutput | IJSVGExporterOptionCollapseGradients | IJSVGExporterOptionRemoveWidthHeightAttributes | IJSVGExporterOptionColorAllowRRGGBBAA | IJSVGExporterOptionRemoveComments | IJSVGExporterOptionCenterWithinViewBox
IJSVGExporterOptionRemoveXMLDeclaration = 1 << 17,
IJSVGExporterOptionConvertArcs = 1 << 18,
IJSVGExporterOptionConvertShapesToPaths = 1 << 19,
IJSVGExporterOptionRoundTransforms = 1 << 20,
IJSVGExporterOptionRemoveDefaultValues = 1 << 21,
IJSVGExporterOptionConvertStrokesToPaths = 1 << 22,
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef | IJSVGExporterOptionRemoveUselessGroups |
IJSVGExporterOptionCreateUseForPaths | IJSVGExporterOptionMoveAttributesToGroup |
IJSVGExporterOptionSortAttributes | IJSVGExporterOptionCollapseGroups |
IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements | IJSVGExporterOptionCompressOutput |
IJSVGExporterOptionCollapseGradients | IJSVGExporterOptionRemoveWidthHeightAttributes |
IJSVGExporterOptionColorAllowRRGGBBAA | IJSVGExporterOptionRemoveComments |
IJSVGExporterOptionCenterWithinViewBox | IJSVGExporterOptionRemoveXMLDeclaration |
IJSVGExporterOptionConvertArcs | IJSVGExporterOptionConvertShapesToPaths |
IJSVGExporterOptionRoundTransforms | IJSVGExporterOptionRemoveDefaultValues |
IJSVGExporterOptionConvertStrokesToPaths
};
BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option);
void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlock enumBlock);
const NSArray* IJSVGShortCharacterArray(void);
const NSArray<NSString*>* IJSVGShortCharacterArray(void);
const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes(void);
@protocol IJSVGExporterDelegate <NSObject>
@optional
- (NSString* _Nullable)svgExporter:(IJSVGExporter*)exporter
identifierForElement:(NSXMLElement* _Nullable)element
type:(IJSVGNodeType)type
defaultID:(NSString* (^)(void))defaultID;
- (NSString* _Nullable)svgExporter:(IJSVGExporter*)exporter
stringForColor:(NSColor*)color
flags:(IJSVGColorUsageTraits)flag
options:(IJSVGColorStringOptions)options;
@end
@interface IJSVGExporter : NSObject {
@@ -50,15 +89,32 @@ const NSArray* IJSVGShortCharacterArray(void);
NSXMLElement* _defElement;
NSInteger _idCount;
NSInteger _shortIdCount;
BOOL _appliedXLink;
IJSVGThreadManager* _threadManager;
struct {
unsigned int identifierForElement: 1;
unsigned int stringForColor: 1;
} _respondsTo;
}
@property (nonatomic, copy) NSString* title;
@property (nonatomic, copy) NSString* description;
@property (nonatomic, assign) id<IJSVGExporterDelegate> delegate;
@property (nonatomic, assign) IJSVGFloatingPointOptions floatingPointOptions;
@property (nonatomic, copy, nullable) NSString* title;
@property (nonatomic, copy, nullable) NSString* desc;
- (id)initWithSVG:(IJSVG*)svg
size:(CGSize)size
options:(IJSVGExporterOptions)options;
- (id)initWithSVG:(IJSVG*)svg
size:(CGSize)size
options:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
- (NSString*)SVGString;
- (NSData*)SVGData;
- (IJSVG*)SVG:(NSError**)error;
@end
NS_ASSUME_NONNULL_END
File diff suppressed because it is too large Load Diff
@@ -10,35 +10,54 @@
NS_ASSUME_NONNULL_BEGIN
typedef struct {
char instruction;
NSArray<NSString*>* params;
} IJSVGExporterPathInstructionCommand;
@interface IJSVGExporterPathInstructionCommand : NSObject {
}
@property (nonatomic, assign) char instruction;
@property (nonatomic, strong) NSArray<NSString*>* params;
@end
@interface IJSVGExporterPathInstruction : NSObject {
@private
NSInteger _dataCount;
char _instruction;
CGFloat* _data;
CGFloat* _base;
CGFloat* _coords;
}
IJSVGExporterPathInstructionCommand* IJSVGExporterPathInstructionCommandCopy(IJSVGExporterPathInstructionCommand command);
void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand* _Nullable command);
@property (nonatomic, assign) char instruction;
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path;
void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length, IJSVGFloatingPointOptions options);
CGFloat IJSVGExporterPathFloatToFixed(CGFloat number, int precision);
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
- (id)initWithInstruction:(char)instruction
dataCount:(NSInteger)floatCount;
- (void)setInstruction:(char)newInstruction;
- (char)instruction;
- (CGFloat*)data;
- (NSInteger)dataLength;
+ (void)convertInstructionsToRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions;
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions;
+ (NSString*)pathStringWithInstructionSet:(NSArray<NSValue*>*)instructionSets;
+ (NSArray<IJSVGExporterPathInstruction*>*)convertInstructionsCurves:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
+ (void)convertInstructionsToMixedAbsoluteRelative:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
+ (void)convertInstructionsDataToRounded:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
+ (void)convertInstructionsToRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
+ (NSString*)pathStringWithInstructionSet:(NSArray<NSValue*>*)instructionSets
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
@end
NS_ASSUME_NONNULL_END
static NSInteger const kIJSVGExporterPathInstructionFloatPrecision = 3;
static CGFloat const kIJSVGExporterPathInstructionErrorThreshold = 1e-2;
#define IJ_SVG_EXPORT_ROUND(value) IJSVGExporterPathFloatToFixed(value, kIJSVGExporterPathInstructionFloatPrecision)
@@ -6,30 +6,46 @@
// 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) {
free(_data);
if(_data != NULL) {
(void)free(_data), _data = NULL;
}
if(_base != NULL) {
(void)free(_base), _base = 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);
}
// setup base and coords
_base = (CGFloat*)malloc(sizeof(CGFloat) * 2);
_coords = (CGFloat*)malloc(sizeof(CGFloat) * 2);
}
return self;
}
@@ -39,104 +55,63 @@
return _dataCount;
}
- (void)setInstruction:(char)newInstruction
{
_instruction = newInstruction;
}
- (char)instruction
{
return _instruction;
}
- (CGFloat*)data
{
return _data;
}
IJSVGExporterPathInstructionCommand* IJSVGExporterPathInstructionCommandCopy(IJSVGExporterPathInstructionCommand command)
- (CGFloat*)base
{
IJSVGExporterPathInstructionCommand* copy = NULL;
copy = (IJSVGExporterPathInstructionCommand*)malloc(sizeof(IJSVGExporterPathInstructionCommand));
copy->instruction = command.instruction;
copy->params = command.params;
return copy;
return _base;
}
void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand* _Nullable command)
- (CGFloat*)coords
{
if (command != NULL) {
free(command);
}
return _coords;
}
+ (NSString*)pathStringWithInstructionSet:(NSArray<NSValue*>*)instructionSets
+ (NSString*)pathStringWithInstructionSet:(NSArray<IJSVGExporterPathInstructionCommand*>*)instructionSets
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
IJSVGExporterPathInstructionCommand* lastCommand = NULL;
NSMutableString* string = [[[NSMutableString alloc] init] autorelease];
char* lastCommandChars = NULL;
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:@" "];
}
NSInteger index = 0;
for (NSString* dataString in command.params) {
const char* chars = dataString.UTF8String;
// work out if the command is signed and or decimal
BOOL isSigned = chars[0] == '-';
BOOL isDecimal = (isSigned == NO && chars[0] == '.') || (isSigned == YES && chars[1] == '.');
// we also need to know if the previous command was a decimal or not
BOOL lastWasDecimal = NO;
if (lastCommandChars != NULL) {
lastWasDecimal = strchr(lastCommandChars, '.') != NULL;
}
// we only need a space if the current command is not signed
// a decimal and the previous command was decimal too
if (index++ == 0 || isSigned || (isDecimal == YES && lastWasDecimal == YES)) {
[string appendString:dataString];
} else {
[string appendFormat:@" %@", dataString];
}
// store last command chars
lastCommandChars = (char*)chars;
}
// compresses the floats
NSString* compressedFloats = IJSVGCompressFloatParameterArray(command.params);
[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);
NSArray<NSString*>* set = nil;
switch (lowerInstruction) {
case 't':
case 'm':
case 'l': {
set = @[
IJSVGShortFloatString(data[0]),
IJSVGShortFloatString(data[1])
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions)
];
break;
}
@@ -144,29 +119,43 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
case 'v':
case 'h': {
set = @[
IJSVGShortFloatString(data[0])
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions)
];
break;
}
case 'c': {
set = @[
IJSVGShortFloatString(data[0]),
IJSVGShortFloatString(data[1]),
IJSVGShortFloatString(data[2]),
IJSVGShortFloatString(data[3]),
IJSVGShortFloatString(data[4]),
IJSVGShortFloatString(data[5])
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[2], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[3], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[4], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[5], floatingPointOptions)
];
break;
}
case 's':
case 'q': {
set = @[
IJSVGShortFloatString(data[0]),
IJSVGShortFloatString(data[1]),
IJSVGShortFloatString(data[2]),
IJSVGShortFloatString(data[3])
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[2], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[3], floatingPointOptions)
];
break;
}
case 'a': {
set = @[
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[2], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[3], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[4], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[5], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[6], floatingPointOptions),
];
break;
}
@@ -178,142 +167,381 @@ 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];
return [self pathStringWithInstructionSet:pathInstructions
floatingPointOptions:floatingPointOptions];
}
CGFloat IJSVGExporterPathFloatToFixed(CGFloat number, int precision)
{
return floorf(pow(10, precision) * number) / pow(10, precision);
}
void IJSVGExporterPathInstructionRoundData(CGFloat* data, NSInteger length,
IJSVGFloatingPointOptions options)
{
for (NSInteger i = length; i-- > 0;) {
CGFloat d = data[i];
CGFloat proposed = IJSVGExporterPathFloatToFixed(d, options.precision);
if(proposed != d) {
CGFloat rounded = +IJSVGExporterPathFloatToFixed(d, options.precision - 1);
data[i] = IJSVGExporterPathFloatToFixed(+fabs(rounded - d), options.precision + 1)
>= kIJSVGExporterPathInstructionErrorThreshold
? +IJSVGExporterPathFloatToFixed(d, options.precision)
: rounded;
}
}
}
+ (void)convertInstructionsToRoundRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
CGFloat relSubPoint[2] = { 0.f, 0.f };
for (IJSVGExporterPathInstruction* instruction in instructions) {
char instructionChar = instruction.instruction;
NSInteger length = instruction.dataLength;
CGFloat* data = instruction.data;
if(strchr("mltqsc", instructionChar) != NULL) {
for (NSInteger i = length; i--;) {
data[i] += instruction.base[i % 2] - relSubPoint[i % 2];
}
} else if(instructionChar == 'h') {
data[0] += instruction.base[0] - relSubPoint[0];
} else if(instructionChar == 'v') {
data[0] += instruction.base[1] - relSubPoint[1];
} 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') {
relSubPoint[0] += data[0];
} else if(instructionChar == 'v') {
relSubPoint[1] += data[0];
} else {
relSubPoint[0] += data[length - 2];
relSubPoint[1] += data[length - 1];
}
IJSVGExporterPathInstructionRoundData(relSubPoint, 2, floatingPointOptions);
}
}
+ (void)convertInstructionsToMixedAbsoluteRelative:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
IJSVGExporterPathInstruction* prevInstruction = nil;
for (IJSVGExporterPathInstruction* instruction in instructions) {
if(prevInstruction == nil || instruction.dataLength == 0) {
prevInstruction = instruction;
continue;
}
char instructionChar = instruction.instruction;
CGFloat* data = instruction.data;
NSInteger length = instruction.dataLength;
CGFloat* adata = (CGFloat*)malloc(sizeof(CGFloat) * length);
memcpy(adata, data, sizeof(CGFloat) * length);
if(strchr("mltqsc", instructionChar) != NULL) {
for (NSInteger i = length; i--;) {
adata[i] += instruction.base[i % 2];
}
} else if(instructionChar == 'h') {
adata[0] += instruction.base[0];
} else if(instructionChar == 'v') {
adata[0] += instruction.base[1];
} else if(instructionChar == 'a') {
adata[5] += instruction.base[0];
adata[6] += instruction.base[1];
}
IJSVGExporterPathInstructionRoundData(adata, length, floatingPointOptions);
IJSVGExporterPathInstruction* ainstruction = nil;
ainstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:instructionChar
dataCount:length];
memcpy(ainstruction.data, adata, sizeof(CGFloat) * length);
// run these through our default string runner
// to compare the outputs
NSString* orig = [self pathStringFromInstructions:@[ instruction ]
floatingPointOptions:floatingPointOptions];
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)) {
instruction.instruction = toupper(instructionChar);
memcpy(data, adata, sizeof(CGFloat) * length);
}
(void)free(adata), adata = NULL;
prevInstruction = instruction;
}
}
+ (void)convertInstructionsDataToRounded:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
for (IJSVGExporterPathInstruction* instruction in instructions) {
CGFloat* data = instruction.data;
IJSVGExporterPathInstructionRoundData(data, instruction.dataLength,
floatingPointOptions);
}
}
+ (NSArray<IJSVGExporterPathInstruction*>*)convertInstructionsCurves:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
NSMutableArray<IJSVGExporterPathInstruction*>* nInstructions = nil;
nInstructions = [[NSMutableArray alloc] initWithCapacity:instructions.count];
IJSVGExporterPathInstruction* lastInstruction = nil;
for (IJSVGExporterPathInstruction* instruction in instructions) {
lastInstruction = nInstructions.lastObject;
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])) {
IJSVGExporterPathInstruction* nInstruction = nil;
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])) {
IJSVGExporterPathInstruction* nInstruction = nil;
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) {
IJSVGExporterPathInstruction* nInstruction = nil;
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(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];
nInstruction.data[0] = instruction.data[2];
nInstruction.data[1] = instruction.data[3];
[nInstructions addObject:nInstruction];
continue;
} else if(lastInstruction.instruction == 't' &&
instruction.data[2] == lastInstruction.data[0] &&
instruction.data[3] == lastInstruction.data[1]) {
IJSVGExporterPathInstruction* nInstruction = nil;
nInstruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'t'
dataCount:2];
nInstruction.data[0] = instruction.data[2];
nInstruction.data[1] = instruction.data[3];
[nInstructions addObject:nInstruction];
continue;
}
}
[nInstructions addObject:instruction];
}
return nInstructions;
}
+ (void)convertInstructionsToRelativeCoordinates:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
CGFloat point[2] = { 0, 0 };
CGFloat subpathPoint[2] = { 0, 0 };
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];
}
} 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];
} 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') {
instruction = 'h';
data[0] -= point[0];
point[0] += data[0];
} else if (instruction == 'V') {
instruction = 'v';
data[0] -= point[1];
point[1] += data[0];
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] -= cursor[0];
cursor[0] += data[0];
break;
}
case 'v': {
cursor[1] += data[0];
break;
}
case 'V': {
instruction = 'v';
data[0] -= cursor[1];
cursor[1] += data[0];
break;
}
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;
}
// reset the instruction
[anInstruction setInstruction:instruction];
} else if (instruction == 'Z' || instruction == 'z') {
point[0] = subpathPoint[0];
point[1] = subpathPoint[1];
}
// increment index
// 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++;
}
}
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
// 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) {
@@ -323,8 +551,8 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
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;
@@ -337,17 +565,17 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
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;
}
@@ -361,8 +589,8 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
// 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;
@@ -378,9 +606,10 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
CGPoint controlPoint1 = pathElement->points[0];
CGPoint controlPoint2 = pathElement->points[1];
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;
@@ -394,8 +623,8 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
case kCGPathElementCloseSubpath: {
// close command
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z'
dataCount:0] autorelease];
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z'
dataCount:0];
[instructions addObject:instruction];
break;
}
@@ -407,11 +636,11 @@ void IJSVGExporterPathInstructionCommandFree(IJSVGExporterPathInstructionCommand
// 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,69 @@
//
// 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:self.backingScaleFactor];
}
- (void)layoutSublayers
{
CGRect frame = _sublayer.innerBoundingBox;
_hostingLayer.frame = frame;
_hostingLayer.contents = (__bridge id)_image;
}
- (NSArray<CALayer<IJSVGBasicLayer>*>*)debugLayers
{
return @[_sublayer];
}
@end
@@ -6,18 +6,16 @@
// Copyright © 2016 Curtis Hard. All rights reserved.
//
#import "IJSVGGradient.h"
#import "IJSVGLayer.h"
#import "IJSVGPath.h"
#import <IJSVG/IJSVGGradient.h>
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGPath.h>
#import <QuartzCore/QuartzCore.h>
@interface IJSVGGradientLayer : IJSVGLayer {
}
@property (nonatomic, strong) IJSVGGradient* gradient;
@property (nonatomic, assign) CGRect viewBox;
@property (nonatomic, retain) IJSVGGradient* gradient;
@property (nonatomic, assign) CGAffineTransform absoluteTransform;
@property (nonatomic, assign) CGRect objectRect;
@end
@@ -6,46 +6,24 @@
// Copyright © 2016 Curtis Hard. All rights reserved.
//
#import "IJSVGGradientLayer.h"
#import <IJSVG/IJSVGGradientLayer.h>
#import <IJSVG/IJSVGRootLayer.h>
@implementation IJSVGGradientLayer
@synthesize viewBox;
@synthesize gradient;
@synthesize absoluteTransform;
@synthesize objectRect;
- (void)dealloc
- (BOOL)requiresBackingScale
{
(void)([gradient release]), gradient = nil;
[super dealloc];
}
- (id)init
{
if ((self = [super init]) != nil) {
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
}
return self;
return YES;
}
- (void)setGradient:(IJSVGGradient*)newGradient
{
if (gradient != nil) {
(void)([gradient release]), gradient = nil;
}
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;
}
@@ -55,7 +33,7 @@
- (void)setOpacity:(float)opacity
{
if (opacity != 1.f) {
if(opacity != 1.f) {
self.opaque = NO;
}
[super setOpacity:opacity];
@@ -64,40 +42,66 @@
- (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];
}
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
{
return [super referencingLayer] ?: self.superlayer;
}
- (void)drawInContext:(CGContextRef)ctx
{
[super drawInContext:ctx];
// nothing to do :(
if (self.gradient == nil) {
if(self.gradient == nil) {
return;
}
// draw the gradient
CGAffineTransform trans = CGAffineTransformMakeTranslation(-CGRectGetMinX(objectRect),
-CGRectGetMinY(objectRect));
CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform, trans);
CGContextSaveGState(ctx);
// perform the draw
CGRect bounds = CGRectZero;
CGAffineTransform transform = CGAffineTransformIdentity;
CALayer<IJSVGDrawableLayer>* layer = (CALayer<IJSVGDrawableLayer>*)self.referencingLayer;
if(self.gradient.units == IJSVGUnitUserSpaceOnUse) {
IJSVGRootLayer* rootNode = (IJSVGRootLayer*)[IJSVGLayer rootLayerForLayer:self];
bounds = [rootNode.viewBox computeValue:CGSizeZero];
transform = [IJSVGLayer userSpaceTransformForLayer:layer];
} else {
bounds = IJSVGLayerGetBoundingBoxBounds(layer);
}
// 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:transform
viewPort:self.viewBox];
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
@@ -6,10 +6,18 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGLayer.h"
#import "IJSVGShapeLayer.h"
#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, strong) IJSVGUnitSize* intrinsicSize;
@property (nonatomic, strong) IJSVGUnitRect* viewBox;
@property (nonatomic, assign) IJSVGViewBoxAlignment viewBoxAlignment;
@property (nonatomic, assign) IJSVGViewBoxMeetOrSlice viewBoxMeetOrSlice;
@end
@@ -6,8 +6,16 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGGroupLayer.h"
#import <IJSVG/IJSVGGroupLayer.h>
#import <IJSVG/IJSVGViewBox.h>
#import <IJSVG/IJSVGUnitRect.h>
#import <IJSVG/IJSVGLayer.h>
@implementation IJSVGGroupLayer
- (CGRect)innerBoundingBox
{
return self.outerBoundingBox;
}
@end
@@ -6,14 +6,19 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGLayer.h"
#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 {
@interface IJSVGImageLayer : IJSVGTileLayer {
}
- (id)initWithImage:(NSImage*)image;
- (id)initWithCGImage:(CGImageRef)imageRef;
@property (nonatomic, strong) IJSVGImage* image;
- (id)initWithImage:(IJSVGImage*)image;
@end
@@ -6,50 +6,43 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGImageLayer.h"
#import <IJSVG/IJSVGImageLayer.h>
@implementation IJSVGImageLayer
- (id)initWithImage:(NSImage*)image
- (id)initWithImage:(IJSVGImage*)image
{
NSRect rect = (NSRect){
.origin = NSZeroPoint,
.size = image.size
};
CGImageRef ref = [image CGImageForProposedRect:&rect
context:nil
hints:nil];
return [self initWithCGImage:ref];
}
- (id)initWithCGImage:(CGImageRef)imageRef
{
if ((self = [super init]) != nil) {
// set the contents
self.contents = (id)imageRef;
// make sure we say we need help
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
// set the frame, simple stuff
self.frame = (CGRect){
.origin = CGPointZero,
.size = CGSizeMake(CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef))
};
if((self = [super init]) != nil) {
self.image = image;
}
return self;
}
- (void)setNeedsDisplay
- (BOOL)requiresBackingScale
{
// swap the content around on call
// because set needs display discards previous
// content - yolo!
id oldContent = self.contents;
[super setNeedsDisplay];
self.contents = oldContent;
return YES;
}
- (void)setImage:(IJSVGImage *)image
{
_image = image;
[self setNeedsDisplay];
}
- (void)drawInContext:(CGContextRef)ctx
{
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
+162 -16
View File
@@ -6,8 +6,8 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGRendering.h"
#import "IJSVGTransaction.h"
#import <IJSVG/IJSVGRendering.h>
#import <IJSVG/IJSVGTransaction.h>
#import <QuartzCore/QuartzCore.h>
@class IJSVGShapeLayer;
@@ -15,31 +15,177 @@
@class IJSVGPatternLayer;
@class IJSVGStrokeLayer;
@class IJSVGGroupLayer;
@class IJSVGLayer;
@class IJSVGFilter;
@class IJSVGTraitedColorStorage;
@interface IJSVGLayer : CALayer {
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,
IJSVGLayerFillTypePattern,
IJSVGLayerFillTypeGradient,
IJSVGLayerFillTypeUnknown
};
typedef NS_ENUM(NSUInteger, IJSVGLayerUsageType) {
IJSVGLayerUsageTypeFillGeneric,
IJSVGLayerUsageTypeFillPattern,
IJSVGLayerUsageTypeFillGradient,
IJSVGLayerUsageTypeStrokeGeneric,
IJSVGLayerUsageTypeStrokePattern,
IJSVGLayerUsageTypeStrokeGradient,
IJSVGLayerUsageTypeStroke
};
@protocol IJSVGPathableLayer <NSObject>
@required
@property (nonatomic, assign) CGPathRef path;
@end
@protocol IJSVGBasicLayer <NSObject>
@required
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, readonly) BOOL requiresBackingScale;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, readonly) NSArray<CALayer<IJSVGBasicLayer>*>* debugLayers;
@end
@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, assign) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
+ (IJSVGLayerFillType)fillTypeForFill:(id)fill;
+ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer;
+ (void)recursivelyWalkLayer:(CALayer*)layer
withBlock:(void (^)(CALayer* layer, BOOL isMask))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
options:(IJSVGLayerDrawingOptions)options;
+ (void)applyBlendingMode:(CGBlendMode)blendMode
toContext:(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<IJSVGMaskingLayer>*)maskLayer
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)context
drawingBlock:(dispatch_block_t)drawingBlock;
+ (CALayer<IJSVGDrawableLayer>*)rootLayerForLayer:(CALayer<IJSVGDrawableLayer>*)layer;
+ (CGAffineTransform)absoluteTransformForLayer:(CALayer*)layer;
+ (CGRect)absoluteFrameForLayer:(CALayer<IJSVGDrawableLayer>*)layer;
+ (CGRect)calculateFrameForSublayers:(NSArray<CALayer<IJSVGDrawableLayer>*>*)layers;
+ (CGAffineTransform)userSpaceTransformForLayer:(CALayer<IJSVGDrawableLayer>*)layer;
+ (void)transformLayer:(CALayer<IJSVGDrawableLayer>*)layer
intoUserSpaceUnitsFrom:(CALayer<IJSVGDrawableLayer>*)fromLayer;
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer;
@end
+681 -71
View File
@@ -6,35 +6,480 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVG.h"
#import "IJSVGGroupLayer.h"
#import "IJSVGLayer.h"
#import "IJSVGShapeLayer.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 gradientFillLayer;
@synthesize patternFillLayer;
@synthesize gradientStrokeLayer;
@synthesize patternStrokeLayer;
@synthesize strokeLayer;
@synthesize requiresBackingScaleHelp;
@synthesize backingScaleFactor;
@synthesize backingScaleFactor = _backingScaleFactor;
@synthesize requiresBackingScale;
@synthesize renderQuality;
@synthesize blendingMode;
@synthesize convertMasksToPaths;
@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
{
self.contents = nil;
(void)([_maskingLayer release]), _maskingLayer = nil;
[super dealloc];
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
}
- (instancetype)init
{
if((self = [super init]) != nil) {
_boundingBox = CGRectNull;
_outerBoundingBox = CGRectNull;
}
return self;
}
- (id<CAAction>)actionForKey:(NSString*)event
{
return nil;
}
- (CAShapeLayerFillRule)fillRule
{
return kCAFillRuleNonZero;
}
- (CAShapeLayerFillRule)clipRule
{
if(_clipRule == nil) {
return self.fillRule;
}
return _clipRule;
}
+ (IJSVGLayerFillType)fillTypeForFill:(id)fill
{
if([fill isKindOfClass:IJSVGColorNode.class]) {
return IJSVGLayerFillTypeColor;
}
if([fill isKindOfClass:IJSVGGradient.class]) {
return IJSVGLayerFillTypeGradient;
}
if([fill isKindOfClass:IJSVGPattern.class]) {
return IJSVGLayerFillTypePattern;
}
return IJSVGLayerFillTypeUnknown;
}
+ (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;
CALayer<IJSVGDrawableLayer>* parentLayer = layer;
while((parentLayer = parentLayer.referencingLayer) != nil) {
identity = [self absoluteTransformForLayer:parentLayer];
// only go up until we find a root layer, at that point, we know
// we can stop looking
if([parentLayer isKindOfClass:IJSVGRootLayer.class] == YES) {
break;
}
}
return CGAffineTransformConcat(identity, layer.affineTransform);
}
+ (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;
while([parentLayer isKindOfClass:IJSVGRootLayer.class] == NO &&
parentLayer.referencingLayer != nil) {
parentLayer = (CALayer<IJSVGDrawableLayer>*)parentLayer.referencingLayer;
}
return parentLayer;
}
+ (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
IJSVGLayerDrawingOptions opt = IJSVGLayerDrawingOptionIgnoreClipping;
BOOL ignoreClipping = (options & opt) == opt;
if(ignoreClipping == YES || layer.clipLayers == nil) {
drawingBlock();
return;
}
[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) {
drawingBlock();
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
//{
// 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
{
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;
}
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);
}
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);
}
+ (void)clipContextWithMask:(CALayer<IJSVGDrawableLayer>*)maskLayer
toLayer:(CALayer<IJSVGDrawableLayer>*)layer
inContext:(CGContextRef)ctx
drawingBlock:(dispatch_block_t)drawingBlock
{
CGContextSaveGState(ctx);
CGFloat scale = layer.backingScaleFactor;
CGImageRef maskImage = [self newMaskImageForLayer:maskLayer
options:IJSVGLayerDrawingOptionNone
scale:scale];
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 alphaMask = [self newImageForLayer:layer
options:options
colorSpace:colorSpace
bitmapInfo:kCGImageAlphaNone
scale:scale];
// low - high pairs
const CGFloat colors[6] = {
0.f, 11.f,
0.f, 11.f,
0.f, 11.f
};
CGImageRef masked = CGImageCreateWithMaskingColors(alphaMask, colors);
CGImageRelease(alphaMask);
CGColorSpaceRelease(colorSpace);
return masked;
}
+ (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
{
CALayer<IJSVGDrawableLayer>* referenceLayer = layer.referencingLayer ?: layer;
CGRect frame = layer.outerBoundingBox;
CGRect bounds = CGRectApplyAffineTransform(layer.innerBoundingBox,
[self userSpaceTransformForLayer:referenceLayer]);
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
ceilf(frame.size.width*scale),
ceilf(frame.size.height*scale),
8, 0, colorSpace, bitmapInfo);
CGContextScaleCTM(offscreenContext, scale, scale);
CGContextConcatCTM(offscreenContext, CGAffineTransformMakeTranslation(-bounds.origin.x,
-bounds.origin.y));
[IJSVGLayer renderLayer:layer
inContext:offscreenContext
options:options];
CGImageRef image = CGBitmapContextCreateImage(offscreenContext);
CGContextRelease(offscreenContext);
return image;
}
+ (CGRect)absoluteFrameForLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
return (CGRect) {
.origin = [self absoluteOriginForLayer:layer],
.size = layer.frame.size
};
}
+ (CGPoint)absoluteOriginForLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
CGPoint point = CGPointZero;
CALayer<IJSVGDrawableLayer>* pLayer = layer;
while (pLayer != nil) {
point.x += pLayer.frame.origin.x;
point.y += pLayer.frame.origin.y;
pLayer = pLayer.referencingLayer;
}
return point;
}
+ (NSArray*)deepestSublayersOfLayer:(CALayer*)layer
{
NSMutableArray* arr = [[[NSMutableArray alloc] init] autorelease];
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 {
@@ -44,67 +489,108 @@
return arr;
}
+ (void)recursivelyWalkLayer:(CALayer*)layer
withBlock:(void (^)(CALayer* layer, BOOL isMask))block
+ (void)recursivelyWalkLayer:(CALayer<IJSVGBasicLayer>*)layer
withBlock:(void (^)(CALayer<IJSVGBasicLayer>* layer, BOOL* stop))block
{
// call for layer and mask if there is one
block(layer, NO);
// do the mask too!
if (layer.mask != nil) {
block(layer.mask, YES);
BOOL stop = NO;
block(layer, &stop);
if(stop == YES) {
return;
}
// sublayers!!
for (CALayer* aLayer in layer.sublayers) {
for (CALayer<IJSVGBasicLayer>* aLayer in layer.sublayers) {
[self recursivelyWalkLayer:aLayer
withBlock:block];
}
}
- (void)setBackingScaleFactor:(CGFloat)newFactor
+ (void)setBackingScaleFactor:(CGFloat)scale
renderQuality:(IJSVGRenderQuality)quality
recursivelyToLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
if (self.backingScaleFactor == newFactor) {
return;
}
backingScaleFactor = newFactor;
self.contentsScale = newFactor;
self.rasterizationScale = newFactor;
[self setNeedsDisplay];
[self recursivelyWalkLayer:layer
withBlock:^(CALayer<IJSVGDrawableLayer>*sublayer, BOOL *stop) {
if(sublayer.requiresBackingScale == YES) {
sublayer.backingScaleFactor = scale;
}
sublayer.renderQuality = quality;
}];
}
- (void)_customRenderInContext:(CGContextRef)ctx
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer
{
if (self.convertMasksToPaths == YES && _maskingLayer != nil) {
CGContextSaveGState(ctx);
[self applySublayerMaskToContext:ctx
forSublayer:(IJSVGLayer*)self
withOffset:CGPointZero];
[super renderInContext:ctx];
CGContextRestoreGState(ctx);
[self logLayer:layer
depth:0];
}
+ (void)logLayer:(CALayer<IJSVGDrawableLayer>*)layer
depth:(NSUInteger)depth
{
NSLog(@"%@ %@ frame: %@ transform: %@",[@"" stringByPaddingToLength:depth
withString:@"- - "
startingAtIndex:0], layer,
NSStringFromRect(layer.frame),
[IJSVGTransform affineTransformToSVGTransformComponentString:layer.affineTransform]);
for(CALayer<IJSVGDrawableLayer>* sublayer in layer.debugLayers) {
[self logLayer:sublayer
depth:depth+1];
}
}
+ (CGRect)calculateFrameForSublayers:(NSArray<CALayer<IJSVGDrawableLayer>*>*)layers
{
CGRect rect = CGRectNull;
for(CALayer<IJSVGDrawableLayer>* layer in layers) {
CGRect layerFrame = layer.outerBoundingBox;
// if we are a transform layer, we can just apply its transform
// to its sublayers and keep going down the tree
if([layer isKindOfClass:IJSVGTransformLayer.class] == YES) {
CGRect frame = [self calculateFrameForSublayers:layer.sublayers];
frame = CGRectApplyAffineTransform(frame, layer.affineTransform);
layerFrame = frame;
}
if(CGRectIsNull(rect)) {
rect = layerFrame;
continue;
}
rect = CGRectUnion(rect, layerFrame);
}
return rect;
}
- (void)setBackingScaleFactor:(CGFloat)newFactor
{
if(_backingScaleFactor == newFactor) {
return;
}
_backingScaleFactor = newFactor;
self.contentsScale = newFactor;
self.rasterizationScale = newFactor;
// make sure its applied to any mask or clipPath
_maskLayer.backingScaleFactor = newFactor;
for(CALayer<IJSVGDrawableLayer>* clipLayer in _clipLayers) {
clipLayer.backingScaleFactor = newFactor;
}
}
- (void)performRenderInContext:(CGContextRef)ctx
{
if(_maskLayer != nil) {
[self.class clipContextWithMask:_maskLayer
toLayer:self
inContext:ctx
drawingBlock:^{
[super renderInContext:ctx];
}];
return;
}
[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
@@ -116,7 +602,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];
@@ -127,14 +613,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);
@@ -145,6 +631,16 @@
CGContextConcatCTM(context, sublayerTransform);
}
- (CGAffineTransform)absoluteTransform
{
return [IJSVGLayer absoluteTransformForLayer:self];
}
- (BOOL)requiresBackingScale
{
return _maskLayer != nil || (_clipLayers != nil && _clipLayers.count != 0);
}
- (IJSVGShapeLayer*)maskingLayer
{
return (IJSVGShapeLayer*)_maskingLayer ?: nil;
@@ -152,19 +648,133 @@
- (void)renderInContext:(CGContextRef)ctx
{
if (self.blendingMode != kCGBlendModeNormal) {
CGContextSaveGState(ctx);
CGContextSetBlendMode(ctx, self.blendingMode);
[self _customRenderInContext:ctx];
CGContextRestoreGState(ctx);
return;
}
[self _customRenderInContext:ctx];
[IJSVGLayer renderLayer:self
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
}
- (id<CAAction>)actionForKey:(NSString*)event
- (CGRect)absoluteFrame
{
return [self.class absoluteFrameForLayer:self];
}
- (CGRect)boundingBox
{
return CGRectIsNull(_boundingBox) == NO ? _boundingBox : self.frame;
}
- (CGRect)outerBoundingBox
{
return CGRectIsNull(_outerBoundingBox) == NO ? _outerBoundingBox : self.frame;
}
- (CGRect)boundingBoxBounds
{
return (CGRect) {
.origin = CGPointZero,
.size = self.boundingBox.size
};
}
- (CGRect)innerBoundingBox
{
return (CGRect) {
.origin = CGPointZero,
.size = self.outerBoundingBox.size
};
}
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
{
return _referencingLayer ?: self.superlayer;
}
-(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;
}
- (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) IJSVGLayer* 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
@@ -6,36 +6,103 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGPatternLayer.h"
#import <IJSVG/IJSVGPatternLayer.h>
#import <IJSVG/IJSVGTransform.h>
#import <IJSVG/IJSVGUnitRect.h>
#import <IJSVG/IJSVGViewBox.h>
@interface IJSVGPatternLayer ()
@property (nonatomic, assign, readonly) CGSize cellSize;
@property (nonatomic, assign) CGRect viewBox;
@end
@implementation IJSVGPatternLayer
@synthesize pattern;
@synthesize patternNode;
- (void)dealloc
- (BOOL)requiresBackingScale
{
(void)([pattern release]), pattern = nil;
(void)([patternNode release]), patternNode = nil;
[super dealloc];
return YES;
}
- (id)init
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
if ((self = [super init]) != nil) {
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
}
return self;
[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;
[layer.pattern renderInContext:ctx];
IJSVGPatternLayer* layer = (__bridge IJSVGPatternLayer*)info;
CGSize size = layer.cellSize;
CGContextSaveGState(ctx);
CGRect rect = CGRectMake(0.f, 0.f, size.width, size.height);
CGContextClipToRect(ctx, rect);
IJSVGViewBoxAlignment alignment = layer.patternNode.viewBoxAlignment;
IJSVGViewBoxMeetOrSlice meetOrSlice = layer.patternNode.viewBoxMeetOrSlice;
CGRect viewBox = layer.viewBox;
IJSVGViewBoxDrawingBlock drawBlock = ^(CGFloat scale[]) {
[IJSVGLayer renderLayer:layer.pattern
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
};
IJSVGContextDrawViewBox(ctx, viewBox, rect, alignment, meetOrSlice,
drawBlock);
CGContextSaveGState(ctx);
};
- (CALayer<IJSVGDrawableLayer>*)referencingLayer
{
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
@@ -45,13 +112,32 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
CGContextSetFillColorSpace(ctx, patternSpace);
CGColorSpaceRelease(patternSpace);
CALayer<IJSVGDrawableLayer>* layer = (CALayer<IJSVGDrawableLayer>*)self.referencingLayer;
// transform us back into the correct space
CGAffineTransform transform = CGAffineTransformIdentity;
if(_patternNode.units == IJSVGUnitUserSpaceOnUse) {
transform = [IJSVGLayer userSpaceTransformForLayer:layer];
}
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 rect = self.bounds;
CGPatternRef ref = CGPatternCreate((void*)self, self.bounds,
CGAffineTransformIdentity,
roundf(rect.size.width * self.patternNode.width.value),
roundf(rect.size.height * self.patternNode.height.value),
CGRect selfBounds = IJSVGLayerGetBoundingBoxBounds(self);
CGPatternRef ref = CGPatternCreate((void*)self, selfBounds,
transform, _cellSize.width, _cellSize.height,
kCGPatternTilingConstantSpacing,
true, &callbacks);
@@ -61,7 +147,17 @@ void IJSVGPatternDrawingCallBack(void* info, CGContextRef ctx)
CGPatternRelease(ref);
// fill it
CGContextFillRect(ctx, rect);
CGContextFillRect(ctx, selfBounds);
}
- (NSArray<CALayer<IJSVGDrawableLayer>*>*)debugLayers
{
return @[self.pattern];
}
- (IJSVGTraitedColorStorage*)colors
{
return _pattern.colors;
}
@end
@@ -1,23 +0,0 @@
//
// IJSVGRadialGradient.h
// IJSVGExample
//
// Created by Curtis Hard on 03/09/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGGradient.h"
#import <Foundation/Foundation.h>
@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* radius;
+ (NSGradient*)parseGradient:(NSXMLElement*)element
gradient:(IJSVGRadialGradient*)gradient;
@end
@@ -1,159 +0,0 @@
//
// IJSVGRadialGradient.m
// IJSVGExample
//
// Created by Curtis Hard on 03/09/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGRadialGradient.h"
@implementation IJSVGRadialGradient
@synthesize cx;
@synthesize cy;
@synthesize fx;
@synthesize fy;
@synthesize radius;
- (void)dealloc
{
(void)([cx release]), cx = nil;
(void)([cy release]), cy = nil;
(void)([fx release]), fx = nil;
(void)([fy release]), fy = nil;
(void)([radius release]), radius = nil;
[super dealloc];
}
- (id)copyWithZone:(NSZone*)zone
{
IJSVGRadialGradient* grad = [super copyWithZone:zone];
grad.fx = self.fx;
grad.fy = self.fy;
grad.cx = self.cx;
grad.cy = self.cy;
grad.radius = self.radius;
return grad;
}
+ (NSGradient*)parseGradient:(NSXMLElement*)element
gradient:(IJSVGRadialGradient*)gradient
{
// cx defaults to 50% if not specified
NSDictionary* kv = @{ @"cx" : @"cx",
@"cy" : @"cy",
@"r" : @"radius" };
for (NSString* key in kv.allKeys) {
NSString* str = [element attributeForName:key].stringValue;
IJSVGUnitLength* unit = nil;
if (str != nil) {
unit = [IJSVGUnitLength unitWithString:str
fromUnitType:gradient.units];
} else {
// spec says to say 50% for missing property default
unit = [IJSVGUnitLength unitWithPercentageFloat:.5f];
}
[gradient setValue:unit
forKey:kv[key]];
}
// fx and fy are the same unless specified otherwise
gradient.fx = gradient.cx;
gradient.fy = gradient.cy;
// needs fixing
NSString* fx = [element attributeForName:@"fx"].stringValue;
if (fx != nil) {
gradient.fx = [IJSVGUnitLength unitWithString:fx
fromUnitType:gradient.units];
}
NSString* fy = [element attributeForName:@"fy"].stringValue;
if (fx != nil) {
gradient.fy = [IJSVGUnitLength unitWithString:fy
fromUnitType:gradient.units];
}
if (gradient.gradient != nil) {
return nil;
}
NSArray* colors = nil;
CGFloat* colorStops = [self.class computeColorStopsFromString:element colors:&colors];
NSGradient* ret = [[[NSGradient alloc] initWithColors:colors
atLocations:colorStops
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
free(colorStops);
return ret;
}
- (void)drawInContextRef:(CGContextRef)ctx
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
{
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGFloat radius = 0.f;
CGPoint startPoint = CGPointZero;
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
// transforms
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
// make sure we apply the absolute position to
// transform us back into the correct space
if (inUserSpace == YES) {
CGContextConcatCTM(ctx, absoluteTransform);
}
// compute size based on percentages
CGFloat x = [self.cx computeValue:CGRectGetWidth(boundingBox)];
CGFloat y = [self.cy computeValue:CGRectGetHeight(boundingBox)];
startPoint = CGPointMake(x, y);
CGFloat val = MIN(CGRectGetWidth(boundingBox),
CGRectGetHeight(boundingBox));
radius = [self.radius computeValue:val];
CGFloat ex = [self.fx computeValue:CGRectGetWidth(boundingBox)];
CGFloat ey = [self.fy computeValue:CGRectGetHeight(boundingBox)];
gradientEndPoint = CGPointMake(ex, ey);
gradientStartPoint = startPoint;
// transform if width or height is not equal - this can only
// be done if we are using objectBoundingBox
if (inUserSpace == NO && CGRectGetWidth(boundingBox) != CGRectGetHeight(boundingBox)) {
CGAffineTransform tr = CGAffineTransformMakeTranslation(gradientStartPoint.x,
gradientStartPoint.y);
if (CGRectGetWidth(boundingBox) > CGRectGetHeight(boundingBox)) {
tr = CGAffineTransformScale(tr, CGRectGetWidth(boundingBox) / CGRectGetHeight(boundingBox), 1);
} else {
tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(boundingBox) / CGRectGetWidth(boundingBox));
}
tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y);
selfTransform = CGAffineTransformConcat(tr, selfTransform);
}
// transform the context
CGContextConcatCTM(ctx, selfTransform);
// draw the gradient
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
CGContextDrawRadialGradient(ctx, self.CGGradient,
gradientEndPoint, 0,
gradientStartPoint,
radius, options);
#ifdef IJSVG_DEBUG_GRADIENTS
[self _debugStart:gradientStartPoint
end:gradientEndPoint
context:ctx];
#endif
}
@end
@@ -0,0 +1,24 @@
//
// IJSVGRootLayer.h
// IJSVG
//
// Created by Curtis Hard on 15/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVG.h>
@interface IJSVGRootLayer : IJSVGGroupLayer {
@private
BOOL _disableBackingScalePropagation;
}
- (void)renderInContext:(CGContextRef)ctx
viewPort:(CGRect)viewPort
backingScale:(CGFloat)backingScale
quality:(IJSVGRenderQuality)quality
ignoreIntrinsicSize:(BOOL)ignoreIntrinsicSize;
@end
@@ -0,0 +1,93 @@
//
// IJSVGRootLayer.m
// IJSVG
//
// Created by Curtis Hard on 15/04/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGRootLayer.h>
@implementation IJSVGRootLayer
- (void)performRenderInContext:(CGContextRef)ctx
{
if(self.viewBox != nil) {
CGRect viewBox = [self.viewBox computeValue:CGSizeZero];
__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
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);
};
IJSVGContextDrawViewBox(ctx, viewBox, IJSVGLayerGetBoundingBoxBounds(self),
self.viewBoxAlignment,
self.viewBoxMeetOrSlice, drawingBlock);
return;
}
[super performRenderInContext:ctx];
}
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
// get nearest .5f
backingScaleFactor = MAX(round(backingScaleFactor * 2.f) / 2.f, .5f);
[super setBackingScaleFactor:backingScaleFactor];
if(_disableBackingScalePropagation == YES) {
return;
}
[self propagateBackingScalePropertiesToSublayers];
}
- (void)propagateBackingScalePropertiesToSublayers
{
for(CALayer<IJSVGDrawableLayer>* layer in self.sublayers) {
[IJSVGLayer setBackingScaleFactor:self.backingScaleFactor
renderQuality:self.renderQuality
recursivelyToLayer:layer];
}
}
- (void)renderInContext:(CGContextRef)ctx
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 renderInContext:ctx];
}
- (BOOL)treatImplicitOriginAsTransform
{
return NO;
}
@end
@@ -6,28 +6,17 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGLayer.h"
#import "IJSVGUtils.h"
#import <IJSVG/IJSVGLayer.h>
#import <IJSVG/IJSVGUtils.h>
#import <QuartzCore/QuartzCore.h>
@interface IJSVGShapeLayer : CAShapeLayer {
@interface IJSVGShapeLayer : CAShapeLayer <IJSVGDrawableLayer, IJSVGPathableLayer> {
@private
IJSVGLayer* _maskingLayer;
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) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) CGPoint originalPathOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
@property (nonatomic, assign) IJSVGPrimitivePathType primitiveType;
- (void)applySublayerMaskToContext:(CGContextRef)context
@@ -6,74 +6,124 @@
// 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 gradientFillLayer;
@synthesize patternFillLayer;
@synthesize gradientStrokeLayer;
@synthesize patternStrokeLayer;
@synthesize strokeLayer;
@synthesize requiresBackingScaleHelp;
@synthesize backingScaleFactor;
@synthesize blendingMode;
@synthesize convertMasksToPaths;
@synthesize originalPathOrigin;
@synthesize backingScaleFactor = _backingScaleFactor;
@synthesize requiresBackingScale;
@synthesize renderQuality;
@synthesize primitiveType;
@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
{
self.contents = nil;
(void)([_maskingLayer release]), _maskingLayer = nil;
[super dealloc];
if(_clipPath != NULL) {
CGPathRelease(_clipPath);
}
}
- (id<CAAction>)actionForKey:(NSString*)event
{
return nil;
}
- (CGRect)absoluteFrame
{
return [IJSVGLayer absoluteFrameForLayer:self];
}
- (CGAffineTransform)absoluteTransform
{
return [IJSVGLayer absoluteTransformForLayer:self];
}
- (CALayer<IJSVGDrawableLayer> *)referencingLayer
{
return _referencingLayer ?: self.superlayer;
}
- (CGRect)boundingBoxBounds
{
return (CGRect) {
.origin = CGPointZero,
.size = self.boundingBox.size
};
}
- (CGRect)innerBoundingBox
{
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 (self.backingScaleFactor == newFactor) {
if(_backingScaleFactor == newFactor) {
return;
}
backingScaleFactor = newFactor;
_backingScaleFactor = newFactor;
self.contentsScale = newFactor;
self.rasterizationScale = newFactor;
// make sure its applied to any mask or clipPath
_maskLayer.backingScaleFactor = newFactor;
for(CALayer<IJSVGDrawableLayer>* clipLayer in _clipLayers) {
clipLayer.backingScaleFactor = newFactor;
}
[self setNeedsDisplay];
}
- (void)_customRenderInContext:(CGContextRef)ctx
- (void)performRenderInContext:(CGContextRef)ctx
{
if (self.convertMasksToPaths == YES && _maskingLayer != nil) {
CGContextSaveGState(ctx);
[self applySublayerMaskToContext:ctx
forSublayer:(IJSVGLayer*)self
withOffset:CGPointZero];
[super renderInContext:ctx];
CGContextRestoreGState(ctx);
if(_maskLayer != nil) {
[IJSVGLayer clipContextWithMask:_maskLayer
toLayer:self
inContext:ctx
drawingBlock:^{
[super renderInContext:ctx];
}];
return;
}
[super renderInContext:ctx];
}
- (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
@@ -85,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];
@@ -96,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);
@@ -121,31 +171,142 @@
- (void)renderInContext:(CGContextRef)ctx
{
if (self.blendingMode != kCGBlendModeNormal) {
CGContextSaveGState(ctx);
CGContextSetBlendMode(ctx, self.blendingMode);
[self _customRenderInContext:ctx];
CGContextRestoreGState(ctx);
return;
}
[self _customRenderInContext:ctx];
[IJSVGLayer renderLayer:(IJSVGLayer*)self
inContext:ctx
options:IJSVGLayerDrawingOptionNone];
}
- (CGPoint)absoluteOrigin
- (NSMapTable<NSNumber*,CALayer<IJSVGDrawableLayer>*>*)layerUsageMapTable
{
CGPoint point = CGPointZero;
CALayer* pLayer = self;
while (pLayer != nil) {
point.x += pLayer.frame.origin.x;
point.y += pLayer.frame.origin.y;
pLayer = pLayer.superlayer;
if(_layerUsageMapTable == nil) {
_layerUsageMapTable = IJSVGLayerDefaultUsageMapTable();
}
return point;
return _layerUsageMapTable;
}
- (id<CAAction>)actionForKey:(NSString*)event
- (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;
}
-(NSArray<CALayer<IJSVGDrawableLayer>*>*)debugLayers
{
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,7 +6,7 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGStrokeLayer.h"
#import <IJSVG/IJSVGStrokeLayer.h>
@implementation IJSVGStrokeLayer
@@ -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
@@ -0,0 +1,17 @@
//
// IJSVGTransformLayer.h
// IJSVG
//
// Created by Curtis Hard on 31/03/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import <IJSVG/IJSVGLayer.h>
@interface IJSVGTransformLayer : CATransformLayer <IJSVGDrawableLayer> {
@private
NSMapTable<NSNumber*, CALayer<IJSVGDrawableLayer>*>* _layerUsageMapTable;
}
@end
@@ -0,0 +1,160 @@
//
// IJSVGTransformLayer.m
// IJSVG
//
// Created by Curtis Hard on 31/03/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGTransformLayer.h>
#import <IJSVG/IJSVGTraitedColorStorage.h>
@implementation IJSVGTransformLayer
@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 colors;
@synthesize absoluteOrigin;
@synthesize blendingMode;
@synthesize referencingLayer = _referencingLayer;
- (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];
}
- (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,88 @@
//
// 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
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributeX];
[storage setBit:IJSVGNodeAttributeY];
[storage setBit:IJSVGNodeAttributeWidth];
[storage setBit:IJSVGNodeAttributeHeight];
[storage setBit:IJSVGNodeAttributeClipPathUnits];
[storage setBit:IJSVGNodeAttributeClipRule];
return storage;
}
- (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
@@ -0,0 +1,22 @@
//
// IJSVGColorNode.h
// IJSVG
//
// Created by Curtis Hard on 29/03/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGNode.h>
@interface IJSVGColorNode : IJSVGNode {
}
@property (nonatomic, strong) NSColor* color;
@property (nonatomic, assign) BOOL isNoneOrTransparent;
+ (IJSVGNode*)colorNodeWithColor:(NSColor*)color;
- (id)initWithColor:(NSColor*)color;
@end
@@ -0,0 +1,33 @@
//
// IJSVGColorNode.m
// IJSVG
//
// Created by Curtis Hard on 29/03/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGColorNode.h>
@implementation IJSVGColorNode
+ (IJSVGNode*)colorNodeWithColor:(NSColor *)color
{
return [[self alloc] initWithColor:color];
}
- (id)initWithColor:(NSColor*)color {
if((self = [super init]) != nil) {
[self addTraits:IJSVGNodeTraitPaintable];
self.color = color;
}
return self;
}
- (void)applyPropertiesFromNode:(IJSVGNode*)node
{
if([node isKindOfClass:self.class]) {
self.color = ((IJSVGColorNode*)node).color;
}
}
@end
@@ -1,21 +0,0 @@
//
// IJSVGDef.h
// IJSVGExample
//
// Created by Curtis Hard on 03/09/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "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,80 @@
//
// 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>
#import <IJSVG/IJSVGUtils.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.UTF8String;
if(name == NULL) {
return IJSVGFilterEffectSourceGraphic;
}
if(IJSVGCharBufferCaseInsensitiveCompare(name, "sourcegraphic") == YES) {
return IJSVGFilterEffectSourceGraphic;
}
if(IJSVGCharBufferCaseInsensitiveCompare(name, "sourcealpha") == YES) {
return IJSVGFilterEffectSourceAlpha;
}
if(IJSVGCharBufferCaseInsensitiveCompare(name, "backgroundimage") == YES) {
return IJSVGFilterEffectSourceBackgroundImage;
}
if(IJSVGCharBufferCaseInsensitiveCompare(name, "backgroundalpha") == YES) {
return IJSVGFilterEffectSourceBackgroundAlpha;
}
if(IJSVGCharBufferCaseInsensitiveCompare(name, "fillpaint") == YES) {
return IJSVGFilterEffectSourceFillPaint;
}
if(IJSVGCharBufferCaseInsensitiveCompare(name, "strokepain") == YES) {
return IJSVGFilterEffectSourceStrokePaint;
}
return IJSVGFilterEffectSourcePrimitiveReference;
}
+ (IJSVGFilterEffectEdgeMode)edgeModeForString:(NSString*)string
{
const char* name = string.lowercaseString.UTF8String;
if(name == NULL) {
return IJSVGFilterEffectEdgeModeNone;
}
if(IJSVGCharBufferCompare(name, "none") == YES) {
return IJSVGFilterEffectEdgeModeNone;
}
if(IJSVGCharBufferCompare(name, "wrap") == YES) {
return IJSVGFilterEffectEdgeModeWrap;
}
if(IJSVGCharBufferCompare(name, "duplicate") == YES) {
return IJSVGFilterEffectEdgeModeDuplicate;
}
return IJSVGFilterEffectEdgeModeNone;
}
- (CIImage*)processImage:(CIImage*)image
{
return image;
}
@end
@@ -7,14 +7,11 @@
//
#import <Foundation/Foundation.h>
#import "IJSVGNode.h"
#import <IJSVG/IJSVGNode.h>
@interface IJSVGForeignObject : IJSVGNode {
NSString * requiredExtension;
}
@property ( nonatomic, copy ) NSString * requiredExtension;
@property (nonatomic, copy) NSString* requiredExtension;
@end
@@ -6,16 +6,8 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGForeignObject.h"
#import <IJSVG/IJSVGForeignObject.h>
@implementation IJSVGForeignObject
@synthesize requiredExtension;
- (void)dealloc
{
(void)([requiredExtension release]), requiredExtension = nil;
[super dealloc];
}
@end
@@ -6,33 +6,28 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGColorList.h"
#import "IJSVGDef.h"
#import "IJSVGTransform.h"
#import <Foundation/Foundation.h>
#import <IJSVG/IJSVGTraitedColorStorage.h>
#import <IJSVG/IJSVGTransform.h>
#import <IJSVG/IJSVGGroup.h>
@interface IJSVGGradient : IJSVGNode
@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;
+ (CGFloat*)computeColorStopsFromString:(NSXMLElement*)element
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*)computedColorList;
bounds:(NSRect)objectRect
transform:(CGAffineTransform)absoluteTransform;
@end

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