Compare commits

..

308 Commits

Author SHA1 Message Date
Curtis Hard 35fc5157b3 fix crash with realloc call being incorrect 2025-01-26 12:44:09 +00:00
Curtis Hard 3742cfd16e implement better sizing 2024-12-15 20:47:30 +00:00
Curtis Hard b47b487a8d Speed up Xcode 16 build times 2024-09-17 23:00:34 +01:00
Curtis Hard 6dc767f88e Remove file 2024-07-21 13:45:39 +01:00
Curtis Hard f8efb68277 Merge branch 'fixes/gradient-stop-parsing' 2024-07-21 13:44:32 +01:00
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
Curtis Hard 849807d3c5 Updated build number 2020-01-05 17:11:41 +00:00
Curtis Hard eeb03bd89c Fixes exporter being wrong if the viewbox is not zero 2020-01-02 14:16:17 +00:00
Curtis Hard fdc0859e3f Faster parsing still 2020-01-01 22:06:29 +00:00
Curtis Hard e2a7f51507 Fixes 2020-01-01 17:48:15 +00:00
Curtis Hard ab69ed94dc Formatting 2019-12-29 20:50:44 +00:00
Curtis Hard c5be83f57f Code cleanup 2019-12-28 15:48:43 +00:00
Curtis Hard ed00aca06e Refactor 2019-12-27 16:48:12 +00:00
Curtis Hard f51fda5f1e Removed cache
- also fixes center if no scale was applied
2019-12-27 15:01:20 +00:00
Curtis Hard dd655053ca Finally fixes memory leak
- due to this being fixed, we can also get rid of the transaction lock
2019-12-26 20:10:47 +00:00
Curtis Hard 8c89627f74 Just use matrix, attributes are a pain in the butt 2019-12-26 16:08:14 +00:00
Curtis Hard eb1d27decd Much better path compression and float rewriting for exporting 2019-12-26 13:49:41 +00:00
Curtis Hard e6141d7a0f Fixes a long time ago bug with transforms with matrix converting to attribute strings 2019-12-25 21:05:56 +00:00
Curtis Hard 3b7ad40794 Vey strange... 2019-12-25 18:40:50 +00:00
Curtis Hard 674d17863f Fixes memory overflow issues
- also added centering for exported SVG’s as an option
2019-12-25 18:19:28 +00:00
Curtis Hard a59072fa1d Refactor 2019-12-25 13:53:42 +00:00
Curtis Hard 910b90cd4e More perf stuff 2019-12-25 13:45:13 +00:00
Curtis Hard bb3b9c5378 More improvements 2019-12-25 11:58:10 +00:00
Curtis Hard 6d10b172e7 Increases again 2019-12-24 14:47:47 +00:00
Curtis Hard c6e59a9280 More perf increases 2019-12-24 09:27:06 +00:00
Curtis Hard df5b3219ca Refactor of naming 2019-12-23 21:59:19 +00:00
Curtis Hard 2c1ae8d0f3 Credit where its due 2019-12-23 21:40:02 +00:00
Curtis Hard 7ba939aabf This is insanely fast 2019-12-23 20:48:12 +00:00
Curtis Hard 24e097fedf Faster again! 2019-12-23 20:30:05 +00:00
Curtis Hard 025ac84958 Refactor of command parsing 2019-12-23 19:37:56 +00:00
Curtis Hard ac9ccdda25 Refactor 2019-12-23 16:17:47 +00:00
Curtis Hard 14641ddd60 More goodies 2019-12-23 15:40:41 +00:00
Curtis Hard 5f32d03744 Intiial commit 2019-12-23 14:24:49 +00:00
Curtis Hard af086622b1 Faster implementation of transaction 2019-12-22 22:19:20 +00:00
Curtis Hard 79187326bc Added CGImageRef method 2019-12-21 13:23:52 +00:00
Curtis Hard ee570eb77f Fixes scale being incorrect 2019-12-20 08:36:12 +00:00
Curtis Hard d8e1ce8d70 This is much more performant then using nsimage lockFocus 2019-12-19 22:32:55 +00:00
Curtis Hard a900e2dc50 Resorted this list as its actually faster, basically stick the commonly used commands first 2019-12-17 21:48:52 +00:00
Curtis Hard 21f97babec Refactor of contsant names 2019-12-12 11:02:49 +00:00
Curtis Hard 0273a491de Refactor of path - uses less memory and makes more sense 2019-12-12 10:51:20 +00:00
Curtis Hard 488a0c3654 Update all things! 2019-12-12 08:09:08 +00:00
Curtis Hard 7f7321e6a7 Merge branch 'feature/primitiveExportTypes' 2019-12-12 08:07:05 +00:00
228 changed files with 69998 additions and 22533 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 * }
}
+308 -90
View File
@@ -3,38 +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, ); }; };
@@ -44,20 +82,15 @@
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 */; };
59EB760323905F7300F5AE63 /* IJSVGNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759223905F6D00F5AE63 /* IJSVGNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB760423905F7300F5AE63 /* IJSVGCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759323905F6D00F5AE63 /* IJSVGCache.m */; };
59EB760523905F7300F5AE63 /* IJSVGUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759423905F6D00F5AE63 /* IJSVGUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB760623905F7300F5AE63 /* IJSVGCommandHorizontalLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB759523905F6D00F5AE63 /* IJSVGCommandHorizontalLine.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB760723905F7300F5AE63 /* IJSVGNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB759623905F6D00F5AE63 /* IJSVGNode.m */; };
@@ -71,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, ); }; };
@@ -79,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, ); }; };
@@ -100,12 +133,10 @@
59EB762C23905F7300F5AE63 /* IJSVGPattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BB23905F7000F5AE63 /* IJSVGPattern.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB762D23905F7300F5AE63 /* IJSVGLayerTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BC23905F7000F5AE63 /* IJSVGLayerTree.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB762E23905F7300F5AE63 /* IJSVGExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EB75BD23905F7000F5AE63 /* IJSVGExporter.m */; };
59EB762F23905F7300F5AE63 /* IJSVGCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BE23905F7000F5AE63 /* IJSVGCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
59EB763023905F7300F5AE63 /* IJSVGPatternLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
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,62 +155,108 @@
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; name = IJSVG.h; path = ../../../../source/IJSVG.h; 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; name = IJSVGWriter.h; path = ../../../../source/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; name = IJSVGFontConverter.m; path = ../../../../source/IJSVGFontConverter.m; sourceTree = "<group>"; };
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGImageRep.m; path = ../../../../source/IJSVGImageRep.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>"; };
59EB758023905F6C00F5AE63 /* IJSVGUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGUtils.m; sourceTree = "<group>"; };
59EB758123905F6C00F5AE63 /* IJSVGStyleSheetSelectorRaw.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheetSelectorRaw.m; sourceTree = "<group>"; };
59EB758223905F6C00F5AE63 /* IJSVGGroupLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroupLayer.m; sourceTree = "<group>"; };
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; name = IJSVGError.h; path = ../../../../source/IJSVGError.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; name = IJSVGFontConverter.h; path = ../../../../source/IJSVGFontConverter.h; sourceTree = "<group>"; };
59EB758923905F6D00F5AE63 /* IJSVGWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGWriter.m; path = ../../../../source/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>"; };
59EB759223905F6D00F5AE63 /* IJSVGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGNode.h; sourceTree = "<group>"; };
59EB759323905F6D00F5AE63 /* IJSVGCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVGCache.m; path = ../../../../source/IJSVGCache.m; sourceTree = "<group>"; };
59EB759423905F6D00F5AE63 /* IJSVGUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGUtils.h; sourceTree = "<group>"; };
59EB759523905F6D00F5AE63 /* IJSVGCommandHorizontalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandHorizontalLine.h; sourceTree = "<group>"; };
59EB759623905F6D00F5AE63 /* IJSVGNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGNode.m; sourceTree = "<group>"; };
@@ -193,18 +270,18 @@
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>"; };
59EB75A223905F6E00F5AE63 /* IJSVG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJSVG.m; path = ../../../../source/IJSVG.m; sourceTree = "<group>"; };
59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGImageRep.h; path = ../../../../source/IJSVGImageRep.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>"; };
59EB75A523905F6E00F5AE63 /* IJSVGParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGParser.m; sourceTree = "<group>"; };
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>"; };
@@ -222,12 +299,10 @@
59EB75BB23905F7000F5AE63 /* IJSVGPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGPattern.h; sourceTree = "<group>"; };
59EB75BC23905F7000F5AE63 /* IJSVGLayerTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGLayerTree.h; sourceTree = "<group>"; };
59EB75BD23905F7000F5AE63 /* IJSVGExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporter.m; sourceTree = "<group>"; };
59EB75BE23905F7000F5AE63 /* IJSVGCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGCache.h; path = ../../../../source/IJSVGCache.h; sourceTree = "<group>"; };
59EB75BF23905F7000F5AE63 /* IJSVGPatternLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGPatternLayer.h; sourceTree = "<group>"; };
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; name = IJSVGView.m; path = ../../../../source/IJSVGView.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>"; };
@@ -237,7 +312,7 @@
59EB75CA23905F7200F5AE63 /* IJSVGCommandSmoothQuadraticCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGCommandSmoothQuadraticCurve.h; sourceTree = "<group>"; };
59EB75CB23905F7200F5AE63 /* IJSVGCommandEllipticalArc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGCommandEllipticalArc.m; sourceTree = "<group>"; };
59EB75CC23905F7200F5AE63 /* IJSVGGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroup.m; sourceTree = "<group>"; };
59EB75CD23905F7200F5AE63 /* IJSVGView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJSVGView.h; path = ../../../../source/IJSVGView.h; sourceTree = "<group>"; };
59EB75CD23905F7200F5AE63 /* IJSVGView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGView.h; sourceTree = "<group>"; };
59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGForeignObject.h; sourceTree = "<group>"; };
59EB75CF23905F7200F5AE63 /* IJSVGExporterPathInstruction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporterPathInstruction.m; sourceTree = "<group>"; };
59EB75D023905F7200F5AE63 /* IJSVGImageLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImageLayer.h; 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>";
@@ -346,6 +452,8 @@
592ABBE62397A00C00F44380 /* Parsing */ = {
isa = PBXGroup;
children = (
59E7CFAD23B148600077D599 /* IJSVGCommandParser.h */,
59E7CFAE23B148600077D599 /* IJSVGCommandParser.m */,
59EB75A723905F6F00F5AE63 /* IJSVGParser.h */,
59EB75A523905F6E00F5AE63 /* IJSVGParser.m */,
);
@@ -355,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 */,
@@ -375,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>";
@@ -394,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>";
@@ -416,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>";
@@ -425,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>";
@@ -453,6 +596,7 @@
594CF471238FF38E009B251B /* IJSVG */ = {
isa = PBXGroup;
children = (
596AB830298854270013110A /* IJSVG.modulemap */,
59EB756423905F3100F5AE63 /* Source */,
594CF473238FF38E009B251B /* Info.plist */,
);
@@ -470,9 +614,25 @@
name = Frameworks;
sourceTree = "<group>";
};
59DD1FD123A22CFD00E28C56 /* Core */ = {
isa = PBXGroup;
children = (
59EB756A23905F6B00F5AE63 /* IJSVG.h */,
59EB75A223905F6E00F5AE63 /* IJSVG.m */,
59EB758423905F6C00F5AE63 /* IJSVGError.h */,
59EB75A323905F6E00F5AE63 /* IJSVGImageRep.h */,
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */,
59EB75CD23905F7200F5AE63 /* IJSVGView.h */,
59EB75C123905F7100F5AE63 /* IJSVGView.m */,
595FD12E29EC56BA00666897 /* IJSVGUmbrella.h */,
);
path = Core;
sourceTree = "<group>";
};
59EB756423905F3100F5AE63 /* Source */ = {
isa = PBXGroup;
children = (
59DD1FD123A22CFD00E28C56 /* Core */,
592ABBEB2397A11800F44380 /* Additions */,
592ABBEA2397A10000F44380 /* Rendering */,
592ABBE92397A08500F44380 /* Exporter */,
@@ -483,19 +643,6 @@
592ABBE423979FD200F44380 /* Colors */,
592ABBE323979FBB00F44380 /* Stylesheets */,
592ABBE223979F9B00F44380 /* Commands */,
59EB756A23905F6B00F5AE63 /* IJSVG.h */,
59EB75A223905F6E00F5AE63 /* IJSVG.m */,
59EB75BE23905F7000F5AE63 /* IJSVGCache.h */,
59EB759323905F6D00F5AE63 /* IJSVGCache.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 */,
);
path = Source;
sourceTree = "<group>";
@@ -509,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 */,
@@ -517,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 */,
@@ -537,16 +682,14 @@
59EB75E823905F7300F5AE63 /* IJSVGUnitLength.h in Headers */,
59EB762723905F7300F5AE63 /* IJSVGMath.h in Headers */,
59EB761523905F7300F5AE63 /* IJSVGStrokeLayer.h in Headers */,
59EB762F23905F7300F5AE63 /* IJSVGCache.h in Headers */,
59EB75DE23905F7300F5AE63 /* IJSVGCommandVerticalLine.h in Headers */,
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 */,
@@ -555,14 +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;
@@ -594,7 +763,8 @@
594CF466238FF38E009B251B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1100;
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1600;
ORGANIZATIONNAME = "Curtis Hard";
TargetAttributes = {
594CF46E238FF38E009B251B = {
@@ -635,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 */,
@@ -653,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 */,
59EB760423905F7300F5AE63 /* IJSVGCache.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 */,
@@ -723,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;
@@ -731,13 +923,17 @@
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_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)",
@@ -748,10 +944,15 @@
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;
OTHER_LDFLAGS = "-Wl,-no_warn_duplicate_libraries";
PRODUCT_MODULE_NAME = IJSVG;
SDKROOT = macosx;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -784,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;
@@ -792,20 +994,30 @@
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;
OTHER_LDFLAGS = "-Wl,-no_warn_duplicate_libraries";
PRODUCT_MODULE_NAME = IJSVG;
SDKROOT = macosx;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -815,12 +1027,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;
DEFINES_MODULE = NO;
CURRENT_PROJECT_VERSION = 2;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 9KTR4W9XX6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -832,7 +1046,8 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 2.1;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
@@ -842,12 +1057,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;
DEFINES_MODULE = NO;
CURRENT_PROJECT_VERSION = 2;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 9KTR4W9XX6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -859,7 +1076,8 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 2.1;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1120"
LastUpgradeVersion = "1600"
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,17 +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;
@end
@@ -1,26 +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];
}
@end
@@ -10,9 +10,10 @@
@interface NSString (IJSVGAdditions)
- (NSArray<NSString *> *)ijsvg_componentsSeparatedByChars:(char *)aChar;
- (NSArray<NSString*>*)ijsvg_componentsSeparatedByChars:(const char*)aChar;
- (BOOL)ijsvg_isNumeric;
- (BOOL)ijsvg_containsAlpha;
- (NSArray*)ijsvg_componentsSplitByWhiteSpace;
- (BOOL)ijsvg_isHexString;
@end
@@ -6,65 +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:(char*)aChar
- (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;
// block for easy comparison
NSUInteger aLength = strlen(aChar);
BOOL (^charsContainsChar)(char anotherChar) = ^(char anotherChar) {
for (NSInteger i = 0; i < aLength; i++) {
if (aChar[i] == anotherChar) {
return YES;
}
}
return NO;
};
for (NSInteger i = 0; i < length; i++) {
// the char
unichar theChar = [self characterAtIndex:i];
// start the buffer
BOOL isEqualToChar = charsContainsChar(theChar);
if (isEqualToChar == NO) {
startedString = YES;
chars[ind++] = theChar;
}
// has started and char is the search char, or its at end
if ((startedString == YES && isEqualToChar) || (i == (length - 1) && startedString == YES)) {
startedString = NO;
// append the comp
[comp addObject:[NSString stringWithCharacters:chars length:ind]];
free(chars);
// restart and realloc the memory
ind = 0;
chars = (unichar*)calloc(sizeof(unichar), self.length);
}
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;
}
}
@@ -74,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;
}
}
@@ -88,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
+128 -78
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)];
}
@@ -385,8 +432,8 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
}
// note the %g, CSS alpha is 0 to 1, not 0 - 100, my bad!
return [NSString stringWithFormat:@"rgba(%d,%d,%d,%g)", red, green, blue,
((float)alpha / 100.f)];
return [NSString stringWithFormat:@"rgba(%d,%d,%d,%@)", red, green, blue,
IJSVGShortFloatString((float)alpha / 100.f)];
}
+ (NSString*)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color
@@ -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,7 +6,8 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGPath.h"
#import <IJSVG/IJSVGCommandParser.h>
#import <IJSVG/IJSVGPath.h>
#import <Foundation/Foundation.h>
static const NSInteger IJSVGCustomVariableParameterCount = NSNotFound;
@@ -16,31 +17,16 @@ typedef NS_ENUM(NSInteger, IJSVGCommandType) {
kIJSVGCommandTypeRelative
};
typedef NS_ENUM(NSUInteger, IJSVGPathDataSequence) {
kIJSVGPathDataSequenceTypeFloat,
kIJSVGPathDataSequenceTypeFlag
};
@interface IJSVGCommand : NSObject {
NSString* commandString;
NSString* 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, copy) NSString* command;
@property (nonatomic, assign) char command;
@property (nonatomic, assign) CGFloat* parameters;
@property (nonatomic, assign) NSInteger parameterCount;
@property (nonatomic, assign) NSInteger requiredParameters;
@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;
@@ -54,15 +40,30 @@ typedef NS_ENUM(NSUInteger, IJSVGPathDataSequence) {
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*)commandString;
+ (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,32 +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 requiredParameters;
@synthesize type;
@synthesize previousCommand;
@synthesize isSubCommand;
+ (BOOL)requiresCustomParameterParsing
{
return NO;
@@ -52,7 +42,7 @@
command:(IJSVGCommand*)currentCommand
previousCommand:(IJSVGCommand*)command
type:(IJSVGCommandType)type
path:(IJSVGPath*)path
path:(CGMutablePathRef)path
{
}
@@ -102,38 +92,139 @@
return nil;
}
- (void)dealloc
+ (CGMutablePathRef)newPathForCommandsArray:(NSArray<IJSVGCommand*>*)commands
{
(void)([commandString release]), commandString = nil;
(void)([command release]), command = 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
+ (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 substringToIndex:1] copy];
type = [IJSVGUtils typeForCommandString:self.command];
requiredParameters = [self.class requiredParameterCount];
_command = str[0];
_type = [IJSVGUtils typeForCommandChar:_command];
NSInteger sets = 0;
NSInteger paramCount = [self.class requiredParameterCount];
IJSVGPathDataSequence* sequence = [self.class pathDataSequence];
parameters = IJSVGParsePathDataSequence(str, sequence, requiredParameters, &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;
@@ -143,6 +234,7 @@
// generate the subcommand
IJSVGCommand* command = [self subcommandWithParameters:subParams
paramCount:paramCount
previousCommand:lastCommand];
// make sure we assign the last command or hell breaks
@@ -153,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.requiredParameters;
if (req != 0) {
NSInteger req = [self.class requiredParameterCount];
if(req != 0) {
subParams = (CGFloat*)malloc(req * sizeof(CGFloat));
memcpy(subParams, &self.parameters[index * req], sizeof(CGFloat) * req);
}
@@ -171,11 +293,12 @@
}
- (IJSVGCommand*)subcommandWithParameters:(CGFloat*)subParams
paramCount:(NSInteger)paramCount
previousCommand:(IJSVGCommand*)aPreviousCommand
{
// create a subcommand per set
IJSVGCommand* c = [[[self.class alloc] init] autorelease];
c.parameterCount = self.requiredParameters;
IJSVGCommand* c = [[self.class alloc] init];
c.parameterCount = paramCount;
c.parameters = subParams;
c.type = self.type;
c.command = self.command;
@@ -186,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);
}
@@ -209,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 currentSubpath] 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 currentSubpath] 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.currentSubpath 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.currentSubpath transformUsingAffineTransform:trans];
trans = NSAffineTransform.transform;
[trans scaleXBy:(1 / scale.x) yBy:(1 / scale.y)];
[path.currentSubpath transformUsingAffineTransform:trans];
[path.currentSubpath appendBezierPathWithArcWithCenter:NSZeroPoint
radius:radius
startAngle:radians_to_degrees(startAngle)
endAngle:radians_to_degrees(startAngle + angleDelta)
clockwise:!sweepFlag];
trans = NSAffineTransform.transform;
[trans scaleXBy:scale.x yBy:scale.y];
[path.currentSubpath transformUsingAffineTransform:trans];
trans = NSAffineTransform.transform;
[trans rotateByRadians:xAxisRotation];
[path.currentSubpath transformUsingAffineTransform:trans];
trans = NSAffineTransform.transform;
[trans translateXBy:centerPoint.x yBy:centerPoint.y];
[path.currentSubpath transformUsingAffineTransform:trans];
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 currentSubpath] lineToPoint:NSMakePoint(params[0], [path currentSubpath].currentPoint.y)];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, params[0], CGPathGetCurrentPoint(path).y);
return;
}
[[path currentSubpath] 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 currentSubpath] lineToPoint:NSMakePoint(params[0], params[1])];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, params[0], params[1]);
return;
}
NSPoint point = NSMakePoint([path currentSubpath].currentPoint.x + params[0],
[path currentSubpath].currentPoint.y + params[1]);
[[path currentSubpath] 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 currentSubpath] 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 currentSubpath] relativeMoveToPoint:NSMakePoint(params[0], params[1])];
}
@catch (NSException* exception) {
[[path currentSubpath] 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 currentSubpath] 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 currentSubpath] addQuadCurveToPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[2], [path currentSubpath].currentPoint.y + params[3])
controlPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[0], [path currentSubpath].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 currentSubpath].currentPoint.x, [path currentSubpath].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 currentSubpath].currentPoint.x,
-1 * command.parameters[3] + 2 * [path currentSubpath].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 currentSubpath].currentPoint.x - command.parameters[4],
[path currentSubpath].currentPoint.y - command.parameters[5]);
firstControl = NSMakePoint(-1 * (command.parameters[2] + oldPoint.x) + 2 * [path currentSubpath].currentPoint.x,
-1 * (command.parameters[3] + oldPoint.y) + 2 * [path currentSubpath].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 currentSubpath].currentPoint.x,
-1 * command.parameters[1] + 2 * [path currentSubpath].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 currentSubpath].currentPoint.x - command.parameters[2],
[path currentSubpath].currentPoint.y - command.parameters[3]);
firstControl = NSMakePoint(-1 * (command.parameters[0] + oldPoint.x) + 2 * [path currentSubpath].currentPoint.x,
-1 * (command.parameters[1] + oldPoint.y) + 2 * [path currentSubpath].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 currentSubpath] 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 currentSubpath] curveToPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[2], [path currentSubpath].currentPoint.y + params[3])
controlPoint1:NSMakePoint(firstControl.x, firstControl.y)
controlPoint2:NSMakePoint([path currentSubpath].currentPoint.x + params[0], [path currentSubpath].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 currentSubpath].currentPoint.x, [path currentSubpath].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 currentSubpath].currentPoint.x,
-1 * command.parameters[1] + 2 * [path currentSubpath].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 currentSubpath].currentPoint.x - command.parameters[2],
[path currentSubpath].currentPoint.y - command.parameters[3]);
commandPoint = CGPointMake(-1 * (command.parameters[0] + oldPoint.x) + 2 * ([path currentSubpath].currentPoint.x),
-1 * (command.parameters[1] + oldPoint.y) + 2 * [path currentSubpath].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 currentSubpath].currentPoint.x),
-1 * (path.lastControlPoint.y) + 2 * [path currentSubpath].currentPoint.y);
commandPoint = CGPointMake(-1 * (lastControlPoint.x) + 2 * (currentPoint.x),
-1 * (lastControlPoint.y) + 2 * currentPoint.y);
}
}
path.lastControlPoint = commandPoint;
if (type == kIJSVGCommandTypeAbsolute) {
[[path currentSubpath] 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 currentSubpath] addQuadCurveToPoint:NSMakePoint([path currentSubpath].currentPoint.x + params[0], [path currentSubpath].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 currentSubpath] lineToPoint:NSMakePoint([path currentSubpath].currentPoint.x, params[0])];
if(type == kIJSVGCommandTypeAbsolute) {
CGPathAddLineToPoint(path, NULL, CGPathGetCurrentPoint(path).x, params[0]);
return;
}
[[path currentSubpath] relativeLineToPoint:NSMakePoint(0.f, params[0])];
CGPoint currentPoint = CGPathGetCurrentPoint(path);
CGPathAddLineToPoint(path, NULL, currentPoint.x, currentPoint.y + params[0]);
}
@end
+162
View File
@@ -0,0 +1,162 @@
//
// IJSVGImage.h
// IconJar
//
// Created by Curtis Hard on 30/08/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#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;
@class IJSVGParser;
@interface IJSVG : NSObject <NSPasteboardWriting> {
@private
IJSVGRootNode* _rootNode;
IJSVGLayerTree* _layerTree;
CGRect _viewBox;
CGFloat _backingScale;
IJSVGUnitSize* _intrinsicSize;
IJSVGParser* _parser;
}
// set this to be called when the layer is about to draw, it will call this
// and ask for the scale of the backing store where its going to be drawn
// and apply the scale to each layer that has custom drawing against it, mainly
// pattern and gradient layers
@property (nonatomic, copy) IJSVGRenderingBackingScaleFactorHelper renderingBackingScaleHelper;
// 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, 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;
- (IJSVGRootNode*)rootNode;
- (CGRect)viewBox;
- (CGSize)sizeWithDefaultSize:(CGSize)size;
- (CGSize)sizeByMaintainingAspectRatioWithSize:(CGSize)aSize;
- (NSString*)identifier;
- (NSSet<IJSVG*>*)directDescendSVGs;
- (IJSVGExporter*)exporterWithSize:(CGSize)size
options:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
- (NSString*)SVGStringWithSize:(CGSize)size
options:(IJSVGExporterOptions)options;
- (NSString*)SVGStringWithSize:(CGSize)size
options:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options;
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions;
+ (id)SVGNamed:(NSString*)string;
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path;
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path
flipped:(BOOL)flipped;
- (id)initWithImage:(NSImage*)image;
- (id)initWithRootNode:(IJSVGRootNode*)rootNode;
- (id)initWithSVGLayer:(IJSVGGroupLayer*)group
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)initWithFilePathURL:(NSURL*)aURL;
- (id)initWithFilePathURL:(NSURL*)aURL
error:(NSError**)error;
- (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:(CGSize)aSize
flipped:(BOOL)flipped;
- (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:(CGPoint)point
size:(CGSize)size;
- (BOOL)drawAtPoint:(CGPoint)point
size:(CGSize)aSize
error:(NSError**)error;
- (BOOL)drawInRect:(CGRect)rect;
- (BOOL)drawInRect:(CGRect)rect
error:(NSError**)error;
- (void)drawInRect:(CGRect)rect
context:(CGContextRef)context;
- (NSData*)PDFData;
- (NSData*)PDFData:(NSError**)error;
- (NSData*)PDFDataWithRect:(CGRect)rect;
- (NSData*)PDFDataWithRect:(CGRect)rect
error:(NSError**)error;
// call this to invalidate the render tree when you change the style
- (void)setNeedsDisplay;
// colors
- (void)performBlock:(dispatch_block_t)block;
// matching
- (BOOL)containsNodesMatchingTraits:(IJSVGNodeTraits)mask;
@end
+747
View File
@@ -0,0 +1,747 @@
//
// IJSVGImage.m
// IconJar
//
// Created by Curtis Hard on 30/08/2014.
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVG.h>
#import <IJSVG/IJSVGExporter.h>
#import <IJSVG/IJSVGTransaction.h>
#import <IJSVG/IJSVGThreadManager.h>
@interface IJSVG (private)
@property (nonatomic, strong) IJSVGParser* parser;
@end
@implementation IJSVG
// these are explicitly implemented
@synthesize title = _title;
@synthesize desc = _desc;
- (void)dealloc
{
// thread manager will deal with this for us, but if we are main thread,
// we want to kick this off as soon as possible, or if the memory is set
// to quick.
IJSVGThreadManager* threadManager = IJSVGThreadManager.currentManager;
BOOL flag = IJSVGBeginTransaction();
_layerTree = nil;
_rootLayer = nil;
if(flag == YES) {
IJSVGEndTransaction();
}
// tell the thread manager we are done with
[threadManager remove:self];
}
+ (id)SVGNamed:(NSString*)string
{
return [self.class SVGNamed:string
error:nil];
}
+ (id)SVGNamed:(NSString*)string
error:(NSError**)error
{
NSBundle* bundle = NSBundle.mainBundle;
NSString* str = nil;
NSString* ext = [string pathExtension];
if(ext == nil || ext.length == 0) {
ext = @"svg";
}
if((str = [bundle pathForResource:[string stringByDeletingPathExtension]
ofType:ext]) != nil) {
return [[self alloc] initWithFile:str
error:error];
}
// check the asset catalogues
return [[self alloc] initWithDataAssetNamed:string
error:error];
}
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path
{
return [self SVGFromCGPathRef:path
flipped:NO];
}
+ (IJSVG*)SVGFromCGPathRef:(CGPathRef)path
flipped:(BOOL)flipped
{
CGRect box = CGPathGetPathBoundingBox(path);
IJSVGRootNode* rootNode = [[IJSVGRootNode alloc] init];
rootNode.viewBox = [IJSVGUnitRect rectWithCGRect:box];
CGMutablePathRef nPath = NULL;
if(flipped) {
CGPathRef transformedPath = [IJSVGUtils newFlippedCGPath:path];
nPath = CGPathCreateMutableCopy(transformedPath);
CGPathRelease(transformedPath);
} else {
nPath = CGPathCreateMutableCopy(path);
}
IJSVGPath* childPath = [[IJSVGPath alloc] init];
childPath.path = nPath;
[rootNode addChild:childPath];
CGPathRelease(nPath);
return [[self.class alloc] initWithRootNode:rootNode];
}
- (id)initWithDataAssetNamed:(NSDataAssetName)name
error:(NSError**)error
{
return [self initWithDataAssetNamed:name
bundle:NSBundle.mainBundle
error:error];
}
- (id)initWithDataAssetNamed:(NSDataAssetName)name
bundle:(NSBundle*)bundle
error:(NSError**)error
{
NSDataAsset* dataAsset = [[NSDataAsset alloc] initWithName:name
bundle:bundle];
if(dataAsset != nil) {
return [self initWithSVGData:dataAsset.data
error:error];
}
return nil;
}
- (id)initWithImage:(NSImage*)image
{
IJSVGRootNode* rootNode = [[IJSVGRootNode alloc] init];
IJSVGImage* imageNode = [[IJSVGImage alloc] init];
imageNode.image = image;
IJSVGUnitSize* size = [IJSVGUnitSize sizeWithCGSize:imageNode.intrinsicSize];
IJSVGUnitRect* viewBox = [IJSVGUnitRect rectWithOrigin:IJSVGUnitPoint.zeroPoint
size:size];
imageNode.width = size.width.copy;
imageNode.height = size.height.copy;
rootNode.viewBox = viewBox;
[rootNode addChild:imageNode];
return [self initWithRootNode:rootNode];
}
- (id)initWithSVGLayer:(IJSVGGroupLayer*)group
viewBox:(CGRect)viewBox
{
// this completely bypasses passing of files
if((self = [super init]) != nil) {
// keep the layer tree
_viewBox = viewBox;
// any setups
[self _setupBasicsFromAnyInitializer];
}
return self;
}
- (id)initWithRootNode:(IJSVGRootNode*)rootNode
{
if((self = [super init]) != nil) {
_rootNode = rootNode;
[self _setupBasicInfoFromGroup];
[self _setupBasicsFromAnyInitializer];
}
return self;
}
- (id)initWithFile:(NSString*)file
{
return [self initWithFile:file
error:nil];
}
- (id)initWithFile:(NSString*)file
error:(NSError**)error
{
return [self initWithFilePathURL:[NSURL fileURLWithPath:file isDirectory:NO]
error:error];
}
- (id)initWithFilePathURL:(NSURL*)aURL
{
return [self initWithFilePathURL:aURL
error:nil];
}
- (id)initWithFilePathURL:(NSURL*)aURL
error:(NSError**)error
{
// create the object
if((self = [super init]) != nil) {
NSError* anError = nil;
// create the group
IJSVGParser *parser = [IJSVGParser parserForFileURL:aURL
error:&anError];
self.parser = parser;
[self _setupBasicInfoFromGroup];
[self _setupBasicsFromAnyInitializer];
// something went wrong...
if(_rootNode == nil) {
if(error != NULL) {
*error = anError;
}
self = nil;
return nil;
}
}
return self;
}
- (id)initWithSVGData:(NSData*)data
{
return [self initWithSVGData:data
error:nil];
}
- (void)setParser:(IJSVGParser*)parser {
_rootNode = [parser rootNodeWithSize:CGSizeZero];
// if the rootNode has any form of relative units, we need to keep hold of
// the parser so when we render, we can ask for new values.
if(_rootNode.viewBoxContainsRelativeUnits) {
_parser = parser;
}
}
- (id)initWithSVGData:(NSData*)data
error:(NSError**)error
{
NSString* svgString = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
return [self initWithSVGString:svgString
error:error];
}
- (id)initWithSVGString:(NSString*)string
{
return [self initWithSVGString:string
error:nil];
}
- (id)initWithSVGString:(NSString*)string
error:(NSError**)error
{
if((self = [super init]) != nil) {
// this is basically the same as init with URL just
// bypasses the loading of a file
NSError* anError = nil;
// setup the parser
IJSVGParser* parser = [[IJSVGParser alloc] initWithSVGString:string
error:&anError];
self.parser = parser;
[self _setupBasicInfoFromGroup];
[self _setupBasicsFromAnyInitializer];
// something went wrong :(
if(_rootNode == nil) {
if(error != NULL) {
*error = anError;
}
self = nil;
return nil;
}
}
return self;
}
- (void)performBlock:(dispatch_block_t)block
{
IJSVGPerformTransactionBlock(^{
block();
});
}
- (void)_setupBasicInfoFromGroup
{
_viewBox = [_rootNode.viewBox computeValue:CGSizeZero];
_intrinsicSize = _rootNode.intrinsicSize;
}
- (CGSize)size
{
return [_intrinsicSize computeValue:self.defaultSize];
}
- (CGSize)sizeWithDefaultSize:(CGSize)size
{
return [_intrinsicSize computeValue:size];
}
- (void)_setupBasicsFromAnyInitializer
{
self.style = [[IJSVGStyle alloc] init];
self.ignoreIntrinsicSize = YES;
self.renderQuality = kIJSVGRenderQualityFullResolution;
self.defaultSize = CGSizeMake(200.f, 200.f);
self.renderingBackingScaleHelper = ^CGFloat {
if(NSScreen.mainScreen != nil) {
return NSScreen.mainScreen.backingScaleFactor;
}
return 1.f;
};
// tell the thread manager we exist
[IJSVGThreadManager.currentManager adopt:self];
}
- (BOOL)hasDynamicSize
{
IJSVGUnitSize* size = _intrinsicSize;
return size.width.type == IJSVGUnitLengthTypePercentage ||
size.height.type == IJSVGUnitLengthTypePercentage;
}
- (IJSVGIntrinsicDimensions)intrinsicDimensions
{
return self.rootNode.intrinsicDimensions;
}
- (void)setTitle:(NSString*)title
{
_rootNode.title = title;
}
- (NSString*)title
{
return _rootNode.title;
}
- (void)setDesc:(NSString*)description
{
_rootNode.desc = description;
}
- (NSString*)desc
{
return _rootNode.desc;
}
- (NSString*)identifier
{
return _rootNode.identifier;
}
- (CGRect)viewBox
{
return _viewBox;
}
- (IJSVGRootNode*)rootNode
{
return _rootNode;
}
- (NSSet<IJSVG*>*)directDescendSVGs
{
NSMutableSet<IJSVG*>* svgs = [[NSMutableSet alloc] init];
NSSet<IJSVGNode*>* nodes = [self.rootNode childrenOfType:IJSVGNodeTypeSVG];
for(IJSVGNode* node in nodes) {
IJSVG* newSVG = nil;
newSVG = [[self.class alloc] initWithRootNode:(IJSVGRootNode*)node];
[svgs addObject:newSVG];
}
return svgs;
}
- (IJSVGExporter*)exporterWithSize:(CGSize)size
options:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
return [[IJSVGExporter alloc] initWithSVG:self
size:size
options:options
floatingPointOptions:floatingPointOptions];
}
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options
{
IJSVGFloatingPointOptions fpo = IJSVGFloatingPointOptionsDefault();
return [self exporterWithSize:_viewBox.size
options:options
floatingPointOptions:fpo].SVGString;
}
- (NSString*)SVGStringWithOptions:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
return [self exporterWithSize:_viewBox.size
options:options
floatingPointOptions:floatingPointOptions].SVGString;
}
- (NSString *)SVGStringWithSize:(CGSize)size
options:(IJSVGExporterOptions)options
{
IJSVGFloatingPointOptions fpo = IJSVGFloatingPointOptionsDefault();
return [self exporterWithSize:size
options:options
floatingPointOptions:fpo].SVGString;
}
- (NSString *)SVGStringWithSize:(CGSize)size
options:(IJSVGExporterOptions)options
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
return [self exporterWithSize:size
options:options
floatingPointOptions:floatingPointOptions].SVGString;
}
- (NSImage*)imageWithSize:(CGSize)aSize
{
return [self imageWithSize:aSize
flipped:NO
error:nil];
}
- (NSImage*)imageWithSize:(CGSize)aSize
error:(NSError**)error;
{
return [self imageWithSize:aSize
flipped:NO
error:error];
}
- (NSImage*)imageWithSize:(CGSize)aSize
flipped:(BOOL)flipped
{
return [self imageWithSize:aSize
flipped:flipped
error:nil];
}
- (CGImageRef)newCGImageRefWithSize:(CGSize)size
flipped:(BOOL)flipped
error:(NSError**)error
{
// setup the drawing rect, this is used for both the intial drawing
// and the backing scale helper block
CGRect rect = (CGRect) {
.origin = CGPointZero,
.size = (CGSize)size
};
// make sure we setup the scale based on the backing scale factor
CGFloat scale = [self backingScaleFactor];
// create the context and colorspace
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ref = CGBitmapContextCreate(NULL, (int)size.width * scale,
(int)size.height * scale, 8, 0, colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
// scale the context
CGContextScaleCTM(ref, scale, scale);
if(flipped == YES) {
CGContextTranslateCTM(ref, 0.f, size.height);
CGContextScaleCTM(ref, 1.f, -1.f);
}
// draw the SVG into the context
[self _drawInRect:rect
context:ref
error:error];
// create the image from the context
CGImageRef imageRef = CGBitmapContextCreateImage(ref);
// release all things!
CGColorSpaceRelease(colorSpace);
CGContextRelease(ref);
return imageRef;
}
- (NSImage*)imageWithSize:(CGSize)aSize
flipped:(BOOL)flipped
error:(NSError**)error
{
CGImageRef ref = [self newCGImageRefWithSize:aSize
flipped:flipped
error:error];
NSImage* image = [[NSImage alloc] initWithCGImage:ref
size:aSize];
CGImageRelease(ref);
return image;
}
- (CGSize)sizeByMaintainingAspectRatioWithSize:(CGSize)aSize
{
CGSize ogSize = [_rootNode.intrinsicSize computeValue:aSize];
CGFloat ratio = 0.f;
CGFloat imageWidth = ogSize.width;
CGFloat imageHeight = ogSize.height;
CGFloat maxWidth = aSize.width;
CGFloat maxHeight = aSize.height;
if(imageWidth > imageHeight) {
ratio = maxWidth / imageWidth;
} else {
ratio = maxHeight / imageHeight;
}
ogSize.width = ceilf(imageWidth * ratio);
ogSize.height = ceilf(imageHeight * ratio);
return ogSize;
}
- (NSImage*)imageByMaintainingAspectRatioWithSize:(CGSize)aSize
flipped:(BOOL)flipped
error:(NSError**)error
{
CGSize ogSize = [self sizeByMaintainingAspectRatioWithSize:aSize];
return [self imageWithSize:ogSize
flipped:flipped
error:error];
}
- (NSData*)PDFData
{
return [self PDFData:nil];
}
- (NSData*)PDFData:(NSError**)error
{
return [self
PDFDataWithRect:(CGRect) { .origin = NSZeroPoint, .size = _viewBox.size }
error:error];
}
- (NSData*)PDFDataWithRect:(CGRect)rect
{
return [self PDFDataWithRect:rect error:nil];
}
- (NSData*)PDFDataWithRect:(CGRect)rect
error:(NSError**)error
{
// create the data for the PDF
NSMutableData* data = [[NSMutableData alloc] init];
// assign the data to the consumer
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)data);
const CGRect box = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width,
rect.size.height);
// create the context
CGContextRef context = CGPDFContextCreate(dataConsumer, &box, NULL);
CGContextBeginPage(context, &box);
// the context is currently upside down, doh! flip it...
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, 0, -box.size.height);
// make sure we set the masks to path bits n bobs
// draw the icon
[self _drawInRect:(CGRect)box
context:context
error:error];
CGContextEndPage(context);
// clean up
CGPDFContextClose(context);
CGContextRelease(context);
CGDataConsumerRelease(dataConsumer);
return data;
}
- (void)prepForDrawingInView:(NSView*)view
{
// kill the render
if(view == nil) {
self.renderingBackingScaleHelper = nil;
return;
}
// construct the layer before drawing
[self rootLayer];
// set the scale
__weak NSView* weakView = view;
self.renderingBackingScaleHelper = ^CGFloat {
return weakView.window.screen.backingScaleFactor;
};
}
- (BOOL)drawAtPoint:(CGPoint)point
size:(CGSize)aSize
{
return [self drawAtPoint:point
size:aSize
error:nil];
}
- (BOOL)drawAtPoint:(CGPoint)point
size:(CGSize)aSize
error:(NSError**)error
{
return [self drawInRect:NSMakeRect(point.x, point.y,
aSize.width, aSize.height)
error:error];
}
- (BOOL)drawInRect:(CGRect)rect
{
return [self drawInRect:rect error:nil];
}
- (BOOL)drawInRect:(CGRect)rect
error:(NSError**)error
{
CGContextRef currentCGContext;
currentCGContext = NSGraphicsContext.currentContext.CGContext;
return [self _drawInRect:rect
context:currentCGContext
error:error];
}
- (void)drawInRect:(CGRect)rect
context:(CGContextRef)context
{
[self _drawInRect:rect
context:context
error:nil];
}
- (BOOL)_drawInRect:(CGRect)rect
context:(CGContextRef)ctx
error:(NSError**)error
{
BOOL transaction = IJSVGBeginTransaction();
CGContextSaveGState(ctx);
CGFloat backingScale = MAX([self backingScaleFactor], 1.f);
CGInterpolationQuality quality;
switch (_renderQuality) {
case kIJSVGRenderQualityLow: {
quality = kCGInterpolationLow;
break;
}
case kIJSVGRenderQualityOptimized: {
quality = kCGInterpolationMedium;
break;
}
default: {
quality = kCGInterpolationHigh;
}
}
CGContextSetInterpolationQuality(ctx, quality);
IJSVGRootLayer* rootLayer = [self rootLayerWithRect:rect];
[rootLayer renderInContext:ctx
viewPort:rect
backingScale:backingScale
quality:_renderQuality
ignoreIntrinsicSize:_ignoreIntrinsicSize];
CGContextRestoreGState(ctx);
if(transaction == YES) {
IJSVGEndTransaction();
}
return YES;
}
- (IJSVGLayerTree*)layerTree
{
if(_layerTree == nil) {
_layerTree = [[IJSVGLayerTree alloc] init];
_layerTree.style = _style;
}
return _layerTree;
}
- (IJSVGRootLayer*)rootLayerWithRect:(CGRect)rect {
// no parser, which means there is no need to recompute the value
if(_parser == nil || !_rootNode.viewBoxContainsRelativeUnits ||
CGSizeEqualToSize(_rootNode.clientSize, rect.size)) {
return self.rootLayer;
}
// if we do have a parser, that means the node has relative values, lets recompute
__weak IJSVG* weakSelf = self;
[self performBlock:^{
IJSVG* strongSelf = weakSelf;
strongSelf->_rootNode = [strongSelf->_parser rootNodeWithSize:rect.size];
strongSelf->_rootLayer = [strongSelf.layerTree rootLayerForRootNode:strongSelf->_rootNode];
}];
return _rootLayer;
}
- (IJSVGRootLayer*)rootLayer
{
if(_rootLayer != nil) {
return _rootLayer;
}
__weak IJSVG* weakSelf = self;
[self performBlock:^{
IJSVG* strongSelf = weakSelf;
strongSelf->_rootLayer = [strongSelf.layerTree rootLayerForRootNode:strongSelf->_rootNode];
}];
return _rootLayer;
}
- (CGFloat)backingScaleFactor
{
__block CGFloat scale = 1.f;
if(self.renderingBackingScaleHelper != nil) {
scale = (self.renderingBackingScaleHelper)();
}
scale = MAX(1.f, scale);
return _backingScale = scale;
}
- (void)setNeedsDisplay
{
[self invalidateLayerTree];
}
- (void)invalidateLayerTree
{
__weak IJSVG* weakSelf = self;
[self performBlock:^{
IJSVG* strongSelf = weakSelf;
strongSelf->_rootLayer = nil;
strongSelf->_layerTree = nil;
}];
}
- (IJSVGTraitedColorStorage*)colors
{
return self.rootLayer.colors;
}
#pragma mark NSPasteboard
- (NSArray*)writableTypesForPasteboard:(NSPasteboard*)pasteboard
{
return @[ NSPasteboardTypePDF ];
}
- (id)pasteboardPropertyListForType:(NSString*)type
{
if([type isEqualToString:NSPasteboardTypePDF]) {
return [self PDFData];
}
return nil;
}
#pragma mark matching
- (BOOL)containsNodesMatchingTraits:(IJSVGNodeTraits)traits
{
return [_rootNode containsNodesMatchingTraits:traits];
}
@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;
@@ -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;
}
@@ -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,18 +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,
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef | IJSVGExporterOptionRemoveUselessGroups | IJSVGExporterOptionCreateUseForPaths | IJSVGExporterOptionMoveAttributesToGroup | IJSVGExporterOptionSortAttributes | IJSVGExporterOptionCollapseGroups | IJSVGExporterOptionCleanupPaths | IJSVGExporterOptionRemoveHiddenElements | IJSVGExporterOptionScaleToSizeIfNecessary | IJSVGExporterOptionCompressOutput | IJSVGExporterOptionCollapseGradients | IJSVGExporterOptionRemoveWidthHeightAttributes | IJSVGExporterOptionColorAllowRRGGBBAA | IJSVGExporterOptionRemoveComments
IJSVGExporterOptionCenterWithinViewBox = 1 << 16,
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<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 {
@@ -46,18 +87,34 @@ void IJSVGEnumerateCGPathElements(CGPathRef path, IJSVGPathElementEnumerationBlo
IJSVGExporterOptions _options;
NSXMLDocument* _dom;
NSXMLElement* _defElement;
NSXMLElement* _scaledRootNode;
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
@@ -8,25 +8,56 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@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;
}
+ (NSArray<IJSVGExporterPathInstruction*>*)instructionsFromPath:(CGPathRef)path;
@property (nonatomic, assign) char instruction;
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;
+ (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,29 +6,46 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGExporter.h"
#import "IJSVGExporterPathInstruction.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;
}
@@ -38,228 +55,493 @@
return _dataCount;
}
- (void)setInstruction:(char)newInstruction
{
_instruction = newInstruction;
}
- (char)instruction
{
return _instruction;
}
- (CGFloat*)data
{
return _data;
}
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions
- (CGFloat*)base
{
NSMutableArray* pathData = [[[NSMutableArray alloc] init] autorelease];
return _base;
}
- (CGFloat*)coords
{
return _coords;
}
+ (NSString*)pathStringWithInstructionSet:(NSArray<IJSVGExporterPathInstructionCommand*>*)instructionSets
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
IJSVGExporterPathInstructionCommand* lastCommand = NULL;
NSMutableString* string = [[NSMutableString alloc] init];
for (IJSVGExporterPathInstructionCommand* command in instructionSets) {
// read back the bytes
// 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)) {
[string appendFormat:@"%c", command.instruction];
} else {
[string appendString:@" "];
}
// compresses the floats
NSString* compressedFloats = IJSVGCompressFloatParameterArray(command.params);
[string appendString:compressedFloats];
// store last command
lastCommand = command;
}
return string;
}
+ (NSString*)pathStringFromInstructions:(NSArray<IJSVGExporterPathInstruction*>*)instructions
floatingPointOptions:(IJSVGFloatingPointOptions)floatingPointOptions
{
NSMutableArray* pathInstructions = [[NSMutableArray alloc] init];
for (IJSVGExporterPathInstruction* instruction in instructions) {
CGFloat* data = instruction.data;
NSString* str = nil;
switch (instruction.instruction) {
// move
case 'M':
case 'm': {
char* buffer;
asprintf(&buffer, "%c%g,%g", instruction.instruction, data[0], data[1]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
break;
}
// vertical and horizonal line
case 'V':
case 'v':
case 'H':
case 'h': {
char* buffer;
asprintf(&buffer, "%c%g", instruction.instruction, data[0]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
break;
}
// line
case 'L':
const char lowerInstruction = tolower(instruction.instruction);
NSArray<NSString*>* set = nil;
switch (lowerInstruction) {
case 't':
case 'm':
case 'l': {
char* buffer;
asprintf(&buffer, "%c%g,%g", instruction.instruction, data[0], data[1]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
set = @[
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions),
IJSVGShortFloatStringWithOptions(data[1], floatingPointOptions)
];
break;
}
case 'v':
case 'h': {
set = @[
IJSVGShortFloatStringWithOptions(data[0], floatingPointOptions)
];
break;
}
// curve
case 'C':
case 'c': {
char* buffer;
asprintf(&buffer, "%c%g,%g %g,%g %g,%g", instruction.instruction,
data[0], data[1], data[2], data[3], data[4], data[5]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
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)
];
break;
}
// quadratic curve
case 'Q':
case 's':
case 'q': {
char* buffer;
asprintf(&buffer, "%c%g,%g %g,%g", instruction.instruction,
data[0], data[1], data[2], data[3]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
set = @[
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;
}
// close path
case 'Z':
case 'z': {
str = [NSString stringWithFormat:@"%c", instruction.instruction];
[pathData addObject:str];
set = @[];
}
}
// wrap into the command and give to the array
IJSVGExporterPathInstructionCommand* wrapperCommand = nil;
wrapperCommand = [[IJSVGExporterPathInstructionCommand alloc] init];
wrapperCommand.instruction = instruction.instruction;
wrapperCommand.params = set ?: @[];
[pathInstructions addObject:wrapperCommand];
}
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;
}
}
return [pathData componentsJoinedByString:@""];
}
+ (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) {
@@ -269,8 +551,8 @@
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;
@@ -283,17 +565,17 @@
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;
}
@@ -307,8 +589,8 @@
// 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;
@@ -324,9 +606,10 @@
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;
@@ -340,8 +623,8 @@
case kCGPathElementCloseSubpath: {
// close command
instruction = [[[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z'
dataCount:0] autorelease];
instruction = [[IJSVGExporterPathInstruction alloc] initWithInstruction:'Z'
dataCount:0];
[instructions addObject:instruction];
break;
}
@@ -353,16 +636,16 @@
// 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];
}
}
}
return instructions;
}
@@ -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 -70
View File
@@ -6,34 +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
{
(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 {
@@ -43,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
@@ -115,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];
@@ -126,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);
@@ -144,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;
@@ -151,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,73 +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
{
(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
@@ -84,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];
@@ -95,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);
@@ -120,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,20 +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 : IJSVGNode {
@private
NSMutableDictionary* _dict;
}
- (void)addDef:(IJSVGNode*)aDef;
@end
@@ -1,41 +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 initWithDef:NO]) != nil) {
_dict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)addDef:(IJSVGNode*)aDef
{
if (aDef.identifier == nil) {
return;
}
[_dict setObject:aDef
forKey:aDef.identifier];
}
- (IJSVGDef*)defForID:(NSString*)anID
{
return [_dict objectForKey: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
@@ -6,174 +6,109 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGGradient.h"
#import <IJSVG/IJSVGGradient.h>
#import <IJSVG/IJSVGParser.h>
@implementation IJSVGGradient
@synthesize gradient, CGGradient;
@synthesize x1, x2, y1, y2;
@synthesize colorList = _colorList;
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributeGradientUnits];
[storage setBit:IJSVGNodeAttributeGradientTransform];
return storage;
}
- (void)dealloc
{
(void)([x1 release]), x1 = nil;
(void)([x2 release]), x2 = nil;
(void)([y1 release]), y1 = nil;
(void)([y2 release]), y2 = nil;
(void)([gradient release]), gradient = nil;
(void)([_colorList release]), _colorList = nil;
if (CGGradient != nil) {
CGGradientRelease(CGGradient);
if(_locations != NULL) {
(void)free(_locations), _locations = NULL;
}
if(_CGGradient != NULL) {
(void)CGGradientRelease(_CGGradient), _CGGradient = NULL;
}
[super dealloc];
}
- (id)copyWithZone:(NSZone*)zone
{
IJSVGGradient* clone = [super copyWithZone:zone];
clone.gradient = [[self.gradient copy] autorelease];
IJSVGGradient* clone = [[self.class alloc] init];
[clone applyPropertiesFromNode:self];
return clone;
}
- (void)setColorList:(IJSVGColorList*)list
- (void)applyPropertiesFromNode:(IJSVGGradient*)node
{
(void)([_colorList release]), _colorList = nil;
_colorList = list.retain;
if (CGGradient != nil) {
CGGradientRelease(CGGradient);
}
[super applyPropertiesFromNode:node];
self.numberOfStops = node.numberOfStops;
self.colors = node.colors.copy;
size_t length = sizeof(CGFloat)*node.numberOfStops;
self.locations = (CGFloat*)malloc(length);
memcpy(self.locations, node.locations, length);
self.x1 = node.x1.copy;
self.x2 = node.x2.copy;
self.y1 = node.y1.copy;
self.y2 = node.y2.copy;
}
+ (CGFloat*)computeColorStopsFromString:(NSXMLElement*)element
colors:(NSArray**)someColors
- (void)setLocations:(CGFloat*)locations
{
// find each stop element
NSArray* stops = [element children];
NSMutableArray* colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease];
if(_locations != NULL) {
(void)free(_locations), _locations = NULL;
}
_locations = locations;
}
+ (CGFloat*)computeColorStops:(IJSVGGradient*)gradient
colors:(NSArray**)someColors
{
NSArray<IJSVGNode*>* stops = gradient.children;
NSMutableArray* colors = [[NSMutableArray alloc] initWithCapacity:stops.count];
CGFloat* stopsParams = (CGFloat*)malloc(stops.count * sizeof(CGFloat));
NSInteger i = 0;
for (NSXMLElement* stop in stops) {
// find the offset
CGFloat offset = [stop attributeForName:@"offset"].stringValue.floatValue;
if (offset > 1.f) {
offset /= 100.f;
}
for(IJSVGNode* stopNode in stops) {
NSColor* color = ((IJSVGColorNode*)(stopNode.fill)).color;
CGFloat opacity = stopNode.fillOpacity.value;
CGFloat offset = stopNode.offset.value;
stopsParams[i++] = offset;
// find the stop opacity
CGFloat stopOpacity = 1.f;
NSXMLNode* stopOpacityAttribute = [stop attributeForName:@"stop-opacity"];
if (stopOpacityAttribute != nil) {
stopOpacity = stopOpacityAttribute.stringValue.floatValue;
}
// find the stop color
NSString* scs = [stop attributeForName:@"stop-color"].stringValue;
NSColor* stopColor = [IJSVGColor colorFromString:scs];
if (stopColor != nil && stopOpacity != 1.f) {
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
to:stopOpacity];
}
// compute any style that there was...
NSXMLNode* styleAttribute = [stop attributeForName:@"style"];
if (styleAttribute != nil) {
IJSVGStyle* style = [IJSVGStyle parseStyleString:styleAttribute.stringValue];
NSColor* color = [IJSVGColor colorFromString:[style property:@"stop-color"]];
// we have a color!
if (color != nil) {
// is there a stop opacity?
NSString* numberString = nil;
if ((numberString = [style property:@"stop-opacity"]) != nil) {
color = [IJSVGColor changeAlphaOnColor:color
to:numberString.floatValue];
} else {
color = [IJSVGColor changeAlphaOnColor:color
to:stopOpacity];
}
stopColor = color;
if(color == nil) {
color = [IJSVGColor colorFromHEXInteger:0x000000];
if(opacity != 1.f) {
color = [IJSVGColor changeAlphaOnColor:color
to:opacity];
}
}
// default is black
if (stopColor == nil) {
stopColor = [IJSVGColor colorFromString:@"black"];
if (stopOpacity != 1.f) {
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
to:stopOpacity];
}
}
// add the stop color
[(NSMutableArray*)colors addObject:stopColor];
[colors addObject:color];
}
*someColors = colors;
*someColors = (NSArray*)colors;
return stopsParams;
}
- (IJSVGColorList*)computedColorList
{
IJSVGColorList* sheet = [[[IJSVGColorList alloc] init] autorelease];
NSInteger num = self.gradient.numberOfColorStops;
for (NSInteger i = 0; i < num; i++) {
NSColor* color;
[self.gradient getColor:&color
location:nil
atIndex:i];
[sheet addColor:color];
}
return sheet;
}
- (CGGradientRef)CGGradient
{
// store it in the cache
if (CGGradient != nil) {
return CGGradient;
if(_CGGradient != nil) {
return _CGGradient;
}
// actually create the gradient
NSInteger num = self.gradient.numberOfColorStops;
CGFloat* locations = malloc(sizeof(CGFloat) * num);
NSInteger num = self.numberOfStops;
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num,
&kCFTypeArrayCallBacks);
for (NSInteger i = 0; i < num; i++) {
NSColor* color;
[self.gradient getColor:&color
location:&locations[i]
atIndex:i];
if (_colorList != nil) {
color = [_colorList proposedColorForColor:color];
}
for (NSColor* color in _colors) {
CFArrayAppendValue(colors, color.CGColor);
}
CGGradientRef result = CGGradientCreateWithColors(self.gradient.colorSpace.CGColorSpace,
colors, locations);
CGGradientRef result = CGGradientCreateWithColors(IJSVGColor.defaultColorSpace.CGColorSpace,
colors, _locations);
CFRelease(colors);
free(locations);
return CGGradient = result;
return _CGGradient = result;
}
- (void)drawInContextRef:(CGContextRef)ctx
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
bounds:(NSRect)objectRect
transform:(CGAffineTransform)absoluteTransform
{
}
- (void)_debugStart:(CGPoint)startPoint
end:(CGPoint)endPoint
context:(CGContextRef)ctx
{
CGContextSaveGState(ctx);
CGContextSetStrokeColorWithColor(ctx, NSColor.blackColor.CGColor);
CGContextSetLineWidth(ctx, 1.f);
CGContextMoveToPoint(ctx, startPoint.x, startPoint.y);
CGContextAddLineToPoint(ctx, endPoint.x, endPoint.y);
CGContextStrokePath(ctx);
}
@end
@@ -6,17 +6,25 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGNode.h"
#import "IJSVGPath.h"
#import <IJSVG/IJSVGNode.h>
#import <IJSVG/IJSVGPath.h>
#import <Foundation/Foundation.h>
@interface IJSVGGroup : IJSVGNode {
NSMutableArray* children;
@private
NSMutableArray<IJSVGNode*>* _children;
}
- (void)addChild:(id)child;
- (NSArray*)children;
- (void)purgeChildren;
@property (weak, nonatomic, readonly) NSArray<IJSVGNode*>* children;
- (void)addChild:(IJSVGNode*)child;
- (void)addChildren:(NSArray<IJSVGNode*>*)children;
- (void)removeChild:(IJSVGNode*)child;
- (void)removeChildren:(NSArray<IJSVGNode*>*)children;
- (BOOL)childrenMatchTraits:(IJSVGNodeTraits)traits;
- (BOOL)containsNodesMatchingTraits:(IJSVGNodeTraits)traits;
- (NSArray<IJSVGNode*>*)nodesMatchingTraits:(IJSVGNodeTraits)traits;
- (NSSet<IJSVGNode*>*)childrenOfType:(IJSVGNodeType)type;
@end
+92 -20
View File
@@ -6,27 +6,31 @@
// Copyright (c) 2014 Curtis Hard. All rights reserved.
//
#import "IJSVGGroup.h"
#import <IJSVG/IJSVGGroup.h>
#import <IJSVG/IJSVGImage.h>
@implementation IJSVGGroup
- (void)dealloc
{
(void)([children release]), children = nil;
[super dealloc];
}
- (id)init
{
if ((self = [super init]) != nil) {
children = [[NSMutableArray alloc] init];
if((self = [super init]) != nil) {
_children = [[NSMutableArray alloc] init];
}
return self;
}
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage addBits:[IJSVGPath allowedAttributes]];
[storage addBits:[IJSVGImage allowedAttributes]];
return storage;
}
- (void)prepareFromCopy
{
children = [[NSMutableArray alloc] init];
_children = [[NSMutableArray alloc] init];
}
- (id)copyWithZone:(NSZone*)zone
@@ -34,33 +38,101 @@
IJSVGGroup* node = [super copyWithZone:zone];
[node prepareFromCopy];
for (IJSVGNode* childNode in self.children) {
childNode = [[childNode copy] autorelease];
for (__strong IJSVGNode* childNode in _children) {
childNode = childNode.copy;
childNode.parentNode = node;
[node addChild:childNode];
}
return node;
}
- (void)purgeChildren
- (void)addChild:(IJSVGNode*)child
{
[children removeAllObjects];
if(child == nil || child == self ||
(child.parentNode == self && [_children containsObject:child])) {
return;
}
child.parentNode = self;
[_children addObject:child];
}
- (void)addChild:(id)child
- (void)removeChild:(IJSVGNode*)child
{
if (child != nil)
[children addObject:child];
if(child.parentNode == self) {
[child detach];
}
[_children removeObject:child];
}
- (NSArray*)children
- (void)addChildren:(NSArray<IJSVGNode*>*)children
{
return children;
for(IJSVGNode* node in children) {
[self addChild:node];
}
}
- (void)removeChildren:(NSArray<IJSVGNode*>*)children
{
for(IJSVGNode* node in children) {
[self removeChild:node];
}
}
- (BOOL)childrenMatchTraits:(IJSVGNodeTraits)traits
{
for(IJSVGNode* node in _children) {
if([node matchesTraits:traits] == NO) {
return NO;
}
}
return YES;
}
- (NSSet<IJSVGNode*>*)childrenOfType:(IJSVGNodeType)type
{
NSMutableSet<IJSVGNode*>* nodes = [[NSMutableSet alloc] init];
for(IJSVGNode* node in self.children) {
if(node.type == type) {
[nodes addObject:node];
}
}
return nodes;
}
- (BOOL)containsNodesMatchingTraits:(IJSVGNodeTraits)traits
{
return [self.class node:self
containsNodesMatchingTraits:traits];
}
- (NSArray<IJSVGNode*>*)nodesMatchingTraits:(IJSVGNodeTraits)traits
{
return [self.class node:self
nodesMatchingTraits:traits];
}
- (CGRect)bounds
{
CGRect rect = CGRectNull;
for(IJSVGNode* node in self.children) {
if(CGRectIsNull(rect)) {
rect = node.bounds;
} else {
rect = CGRectUnion(rect, node.bounds);
}
}
return rect;
}
- (NSArray<IJSVGNode*>*)children
{
return _children;
}
- (NSString*)description
{
return [NSString stringWithFormat:@"%@ - %@", [super description], self.children];
return [NSString stringWithFormat:@"%@ - %@",
[super description], self.children];
}
@end

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