Compare commits

...

54 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
54 changed files with 1732 additions and 559 deletions
+5
View File
@@ -0,0 +1,5 @@
framework module IJSVG {
umbrella header "IJSVGUmbrella.h"
export *
module * { export * }
}
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -19,6 +19,8 @@
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, ); }; };
@@ -36,6 +38,7 @@
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 */; };
@@ -43,6 +46,8 @@
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, ); }; };
@@ -160,6 +165,8 @@
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 */
@@ -175,6 +182,8 @@
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>"; };
@@ -194,6 +203,8 @@
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; };
@@ -201,6 +212,8 @@
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; };
@@ -318,6 +331,8 @@
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 */
@@ -449,6 +464,8 @@
isa = PBXGroup;
children = (
590AA093280DE648002BBE12 /* Filter Effects */,
59FE8E4228C7E70800AB38B3 /* IJSVGStop.h */,
59FE8E4128C7E70800AB38B3 /* IJSVGStop.m */,
59EB75CE23905F7200F5AE63 /* IJSVGForeignObject.h */,
59EB75C923905F7200F5AE63 /* IJSVGForeignObject.m */,
59EB759F23905F6E00F5AE63 /* IJSVGLinearGradient.h */,
@@ -516,6 +533,10 @@
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>";
@@ -575,6 +596,7 @@
594CF471238FF38E009B251B /* IJSVG */ = {
isa = PBXGroup;
children = (
596AB830298854270013110A /* IJSVG.modulemap */,
59EB756423905F3100F5AE63 /* Source */,
594CF473238FF38E009B251B /* Info.plist */,
);
@@ -602,6 +624,7 @@
59EB757D23905F6C00F5AE63 /* IJSVGImageRep.m */,
59EB75CD23905F7200F5AE63 /* IJSVGView.h */,
59EB75C123905F7100F5AE63 /* IJSVGView.m */,
595FD12E29EC56BA00666897 /* IJSVGUmbrella.h */,
);
path = Core;
sourceTree = "<group>";
@@ -683,6 +706,7 @@
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 */,
@@ -704,7 +728,10 @@
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;
@@ -736,7 +763,8 @@
594CF466238FF38E009B251B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1220;
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1600;
ORGANIZATIONNAME = "Curtis Hard";
TargetAttributes = {
594CF46E238FF38E009B251B = {
@@ -778,6 +806,7 @@
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 */,
@@ -790,6 +819,7 @@
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 */,
@@ -807,6 +837,7 @@
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 */,
@@ -892,9 +923,12 @@
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;
@@ -910,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 = "";
@@ -955,9 +994,13 @@
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 = "";
@@ -967,9 +1010,14 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MODULEMAP_FILE = IJSVG.modulemap;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
MTL_ENABLE_DEBUG_INFO = 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 = "";
@@ -982,10 +1030,11 @@
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = NO;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 9KTR4W9XX6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -997,6 +1046,7 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
@@ -1010,10 +1060,11 @@
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = NO;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 9KTR4W9XX6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -1025,6 +1076,7 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.iconjar.ijsvg;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1600"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -247,8 +247,9 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
+ (BOOL)isNoneOrTransparent:(NSString*)string
{
const char* str = string.lowercaseString.UTF8String;
return strcmp(str, "none") == 0 || strcmp(str, "transparent") == 0;
const char* str = string.UTF8String;
return IJSVGCharBufferCaseInsensitiveCompare(str, "none") == YES ||
IJSVGCharBufferCaseInsensitiveCompare(str, "transparent") == YES;
}
+ (NSColor*)colorFromString:(NSString*)string
@@ -289,6 +290,16 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
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:","];
@@ -332,8 +343,8 @@ CGFloat* IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightnes
}
// is simply a clear color, dont fill
if(strcmp(str, "none") == 0 ||
strcmp(str, "transparent") == 0) {
if(IJSVGCharBufferCompare(str, "none") == YES ||
IJSVGCharBufferCompare(str, "transparent") == YES) {
(void)free(str), str = NULL;
return nil;
}
@@ -21,6 +21,7 @@
#import <Foundation/Foundation.h>
@class IJSVG;
@class IJSVGParser;
@interface IJSVG : NSObject <NSPasteboardWriting> {
@@ -30,6 +31,7 @@
CGRect _viewBox;
CGFloat _backingScale;
IJSVGUnitSize* _intrinsicSize;
IJSVGParser* _parser;
}
// set this to be called when the layer is about to draw, it will call this
@@ -68,6 +70,7 @@
- (IJSVGRootNode*)rootNode;
- (CGRect)viewBox;
- (CGSize)sizeWithDefaultSize:(CGSize)size;
- (CGSize)sizeByMaintainingAspectRatioWithSize:(CGSize)aSize;
- (NSString*)identifier;
- (NSSet<IJSVG*>*)directDescendSVGs;
- (IJSVGExporter*)exporterWithSize:(CGSize)size
+82 -40
View File
@@ -9,6 +9,11 @@
#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
@@ -18,14 +23,19 @@
- (void)dealloc
{
// this can all be called on the background thread to be released
BOOL hasTransaction = IJSVGBeginTransaction();
// kill any memory that has been around
(void)(_layerTree), _layerTree = nil;
(void)(_rootLayer), _rootLayer = nil;
if(hasTransaction == YES) {
// 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
@@ -168,10 +178,10 @@
NSError* anError = nil;
// create the group
IJSVGParser* parser = [IJSVGParser parserForFileURL:aURL
IJSVGParser *parser = [IJSVGParser parserForFileURL:aURL
error:&anError];
_rootNode = parser.rootNode;
self.parser = parser;
[self _setupBasicInfoFromGroup];
[self _setupBasicsFromAnyInitializer];
@@ -180,7 +190,7 @@
if(error != NULL) {
*error = anError;
}
(void)(self), self = nil;
self = nil;
return nil;
}
}
@@ -193,6 +203,16 @@
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
{
@@ -218,9 +238,9 @@
// setup the parser
IJSVGParser* parser = [[IJSVGParser alloc] initWithSVGString:string
error:&anError];
_rootNode = parser.rootNode;
error:&anError];
self.parser = parser;
[self _setupBasicInfoFromGroup];
[self _setupBasicsFromAnyInitializer];
@@ -229,7 +249,7 @@
if(error != NULL) {
*error = anError;
}
(void)(self), self = nil;
self = nil;
return nil;
}
}
@@ -238,11 +258,9 @@
- (void)performBlock:(dispatch_block_t)block
{
BOOL hasTransaction = IJSVGBeginTransaction();
block();
if(hasTransaction == YES) {
IJSVGEndTransaction();
}
IJSVGPerformTransactionBlock(^{
block();
});
}
- (void)_setupBasicInfoFromGroup
@@ -273,6 +291,9 @@
}
return 1.f;
};
// tell the thread manager we exist
[IJSVGThreadManager.currentManager adopt:self];
}
- (BOOL)hasDynamicSize
@@ -458,11 +479,9 @@
return image;
}
- (NSImage*)imageByMaintainingAspectRatioWithSize:(CGSize)aSize
flipped:(BOOL)flipped
error:(NSError**)error
- (CGSize)sizeByMaintainingAspectRatioWithSize:(CGSize)aSize
{
CGSize ogSize = _rootNode.intrinsicSize.value;
CGSize ogSize = [_rootNode.intrinsicSize computeValue:aSize];
CGFloat ratio = 0.f;
CGFloat imageWidth = ogSize.width;
CGFloat imageHeight = ogSize.height;
@@ -473,8 +492,16 @@
} else {
ratio = maxHeight / imageHeight;
}
ogSize.width = imageWidth * ratio;
ogSize.height = imageHeight * ratio;
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];
@@ -576,11 +603,7 @@
error:(NSError**)error
{
CGContextRef currentCGContext;
if(@available(macOS 10.10, *)) {
currentCGContext = NSGraphicsContext.currentContext.CGContext;
} else {
currentCGContext = NSGraphicsContext.currentContext.graphicsPort;
}
currentCGContext = NSGraphicsContext.currentContext.CGContext;
return [self _drawInRect:rect
context:currentCGContext
error:error];
@@ -616,7 +639,7 @@
}
}
CGContextSetInterpolationQuality(ctx, quality);
IJSVGRootLayer* rootLayer = self.rootLayer;
IJSVGRootLayer* rootLayer = [self rootLayerWithRect:rect];
[rootLayer renderInContext:ctx
viewPort:rect
backingScale:backingScale
@@ -638,16 +661,35 @@
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) {
__weak IJSVG* weakSelf = self;
[self performBlock:^{
IJSVG* strongSelf = weakSelf;
strongSelf->_rootLayer = [strongSelf.layerTree rootLayerForRootNode:strongSelf->_rootNode];
}];
}
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
@@ -670,8 +712,8 @@
__weak IJSVG* weakSelf = self;
[self performBlock:^{
IJSVG* strongSelf = weakSelf;
(void)(strongSelf->_rootLayer), strongSelf->_rootLayer = nil;
(void)(strongSelf->_layerTree), strongSelf->_layerTree = nil;
strongSelf->_rootLayer = nil;
strongSelf->_layerTree = nil;
}];
}
@@ -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 */
@@ -90,6 +90,7 @@ const NSDictionary<NSString*, NSString*>* IJSVGDefaultAttributes(void);
NSInteger _idCount;
NSInteger _shortIdCount;
BOOL _appliedXLink;
IJSVGThreadManager* _threadManager;
struct {
unsigned int identifierForElement: 1;
@@ -21,6 +21,7 @@
#import <IJSVG/IJSVGFilterLayer.h>
#import <IJSVG/IJSVGTransformLayer.h>
#import <IJSVG/IJSVGParser.h>
#import <IJSVG/IJSVGThreadManager.h>
@implementation IJSVGExporter
@@ -151,6 +152,7 @@ NSString* IJSVGHash(NSString* key)
_options = options;
_size = size;
_svg = svg;
_threadManager = IJSVGThreadManager.currentManager;
// defaults for floating point rounding, if any
_floatingPointOptions = floatingPointOptions;
@@ -971,6 +973,15 @@ NSString* IJSVGHash(NSString* key)
}
}
- (NSString*)transformAttributeStringForTransforms:(NSArray<IJSVGTransform*>*)transforms
{
NSMutableArray* strings = [[NSMutableArray alloc] initWithCapacity:transforms.count];
for(IJSVGTransform* transform in transforms) {
[strings addObject:[self transformAttributeStringForTransform:transform.CGAffineTransform]];
}
return [strings componentsJoinedByString:@" "];
}
- (NSString*)transformAttributeStringForTransform:(CGAffineTransform)transform
{
if(IJSVGExporterHasOption(_options, IJSVGExporterOptionRoundTransforms) == YES) {
@@ -1180,9 +1191,9 @@ NSString* IJSVGHash(NSString* key)
// apply any actual pattern transform from the node, only if the
// actual transform has something
transform = IJSVGConcatTransforms(layer.patternNode.transforms);
if(CGAffineTransformIsIdentity(transform) == NO) {
dict[IJSVGAttributePatternTransform] = [self transformAttributeStringForTransform:transform];
NSArray<IJSVGTransform*>* transforms = layer.patternNode.transforms;
if(transforms.count != 0) {
dict[IJSVGAttributePatternTransform] = [self transformAttributeStringForTransforms:transforms];
}
IJSVGApplyAttributesToElement(dict, patternElement);
@@ -1315,8 +1326,7 @@ NSString* IJSVGHash(NSString* key)
// work out the transform
NSArray* transforms = layer.gradient.transforms;
if(transforms.count != 0.f) {
CGAffineTransform transform = IJSVGConcatTransforms(transforms);
NSString* transformString = [self transformAttributeStringForTransform:transform];
NSString* transformString = [self transformAttributeStringForTransforms:transforms];
IJSVGApplyAttributesToElement(@{
IJSVGAttributeGradientTransform: transformString
}, gradientElement);
@@ -51,17 +51,13 @@
(void)CGImageRelease(_image), _image = nil;
}
_image = [self.filter newImageByApplyFilterToLayer:_sublayer
scale:1.f];
scale:self.backingScaleFactor];
}
- (void)layoutSublayers
{
CGFloat width = CGImageGetWidth(_image);
CGFloat height = CGImageGetHeight(_image);
CGRect frame = _sublayer.innerBoundingBox;
_hostingLayer.frame = CGRectMake(frame.origin.x + (frame.size.width / 2.f - width / 2.f),
frame.origin.y + (frame.size.height / 2.f - height / 2.f),
width, height);
_hostingLayer.frame = frame;
_hostingLayer.contents = (__bridge id)_image;
}
@@ -396,13 +396,21 @@ intoUserSpaceUnitsFrom:(CALayer<IJSVGDrawableLayer>*)fromLayer
scale:(CGFloat)scale
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGImageRef ref = [self newImageForLayer:layer
options:options
colorSpace:colorSpace
bitmapInfo:kCGImageAlphaNone
scale:scale];
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 ref;
return masked;
}
+ (CGImageRef)newImageWithSize:(CGSize)size
@@ -428,8 +436,10 @@ intoUserSpaceUnitsFrom:(CALayer<IJSVGDrawableLayer>*)fromLayer
bitmapInfo:(uint32_t)bitmapInfo
scale:(CGFloat)scale
{
CALayer<IJSVGDrawableLayer>* referenceLayer = layer.referencingLayer ?: layer;
CGRect frame = layer.outerBoundingBox;
CGRect bounds = layer.innerBoundingBox;
CGRect bounds = CGRectApplyAffineTransform(layer.innerBoundingBox,
[self userSpaceTransformForLayer:referenceLayer]);
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
ceilf(frame.size.width*scale),
ceilf(frame.size.height*scale),
@@ -11,6 +11,19 @@
@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;
@@ -8,6 +8,7 @@
#import <IJSVG/IJSVGFilterEffect.h>
#import <IJSVG/IJSVGFilterEffectGaussianBlur.h>
#import <IJSVG/IJSVGUtils.h>
@implementation IJSVGFilterEffect
@@ -28,26 +29,26 @@ static NSDictionary<NSString*, Class>* _elementClassMap = nil;
+ (IJSVGFilterEffectSource)sourceForString:(NSString*)string
{
const char* name = string.lowercaseString.UTF8String;
const char* name = string.UTF8String;
if(name == NULL) {
return IJSVGFilterEffectSourceGraphic;
}
if(strcmp(name, "sourcegraphic") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "sourcegraphic") == YES) {
return IJSVGFilterEffectSourceGraphic;
}
if(strcmp(name, "sourcealpha") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "sourcealpha") == YES) {
return IJSVGFilterEffectSourceAlpha;
}
if(strcmp(name, "backgroundimage") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "backgroundimage") == YES) {
return IJSVGFilterEffectSourceBackgroundImage;
}
if(strcmp(name, "backgroundalpha") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "backgroundalpha") == YES) {
return IJSVGFilterEffectSourceBackgroundAlpha;
}
if(strcmp(name, "fillpaint") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "fillpaint") == YES) {
return IJSVGFilterEffectSourceFillPaint;
}
if(strcmp(name, "strokepain") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "strokepain") == YES) {
return IJSVGFilterEffectSourceStrokePaint;
}
return IJSVGFilterEffectSourcePrimitiveReference;
@@ -59,13 +60,13 @@ static NSDictionary<NSString*, Class>* _elementClassMap = nil;
if(name == NULL) {
return IJSVGFilterEffectEdgeModeNone;
}
if(strcmp(name, "none") == 0) {
if(IJSVGCharBufferCompare(name, "none") == YES) {
return IJSVGFilterEffectEdgeModeNone;
}
if(strcmp(name, "wrap") == 0) {
if(IJSVGCharBufferCompare(name, "wrap") == YES) {
return IJSVGFilterEffectEdgeModeWrap;
}
if(strcmp(name, "duplicate") == 0) {
if(IJSVGCharBufferCompare(name, "duplicate") == YES) {
return IJSVGFilterEffectEdgeModeDuplicate;
}
return IJSVGFilterEffectEdgeModeNone;
@@ -11,6 +11,15 @@
@implementation IJSVGGradient
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributeGradientUnits];
[storage setBit:IJSVGNodeAttributeGradientTransform];
return storage;
}
- (void)dealloc
{
if(_locations != NULL) {
@@ -7,6 +7,7 @@
//
#import <IJSVG/IJSVGGroup.h>
#import <IJSVG/IJSVGImage.h>
@implementation IJSVGGroup
@@ -18,11 +19,17 @@
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
{
if(_children != nil) {
(void)_children, _children = nil;
}
_children = [[NSMutableArray alloc] init];
}
@@ -17,6 +17,18 @@
(void)(CGImageRelease(CGImage)), CGImage = nil;
}
+ (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:IJSVGNodeAttributePreserveAspectRatio];
return storage;
}
- (void)setDefaults
{
[super setDefaults];
@@ -12,6 +12,17 @@
@implementation IJSVGLinearGradient
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributeX1];
[storage setBit:IJSVGNodeAttributeX2];
[storage setBit:IJSVGNodeAttributeY1];
[storage setBit:IJSVGNodeAttributeY2];
return storage;
}
+ (void)parseGradient:(NSXMLElement*)element
gradient:(IJSVGLinearGradient*)aGradient
{
@@ -42,7 +53,6 @@
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
CGRect boundingBox = objectRect;
// make sure we apply the absolute position to
@@ -64,8 +74,8 @@
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
[self.y2 computeValue:height]);
// apply the gradient transform if there is one
CGContextConcatCTM(ctx, selfTransform);
// concat the gradient transform into the context
IJSVGConcatTransformsCTM(ctx, self.transforms);
// draw the gradient
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
@@ -11,6 +11,19 @@
@implementation IJSVGMask
+ (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:IJSVGNodeAttributeMaskUnits];
[storage setBit:IJSVGNodeAttributeMaskContentUnits];
return storage;
}
- (void)setDefaults
{
[super setDefaults];
+75 -3
View File
@@ -9,6 +9,7 @@
#import <IJSVG/IJSVGStyleSheetStyle.h>
#import <IJSVG/IJSVGUnitLength.h>
#import <IJSVG/IJSVGViewBox.h>
#import <IJSVG/IJSVGBitFlags64.h>
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
@@ -24,9 +25,79 @@
@class IJSVGFilter;
@class IJSVGMask;
@class IJSVGClipPath;
@class IJSVGThreadManager;
typedef void (^IJSVGNodeWalkHandler)(IJSVGNode* node, BOOL* allowChildNodes, BOOL* stop);
typedef NS_ENUM(NSInteger, IJSVGNodeAttribute) {
IJSVGNodeAttributeVersion,
IJSVGNodeAttributeXMLNS,
IJSVGNodeAttributeXMLNSXlink,
IJSVGNodeAttributeViewBox,
IJSVGNodeAttributePreserveAspectRatio,
IJSVGNodeAttributeID,
IJSVGNodeAttributeClass,
IJSVGNodeAttributeX,
IJSVGNodeAttributeY,
IJSVGNodeAttributeWidth,
IJSVGNodeAttributeHeight,
IJSVGNodeAttributeOpacity,
IJSVGNodeAttributeStrokeOpacity,
IJSVGNodeAttributeStrokeWidth,
IJSVGNodeAttributeStrokeDashOffset,
IJSVGNodeAttributeFillOpacity,
IJSVGNodeAttributeClipPath,
IJSVGNodeAttributeClipPathUnits,
IJSVGNodeAttributeClipRule,
IJSVGNodeAttributeMask,
IJSVGNodeAttributeGradientUnits,
IJSVGNodeAttributePatternUnits,
IJSVGNodeAttributePatternContentUnits,
IJSVGNodeAttributePatternTransform,
IJSVGNodeAttributeMaskUnits,
IJSVGNodeAttributeMaskContentUnits,
IJSVGNodeAttributeTransform,
IJSVGNodeAttributeGradientTransform,
IJSVGNodeAttributeUnicode,
IJSVGNodeAttributeStrokeLineCap,
IJSVGNodeAttributeStrokeLineJoin,
IJSVGNodeAttributeStroke,
IJSVGNodeAttributeStrokeDashArray,
IJSVGNodeAttributeStrokeMiterLimit,
IJSVGNodeAttributeFill,
IJSVGNodeAttributeFillRule,
IJSVGNodeAttributeBlendMode,
IJSVGNodeAttributeDisplay,
IJSVGNodeAttributeStyle,
IJSVGNodeAttributeD,
IJSVGNodeAttributeXLink,
IJSVGNodeAttributeX1,
IJSVGNodeAttributeX2,
IJSVGNodeAttributeY1,
IJSVGNodeAttributeY2,
IJSVGNodeAttributeRX,
IJSVGNodeAttributeRY,
IJSVGNodeAttributeCX,
IJSVGNodeAttributeCY,
IJSVGNodeAttributeR,
IJSVGNodeAttributeFX,
IJSVGNodeAttributeFY,
IJSVGNodeAttributeFR,
IJSVGNodeAttributePoints,
IJSVGNodeAttributeOffset,
IJSVGNodeAttributeStopColor,
IJSVGNodeAttributeStopOpacity,
IJSVGNodeAttributeHref,
IJSVGNodeAttributeOverflow,
IJSVGNodeAttributeFilter,
IJSVGNodeAttributeStdDeviation,
IJSVGNodeAttributeIn,
IJSVGNodeAttributeEdgeMode,
IJSVGNodeAttributeMarker
};
static const int kIJSVGNodeAttributeStorageLength = 64;
typedef NS_OPTIONS(NSInteger, IJSVGIntrinsicDimensions) {
IJSVGIntrinsicDimensionNone = 0,
IJSVGIntrinsicDimensionWidth = 1 << 1,
@@ -184,6 +255,8 @@ void IJSVGAssertPaintableObject(id object);
@property (nonatomic, readonly) BOOL detachedFromParentNode;
@property (nonatomic, readonly) IJSVGRootNode* rootNode;
+ (IJSVGBitFlags*)computedAllowedAttributes;
+ (IJSVGBitFlags*)allowedAttributes;
+ (void)walkNodeTree:(IJSVGNode*)node
handler:(IJSVGNodeWalkHandler)handler;
@@ -211,11 +284,10 @@ containsNodesMatchingTraits:(IJSVGNodeTraits)traits;
- (void)removeTraits:(IJSVGNodeTraits)traits;
- (BOOL)matchesTraits:(IJSVGNodeTraits)traits;
- (void)computeTraits;
- (void)normalizeWithOffset:(CGPoint)offset;
- (NSSet<IJSVGNode*>*)nodesMatchingTypes:(NSIndexSet*)types;
- (instancetype)parentNodeMatchingClass:(Class)class;
- (instancetype)rootNodeMatchingClass:(Class)class;
- (instancetype)parentNodeMatchingClass:(Class)someClass;
- (instancetype)rootNodeMatchingClass:(Class)someClass;
@end
+73 -53
View File
@@ -10,6 +10,7 @@
#import <IJSVG/IJSVGGroup.h>
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGRootNode.h>
#import <IJSVG/IJSVGThreadManager.h>
@implementation IJSVGNode
@@ -18,111 +19,143 @@
- (void)dealloc
{
(void)free(_strokeDashArray), _strokeDashArray = NULL;
if(_strokeDashArray != NULL) {
(void)free(_strokeDashArray), _strokeDashArray = NULL;
}
}
+ (IJSVGNodeType)typeForString:(NSString*)string
kind:(NSXMLNodeKind)kind
{
// possible fix for older os's that complain
if(string == nil || kind != NSXMLElementKind) {
// if string is nil, or its not a generic element or some text span
if(string == nil || (kind != NSXMLElementKind && kind != NSXMLTextKind)) {
return IJSVGNodeTypeNotFound;
}
const char* name = string.lowercaseString.UTF8String;
if(name == NULL) {
const char* nodeType = string.UTF8String;
if(nodeType == NULL) {
return IJSVGNodeTypeNotFound;
}
if(strcmp(name, "style") == 0) {
return IJSVGNodeTypeStyle;
}
if(strcmp(name, "switch") == 0) {
return IJSVGNodeTypeSwitch;
}
if(strcmp(name, "defs") == 0) {
return IJSVGNodeTypeDef;
}
if(strcmp(name, "g") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "g") == YES) {
return IJSVGNodeTypeGroup;
}
if(strcmp(name, "path") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "path") == YES) {
return IJSVGNodeTypePath;
}
if(strcmp(name, "polygon") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "style") == YES) {
return IJSVGNodeTypeStyle;
}
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "switch") == YES) {
return IJSVGNodeTypeSwitch;
}
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "defs") == YES) {
return IJSVGNodeTypeDef;
}
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "polygon") == YES) {
return IJSVGNodeTypePolygon;
}
if(strcmp(name, "polyline") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "polyline") == YES) {
return IJSVGNodeTypePolyline;
}
if(strcmp(name, "rect") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "rect") == YES) {
return IJSVGNodeTypeRect;
}
if(strcmp(name, "line") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "line") == YES) {
return IJSVGNodeTypeLine;
}
if(strcmp(name, "circle") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "circle") == YES) {
return IJSVGNodeTypeCircle;
}
if(strcmp(name, "ellipse") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "ellipse") == YES) {
return IJSVGNodeTypeEllipse;
}
if(strcmp(name, "use") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "use") == YES) {
return IJSVGNodeTypeUse;
}
if(strcmp(name, "lineargradient") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "lineargradient") == YES) {
return IJSVGNodeTypeLinearGradient;
}
if(strcmp(name, "radialgradient") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "radialgradient") == YES) {
return IJSVGNodeTypeRadialGradient;
}
if(strcmp(name, "stop") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "stop") == YES) {
return IJSVGNodeTypeStop;
}
if(strcmp(name, "glyph") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "glyph") == YES) {
return IJSVGNodeTypeGlyph;
}
if(strcmp(name, "font") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "font") == YES) {
return IJSVGNodeTypeFont;
}
if(strcmp(name, "clippath") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "clippath") == YES) {
return IJSVGNodeTypeClipPath;
}
if(strcmp(name, "mask") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "mask") == YES) {
return IJSVGNodeTypeMask;
}
if(strcmp(name, "image") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "image") == YES) {
return IJSVGNodeTypeImage;
}
if(strcmp(name, "pattern") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "pattern") == YES) {
return IJSVGNodeTypePattern;
}
if(strcmp(name, "svg") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "svg") == YES) {
return IJSVGNodeTypeSVG;
}
if(strcmp(name, "text") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "text") == YES) {
return IJSVGNodeTypeText;
}
if(strcmp(name, "tspan") == 0 || kind == NSXMLTextKind) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "tspan") == YES || kind == NSXMLTextKind) {
return IJSVGNodeTypeTextSpan;
}
if(strcmp(name, "title") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "title") == YES) {
return IJSVGNodeTypeTitle;
}
if(strcmp(name, "desc") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "desc") == YES) {
return IJSVGNodeTypeDesc;
}
if(strcmp(name, "foreignobject") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "foreignobject") == YES) {
return IJSVGNodeTypeForeignObject;
}
if(strcmp(name, "filter") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "filter") == YES) {
return IJSVGNodeTypeFilter;
}
if(strcmp(name, "fegaussianblur") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(nodeType, "fegaussianblur") == YES) {
return IJSVGNodeTypeFilterEffect;
}
return IJSVGNodeTypeUnknown;
}
+ (IJSVGBitFlags*)computedAllowedAttributes
{
static NSMutableDictionary<Class, IJSVGBitFlags*>* computed = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
computed = [[NSMutableDictionary alloc] init];
});
@synchronized (computed) {
IJSVGBitFlags* set = computed[self];
if(set == nil) {
set = [self allowedAttributes];
computed[(id<NSCopying>)self] = set;
}
return set;
}
}
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage setBit:IJSVGNodeAttributeStyle];
[storage setBit:IJSVGNodeAttributeClass];
[storage setBit:IJSVGNodeAttributeTransform];
[storage setBit:IJSVGNodeAttributeID];
[storage setBit:IJSVGNodeAttributeDisplay];
return storage;
}
+ (BOOL)typeIsPathable:(IJSVGNodeType)type
{
return type == IJSVGNodeTypePath || type == IJSVGNodeTypeRect ||
@@ -626,17 +659,4 @@ containsNodesMatchingTraits:(IJSVGNodeTraits)traits
return foundNode;
}
- (void)normalizeWithOffset:(CGPoint)offset
{
// if an SVG has been asked to normalize, its root will give us an offset
// to transform by to shift everything based on the viewBox's origin, we can
// simply just create a translate transform and stick at first position.
NSMutableArray* transforms = self.transforms ?
self.transforms.mutableCopy : [[NSMutableArray alloc] init];
IJSVGTransform* transform = [IJSVGTransform transformByTranslatingX:-offset.x
y:-offset.y];
[transforms insertObject:transform atIndex:0];
self.transforms = transforms;
}
@end
@@ -11,6 +11,29 @@
@implementation IJSVGPath
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributeFill];
[storage setBit:IJSVGNodeAttributeFillOpacity];
[storage setBit:IJSVGNodeAttributeFillRule];
[storage setBit:IJSVGNodeAttributeX];
[storage setBit:IJSVGNodeAttributeY];
[storage setBit:IJSVGNodeAttributeStroke];
[storage setBit:IJSVGNodeAttributeStrokeWidth];
[storage setBit:IJSVGNodeAttributeStrokeOpacity];
[storage setBit:IJSVGNodeAttributeStrokeLineCap];
[storage setBit:IJSVGNodeAttributeStrokeLineJoin];
[storage setBit:IJSVGNodeAttributeStrokeDashArray];
[storage setBit:IJSVGNodeAttributeStrokeDashOffset];
[storage setBit:IJSVGNodeAttributeClipPath];
[storage setBit:IJSVGNodeAttributeMask];
[storage setBit:IJSVGNodeAttributeOpacity];
[storage setBit:IJSVGNodeAttributeBlendMode];
return storage;
}
+ (void)recursivelyAddPathedNodesPaths:(NSArray<IJSVGNode*>*)nodes
transform:(CGAffineTransform)transform
toPath:(CGMutablePathRef)mutPath
@@ -12,6 +12,17 @@
@implementation IJSVGPattern
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributePatternTransform];
[storage setBit:IJSVGNodeAttributePatternUnits];
[storage setBit:IJSVGNodeAttributePatternContentUnits];
[storage setBit:IJSVGNodeAttributeViewBox];
return storage;
}
- (instancetype)init
{
if((self = [super init]) != nil) {
@@ -11,6 +11,19 @@
@implementation IJSVGRadialGradient
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributeFX];
[storage setBit:IJSVGNodeAttributeFY];
[storage setBit:IJSVGNodeAttributeFR];
[storage setBit:IJSVGNodeAttributeCX];
[storage setBit:IJSVGNodeAttributeCY];
[storage setBit:IJSVGNodeAttributeR];
return storage;
}
- (id)copyWithZone:(NSZone*)zone
{
IJSVGRadialGradient* grad = [super copyWithZone:zone];
@@ -85,16 +98,12 @@
transform:(CGAffineTransform)absoluteTransform
{
CGContextSaveGState(ctx);
CGContextSetInterpolationQuality(ctx, kCGInterpolationLow);
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGFloat radius = 0.f;
CGPoint startPoint = CGPointZero;
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
CGRect boundingBox = objectRect;
// transforms
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
// compute size based on percentages
CGFloat width = 0.f;
@@ -117,22 +126,20 @@
CGFloat fx = [_fx computeValue:width];
CGFloat fy = [_fy computeValue:height];
gradientEndPoint = CGPointMake(fx, fy);
gradientStartPoint = startPoint;
gradientEndPoint = CGPointMake(fx, fy);
// transform if width or height is not equal - this can only
// be done if we are using objectBoundingBox
if(inUserSpace == YES) {
CGFloat rad = 2.f * radius;
CGRect rect = CGRectMake(startPoint.x, startPoint.y, rad, rad);
radius = CGRectGetHeight(rect) / 2.f;
CGContextConcatCTM(ctx, absoluteTransform);
} else {
CGContextConcatCTM(ctx, CGAffineTransformMakeScale(CGRectGetWidth(boundingBox),
CGRectGetHeight(boundingBox)));
}
CGContextConcatCTM(ctx, selfTransform);
// concat the gradient transform into the context
IJSVGConcatTransformsCTM(ctx, self.transforms);
// draw the gradient
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
@@ -12,6 +12,8 @@
@interface IJSVGRootNode : IJSVGGroup
@property (nonatomic, assign) CGSize clientSize;
@property (nonatomic, assign) BOOL viewBoxContainsRelativeUnits;
@property (nonatomic, assign) IJSVGIntrinsicDimensions intrinsicDimensions;
@property (nonatomic, strong) IJSVGUnitSize* intrinsicSize;
@property (nonatomic, readonly) CGRect bounds;
@@ -7,9 +7,23 @@
//
#import <IJSVG/IJSVGRootNode.h>
#import <IJSVG/IJSVGThreadManager.h>
@implementation IJSVGRootNode
+ (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:IJSVGNodeAttributePreserveAspectRatio];
[storage setBit:IJSVGNodeAttributeViewBox];
return storage;
}
- (instancetype)init
{
if((self = [super init]) != nil) {
@@ -32,7 +46,7 @@
- (IJSVGRootNode *)rootNode
{
IJSVGRootNode* rootNode = nil;
if((rootNode = [super rootNode]) == self) {
if((rootNode = super.rootNode) == self) {
IJSVGNode* parent = self.parentNode;
if([parent isKindOfClass:IJSVGRootNode.class]) {
return (IJSVGRootNode*)parent;
@@ -42,26 +56,4 @@
return rootNode;
}
- (void)normalizeWithOffset:(CGPoint)offset
{
for(IJSVGNode* node in self.children) {
[node normalizeWithOffset:offset];
}
}
- (void)postProcess
{
// Some SVG's will have a viewBox such as 5, 5, 10, 10, given that
// we can zero out the origin and shift all its direct children by
// the viewBox's origin
if(IJSVGThreadManager.currentManager.featureFlags.viewBoxNormalization.enabled == YES) {
CGRect vBox = [self.viewBox computeValue:CGSizeZero];
if(CGPointEqualToPoint(vBox.origin, CGPointZero) == YES) {
return;
}
[self normalizeWithOffset:vBox.origin];
self.viewBox.origin = IJSVGUnitPoint.zeroPoint;
}
}
@end
@@ -0,0 +1,13 @@
//
// IJSVGStop.h
// IJSVG
//
// Created by Curtis Hard on 05/09/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVG.h>
@interface IJSVGStop : IJSVGNode
@end
@@ -0,0 +1,23 @@
//
// IJSVGStop.m
// IJSVG
//
// Created by Curtis Hard on 05/09/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import "IJSVGStop.h"
@implementation IJSVGStop
+ (IJSVGBitFlags*)allowedAttributes
{
IJSVGBitFlags64* storage = [[IJSVGBitFlags64 alloc] init];
[storage addBits:[super allowedAttributes]];
[storage setBit:IJSVGNodeAttributeStopColor];
[storage setBit:IJSVGNodeAttributeStopOpacity];
[storage setBit:IJSVGNodeAttributeOffset];
return storage;
}
@end
@@ -153,6 +153,16 @@ CGFloat* _Nullable IJSVGParsePathDataStreamSequence(const char* commandChars, NS
// null value of the end of the string instead of nulling out
// with memset \0 - huzzah!
dataStream->charBuffer[bufferCount] = '\0';
// lets check to make the buffer actually has a valid float, and
// not either just a sign or white space or some random char.
if(strlen(dataStream->charBuffer) == 1 && !VALID_DIGIT(dataStream->charBuffer[0])) {
isDecimal = false;
bufferCount = 0;
continue;
}
// actually add the float into the buffer
dataStream->floatBuffer[counter++] = IJSVGParseFloat(dataStream->charBuffer);
// reset
@@ -166,7 +176,7 @@ CGFloat* _Nullable IJSVGParsePathDataStreamSequence(const char* commandChars, NS
if(commandsFound != NULL) {
*commandsFound = (NSInteger)round(counter / commandLength);
}
// allocate the new buffer from memory
CGFloat* floats = (CGFloat*)malloc(sizeof(CGFloat) * counter);
memcpy(floats, dataStream->floatBuffer, counter * sizeof(CGFloat));
@@ -12,6 +12,7 @@
#import <IJSVG/IJSVGForeignObject.h>
#import <IJSVG/IJSVGGroup.h>
#import <IJSVG/IJSVGColorNode.h>
#import <IJSVG/IJSVGStop.h>
#import <IJSVG/IJSVGImage.h>
#import <IJSVG/IJSVGLinearGradient.h>
#import <IJSVG/IJSVGPath.h>
@@ -26,7 +27,6 @@
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGFilter.h>
#import <IJSVG/IJSVGFilterEffect.h>
#import <IJSVG/IJSVGThreadManager.h>
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
@@ -110,6 +110,14 @@ extern NSString* const IJSVGAttributeMarker;
@class IJSVGParser;
@class IJSVGThreadManager;
typedef struct {
char* nodeType;
} IJSVGParserMallocBuffers;
IJSVGParserMallocBuffers* IJSVGParserMallocBuffersCreate(void);
void IJSVGParserMallocBuffersFree(IJSVGParserMallocBuffers* buffers);
@interface IJSVGParser : NSObject {
@@ -117,10 +125,13 @@ extern NSString* const IJSVGAttributeMarker;
NSXMLDocument* _document;
IJSVGPathDataStream* _commandDataStream;
IJSVGStyleSheet* _styleSheet;
NSMapTable<IJSVGNode*, NSMutableDictionary<NSString*, NSXMLElement*>*>* _detachedElements;
NSMutableDictionary<NSString*, NSXMLElement*>* _detachedReferences;
IJSVGThreadManager* _threadManager;
CGSize _rootSize;
IJSVGRootNode* _rootNode;
}
@property (nonatomic, strong, readonly) IJSVGRootNode* rootNode;
@property (nonatomic, assign) CGSize defaultSize;
+ (BOOL)isDataSVG:(NSData*)data;
@@ -133,4 +144,6 @@ extern NSString* const IJSVGAttributeMarker;
+ (IJSVGParser*)parserForFileURL:(NSURL*)aURL
error:(NSError**)error;
- (IJSVGRootNode*)rootNodeWithSize:(CGSize)size;
@end
File diff suppressed because it is too large Load Diff
@@ -26,6 +26,7 @@
#import <IJSVG/IJSVGUtils.h>
#import <IJSVG/IJSVGTransformLayer.h>
#import <IJSVG/IJSVGFilterLayer.h>
#import <IJSVG/IJSVGThreadManager.h>
@implementation IJSVGLayerTree
@@ -601,6 +602,16 @@
maskingBounds.origin.x += maskBounds.origin.x;
maskingBounds.origin.y += maskBounds.origin.y;
maskingBounds = CGRectApplyAffineTransform(maskingBounds, userSpaceTransform);
// we need to move all the layers back if they are into the userSpace
// coordinate system
for(CALayer<IJSVGDrawableLayer> *childLayer in maskLayer.sublayers) {
CGRect innerBoundingBox = childLayer.innerBoundingBox;
CGAffineTransform innerTransform = CGAffineTransformMakeTranslation(-innerBoundingBox.origin.x,
-innerBoundingBox.origin.y);
childLayer.frame = CGRectApplyAffineTransform(childLayer.frame, userSpaceTransform);
childLayer.frame = CGRectApplyAffineTransform(childLayer.frame, innerTransform);
}
}
if(maskNode.units == IJSVGUnitUserSpaceOnUse) {
@@ -767,6 +778,7 @@
}
parentLayer.affineTransform = identity;
[parentLayer addSublayer:layer];
parentLayer.outerBoundingBox = [IJSVGLayer calculateFrameForSublayers:parentLayer.sublayers];
return parentLayer;
}
@@ -17,9 +17,17 @@
_lineJoinStyle = IJSVGLineJoinStyleNone;
_lineWidth = IJSVGInheritedFloatValue;
_miterLimit = IJSVGInheritedFloatValue;
_colors = [[IJSVGTraitedColorStorage alloc] init];
}
return self;
}
- (IJSVGTraitedColorStorage*)colors
{
// this can be lazy as most users wont use this functionality
if(_colors == nil) {
_colors = [[IJSVGTraitedColorStorage alloc] init];
}
return _colors;
}
@end
@@ -0,0 +1,25 @@
//
// IJSVGBitStorage.h
// IJSVG
//
// Created by Curtis Hard on 06/09/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface IJSVGBitFlags : NSObject {
@private
int* _storage;
}
@property (nonatomic, readonly) int length;
@property (nonatomic, readonly) int* storage;
- (id)initWithLength:(int)length;
- (void)addBits:(IJSVGBitFlags*)storage;
- (BOOL)bitIsSet:(int)bit;
- (void)setBit:(int)bit;
@end
@@ -0,0 +1,53 @@
//
// IJSVGBitStorage.m
// IJSVG
//
// Created by Curtis Hard on 06/09/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import "IJSVGBitFlags.h"
@implementation IJSVGBitFlags
- (void)dealloc
{
if(_storage != NULL) {
(void)free(_storage), _storage = NULL;
}
}
- (id)initWithLength:(int)length
{
if((self = [super init]) != nil) {
_length = length;
_storage = (int*)calloc(sizeof(int), length);
}
return self;
}
- (void)addBits:(IJSVGBitFlags*)storage
{
int* ps = storage.storage;
int* ss = _storage;
for(int i = 0; i < storage.length; i++) {
int* current = ss++;
if(*ps++ == 1) {
*current = 1;
}
}
}
- (BOOL)bitIsSet:(int)bit
{
return *(_storage + bit) == 1;
}
- (void)setBit:(int)bit
{
*(_storage + bit) = 1;
}
@end
@@ -0,0 +1,16 @@
//
// IJSVGBitFlags64.h
// IJSVG
//
// Created by Curtis Hard on 08/09/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGBitFlags.h>
@interface IJSVGBitFlags64 : IJSVGBitFlags {
@private
int64_t _storage64;
}
@end
@@ -0,0 +1,40 @@
//
// IJSVGBitFlags64.m
// IJSVG
//
// Created by Curtis Hard on 08/09/2022.
// Copyright © 2022 Curtis Hard. All rights reserved.
//
#import "IJSVGBitFlags64.h"
@implementation IJSVGBitFlags64
- (instancetype)init
{
if((self = [super init]) != nil) {
_storage64 = 0ULL;
}
return self;
}
- (void)addBits:(IJSVGBitFlags*)storage
{
for(int i = 0; i < 64; i++) {
if([storage bitIsSet:i] == YES) {
[self setBit:i];
}
}
}
- (BOOL)bitIsSet:(int)bit
{
return ((_storage64 >> bit) & 1ULL) == 1;
}
- (void)setBit:(int)bit
{
_storage64 |= (1ULL << bit);
}
@end
@@ -94,7 +94,7 @@ IJSVGParsingStringMethod** IJSVGParsingMethodParseString(const char* string,
// now we can add
if(methodCount + 1 > currentBufferSize) {
currentBufferSize += defBufferSize;
*methods = *(IJSVGParsingStringMethod**)realloc(methods, sizeof(IJSVGParsingStringMethod*)*currentBufferSize);
methods = (IJSVGParsingStringMethod**)realloc(methods, sizeof(IJSVGParsingStringMethod*)*currentBufferSize);
}
methods[methodCount++] = method;
method = NULL;
@@ -12,21 +12,28 @@
#import <IJSVG/IJSVGParsing.h>
#import <IJSVG/IJSVGCommandParser.h>
#import <IJSVG/IJSVGFeatureFlags.h>
#import <IJSVG/IJSVG.h>
#import <IJSVG/IJSVGParser.h>
@interface IJSVGThreadManager : NSObject {
@private
NSMutableDictionary* _userInfo;
NSHashTable* _allocedSVGs;
}
@property (nonatomic, readonly) IJSVGFeatureFlags* featureFlags;
@property (nonatomic, readonly) NSThread* thread;
@property (nonatomic, readonly) CIContext* CIContext;
@property (nonatomic, readonly) IJSVGPathDataStream* pathDataStream;
+ (IJSVGThreadManager*)managerForThread:(NSThread*)thread;
+ (IJSVGThreadManager*)managerForSVG:(IJSVG*)svg;
+ (IJSVGThreadManager*)currentManager;
- (void)adopt:(IJSVG*)svg;
- (void)remove:(IJSVG*)svg;
- (BOOL)manages:(IJSVG*)svg;
- (void)setUserInfoObject:(id)object
forKey:(id<NSCopying>)key;
- (id)userInfoObjectForKey:(id<NSCopying>)key;
@@ -39,6 +39,21 @@ static NSMapTable<NSThread*, IJSVGThreadManager*>* managerMap;
return manager;
}
+ (IJSVGThreadManager*)managerForSVG:(IJSVG*)svg
{
NSMapTable* map = [self mapTable];
IJSVGThreadManager* found = nil;
@synchronized (map) {
for(IJSVGThreadManager* manager in map) {
if([manager manages:svg] == YES) {
found = manager;
break;
}
}
}
return found;
}
+ (IJSVGThreadManager *)currentManager
{
return [self managerForThread:NSThread.currentThread];
@@ -60,6 +75,10 @@ static NSMapTable<NSThread*, IJSVGThreadManager*>* managerMap;
// setup the feature flags
_featureFlags = [[IJSVGFeatureFlags alloc] init];
// hash table for the SVGs for this given thread
_allocedSVGs = [[NSHashTable alloc] initWithOptions:NSPointerFunctionsWeakMemory
capacity:1];
// listen for teardown of the thread
NSNotificationCenter* center = NSNotificationCenter.defaultCenter;
[center addObserver:self
@@ -87,8 +106,31 @@ static NSMapTable<NSThread*, IJSVGThreadManager*>* managerMap;
return _userInfo[key];
}
- (BOOL)manages:(IJSVG*)svg
{
return [_allocedSVGs containsObject:svg];
}
- (void)adopt:(IJSVG*)svg
{
if([self manages:svg] == YES) {
return;
}
[_allocedSVGs addObject:svg];
}
- (void)remove:(IJSVG*)svg
{
[_allocedSVGs removeObject:svg];
}
- (void)tearDownFromThreadExit
{
// it is important that we call a transaction commit
// at the end of the thread or any changes will cause a memory leak
IJSVGPerformTransactionBlock(^{
[self->_allocedSVGs removeAllObjects];
});
NSMapTable* map = [self.class mapTable];
@synchronized (map) {
[map removeObjectForKey:_thread];
@@ -12,3 +12,4 @@
BOOL IJSVGIsMainThread(void);
BOOL IJSVGBeginTransaction(void);
void IJSVGEndTransaction(void);
void IJSVGPerformTransactionBlock(dispatch_block_t _Nonnull block);
@@ -6,10 +6,13 @@
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import <IJSVG/IJSVGThreadManager.h>
#import <IJSVG/IJSVGTransaction.h>
#import <AppKit/AppKit.h>
BOOL IJSVGIsMainThread(void) { return NSThread.isMainThread; };
BOOL IJSVGIsMainThread(void) {
return IJSVGThreadManager.currentManager.thread.isMainThread;
};
BOOL IJSVGBeginTransaction(void)
{
@@ -20,12 +23,21 @@ BOOL IJSVGBeginTransaction(void)
// of the catransaction for background composites
[CATransaction begin];
[CATransaction setDisableActions:YES];
[CATransaction lock];
// [CATransaction lock];
return YES;
};
void IJSVGEndTransaction(void)
{
[CATransaction unlock];
// [CATransaction unlock];
[CATransaction commit];
};
void IJSVGPerformTransactionBlock(dispatch_block_t _Nonnull block)
{
BOOL begin = IJSVGBeginTransaction();
block();
if(begin == YES) {
IJSVGEndTransaction();
}
}
@@ -37,6 +37,7 @@ typedef NS_ENUM(NSInteger, IJSVGTransformCommand) {
void IJSVGApplyTransform(NSArray<IJSVGTransform*>* transforms, IJSVGTransformApplyBlock block);
BOOL IJSVGAffineTransformScalesAndTranslates(CGAffineTransform affineTransform);
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform*>* transforms);
void IJSVGConcatTransformsCTM(CGContextRef context, NSArray<IJSVGTransform*>* transforms);
NSString* IJSVGTransformAttributeString(CGAffineTransform transform);
+ (NSArray<NSDictionary*>*)affineTransformToSVGTransformComponents:(CGAffineTransform)transform;
@@ -28,6 +28,13 @@
return trans;
}
void IJSVGConcatTransformsCTM(CGContextRef context, NSArray<IJSVGTransform*>* transforms)
{
IJSVGApplyTransform(transforms, ^(IJSVGTransform* transform) {
CGContextConcatCTM(context, transform.CGAffineTransform);
});
}
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform*>* transforms)
{
__block CGAffineTransform trans = CGAffineTransformIdentity;
@@ -87,29 +94,28 @@ BOOL IJSVGAffineTransformScalesAndTranslates(CGAffineTransform transform)
+ (IJSVGTransformCommand)commandForCommandCString:(char*)str
{
IJSVGCharBufferToLower(str);
if(strcmp(str, "matrix") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "matrix") == YES) {
return IJSVGTransformCommandMatrix;
}
if(strcmp(str, "translate") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "translate") == YES) {
return IJSVGTransformCommandTranslate;
}
if(strcmp(str, "translatex") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "translatex") == YES) {
return IJSVGTransformCommandTranslateX;
}
if(strcmp(str, "translatey") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "translatey") == YES) {
return IJSVGTransformCommandTranslateY;
}
if(strcmp(str, "scale") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "scale") == YES) {
return IJSVGTransformCommandScale;
}
if(strcmp(str, "skewx") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "skewx") == YES) {
return IJSVGTransformCommandSkewX;
}
if(strcmp(str, "skewy") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "skewy") == YES) {
return IJSVGTransformCommandSkewY;
}
if(strcmp(str, "rotate") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(str, "rotate") == YES) {
return IJSVGTransformCommandRotate;
}
return IJSVGTransformCommandNotImplemented;
@@ -153,7 +153,7 @@
// is inherit or just nothing
size_t strl = strlen(chars);
if(strcmp(chars, "inherit") == 0 || strl == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(chars, "inherit") == YES || strl == 0) {
(void)free(chars), chars = NULL;
return nil;
}
@@ -239,7 +239,7 @@
- (NSString*)stringValue
{
if(self.type == IJSVGUnitLengthTypePercentage) {
if(self.type == IJSVGUnitLengthTypePercentage && self.value != 0.f) {
return [NSString stringWithFormat:@"%@%%",
IJSVGShortFloatString(self.value * 100.f)];
}
@@ -248,7 +248,7 @@
- (NSString*)stringValueWithFloatingPointOptions:(IJSVGFloatingPointOptions)options
{
if(_type == IJSVGUnitLengthTypePercentage) {
if(_type == IJSVGUnitLengthTypePercentage && self.value != 0.f) {
return [NSString stringWithFormat:@"%@%%",
IJSVGShortFloatStringWithOptions(_value * 100.f, options)];
}
@@ -14,6 +14,7 @@
@property (nonatomic, strong) IJSVGUnitLength* width;
@property (nonatomic, strong) IJSVGUnitLength* height;
@property (nonatomic, readonly) CGSize value;
@property (nonatomic, readonly) BOOL isZeroSize;
+ (IJSVGUnitSize*)zeroSize;
@@ -38,6 +38,11 @@
return size;
}
- (BOOL)isZeroSize
{
return self.width.value == 0.f && self.height.value == 0.f;
}
- (void)convertUnitsToLengthType:(IJSVGUnitLengthType)lengthType
{
_width.type = _height.type = lengthType;
@@ -25,6 +25,9 @@ CGFloat IJSVGAngle(CGPoint a, CGPoint b);
CGFloat IJSVGRadiansToDegrees(CGFloat radians);
CGFloat IJSVGDegreesToRadians(CGFloat degrees);
char IJSVGCharToLower(char c);
BOOL IJSVGCharBufferCaseInsensitiveCompare(const char* str1, const char* str2);
BOOL IJSVGCharBufferCompare(const char* str1, const char* str2);
BOOL IJSVGCharBufferIsHEX(char* buffer);
BOOL IJSVGCharBufferHasPrefix(char* pre, char* str);
BOOL IJSVGCharBufferHasSuffix(char* s1, char* s2);
@@ -39,12 +39,12 @@ BOOL IJSVGCharBufferIsHEX(char* buffer) {
return YES;
}
BOOL IJSVGCharBufferHasPrefix(char *str, char *pre)
inline BOOL IJSVGCharBufferHasPrefix(char *str, char *pre)
{
return strncmp(pre, str, strlen(pre)) == 0;
}
BOOL IJSVGCharBufferHasSuffix(char* s1, char* s2)
inline BOOL IJSVGCharBufferHasSuffix(char* s1, char* s2)
{
size_t slen = strlen(s1);
size_t tlen = strlen(s2);
@@ -61,7 +61,7 @@ char* IJSVGTimmedCharBufferCreate(const char* buffer)
while(length-1 > 0 && isspace(buffer[length-1])) {
length--;
}
while(isspace(buffer[start])) {
while(isspace(buffer[start]) && start < length) {
start++;
}
char* chars = (char*)malloc(sizeof(char)*((length-start)+1) ?: sizeof(char));
@@ -83,10 +83,44 @@ void IJSVGTrimCharBuffer(char* buffer) {
memmove(buffer, ptr, length+1);
}
void IJSVGCharBufferToLower(char* buffer)
inline char IJSVGCharToLower(char c)
{
if(c >= 'A' && c <= 'Z') {
return c - ('A' - 'a');
}
return c;
}
BOOL IJSVGCharBufferCaseInsensitiveCompare(const char* str1, const char* str2)
{
if(str1 == str2) {
return YES;
}
const char *p1 = str1;
const char *p2 = str2;
int result = 0;
while((result = IJSVGCharToLower(*p1) - IJSVGCharToLower(*p2++)) == 0) {
if(*p1++ == '\0') {
break;
}
}
return result == 0;
}
inline BOOL IJSVGCharBufferCompare(const char* str1, const char* str2)
{
if(str1[0] != str2[0]) {
return NO;
}
return strcmp(str1, str2) == 0;
}
inline void IJSVGCharBufferToLower(char* buffer)
{
for(char *p = buffer; *p; p++) {
*p = tolower(*p);
*p = IJSVGCharToLower(*p);
}
}
@@ -290,8 +324,7 @@ CGFloat IJSVGDegreesToRadians(CGFloat degrees)
// what type of method is it?
IJSVGParsingStringMethod* method = methods[0];
IJSVGCharBufferToLower(method->name);
if(strcmp(method->name, "url") != 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(method->name, "url") == NO) {
(void)IJSVGParsingStringMethodsRelease(methods, count), methods = NULL;
return nil;
}
@@ -85,14 +85,14 @@
return IJSVGViewBoxMeetOrSliceUnknown;
}
const char* name = string.lowercaseString.UTF8String;
const char* name = string.UTF8String;
if(name == NULL) {
return IJSVGViewBoxMeetOrSliceUnknown;
}
if(strcmp(name, "meet") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "meet") == YES) {
return IJSVGViewBoxMeetOrSliceMeet;
}
if(strcmp(name, "slice") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "slice") == YES) {
return IJSVGViewBoxMeetOrSliceSlice;
}
return IJSVGViewBoxMeetOrSliceUnknown;
@@ -104,38 +104,38 @@
return IJSVGViewBoxAlignmentUnknown;
}
const char* name = string.lowercaseString.UTF8String;
const char* name = string.UTF8String;
if(name == NULL) {
return IJSVGViewBoxAlignmentUnknown;
}
if(strcmp(name, "none") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "none") == YES) {
return IJSVGViewBoxAlignmentNone;
}
if(strcmp(name, "xminymin") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xminymin") == YES) {
return IJSVGViewBoxAlignmentXMinYMin;
}
if(strcmp(name, "xmidymin") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xmidymin") == YES) {
return IJSVGViewBoxAlignmentXMidYMin;
}
if(strcmp(name, "xmaxymin") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xmaxymin") == YES) {
return IJSVGViewBoxAlignmentXMaxYMin;
}
if(strcmp(name, "xminymid") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xminymid") == YES) {
return IJSVGViewBoxAlignmentXMinYMid;
}
if(strcmp(name, "xmidymid") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xmidymid") == YES) {
return IJSVGViewBoxAlignmentXMidYMid;
}
if(strcmp(name, "xmaxymid") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xmaxymid") == YES) {
return IJSVGViewBoxAlignmentXMaxYMid;
}
if(strcmp(name, "xminymax") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xminymax") == YES) {
return IJSVGViewBoxAlignmentXMinYMax;
}
if(strcmp(name, "xmidymax") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xmidymax") == YES) {
return IJSVGViewBoxAlignmentXMidYMax;
}
if(strcmp(name, "xmaxymax") == 0) {
if(IJSVGCharBufferCaseInsensitiveCompare(name, "xmaxymax") == YES) {
return IJSVGViewBoxAlignmentXMaxYMax;
}
return IJSVGViewBoxAlignmentUnknown;
@@ -0,0 +1,123 @@
<svg viewBox="-1 -1 162 92" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="smiley" d="M50,10 A40,40,1,1,1,50,90 A40,40,1,1,1,50,10 M30,40 Q36,35,42,40 M58,40 Q64,35,70,40 M30,60 Q50,75,70,60 Q50,75,30,60" />
<style>
path {
fill: yellow;
stroke: black;
stroke-width: 8px;
stroke-linecap: round;
stroke-linejoin: round;
pointer-events: none;
}</style>
</defs>
<!-- (width>height) meet -->
<rect x="0" y="0" width="20" height="10">
<title>xMidYMid meet</title>
</rect>
<svg viewBox="0 0 100 100" width="20" height="10"
preserveAspectRatio="xMidYMid meet" x="0" y="0">
<use href="#smiley" />
</svg>
<rect x="25" y="0" width="20" height="10">
<title>xMinYMid meet</title>
</rect>
<svg viewBox="0 0 100 100" width="20" height="10"
preserveAspectRatio="xMinYMid meet" x="25" y="0">
<use href="#smiley" />
</svg>
<rect x="50" y="0" width="20" height="10">
<title>xMaxYMid meet</title>
</rect>
<svg viewBox="0 0 100 100" width="20" height="10"
preserveAspectRatio="xMaxYMid meet" x="50" y="0">
<use href="#smiley" />
</svg>
<!-- (width>height) slice -->
<rect x="0" y="15" width="20" height="10">
<title>xMidYMin slice</title>
</rect>
<svg viewBox="0 0 100 100" width="20" height="10"
preserveAspectRatio="xMidYMin slice" x="0" y="15">
<use href="#smiley" />
</svg>
<rect x="25" y="15" width="20" height="10">
<title>xMidYMid slice</title>
</rect>
<svg viewBox="0 0 100 100" width="20" height="10"
preserveAspectRatio="xMidYMid slice" x="25" y="15">
<use href="#smiley" />
</svg>
<rect x="50" y="15" width="20" height="10">
<title>xMidYMax slice</title>
</rect>
<svg viewBox="0 0 100 100" width="20" height="10"
preserveAspectRatio="xMidYMax slice" x="50" y="15">
<use href="#smiley" />
</svg>
<!-- (width<height) meet -->
<rect x="75" y="0" width="10" height="25">
<title>xMidYMin meet</title>
</rect>
<svg viewBox="0 0 100 100" width="10" height="25"
preserveAspectRatio="xMidYMin meet" x="75" y="0">
<use href="#smiley" />
</svg>
<rect x="90" y="0" width="10" height="25">
<title>xMidYMid meet</title>
</rect>
<svg viewBox="0 0 100 100" width="10" height="25"
preserveAspectRatio="xMidYMid meet" x="90" y="0">
<use href="#smiley" />
</svg>
<rect x="105" y="0" width="10" height="25">
<title>xMidYMax meet</title>
</rect>
<svg viewBox="0 0 100 100" width="10" height="25"
preserveAspectRatio="xMidYMax meet" x="105" y="0">
<use href="#smiley" />
</svg>
<!-- (width<height) slice -->
<rect x="120" y="0" width="10" height="25">
<title>xMinYMid slice</title>
</rect>
<svg viewBox="0 0 100 100" width="10" height="25"
preserveAspectRatio="xMinYMid slice" x="120" y="0">
<use href="#smiley" />
</svg>
<rect x="135" y="0" width="10" height="25">
<title>xMidYMid slice</title>
</rect>
<svg viewBox="0 0 100 100" width="10" height="25"
preserveAspectRatio="xMidYMid slice" x="135" y="0">
<use href="#smiley" />
</svg>
<rect x="150" y="0" width="10" height="25">
<title>xMaxYMid slice</title>
</rect>
<svg viewBox="0 0 100 100" width="10" height="25"
preserveAspectRatio="xMaxYMid slice" x="150" y="0">
<use href="#smiley" />
</svg>
<!-- none -->
<rect x="0" y="30" width="160" height="60">
<title>none</title>
</rect>
<svg viewBox="0 0 100 100" width="160" height="60"
preserveAspectRatio="none" x="0" y="30">
<use href="#smiley" />
</svg>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

@@ -0,0 +1,108 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
<g>
<path d="M10.1269 10.7451L10.33 17.2295C10.5629 20.6062 12.5389 21.9852 15.9667 22.0028C15.9779 22.0028 15.9888 22.0029 16 22.0029C16.0111 22.0029 16.022 22.0029 16.0332 22.0029C19.461 21.9854 21.437 20.6062 21.6699 17.2295L21.873 10.7451C21.942 8.54454 20.7559 7.40112 20.1542 7.10449H11.8457C11.244 7.40112 10.0579 8.54454 10.1269 10.7451Z" fill="url(#paint8_radial_3987_24253)"/>
</g>
<defs>
<radialGradient id="paint8_radial_3987_24253" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.5752 15.9951) rotate(174.491) scale(6.18482 6.87814)">
<stop offset="0.282722" stop-color="#FFDD41"/>
<stop offset="1" stop-color="#FDA828"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 895 B

+38 -39
View File
@@ -1,22 +1,39 @@
IJSVG
=====
IJSVG is a Mac OSX 10.7+ COCOA library for rendering SVG's within your COCOA applications, its extremely fast and native.
IJSVG 3.0
===
Orignaly written for IconJar (in development)
IJSVG is a Mac OSX 10.13+ COCOA library for rendering SVG's within your COCOA applications, its extremely fast and native.
It also supports the NSPasteboards writing protocol, an IJSVG object can be put onto the pasteboard and application like Sketch and Photoshop can paste them into the document as vector objects (generated PDF's on the fly).
It also supports the `NSPasteboards` writing protocol, an IJSVG object can be put onto the pasteboard and application like Sketch and Photoshop can paste them into the document as vector objects (generated PDF's on the fly).
### What is new in IJSVG 3.0?
- Its almost a complete full rewrite.
- Is now fully ARC 🎉.
- Parsing and rendering is much faster.
- Support for aspect ratios and nested SVG's.
- Fixes a lot of pattern and gradient rendering.
- Fixes various clipPath issues.
- Masking now correctly uses alpha masking instead of what `CALayer` uses.
- Various improvements with exporting such as modifying the viewBox instead of using a new group for scaling.
- Exporting now supports converting strokes to paths.
- Much simpler to use API's for creating SVG's from scratch.
- Much better threading support.
- Much improved color replacement support (can now specify only replacing a color that is a fill and not touch ths stroke).
- Improved API's for querying the node graph.
- Support for the wild card CSS selector.
- Removed most `NS` graphics API calls and uses `CG` where possible.
- Various memory and performance increases throughout.
Quick Start
====
Add all the IJSVG library files into your project, import the IJSVG.h into the files you wish to use the SVG's. The easiest way to
#### Step 1 - initialize the SVG object
IJSVG * svg = [[IJSVG alloc] initWithFilePathURL:someURLHere];
IJSVG* svg = [[IJSVG alloc] initWithFilePathURL:someURLHere];
// or with and without extension to find it within the bundle
IJSVG * svg = [IJSVG svgNamed:@"my_svg"];
IJSVG* svg = [IJSVG SVGNamed:@"my_svg"];
#### Step 2 - grab the NSImage from it
NSImage * svgImage = [svg imageWithSize:NSMakeSize(100.f,100.f)];
NSImage* svgImage = [svg imageWithSize:CGSizeMake(100.f,100.f)];
#Other ways of drawing
@@ -33,49 +50,31 @@ IJSVG provides a very simple way of helping out the backing scale factor of the
__block IJSVG * svg ....
svg.renderingBackingScaleHelper = ^{
return [svg computeBackingScale:someView.window.backingScaleFactor];
return NSScreen.mainScreen.backingScaleFactor; // can be changed to whatever
};
# Exporting
#### Yes, thats right... CALayers -> SVG (whos idea was this?!)
IJSVG provides a way of exporting the rendered layer tree back to an SVG file. This isnt 100% perfect but it does a good job of generating what IJSVG renders (have yet to find an issue).
IJSVG provides a way of exporting the rendered layer tree back to an SVG file. This should be a 1:1 representation of what is rendered in CoreGraphics.
Its a simple as doing this:
IJSVG * svg ...
IJSVG* svg ...
IJSVGExporter * exporter = [[IJSVGExporter alloc] initWithSVG:svg options:IJSVGExporterOptionAll];
NSString * svgString = [exporter SVGString];
NSString* svgString = exporter.SVGString;
Which will give you back the SVG code to put into a file, there are various options you can give it for more XML manipulation such s collpasing groups and converting transform's from matrix's back to their human readable counter parts.
The fun part is you can actually create an SVG object from a IJSVGLayer and work with them without needing to load a file, for example:
// create group layer and a shape layer (subclass of CAShapeLayer)
IJSVGGroupLayer * baseSVGGroup = ....
IJSVGShapeLayer * shapeLayer = ....
[baseSVGGroup addSublayer:shapeLayer];
// create the SVG - note the viewbox!
IJSVG * svg = [[IJSVG alloc] initWithSVGLayer:baseSVGGroup viewBox:NSMakeRect(0.f, 0.f, 50.f, 50.f)];
.... do what you want
and now you would have a usuable SVG to render where ever you would like and more importantly you can now export that back to an SVG file.
All layers must be of generic type IJSVGLayer or IJSVGShapeLayer, it will throw an exception if you do not use these. Also if you go out the scope of what those layers can do, it wont render nor will it export (get malformed results).
Which will give you back the SVG code to put into a file, there are various options you can give it for more XML manipulation such as collpasing groups and converting transform's from matrix's back to their human readable counter parts.
# What it supports
* Elements: def, use, g, path, clipPath, circle, elipse, rect, polyline, polygon and line (supports groups heirachy and inheritance, clip-paths etc)
* Commands: A, M, L, H, V, C, S, T, Q and Z and full support for multiple parameters of each type
* Transformations: matrix, rotate, translate, scale and skew transformations
* Stroking: stroking, stroke color, stroke opacity, dashed, dashed offset and phase, stroke line cap style
* Filling: fill color, fill mode (winding rules), fill opacity, linear gradients, radial gradients and patterns
* Color: supports all predefined colors from the SVG spec and hex values
* Caching: has basic caching implemenation
* CSS: Basic embedded style sheets are support with very basic selectors
* Switches and foreign objects, there is a delegate you can implement to handle foreign objects, once you say you can handle it, its up to you to handle the SVG as IJSVG will stop parsing the document once you have told it you will handle it
* Elements: def, use, g, path, clipPath, circle, elipse, rect, polyline, polygon and line (supports groups heirachy and inheritance, clip-paths etc).
* Commands: A, M, L, H, V, C, S, T, Q and Z and full support for multiple parameters of each type.
* Transformations: matrix, rotate, translate, scale and skew transformations.
* Stroking: stroking, stroke color, stroke opacity, dashed, dashed offset and phase, stroke line cap style.
* Filling: fill color, fill mode (winding rules), fill opacity, linear gradients, radial gradients and patterns.
* Color: supports all predefined colors from the SVG spec, HEX values along with RGB(A) and HSL.
* CSS: Basic embedded style sheets are support with very basic selectors.
## Credit
IJSVG is loosely based on [UIBezierPath-SVG](https://github.com/ap4y/UIBezierPath-SVG) by [ap4y](https://github.com/ap4y)
SVG icons in example found around the net, some from [Sketch App Resources](http://www.sketchappsources.com/all-svg-resource.html) all open source and free to use
SVG icons in example found around the net, some from [Sketch App Resources](http://www.sketchappsources.com/all-svg-resource.html) all open source and free to use.
-1
View File
@@ -1 +0,0 @@
theme: jekyll-theme-cayman