1
1
mirror of https://github.com/exyte/Macaw.git synced 2024-09-21 01:47:44 +03:00

Merge branch 'master1' into swift_4.1

This commit is contained in:
Alisa Mylnikova 2018-05-07 11:55:18 +07:00
commit c27db51291
36 changed files with 1907 additions and 139 deletions

View File

@ -253,11 +253,32 @@
57F1087C1F53CA7E00DC365B /* MDisplayLink_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F1087B1F53CA7E00DC365B /* MDisplayLink_iOS.swift */; };
57FCD2771D76EA4600CC0FB6 /* Macaw.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57FCD26C1D76EA4600CC0FB6 /* Macaw.framework */; };
57FCD27C1D76EA4600CC0FB6 /* MacawTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FCD27B1D76EA4600CC0FB6 /* MacawTests.swift */; };
602C561D2081C984003AD452 /* rounded.svg in Resources */ = {isa = PBXBuildFile; fileRef = 602C561C2081C984003AD452 /* rounded.svg */; };
5B1FFD7A207E083600716A46 /* SvgContentLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAA56A7207C73FF0055BC5B /* SvgContentLayout.swift */; };
5BAA56A8207C73FF0055BC5B /* SvgContentLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAA56A7207C73FF0055BC5B /* SvgContentLayout.swift */; };
5BAE201F208E1211006BF277 /* SVGCanvas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAE201E208E1211006BF277 /* SVGCanvas.swift */; };
5BAE2038208E163D006BF277 /* polyline.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2022208E1637006BF277 /* polyline.reference */; };
5BAE2039208E163D006BF277 /* polygon.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2023208E1637006BF277 /* polygon.reference */; };
5BAE203A208E163D006BF277 /* rect.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2024208E1637006BF277 /* rect.reference */; };
5BAE203C208E163D006BF277 /* triangle.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2026208E1637006BF277 /* triangle.reference */; };
5BAE203D208E163D006BF277 /* clipManual.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2027208E1637006BF277 /* clipManual.reference */; };
5BAE203E208E163D006BF277 /* circle.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2028208E1637006BF277 /* circle.reference */; };
5BAE203F208E163D006BF277 /* transform.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2029208E1638006BF277 /* transform.reference */; };
5BAE2040208E163D006BF277 /* ellipse.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE202A208E1638006BF277 /* ellipse.reference */; };
5BAE2042208E163D006BF277 /* group.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE202C208E1638006BF277 /* group.reference */; };
5BAE2043208E163D006BF277 /* textBasicTransform.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE202D208E1638006BF277 /* textBasicTransform.reference */; };
5BAE2044208E163D006BF277 /* style.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE202E208E1639006BF277 /* style.reference */; };
5BAE2045208E163D006BF277 /* arcsgroup.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE202F208E163A006BF277 /* arcsgroup.reference */; };
5BAE2047208E163D006BF277 /* viewBox.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2031208E163B006BF277 /* viewBox.reference */; };
5BAE2048208E163D006BF277 /* line.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2032208E163B006BF277 /* line.reference */; };
5BAE204A208E163D006BF277 /* roundRect.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2034208E163B006BF277 /* roundRect.reference */; };
5BAE204B208E163D006BF277 /* clip.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2035208E163C006BF277 /* clip.reference */; };
5BAE204C208E1EF4006BF277 /* SVGCanvas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAE201E208E1211006BF277 /* SVGCanvas.swift */; };
5BAE2058208F24DE006BF277 /* SceneSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAE2057208F24DE006BF277 /* SceneSerialization.swift */; };
5BAE2061208F2504006BF277 /* color-prop-02-f-manual.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE205B208F2504006BF277 /* color-prop-02-f-manual.svg */; };
5BAE2062208F2504006BF277 /* shapes-circle-01-t-manual.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE205C208F2504006BF277 /* shapes-circle-01-t-manual.svg */; };
5BAE2063208F2504006BF277 /* shapes-circle-01-t-manual.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE205D208F2504006BF277 /* shapes-circle-01-t-manual.reference */; };
5BAE2066208F2504006BF277 /* color-prop-02-f-manual.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE2060208F2504006BF277 /* color-prop-02-f-manual.reference */; };
5BAEA9C9206CEAA20049AAAE /* viewBox.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5BAEA9C8206CEAA20049AAAE /* viewBox.svg */; };
5BAEA9CB206CEB7D0049AAAE /* viewBox.reference in Resources */ = {isa = PBXBuildFile; fileRef = 5BAEA9CA206CEB7D0049AAAE /* viewBox.reference */; };
A718CD441F45C28200966E06 /* Common_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD431F45C28200966E06 /* Common_iOS.swift */; };
A718CD471F45C28700966E06 /* Graphics_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD451F45C28700966E06 /* Graphics_iOS.swift */; };
A718CD481F45C28700966E06 /* MView_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD461F45C28700966E06 /* MView_iOS.swift */; };
@ -271,13 +292,6 @@
C4153A8F1F8793DE001BA5EE /* small-logo.png in Resources */ = {isa = PBXBuildFile; fileRef = C4153A8E1F8793DD001BA5EE /* small-logo.png */; };
C43B064D1F9738EF00787A35 /* clip.svg in Resources */ = {isa = PBXBuildFile; fileRef = C43B064C1F9738EF00787A35 /* clip.svg */; };
C43B06511F9866E400787A35 /* Locus+ToPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43B06501F9866E400787A35 /* Locus+ToPath.swift */; };
C43B06531F989D9300787A35 /* transform.reference in Resources */ = {isa = PBXBuildFile; fileRef = C43B06521F989D9300787A35 /* transform.reference */; };
C43B06551F98A53600787A35 /* group.reference in Resources */ = {isa = PBXBuildFile; fileRef = C43B06541F98A53600787A35 /* group.reference */; };
C43B06571F98A7B700787A35 /* arcsgroup.reference in Resources */ = {isa = PBXBuildFile; fileRef = C43B06561F98A7B700787A35 /* arcsgroup.reference */; };
C43B06591F98A84200787A35 /* style.reference in Resources */ = {isa = PBXBuildFile; fileRef = C43B06581F98A84200787A35 /* style.reference */; };
C43B065B1F98A9E000787A35 /* clipManual.reference in Resources */ = {isa = PBXBuildFile; fileRef = C43B065A1F98A9E000787A35 /* clipManual.reference */; };
C43B065F1F98AAA500787A35 /* clip.reference in Resources */ = {isa = PBXBuildFile; fileRef = C43B065E1F98AAA500787A35 /* clip.reference */; };
C43B06611F98ACFC00787A35 /* textBasicTransform.reference in Resources */ = {isa = PBXBuildFile; fileRef = C43B06601F98ACFC00787A35 /* textBasicTransform.reference */; };
C43B06631F99A33400787A35 /* pathbounds3.svg in Resources */ = {isa = PBXBuildFile; fileRef = C43B06621F99A33400787A35 /* pathbounds3.svg */; };
C43B06661F99EE7300787A35 /* cubicAbsolute.svg in Resources */ = {isa = PBXBuildFile; fileRef = C43B06641F99EE7200787A35 /* cubicAbsolute.svg */; };
C43B06671F99EE7300787A35 /* cubicRelative.svg in Resources */ = {isa = PBXBuildFile; fileRef = C43B06651F99EE7300787A35 /* cubicRelative.svg */; };
@ -454,10 +468,30 @@
57FCD2761D76EA4600CC0FB6 /* MacawTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MacawTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
57FCD27B1D76EA4600CC0FB6 /* MacawTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacawTests.swift; sourceTree = "<group>"; };
57FCD27D1D76EA4600CC0FB6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
602C561C2081C984003AD452 /* rounded.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = rounded.svg; sourceTree = "<group>"; };
5BAA56A7207C73FF0055BC5B /* SvgContentLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SvgContentLayout.swift; sourceTree = "<group>"; };
5BAE201E208E1211006BF277 /* SVGCanvas.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGCanvas.swift; sourceTree = "<group>"; };
5BAE2022208E1637006BF277 /* polyline.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = polyline.reference; sourceTree = "<group>"; };
5BAE2023208E1637006BF277 /* polygon.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = polygon.reference; sourceTree = "<group>"; };
5BAE2024208E1637006BF277 /* rect.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rect.reference; sourceTree = "<group>"; };
5BAE2026208E1637006BF277 /* triangle.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = triangle.reference; sourceTree = "<group>"; };
5BAE2027208E1637006BF277 /* clipManual.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = clipManual.reference; sourceTree = "<group>"; };
5BAE2028208E1637006BF277 /* circle.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = circle.reference; sourceTree = "<group>"; };
5BAE2029208E1638006BF277 /* transform.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = transform.reference; sourceTree = "<group>"; };
5BAE202A208E1638006BF277 /* ellipse.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ellipse.reference; sourceTree = "<group>"; };
5BAE202C208E1638006BF277 /* group.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = group.reference; sourceTree = "<group>"; };
5BAE202D208E1638006BF277 /* textBasicTransform.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = textBasicTransform.reference; sourceTree = "<group>"; };
5BAE202E208E1639006BF277 /* style.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = style.reference; sourceTree = "<group>"; };
5BAE202F208E163A006BF277 /* arcsgroup.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = arcsgroup.reference; sourceTree = "<group>"; };
5BAE2031208E163B006BF277 /* viewBox.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = viewBox.reference; sourceTree = "<group>"; };
5BAE2032208E163B006BF277 /* line.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = line.reference; sourceTree = "<group>"; };
5BAE2034208E163B006BF277 /* roundRect.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = roundRect.reference; sourceTree = "<group>"; };
5BAE2035208E163C006BF277 /* clip.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = clip.reference; sourceTree = "<group>"; };
5BAE2057208F24DE006BF277 /* SceneSerialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneSerialization.swift; sourceTree = "<group>"; };
5BAE205B208F2504006BF277 /* color-prop-02-f-manual.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "color-prop-02-f-manual.svg"; sourceTree = "<group>"; };
5BAE205C208F2504006BF277 /* shapes-circle-01-t-manual.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "shapes-circle-01-t-manual.svg"; sourceTree = "<group>"; };
5BAE205D208F2504006BF277 /* shapes-circle-01-t-manual.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "shapes-circle-01-t-manual.reference"; sourceTree = "<group>"; };
5BAE2060208F2504006BF277 /* color-prop-02-f-manual.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "color-prop-02-f-manual.reference"; sourceTree = "<group>"; };
5BAEA9C8206CEAA20049AAAE /* viewBox.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = viewBox.svg; sourceTree = "<group>"; };
5BAEA9CA206CEB7D0049AAAE /* viewBox.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = viewBox.reference; sourceTree = "<group>"; };
A718CD431F45C28200966E06 /* Common_iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Common_iOS.swift; path = Source/platform/iOS/Common_iOS.swift; sourceTree = SOURCE_ROOT; };
A718CD451F45C28700966E06 /* Graphics_iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Graphics_iOS.swift; path = Source/platform/iOS/Graphics_iOS.swift; sourceTree = SOURCE_ROOT; };
A718CD461F45C28700966E06 /* MView_iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MView_iOS.swift; path = Source/platform/iOS/MView_iOS.swift; sourceTree = SOURCE_ROOT; };
@ -471,13 +505,6 @@
C4153A8E1F8793DD001BA5EE /* small-logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "small-logo.png"; sourceTree = "<group>"; };
C43B064C1F9738EF00787A35 /* clip.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = clip.svg; sourceTree = "<group>"; };
C43B06501F9866E400787A35 /* Locus+ToPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Locus+ToPath.swift"; sourceTree = "<group>"; };
C43B06521F989D9300787A35 /* transform.reference */ = {isa = PBXFileReference; lastKnownFileType = text; path = transform.reference; sourceTree = "<group>"; };
C43B06541F98A53600787A35 /* group.reference */ = {isa = PBXFileReference; lastKnownFileType = text; path = group.reference; sourceTree = "<group>"; };
C43B06561F98A7B700787A35 /* arcsgroup.reference */ = {isa = PBXFileReference; lastKnownFileType = text; path = arcsgroup.reference; sourceTree = "<group>"; };
C43B06581F98A84200787A35 /* style.reference */ = {isa = PBXFileReference; lastKnownFileType = text; path = style.reference; sourceTree = "<group>"; };
C43B065A1F98A9E000787A35 /* clipManual.reference */ = {isa = PBXFileReference; lastKnownFileType = text; path = clipManual.reference; sourceTree = "<group>"; };
C43B065E1F98AAA500787A35 /* clip.reference */ = {isa = PBXFileReference; lastKnownFileType = text; path = clip.reference; sourceTree = "<group>"; };
C43B06601F98ACFC00787A35 /* textBasicTransform.reference */ = {isa = PBXFileReference; lastKnownFileType = text; path = textBasicTransform.reference; sourceTree = "<group>"; };
C43B06621F99A33400787A35 /* pathbounds3.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = pathbounds3.svg; path = Bounds/pathbounds3.svg; sourceTree = "<group>"; };
C43B06641F99EE7200787A35 /* cubicAbsolute.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = cubicAbsolute.svg; path = Bounds/cubicAbsolute.svg; sourceTree = "<group>"; };
C43B06651F99EE7300787A35 /* cubicRelative.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = cubicRelative.svg; path = Bounds/cubicRelative.svg; sourceTree = "<group>"; };
@ -565,29 +592,36 @@
57CAB1241D7832E000FD8E47 /* svg */ = {
isa = PBXGroup;
children = (
602C561C2081C984003AD452 /* rounded.svg */,
5BAEA9C8206CEAA20049AAAE /* viewBox.svg */,
C46E83541F94B20E00208037 /* transform.svg */,
C43B064C1F9738EF00787A35 /* clip.svg */,
C4153A8E1F8793DD001BA5EE /* small-logo.png */,
C410148D1F834D280022EE44 /* style.svg */,
5BAE202F208E163A006BF277 /* arcsgroup.reference */,
5BAE2028208E1637006BF277 /* circle.reference */,
57CAB1251D7832E000FD8E47 /* circle.svg */,
5BAE2035208E163C006BF277 /* clip.reference */,
C43B064C1F9738EF00787A35 /* clip.svg */,
5BAE2027208E1637006BF277 /* clipManual.reference */,
5BAE202A208E1638006BF277 /* ellipse.reference */,
57CAB1261D7832E000FD8E47 /* ellipse.svg */,
5BAE202C208E1638006BF277 /* group.reference */,
57CAB1271D7832E000FD8E47 /* group.svg */,
5BAE2032208E163B006BF277 /* line.reference */,
57CAB1281D7832E000FD8E47 /* line.svg */,
5BAE2023208E1637006BF277 /* polygon.reference */,
57CAB1291D7832E000FD8E47 /* polygon.svg */,
5BAE2022208E1637006BF277 /* polyline.reference */,
57CAB12A1D7832E000FD8E47 /* polyline.svg */,
5BAE2024208E1637006BF277 /* rect.reference */,
57CAB12B1D7832E000FD8E47 /* rect.svg */,
5BAE2034208E163B006BF277 /* roundRect.reference */,
57CAB12C1D7832E000FD8E47 /* roundRect.svg */,
C4153A8E1F8793DD001BA5EE /* small-logo.png */,
5BAE202E208E1639006BF277 /* style.reference */,
C410148D1F834D280022EE44 /* style.svg */,
5BAE202D208E1638006BF277 /* textBasicTransform.reference */,
5BAE2029208E1638006BF277 /* transform.reference */,
C46E83541F94B20E00208037 /* transform.svg */,
5BAE2026208E1637006BF277 /* triangle.reference */,
57CAB12D1D7832E000FD8E47 /* triangle.svg */,
5BAEA9CA206CEB7D0049AAAE /* viewBox.reference */,
C43B06521F989D9300787A35 /* transform.reference */,
C43B06541F98A53600787A35 /* group.reference */,
C43B06561F98A7B700787A35 /* arcsgroup.reference */,
C43B06581F98A84200787A35 /* style.reference */,
C43B065A1F98A9E000787A35 /* clipManual.reference */,
C43B065E1F98AAA500787A35 /* clip.reference */,
C43B06601F98ACFC00787A35 /* textBasicTransform.reference */,
5BAE2031208E163B006BF277 /* viewBox.reference */,
5BAEA9C8206CEAA20049AAAE /* viewBox.svg */,
);
path = svg;
sourceTree = "<group>";
@ -803,6 +837,7 @@
57E5E1451E3B393900D1CB28 /* svg */ = {
isa = PBXGroup;
children = (
5BAE201E208E1211006BF277 /* SVGCanvas.swift */,
57E5E1461E3B393900D1CB28 /* SVGConstants.swift */,
57E5E1471E3B393900D1CB28 /* SVGParser.swift */,
57E5E1481E3B393900D1CB28 /* SVGParserError.swift */,
@ -871,14 +906,27 @@
A7E675541EC4211E00BD9ECB /* Bounds */,
5713C4F11E5AD35900BBA4D9 /* Animation */,
57CAB1241D7832E000FD8E47 /* svg */,
5BAE205A208F2504006BF277 /* w3cSVGTests */,
57CAB1221D782DFC00FD8E47 /* TestUtils.swift */,
57FCD27B1D76EA4600CC0FB6 /* MacawTests.swift */,
C4820B191F458D64008CE0FF /* MacawSVGTests.swift */,
5BAE2057208F24DE006BF277 /* SceneSerialization.swift */,
57FCD27D1D76EA4600CC0FB6 /* Info.plist */,
);
path = MacawTests;
sourceTree = "<group>";
};
5BAE205A208F2504006BF277 /* w3cSVGTests */ = {
isa = PBXGroup;
children = (
5BAE2060208F2504006BF277 /* color-prop-02-f-manual.reference */,
5BAE205B208F2504006BF277 /* color-prop-02-f-manual.svg */,
5BAE205D208F2504006BF277 /* shapes-circle-01-t-manual.reference */,
5BAE205C208F2504006BF277 /* shapes-circle-01-t-manual.svg */,
);
path = w3cSVGTests;
sourceTree = "<group>";
};
A718CD2C1F45BC5300966E06 /* Platform */ = {
isa = PBXGroup;
children = (
@ -1067,39 +1115,50 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5BAE203C208E163D006BF277 /* triangle.reference in Resources */,
C4153A8F1F8793DE001BA5EE /* small-logo.png in Resources */,
5BAE2061208F2504006BF277 /* color-prop-02-f-manual.svg in Resources */,
5BAE2048208E163D006BF277 /* line.reference in Resources */,
57CAB1361D7832E000FD8E47 /* triangle.svg in Resources */,
C43B06691F99FC2300787A35 /* pathbounds4.svg in Resources */,
C43B06631F99A33400787A35 /* pathbounds3.svg in Resources */,
5BAEA9C9206CEAA20049AAAE /* viewBox.svg in Resources */,
5BAE204B208E163D006BF277 /* clip.reference in Resources */,
C43B064D1F9738EF00787A35 /* clip.svg in Resources */,
5BAE2040208E163D006BF277 /* ellipse.reference in Resources */,
57B7A4E11EE70DA5009D78D7 /* logo_base64.txt in Resources */,
5BAE2047208E163D006BF277 /* viewBox.reference in Resources */,
5BAE2042208E163D006BF277 /* group.reference in Resources */,
C43B06671F99EE7300787A35 /* cubicRelative.svg in Resources */,
C43B06571F98A7B700787A35 /* arcsgroup.reference in Resources */,
C43B06531F989D9300787A35 /* transform.reference in Resources */,
C43B06611F98ACFC00787A35 /* textBasicTransform.reference in Resources */,
5BAE204A208E163D006BF277 /* roundRect.reference in Resources */,
5BAE203E208E163D006BF277 /* circle.reference in Resources */,
C43B064D1F9738EF00787A35 /* clip.svg in Resources */,
57B7A4E11EE70DA5009D78D7 /* logo_base64.txt in Resources */,
C43B06591F98A84200787A35 /* style.reference in Resources */,
C43B065F1F98AAA500787A35 /* clip.reference in Resources */,
C410148E1F834D290022EE44 /* style.svg in Resources */,
5BAE2063208F2504006BF277 /* shapes-circle-01-t-manual.reference in Resources */,
C4BD40BB1F8F58B0003034F0 /* pathbounds1.svg in Resources */,
C43B065B1F98A9E000787A35 /* clipManual.reference in Resources */,
C4BD40BC1F8F58B0003034F0 /* pathbounds2.svg in Resources */,
5BAE2039208E163D006BF277 /* polygon.reference in Resources */,
5BAE2043208E163D006BF277 /* textBasicTransform.reference in Resources */,
57CAB1301D7832E000FD8E47 /* group.svg in Resources */,
5BAE2045208E163D006BF277 /* arcsgroup.reference in Resources */,
5BAE2062208F2504006BF277 /* shapes-circle-01-t-manual.svg in Resources */,
5BAE203F208E163D006BF277 /* transform.reference in Resources */,
5BAE2038208E163D006BF277 /* polyline.reference in Resources */,
C43B06661F99EE7300787A35 /* cubicAbsolute.svg in Resources */,
C46E83551F94B20E00208037 /* transform.svg in Resources */,
57CAB1351D7832E000FD8E47 /* roundRect.svg in Resources */,
5BAE203D208E163D006BF277 /* clipManual.reference in Resources */,
57CAB12E1D7832E000FD8E47 /* circle.svg in Resources */,
5BAE2066208F2504006BF277 /* color-prop-02-f-manual.reference in Resources */,
57CAB1331D7832E000FD8E47 /* polyline.svg in Resources */,
5BAEA9CB206CEB7D0049AAAE /* viewBox.reference in Resources */,
57CAB1311D7832E000FD8E47 /* line.svg in Resources */,
57B7A4DF1EE70D17009D78D7 /* logo.png in Resources */,
602C561D2081C984003AD452 /* rounded.svg in Resources */,
57CAB1321D7832E000FD8E47 /* polygon.svg in Resources */,
5BAE203A208E163D006BF277 /* rect.reference in Resources */,
5BAE2044208E163D006BF277 /* style.reference in Resources */,
57CAB12F1D7832E000FD8E47 /* ellipse.svg in Resources */,
57CAB1341D7832E000FD8E47 /* rect.svg in Resources */,
C43B06551F98A53600787A35 /* group.reference in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1177,6 +1236,7 @@
57614B1E1F83D15600875933 /* AnimOperators.swift in Sources */,
57614B1F1F83D15600875933 /* Circle.swift in Sources */,
57614B201F83D15600875933 /* Color.swift in Sources */,
5BAE204C208E1EF4006BF277 /* SVGCanvas.swift in Sources */,
57614B211F83D15600875933 /* PathSegment.swift in Sources */,
57614B221F83D15600875933 /* ImageRenderer.swift in Sources */,
57614B231F83D15600875933 /* PathFunctions.swift in Sources */,
@ -1303,6 +1363,7 @@
57E5E18C1E3B393900D1CB28 /* Circle.swift in Sources */,
57E5E17D1E3B393900D1CB28 /* Color.swift in Sources */,
57E5E1951E3B393900D1CB28 /* PathSegment.swift in Sources */,
5BAE201F208E1211006BF277 /* SVGCanvas.swift in Sources */,
57E5E1A41E3B393900D1CB28 /* ImageRenderer.swift in Sources */,
57E5E1621E3B393900D1CB28 /* PathFunctions.swift in Sources */,
C4820B181F458D0E008CE0FF /* SVGSerializer.swift in Sources */,
@ -1402,6 +1463,7 @@
C4BD40B81F8F55AB003034F0 /* SVGBoundsTest.swift in Sources */,
5713C4F51E5AE2C300BBA4D9 /* CombineAnimationTests.swift in Sources */,
57CAB1231D782DFC00FD8E47 /* TestUtils.swift in Sources */,
5BAE2058208F24DE006BF277 /* SceneSerialization.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- correct bounds
<rect x="33.66" y="9.5" width="16.84" height="41.0" stroke="red" stroke-width="1" fill="none"/>

Before

Width:  |  Height:  |  Size: 367 B

After

Width:  |  Height:  |  Size: 342 B

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- correct bounds
<rect x="49.5" y="49.5" width="51.0" height="17.57" stroke="red" stroke-width="1" fill="none"/>

Before

Width:  |  Height:  |  Size: 367 B

After

Width:  |  Height:  |  Size: 342 B

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="200" height="200">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- correct bounds
<rect x="101.4" y="36.7" width="7.6" height="35.0" fill="none" stroke="red" />

Before

Width:  |  Height:  |  Size: 427 B

After

Width:  |  Height:  |  Size: 390 B

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0"
width="200" height="200">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- correct bounds
<rect x="36.7" y="101.4" width="35.1" height="7.6" fill="none" stroke="red" />
-->

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 386 B

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- correct bounds
<rect x="0.0" y="0.0" width="50.0" height="50.0" stroke="red" stroke-width="1" fill="none"/>

Before

Width:  |  Height:  |  Size: 739 B

After

Width:  |  Height:  |  Size: 714 B

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- correct bounds
<rect x="9.5" y="27.0" width="171.0" height="106.0" stroke="red" stroke-width="1" fill="none"/>

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 360 B

View File

@ -19,7 +19,8 @@ class MacawSVGTests: XCTestCase {
do {
if let path = bundle.path(forResource: referenceFile, ofType: "reference") {
let clipReferenceContent = try String.init(contentsOfFile: path).trimmingCharacters(in: .newlines)
XCTAssertEqual(SVGSerializer.serialize(node: node), clipReferenceContent)
let result = SVGSerializer.serialize(node: node)
XCTAssertEqual(result, clipReferenceContent)
}
} catch {
print(error)
@ -27,22 +28,25 @@ class MacawSVGTests: XCTestCase {
}
}
func validate(_ test: String, withReference: Bool = false) {
func validate(_ test: String) {
let bundle = Bundle(for: type(of: TestUtils()))
var ext = "svg"
if withReference {
ext = "reference"
}
do {
if let path = bundle.path(forResource: test, ofType: ext) {
let referenceContent = try String.init(contentsOfFile: path).trimmingCharacters(in: .newlines)
let node = try SVGParser.parse(bundle:bundle, path: test)
let testContent = SVGSerializer.serialize(node: node)
.replacingOccurrences(of: "version=\"1.1\" ><g>", with: "version=\"1.1\" >")
.replacingOccurrences(of: "defs><g>", with: "defs>")
.replacingOccurrences(of: "</g></svg>", with: "</svg>")
XCTAssertEqual(testContent, referenceContent)
}
let node = try SVGParser.parse(bundle: bundle, path: test)
validate(node: node, referenceFile: test)
} catch {
print(error)
XCTFail()
}
}
func create(_ test: String) {
let bundle = Bundle(for: type(of: TestUtils()))
do {
let path = bundle.path(forResource: test, ofType: "svg")?.replacingOccurrences(of: ".svg", with: ".reference")
let node = try SVGParser.parse(bundle: bundle, path: test)
let result = SVGSerializer.serialize(node: node)
try result.write(to: URL(fileURLWithPath: path!), atomically: true, encoding: String.Encoding.utf8)
} catch {
print(error)
XCTFail()
@ -99,19 +103,19 @@ class MacawSVGTests: XCTestCase {
}
func testViewBox() {
validate("viewBox", withReference: true)
validate("viewBox")
}
func testClipWithParser() {
validate("clip", withReference: true)
validate("clip")
}
func testCSSStyleReference() {
validate("style", withReference: true)
validate("style")
}
func testSVGTransformSkew() {
validate("transform", withReference: true)
validate("transform")
}
func testSVGEllipse() {
@ -123,7 +127,7 @@ class MacawSVGTests: XCTestCase {
}
func testSVGGroup() {
validate("group", withReference: true)
validate("group")
}
func testSVGLine() {
@ -149,4 +153,55 @@ class MacawSVGTests: XCTestCase {
func testSVGTriangle() {
validate("triangle")
}
func validateJSON(node: Node, referenceFile: String) {
let bundle = Bundle(for: type(of: TestUtils()))
do {
if let path = bundle.path(forResource: referenceFile, ofType: "reference"), let node = node as? Serializable {
let referenceContent = try String(contentsOfFile: path)
let jsonData = try JSONSerialization.data(withJSONObject: node.toDictionary(), options: .prettyPrinted)
let nodeContent = String(data: jsonData, encoding: String.Encoding.utf8)
XCTAssertEqual(nodeContent, referenceContent)
}
} catch {
XCTFail(error.localizedDescription)
}
}
func validateJSON(_ test: String) {
let bundle = Bundle(for: type(of: TestUtils()))
do {
let node = try SVGParser.parse(bundle: bundle, path: test)
validateJSON(node: node, referenceFile: test)
} catch {
XCTFail(error.localizedDescription)
}
}
func createJSON(_ test: String) {
let bundle = Bundle(for: type(of: TestUtils()))
do {
let path = bundle.path(forResource: test, ofType: "svg")?.replacingOccurrences(of: ".svg", with: ".reference")
let node = try SVGParser.parse(bundle: bundle, path: test)
guard let serializableNode = node as? Serializable else {
XCTFail()
return
}
let jsonData = try JSONSerialization.data(withJSONObject: serializableNode.toDictionary(), options: .prettyPrinted)
try jsonData.write(to: URL(fileURLWithPath: path!))
} catch {
XCTFail(error.localizedDescription)
}
}
func testColorProp02() {
validateJSON("color-prop-02-f-manual")
}
func testShapesCircle01() {
validateJSON("shapes-circle-01-t-manual")
}
}

View File

@ -0,0 +1,462 @@
//
// SceneSerialization.swift
// MacawTests
//
// Created by Alisa Mylnikova on 23/04/2018.
// Copyright © 2018 Exyte. All rights reserved.
//
import UIKit
import Macaw
protocol Initializable {
init()
}
extension Double : Initializable {}
extension Bool : Initializable {}
extension Int : Initializable {}
func parse<T: Initializable>(_ from: Any?) -> T {
return from as? T ?? T()
}
protocol Serializable {
func toDictionary() -> [String:Any]
}
class NodeSerializer {
var factories = [String:([String:Any]) -> Node]()
let locusSerializer = LocusSerializer()
init() {
factories["Shape"] = { dictionary in
let locusDict = dictionary["form"] as! [String:Any]
let locus = self.locusSerializer.instance(dictionary: locusDict)
let shape = Shape(form: locus)
if let fillDict = dictionary["fill"] as? [String:Any], let fillType = fillDict["type"] as? String, fillType == "Color" {
shape.fill = Color(dictionary: fillDict)
}
if let strokeDict = dictionary["stroke"] as? [String:Any] {
shape.stroke = Stroke(dictionary: strokeDict)
}
return shape
}
factories["Text"] = { dictionary in
let textString = dictionary["text"] as! String
let text = Text(text: textString)
if let fontDict = dictionary["font"] as? [String:Any] {
text.font = Font(dictionary: fontDict)
}
if let fillDict = dictionary["fill"] as? [String:Any],
let fillType = fillDict["type"] as? String,
fillType == "Color",
let color = Color(dictionary: fillDict) {
text.fill = color
}
if let strokeDict = dictionary["stroke"] as? [String:Any] {
text.stroke = Stroke(dictionary: strokeDict)
}
if let alignString = dictionary["align"] as? String {
text.align = Align.instantiate(string: alignString)
}
if let baselineString = dictionary["baseline"] as? String {
text.baseline = baselineForString(baselineString)
}
return text
}
factories["Group"] = { dictionary in
let contents = dictionary["contents"] as! [[String:Any]]
var nodes = [Node]()
for dict in contents {
nodes.append(self.instance(dictionary: dict))
}
return Group(contents: nodes)
}
}
func instance(dictionary: [String:Any]) -> Node {
let type = dictionary["node"] as! String
let node = factories[type]!(dictionary)
node.place = Transform(string: dictionary["place"] as? String)
node.opaque = Bool(dictionary["opaque"] as? String ?? "") ?? true
node.opacity = Double(dictionary["opacity"] as? String ?? "") ?? 0
if let locusDict = dictionary["clip"] as? [String:Any] {
node.clip = locusSerializer.instance(dictionary: locusDict)
}
return node
}
}
extension Node {
func baseToDictionary() -> [String:Any] {
var result = ["place": place.toString(), "opaque": String(describing: opaque), "opacity": String(describing: opacity)] as [String : Any]
if let clip = clip as? Serializable {
result["clip"] = clip.toDictionary()
}
return result
}
}
extension Shape: Serializable {
func toDictionary() -> [String:Any] {
var result = super.baseToDictionary()
result["node"] = "Shape"
if let form = form as? Serializable {
result["form"] = form.toDictionary()
}
if let fillColor = fill as? Color {
result["fill"] = fillColor.toDictionary()
}
if let stroke = stroke {
result["stroke"] = stroke.toDictionary()
}
return result
}
}
extension Text: Serializable {
func toDictionary() -> [String:Any] {
var result = super.baseToDictionary()
result["node"] = "Text"
result["text"] = text
if let font = font {
result["font"] = font.toDictionary()
}
if let fillColor = fill as? Color {
result["fill"] = fillColor.toDictionary()
}
if let stroke = stroke {
result["stroke"] = stroke.toDictionary()
}
result["align"] = align.toString()
result["baseline"] = "\(baseline)"
return result
}
}
extension Group: Serializable {
func toDictionary() -> [String:Any] {
var nodes = [[String:Any]]()
for node in contents {
if let node = node as? Serializable {
nodes.append(node.toDictionary())
}
}
var result = super.baseToDictionary()
result["node"] = "Group"
result["contents"] = nodes
return result
}
}
class LocusSerializer {
var factories = [String:([String:Any]) -> Locus]()
init() {
factories["Arc"] = { dictionary in
Arc(ellipse: self.instance(dictionary: dictionary["Ellipse"] as! [String:Any]) as! Ellipse,
shift: parse(dictionary["shift"]),
extent: parse(dictionary["extent"]))
}
factories["Circle"] = { dictionary in
Circle(cx: parse(dictionary["cx"]),
cy: parse(dictionary["cy"]),
r: parse(dictionary["r"]))
}
factories["Ellipse"] = { dictionary in
Ellipse(cx: parse(dictionary["cx"]),
cy: parse(dictionary["cy"]),
rx: parse(dictionary["rx"]),
ry: parse(dictionary["rx"]))
}
factories["Line"] = { dictionary in
Line(x1: parse(dictionary["x1"]),
y1: parse(dictionary["y1"]),
x2: parse(dictionary["x2"]),
y2: parse(dictionary["y2"]))
}
factories["Path"] = { dictionary in
let array = dictionary["segments"] as! [[String:Any]]
var pathSegments = [PathSegment]()
for dict in array {
pathSegments.append(PathSegment(
type: typeForString(dict["type"] as! String),
data: dict["data"] as! [Double]))
}
return Path(segments: pathSegments)
}
factories["Polygon"] = { dictionary in
Polygon.init(points: dictionary["points"] as! [Double])
}
factories["Polyline"] = { dictionary in
Polyline.init(points: dictionary["points"] as! [Double])
}
factories["Rect"] = { dictionary in
Rect(x: parse(dictionary["x"]),
y: parse(dictionary["y"]),
w: parse(dictionary["w"]),
h: parse(dictionary["h"]))
}
factories["RoundRect"] = { dictionary in
RoundRect(rect: self.instance(dictionary: dictionary["Rect"] as! [String:Any]) as! Rect,
rx: parse(dictionary["rx"]),
ry: parse(dictionary["ry"]))
}
}
func instance(dictionary: [String:Any]) -> Locus {
let type = dictionary["type"] as! String
return factories[type]!(dictionary)
}
}
extension Arc: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Arc", "ellipse": ellipse.toDictionary(), "shift": shift, "extent": extent]
}
}
extension Circle: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Circle", "cx": cx, "cy": cy, "r": r]
}
}
extension Ellipse: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Ellipse", "cx": cx, "cy": cy, "rx": rx, "ry": ry]
}
}
extension Line: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Line", "x1": x1, "y1": y1, "x2": x2, "y2": y2]
}
}
extension Path: Serializable {
func toDictionary() -> [String:Any] {
var pathSegments = [[String:Any]]()
for segment in segments {
pathSegments.append(segment.toDictionary())
}
return ["type": "Path", "segments": pathSegments]
}
}
extension Polygon: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Polygon", "points": points]
}
}
extension Polyline: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Polyline", "points": points]
}
}
extension Rect: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Rect", "x": x, "y": y, "w": w, "h": h]
}
}
extension RoundRect: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "RoundRect", "rect": rect.toDictionary(), "rx": rx, "ry": ry]
}
}
extension PathSegment: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "\(type)", "data": data]
}
}
extension Color: Serializable {
func toDictionary() -> [String:Any] {
return ["type": "Color", "val": val]
}
convenience init?(dictionary: [String:Any]) {
self.init(val: dictionary["val"] as! Int)
}
}
extension Stroke: Serializable {
func toDictionary() -> [String:Any] {
var result = ["width": width, "cap": "\(cap)", "join": "\(join)", "dashes": dashes] as [String : Any]
if let fillColor = fill as? Color {
result["fill"] = fillColor.toDictionary()
}
return result
}
convenience init?(dictionary: [String:Any]) {
guard let fillDict = dictionary["fill"] as? [String:Any], let fillType = fillDict["type"] as? String, fillType == "Color", let fill = Color(dictionary: fillDict) else {
return nil
}
var cap = LineCap.butt
if let lineCapString = dictionary["cap"] as? String {
cap = lineCapForString(lineCapString)
}
var join = LineJoin.miter
if let lineJoinString = dictionary["join"] as? String {
join = lineJoinForString(lineJoinString)
}
let dashes = dictionary["dashes"] as? [Double] ?? []
self.init(fill: fill, width: parse(dictionary["width"]), cap: cap, join: join, dashes: dashes)
}
}
extension Font: Serializable {
func toDictionary() -> [String:Any] {
return ["name": name, "size": size, "weight": weight]
}
convenience init(dictionary: [String:Any]) {
self.init(name: dictionary["name"] as? String ?? "Serif",
size: parse(dictionary["size"]),
weight: dictionary["weight"] as? String ?? "normal")
}
}
extension Transform {
func toString() -> String {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 6
let nums = [m11, m12, m21, m22, dx, dy]
var result = ""
for num in nums {
result += formatter.string(from: num as NSNumber) ?? "n/a"
result += ", "
}
return result.dropLast(2) + ""
}
convenience init(string: String?) {
guard let string = string else {
self.init()
return
}
let vals = string.components(separatedBy: ", ").map{ Double($0) ?? 0 }
if vals.count == 6 {
self.init(m11: vals[0], m12: vals[1], m21: vals[2], m22: vals[3], dx: vals[4], dy: vals[5])
} else {
self.init()
}
}
}
extension Align {
func toString() -> String {
if self === Align.mid {
return "mid"
}
if self === Align.max {
return "max"
}
return "min"
}
static func instantiate(string: String) -> Align {
switch string {
case "mid":
return .mid
case "max":
return .max
default:
return .min
}
}
}
fileprivate func typeForString(_ string: String) -> PathSegmentType {
switch(string) {
case "M": return .M
case "m": return .m
case "L": return .L
case "l": return .l
case "C": return .C
case "c": return .c
case "Q": return .Q
case "q": return .q
case "A": return .A
case "a": return .a
case "z", "Z": return .z
case "H": return .H
case "h": return .h
case "V": return .V
case "v": return .v
case "S": return .S
case "s": return .s
case "T": return .T
case "t": return .t
default: return .M
}
}
fileprivate func lineCapForString(_ string: String) -> LineCap {
switch(string) {
case "butt": return .butt
case "round": return .round
case "square": return .square
default: return .butt
}
}
fileprivate func lineJoinForString(_ string: String) -> LineJoin {
switch(string) {
case "miter": return .miter
case "round": return .round
case "bevel": return .bevel
default: return .miter
}
}
fileprivate func baselineForString(_ string: String) -> Baseline {
switch(string) {
case "top": return .top
case "alphabetic": return .alphabetic
case "bottom": return .bottom
case "mid": return .mid
default: return .top
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><circle r="40" cy="50" cx="50" fill="red" stroke="black" stroke-width="3.0"/><circle r="40" cy="50" cx="140" fill="#F0F0AA" stroke="black" stroke-width="3.0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 282 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><defs><clipPath id="clipPath1"><path d="M 20 0m -20 0a 20 20 0 1 0 40 0a 20 20 0 1 0 -40 0M 0 10L 0 45L 100 45L 100 10z M 0 55L 0 90L 100 90L 100 55z " /></clipPath></defs><circle r="50" cy="50" cx="50" clip-path="url(#clipPath1)" fill="black"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><defs><clipPath id="clipPath1"><path d="M 20 0m -20 0a 20 20 0 1 0 40 0a 20 20 0 1 0 -40 0M 0 10L 0 45L 100 45L 100 10z M 0 55L 0 90L 100 90L 100 55z " /></clipPath></defs><g><circle r="50" cy="50" cx="50" clip-path="url(#clipPath1)" fill="black"/></g></svg>

Before

Width:  |  Height:  |  Size: 355 B

After

Width:  |  Height:  |  Size: 361 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><g><ellipse cy="80" ry="50" rx="100" cx="200" fill="yellow" stroke="purple" stroke-width="2.0"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 221 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><path d="M 150 0L 75 200L 225 200z " fill="black" stroke="black" stroke-width="2.0"/><line y1="0" x2="200" x1="0" y2="200" fill="black" stroke="white" stroke-width="2.0"/></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><path d="M 150 0L 75 200L 225 200z " fill="black" stroke="black" stroke-width="2.0"/><line y1="0" x2="200" x1="0" y2="200" fill="black" stroke="white" stroke-width="2.0"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 288 B

After

Width:  |  Height:  |  Size: 295 B

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="group" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="210" width="400">
<svg version="1.1" id="group" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g style="stroke:#000000;stroke-width:2">
<path d="M 150 0 L 75 200 L 225 200 Z" />
<line x1="0" y1="0" x2="200" y2="200" stroke="#ffffff"/>

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 307 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><line y1="0" x2="200" x1="0" y2="200" fill="black" stroke="red" stroke-width="2.0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 205 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><polygon points="200.0,10.0,250.0,190.0,160.0,210.0" fill="black"/></g></g></svg>

After

Width:  |  Height:  |  Size: 188 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><polyline points="0.0,40.0,40.0,40.0,40.0,80.0,80.0,80.0,80.0,120.0,120.0,120.0,120.0,160.0" fill="white" stroke="red" stroke-width="4.0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 260 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><rect height="150" x="50" y="0" width="150" fill="black"/></g></g></svg>

After

Width:  |  Height:  |  Size: 179 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><rect height="150" ry="20" rx="20" width="150" fill="black"/></g></g></svg>

After

Width:  |  Height:  |  Size: 182 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><circle r="10" cy="50" cx="50" fill="white" stroke="#231F20" stroke-width="1.5"/><circle r="10" cy="50" cx="80" fill="black"/></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><circle r="10" cy="50" cx="50" fill="white" stroke="#231F20" stroke-width="1.5"/><circle r="10" cy="50" cx="80" fill="black"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 249 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g transform="matrix(2.0,1.0,1.0,1.0,0.0,0.0)" ><rect height="5" x="0" y="0" width="150" fill="blue"/><rect height="50" x="0" y="0" width="5" fill="red"/><rect height="50" x="150" y="0" width="5" fill="black"/><rect height="5" x="0" y="50" width="150" fill="black"/><ellipse cy="25" ry="15" rx="40" cx="75" fill="purple"/></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g transform="matrix(2.0,1.0,1.0,1.0,0.0,0.0)" ><rect height="5" x="0" y="0" width="150" fill="blue"/><rect height="50" x="0" y="0" width="5" fill="red"/><rect height="50" x="150" y="0" width="5" fill="black"/><rect height="5" x="0" y="50" width="150" fill="black"/><ellipse cy="25" ry="15" rx="40" cx="75" fill="purple"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 448 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><g><g><path d="M 150 0L 75 200L 225 200z " fill="black" stroke="black" stroke-width="2.0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 206 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><defs><clipPath id="clipPath1"><rect height="400" x="100" y="50" width="400" /></clipPath></defs><g clip-path="url(#clipPath1)" transform="matrix(0.444444444444444,0.0,0.0,0.444444444444444,-5.55555555555554,-22.2222222222222)" ><g><g><ellipse cy="80" ry="50" rx="100" cx="200" fill="yellow" stroke="purple" stroke-width="2.0"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ><defs><clipPath id="clipPath1"><rect height="400" x="100" y="50" width="400" /></clipPath></defs><g clip-path="url(#clipPath1)" transform="matrix(0.444444444444444,0.0,0.0,0.444444444444444,-5.55555555555554,-22.2222222222222)" ><g><g><ellipse cy="80" ry="50" rx="100" cx="200" fill="yellow" stroke="purple" stroke-width="2.0"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 446 B

After

Width:  |  Height:  |  Size: 449 B

View File

@ -0,0 +1,14 @@
## W3C SVG Test Suite Coverage
Total: 6
Passed: 33%
|Name |Status |
|------|-------|
|[color-prop-01-b-manual](w3cSVGTests/color-prop-01-b-manual.svg) | ❌ |
|[color-prop-02-f-manual](w3cSVGTests/color-prop-02-f-manual.svg) | ✅ |
|[color-prop-03-t-manual](w3cSVGTests/color-prop-03-t-manual.svg) | [#123](https://github.com/exyte/Macaw/issues/123) |
|[color-prop-04-t-manual](w3cSVGTests/color-prop-04-t-manual.svg) | [#42](https://github.com/exyte/Macaw/issues/42) |
|[color-prop-05-t-manual](w3cSVGTests/color-prop-05-t-manual.svg) | ❌ |
|[shapes-circle-01-t-manual](w3cSVGTests/shapes-circle-01-t-manual.svg) | ✅ |

View File

@ -0,0 +1,722 @@
{
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 40,
"type" : "Circle",
"r" : 20,
"cx" : 75
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 14423100
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 40,
"type" : "Circle",
"r" : 20,
"cx" : 115
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 14423100
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 80,
"type" : "Circle",
"r" : 20,
"cx" : 75
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 14423100
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 80,
"type" : "Circle",
"r" : 20,
"cx" : 115
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 14423100
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 40,
"type" : "Circle",
"r" : 20,
"cx" : 200
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 10025880
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 40,
"type" : "Circle",
"r" : 20,
"cx" : 240
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 10025880
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 80,
"type" : "Circle",
"r" : 20,
"cx" : 200
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 10025880
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 80,
"type" : "Circle",
"r" : 20,
"cx" : 240
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 10025880
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 40,
"type" : "Circle",
"r" : 20,
"cx" : 325
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4286945
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 40,
"type" : "Circle",
"r" : 20,
"cx" : 365
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4286945
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 80,
"type" : "Circle",
"r" : 20,
"cx" : 325
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4286945
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 80,
"type" : "Circle",
"r" : 20,
"cx" : 365
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4286945
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 135,
"type" : "Circle",
"r" : 20,
"cx" : 75
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 11674146
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 135,
"type" : "Circle",
"r" : 20,
"cx" : 115
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 11674146
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 175,
"type" : "Circle",
"r" : 20,
"cx" : 75
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 11674146
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 175,
"type" : "Circle",
"r" : 20,
"cx" : 115
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 11674146
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 135,
"type" : "Circle",
"r" : 20,
"cx" : 200
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 3050327
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 135,
"type" : "Circle",
"r" : 20,
"cx" : 240
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 3050327
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 175,
"type" : "Circle",
"r" : 20,
"cx" : 200
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 3050327
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 175,
"type" : "Circle",
"r" : 20,
"cx" : 240
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 3050327
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 135,
"type" : "Circle",
"r" : 20,
"cx" : 325
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 205
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 135,
"type" : "Circle",
"r" : 20,
"cx" : 365
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 205
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 175,
"type" : "Circle",
"r" : 20,
"cx" : 325
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 205
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 175,
"type" : "Circle",
"r" : 20,
"cx" : 365
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 205
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 230,
"type" : "Circle",
"r" : 20,
"cx" : 75
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 13458524
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 230,
"type" : "Circle",
"r" : 20,
"cx" : 115
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 13458524
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 270,
"type" : "Circle",
"r" : 20,
"cx" : 75
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 13458524
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 270,
"type" : "Circle",
"r" : 20,
"cx" : 115
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 13458524
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 230,
"type" : "Circle",
"r" : 20,
"cx" : 200
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 8190976
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 230,
"type" : "Circle",
"r" : 20,
"cx" : 240
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 8190976
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 270,
"type" : "Circle",
"r" : 20,
"cx" : 200
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 8190976
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 270,
"type" : "Circle",
"r" : 20,
"cx" : 240
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 8190976
},
"opacity" : "1.0"
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 230,
"type" : "Circle",
"r" : 20,
"cx" : 325
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4772300
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 230,
"type" : "Circle",
"r" : 20,
"cx" : 365
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4772300
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 270,
"type" : "Circle",
"r" : 20,
"cx" : 325
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4772300
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 270,
"type" : "Circle",
"r" : 20,
"cx" : 365
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 4772300
},
"opacity" : "1.0"
}
]
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"baseline" : "bottom",
"fill" : {
"type" : "Color",
"val" : 0
},
"node" : "Text",
"align" : "min",
"text" : "$Revision: 1.9 $",
"opacity" : "1.0",
"place" : "1, 0, 0, 1, 10, 340",
"opaque" : "true",
"font" : {
"name" : "SVGFreeSansASCII,sans-serif",
"size" : 32,
"weight" : "normal"
}
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"x" : 1,
"w" : 478,
"type" : "Rect",
"y" : 1,
"h" : 358
},
"node" : "Shape",
"opaque" : "true",
"opacity" : "1.0",
"stroke" : {
"join" : "miter",
"cap" : "butt",
"fill" : {
"type" : "Color",
"val" : 0
},
"dashes" : [
],
"width" : 1
}
}
],
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"clip" : {
"x" : 0,
"w" : 480,
"type" : "Rect",
"y" : 0,
"h" : 360
}
}

View File

@ -0,0 +1,113 @@
<svg version="1.1" baseProfile="full" id="svg-root"
width="100%" height="100%" viewBox="0 0 480 360"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!--======================================================================-->
<!--= SVG 1.1 2nd Edition Test Case =-->
<!--======================================================================-->
<!--= Copyright 2009 World Wide Web Consortium, (Massachusetts =-->
<!--= Institute of Technology, European Research Consortium for =-->
<!--= Informatics and Mathematics (ERCIM), Keio University). =-->
<!--= All Rights Reserved. =-->
<!--= See http://www.w3.org/Consortium/Legal/. =-->
<!--======================================================================-->
<d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
template-version="1.4" reviewer="SVGWG" author="Chris Lilley" status="accepted"
version="$Revision: 1.9 $" testname="$RCSfile: color-prop-02-f.svg,v $">
<d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/color.html#ColorProperty">
<p>
Tests if the color datatype is supported. There are multiple syntaxes for
specifying the same color, such as #37F and #3377FF. This test is focussed on the
X11 color names, which are not part of the tiny profile.
Each group of circles uses four forms - 6-digit hex, rbg() integer form, rgb() percentage form,
and named ('X11') colors. It does not use 3-digit hex, because the colors used in this test
cannot be represented in three digit form.
</p>
</d:testDescription>
<d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
<p>
Run the test. No interaction required.
</p>
</d:operatorScript>
<d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
<p>
For each of the nine groups of circles shown here, all circles must
be identical in color, and the same color as in the reference image.
</p>
</d:passCriteria>
</d:SVGTestCase>
<title id="test-title">$RCSfile: color-prop-02-f.svg,v $</title>
<defs>
<font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
<font-face-src>
<font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
</font-face-src>
</font-face>
</defs>
<g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
<!-- groups of five colors -->
<g>
<circle cx="75" cy="40" r="20" fill="crimson"/>
<circle cx="115" cy="40" r="20" fill="#DC143C"/>
<circle cx="75" cy="80" r="20" fill="rgb(220,20,60)"/>
<circle cx="115" cy="80" r="20" fill="rgb(86.274509803921568627450980392157%,7.8431372549019607843137254901961%,23.529411764705882352941176470588%)"/>
</g>
<g>
<circle cx="200" cy="40" r="20" fill="palegreen"/>
<circle cx="240" cy="40" r="20" fill="#98FB98"/>
<circle cx="200" cy="80" r="20" fill="rgb(152, 251, 152)"/>
<circle cx="240" cy="80" r="20" fill="rgb(59.60784313725490196078431372549%,98.431372549019607843137254901961%,59.60784313725490196078431372549%)"/>
</g>
<g>
<circle cx="325" cy="40" r="20" fill="royalblue"/>
<circle cx="365" cy="40" r="20" fill="#4169E1"/>
<circle cx="325" cy="80" r="20" fill="rgb(65, 105, 225)"/>
<circle cx="365" cy="80" r="20" fill="rgb(25.490196078431372549019607843137%,41.176470588235294117647058823529%,88.235294117647058823529411764706%)"/>
</g>
<g>
<circle cx="75" cy="135" r="20" fill="firebrick"/>
<circle cx="115" cy="135" r="20" fill="#B22222"/>
<circle cx="75" cy="175" r="20" fill="rgb(178,34,34)"/>
<circle cx="115" cy="175" r="20" fill="rgb(69.803921568627450980392156862745%,13.333333333333333333333333333333%,13.333333333333333333333333333333%)"/>
</g>
<g>
<circle cx="200" cy="135" r="20" fill="seagreen"/>
<circle cx="240" cy="135" r="20" fill="#2E8B57"/>
<circle cx="200" cy="175" r="20" fill="rgb(46, 139, 87)"/>
<circle cx="240" cy="175" r="20" fill="rgb(18.039215686274509803921568627451%,54.509803921568627450980392156863%,34.117647058823529411764705882353%)"/>
</g>
<g>
<circle cx="325" cy="135" r="20" fill="mediumblue"/>
<circle cx="365" cy="135" r="20" fill="#0000CD"/>
<circle cx="325" cy="175" r="20" fill="rgb(0, 0, 205)"/>
<circle cx="365" cy="175" r="20" fill="rgb(0%,0%,80.39215686274509803921568627451%)"/>
</g>
<g>
<circle cx="75" cy="230" r="20" fill="indianred"/>
<circle cx="115" cy="230" r="20" fill="#CD5C5C"/>
<circle cx="75" cy="270" r="20" fill="rgb(205, 92, 92)"/>
<circle cx="115" cy="270" r="20" fill="rgb(80.39215686274509803921568627451%,36.078431372549019607843137254902%,36.078431372549019607843137254902%)"/>
</g>
<g>
<circle cx="200" cy="230" r="20" fill="lawngreen"/>
<circle cx="240" cy="230" r="20" fill="#7CFC00"/>
<circle cx="200" cy="270" r="20" fill="rgb(124, 252, 0)"/>
<circle cx="240" cy="270" r="20" fill="rgb(48.627450980392156862745098039216%,98.823529411764705882352941176471%,0%)"/>
</g>
<g>
<circle cx="325" cy="230" r="20" fill="mediumturquoise"/>
<circle cx="365" cy="230" r="20" fill="#48D1CC"/>
<circle cx="325" cy="270" r="20" fill="rgb(72, 209, 204)"/>
<circle cx="365" cy="270" r="20" fill="rgb(28.235294117647058823529411764706%,81.960784313725490196078431372549%,80%)"/>
</g>
</g>
<g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
<text id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
</g>
<rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
<!-- comment out this watermark once the test is approved -->
<!--<g id="draft-watermark">
<rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
<text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
</g>-->
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -0,0 +1,222 @@
{
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 100,
"type" : "Circle",
"r" : 50,
"cx" : 100
},
"node" : "Shape",
"opaque" : "true",
"opacity" : "1.0",
"stroke" : {
"join" : "miter",
"cap" : "butt",
"fill" : {
"type" : "Color",
"val" : 0
},
"dashes" : [
],
"width" : 1
}
},
{
"form" : {
"cy" : 100,
"type" : "Circle",
"r" : 35,
"cx" : 220
},
"node" : "Shape",
"fill" : {
"type" : "Color",
"val" : 32768
},
"opacity" : "1.0",
"stroke" : {
"join" : "miter",
"cap" : "butt",
"fill" : {
"type" : "Color",
"val" : 0
},
"dashes" : [
],
"width" : 1
},
"place" : "1, 0, 0, 1, 0, 0",
"opaque" : "true"
},
{
"form" : {
"cy" : 100,
"type" : "Circle",
"r" : 20,
"cx" : 340
},
"node" : "Shape",
"fill" : {
"type" : "Color",
"val" : 0
},
"opacity" : "1.0",
"stroke" : {
"join" : "miter",
"cap" : "butt",
"fill" : {
"type" : "Color",
"val" : 65280
},
"dashes" : [
],
"width" : 4
},
"place" : "1, 0, 0, 1, 0, 0",
"opaque" : "true"
},
{
"form" : {
"cy" : 260,
"type" : "Circle",
"r" : 20,
"cx" : 100
},
"node" : "Shape",
"fill" : {
"type" : "Color",
"val" : 16776960
},
"opacity" : "1.0",
"stroke" : {
"join" : "miter",
"cap" : "butt",
"fill" : {
"type" : "Color",
"val" : 65280
},
"dashes" : [
],
"width" : 4
},
"place" : "1, 0, 0, 1, 0, 0",
"opaque" : "true"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 260,
"type" : "Circle",
"r" : 35,
"cx" : 220
},
"node" : "Shape",
"opaque" : "true",
"fill" : {
"type" : "Color",
"val" : 255
},
"opacity" : "1.0"
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"cy" : 260,
"type" : "Circle",
"r" : 50,
"cx" : 340
},
"node" : "Shape",
"opaque" : "true",
"opacity" : "1.0",
"stroke" : {
"join" : "miter",
"cap" : "butt",
"fill" : {
"type" : "Color",
"val" : 32768
},
"dashes" : [
],
"width" : 10
}
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"contents" : [
{
"baseline" : "bottom",
"fill" : {
"type" : "Color",
"val" : 0
},
"node" : "Text",
"align" : "min",
"text" : "$Revision: 1.7 $",
"opacity" : "1.0",
"place" : "1, 0, 0, 1, 10, 340",
"opaque" : "true",
"font" : {
"name" : "SVGFreeSansASCII,sans-serif",
"size" : 32,
"weight" : "normal"
}
}
]
},
{
"place" : "1, 0, 0, 1, 0, 0",
"form" : {
"x" : 1,
"w" : 478,
"type" : "Rect",
"y" : 1,
"h" : 358
},
"node" : "Shape",
"opaque" : "true",
"opacity" : "1.0",
"stroke" : {
"join" : "miter",
"cap" : "butt",
"fill" : {
"type" : "Color",
"val" : 0
},
"dashes" : [
],
"width" : 1
}
}
],
"place" : "1, 0, 0, 1, 0, 0",
"node" : "Group",
"opaque" : "true",
"opacity" : "1.0",
"clip" : {
"x" : 0,
"w" : 480,
"type" : "Rect",
"y" : 0,
"h" : 360
}
}

View File

@ -0,0 +1,58 @@
<svg version="1.1" baseProfile="tiny" id="svg-root"
width="100%" height="100%" viewBox="0 0 480 360"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!--======================================================================-->
<!--= SVG 1.1 2nd Edition Test Case =-->
<!--======================================================================-->
<!--= Copyright 2009 World Wide Web Consortium, (Massachusetts =-->
<!--= Institute of Technology, European Research Consortium for =-->
<!--= Informatics and Mathematics (ERCIM), Keio University). =-->
<!--= All Rights Reserved. =-->
<!--= See http://www.w3.org/Consortium/Legal/. =-->
<!--======================================================================-->
<d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
template-version="1.4" reviewer="SVGWG" author="Lofton Henderson" status="accepted"
version="$Revision: 1.7 $" testname="$RCSfile: shapes-circle-01-t.svg,v $">
<d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/shapes.html#CircleElement">
<p>
Tests the circle element
</p>
</d:testDescription>
<d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
<p>
Run the test. No interaction required.
</p>
</d:operatorScript>
<d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
<p>
Six circles are displayed, with position, size, fill and stroke matching the reference image
</p>
</d:passCriteria>
</d:SVGTestCase>
<title id="test-title">$RCSfile: shapes-circle-01-t.svg,v $</title>
<defs>
<font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
<font-face-src>
<font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
</font-face-src>
</font-face>
</defs>
<g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
<circle cx="100" cy="100" r="50" fill="none" stroke="black"/>
<circle cx="220" cy="100" r="35" fill="green" stroke="black"/>
<circle cx="340" cy="100" r="20" fill="black" stroke="lime" stroke-width="4"/>
<circle cx="100" cy="260" r="20" stroke="lime" fill="yellow" stroke-width="4"/>
<circle cx="220" cy="260" r="35" stroke="none" fill="blue"/>
<circle cx="340" cy="260" r="50" stroke="green" fill="none" stroke-width="10"/>
</g>
<g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
<text id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
</g>
<rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
<!-- comment out this watermark once the test is approved -->
<!--<g id="draft-watermark">
<rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
<text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
</g>-->
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -9,21 +9,18 @@
class ShapeAnimation: AnimationImpl<Shape> {
convenience init(animatedNode: Shape, finalValue: Shape, animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
let nodeId = animatedNode.id
let interpolationFunc = { (t: Double) -> Shape in
if t == 0 {
let initialNode = Node.nodeBy(id: nodeId) as! Shape
return Shape(form: initialNode.form,
fill: initialNode.fill,
stroke: initialNode.stroke,
place: initialNode.place,
opaque: initialNode.opaque,
opacity: initialNode.opacity,
clip: initialNode.clip,
effect: initialNode.effect,
visible: initialNode.visible,
tag: initialNode.tag)
return Shape(form: animatedNode.form,
fill: animatedNode.fill,
stroke: animatedNode.stroke,
place: animatedNode.place,
opaque: animatedNode.opaque,
opacity: animatedNode.opacity,
clip: animatedNode.clip,
effect: animatedNode.effect,
visible: animatedNode.visible,
tag: animatedNode.tag)
}
return finalValue
@ -56,6 +53,25 @@ class ShapeAnimation: AnimationImpl<Shape> {
override public func pause() {
stop()
}
open override func reverse() -> Animation {
let factory = { () -> (Double) -> Shape in
let original = self.timeFactory()
return { (t: Double) -> Shape in
return original(1.0 - t)
}
}
let node = Node.nodeBy(id: nodeId!)
let reversedAnimation = ShapeAnimation(animatedNode: node as! Shape,
factory: factory,
animationDuration: duration,
fps: logicalFps)
reversedAnimation.progress = progress
reversedAnimation.completion = completion
return reversedAnimation
}
}
public extension AnimatableVariable {

View File

@ -1,11 +1,17 @@
import Foundation
public enum FillRule {
case nonzero, evenodd
}
open class Path: Locus {
open let segments: [PathSegment]
open let fillRule: FillRule
public init(segments: [PathSegment] = []) {
public init(segments: [PathSegment] = [], fillRule: FillRule = .nonzero) {
self.segments = segments
self.fillRule = fillRule
}
override open func bounds() -> Rect {

View File

@ -77,6 +77,10 @@ extension MFont {
class var mSystemFontSize: CGFloat {
return UIFont.systemFontSize
}
class var mFamilyNames: [String] {
return UIFont.familyNames
}
}
extension UIScreen {

View File

@ -92,6 +92,10 @@ extension NSFont {
class var mSystemFontSize: CGFloat {
return NSFont.systemFontSize
}
class var mFamilyNames: [String] {
return NSFontManager.shared.availableFontFamilies
}
}
extension NSScreen {

View File

@ -90,26 +90,28 @@ class RenderUtils {
fatalError("Unsupported node: \(node)")
}
static let availableFonts = MFont.mFamilyNames.map{ $0.lowercased() }
class func loadFont(name: String, size: Int) -> MFont? {
let separationSet = CharacterSet(charactersIn: ",")
let names = name.components(separatedBy: separationSet)
var customFont: MFont? = .none
names.forEach { fontName in
if customFont != .none {
return
let fontPriorities = name.split(separator: ",").map{ String($0).trimmingCharacters(in: CharacterSet(charactersIn: " '")).lowercased() }
for font in fontPriorities {
if availableFonts.contains(font) {
return MFont(name: font, size: CGFloat(size))
}
if fontName.first == " " {
let index = fontName.index(fontName.startIndex, offsetBy: 1)
let fixedName = String(fontName.suffix(from: index))
customFont = MFont(name: fixedName, size: CGFloat(size))
return
if font == "serif" {
return MFont(name: "Georgia", size: CGFloat(size))
}
if font == "sans-serif" {
return MFont(name: "Arial", size: CGFloat(size))
}
if font == "monospace" {
return MFont(name: "Courier", size: CGFloat(size))
}
customFont = MFont(name: fontName, size: CGFloat(size))
}
return customFont
return .none
}
class func applyOpacity(_ color: Color, opacity: Double) -> Color {

View File

@ -38,7 +38,12 @@ class ShapeRenderer: NodeRenderer {
if shape.fill != nil || shape.stroke != nil {
setGeometry(shape.form, ctx: ctx.cgContext!)
drawPath(shape.fill, stroke: shape.stroke, ctx: ctx.cgContext!, opacity: opacity)
var fillRule = FillRule.nonzero
if let path = shape.form as? Path {
fillRule = path.fillRule
}
drawPath(shape.fill, stroke: shape.stroke, ctx: ctx.cgContext!, opacity: opacity, fillRule: fillRule)
}
}
@ -102,7 +107,7 @@ class ShapeRenderer: NodeRenderer {
return CGRect(x: CGFloat(rect.x), y: CGFloat(rect.y), width: CGFloat(rect.w), height: CGFloat(rect.h))
}
fileprivate func drawPath(_ fill: Fill?, stroke: Stroke?, ctx: CGContext?, opacity: Double) {
fileprivate func drawPath(_ fill: Fill?, stroke: Stroke?, ctx: CGContext?, opacity: Double, fillRule: FillRule) {
var shouldStrokePath = false
if fill is Gradient || stroke?.fill is Gradient {
shouldStrokePath = true
@ -112,15 +117,15 @@ class ShapeRenderer: NodeRenderer {
let path = ctx!.path
setFill(fill, ctx: ctx, opacity: opacity)
if stroke.fill is Gradient && !(fill is Gradient) {
ctx!.drawPath(using: .fill)
ctx!.drawPath(using: fillRule == .nonzero ? .fill : .eoFill)
}
drawWithStroke(stroke, ctx: ctx, opacity: opacity, shouldStrokePath: shouldStrokePath, path: path, mode: .fillStroke)
drawWithStroke(stroke, ctx: ctx, opacity: opacity, shouldStrokePath: shouldStrokePath, path: path, mode: fillRule == .nonzero ? .fillStroke : .eoFillStroke)
return
}
if let fill = fill {
setFill(fill, ctx: ctx, opacity: opacity)
ctx!.drawPath(using: .fill)
ctx!.drawPath(using: fillRule == .nonzero ? .fill : .eoFill)
return
}

View File

@ -79,18 +79,18 @@ class TextRenderer: NodeRenderer {
guard let text = text else {
return MFont.systemFont(ofSize: 18.0)
}
if let textFont = text.font {
if let customFont = RenderUtils.loadFont(name: textFont.name, size: textFont.size) {
return customFont
} else {
if let weight = getWeight(textFont.weight) {
return MFont.systemFont(ofSize: CGFloat(textFont.size), weight: weight)
}
return MFont.systemFont(ofSize: CGFloat(textFont.size))
}
guard let textFont = text.font else {
return MFont.systemFont(ofSize: MFont.mSystemFontSize)
}
if let customFont = RenderUtils.loadFont(name: textFont.name, size: textFont.size) {
return customFont
} else {
if let weight = getWeight(textFont.weight) {
return MFont.systemFont(ofSize: CGFloat(textFont.size), weight: weight)
}
return MFont.systemFont(ofSize: CGFloat(textFont.size))
}
return MFont.systemFont(ofSize: MFont.mSystemFontSize)
}
fileprivate func getWeight(_ weight: String) -> MFont.Weight? {

View File

@ -42,10 +42,10 @@ open class SVGParser {
}
let availableStyleAttributes = ["stroke", "stroke-width", "stroke-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
"fill", "text-anchor", "clip-path", "fill-opacity",
"fill", "fill-rule", "text-anchor", "clip-path", "fill-opacity",
"stop-color", "stop-opacity",
"font-family", "font-size",
"font-weight", "opacity", "color"]
"font-weight", "opacity", "color", "visibility"]
fileprivate let xmlString: String
fileprivate let initialPosition: Transform
@ -88,12 +88,15 @@ open class SVGParser {
}
}
parseSvg(parsedXml.children)
let group = Group(contents: self.nodes, place: initialPosition)
if let viewBoxParams = viewBoxParams {
let group = viewBoxParams.svgSize != nil ?
SVGCanvas(bounds: Rect(x: 0, y: 0, w: viewBoxParams.svgSize!.w, h: viewBoxParams.svgSize!.h), contents: nodes) :
Group(contents: nodes)
addViewBoxClip(toNode: group, viewBoxParams: viewBoxParams)
return group
}
return group
return Group(contents: nodes)
}
fileprivate func prepareSvg(_ children: [XMLIndexer]) {
@ -262,11 +265,18 @@ open class SVGParser {
if styleAttributes["display"] == "none" {
return .none
}
if styleAttributes["visibility"] == "hidden" {
return .none
}
let position = getPosition(element)
switch element.name {
case "path":
if let path = parsePath(node) {
if var path = parsePath(node) {
if let rule = getFillRule(styleAttributes) {
path = Path(segments: path.segments, fillRule: rule)
}
return Shape(form: path, fill: getFillColor(styleAttributes, groupStyle: styleAttributes), stroke: getStroke(styleAttributes, groupStyle: styleAttributes), place: position, opacity: getOpacity(styleAttributes), clip: getClipPath(styleAttributes), tag: getTag(element))
}
case "line":
@ -629,13 +639,8 @@ open class SVGParser {
}
fileprivate func getStrokeWidth(_ styleParts: [String: String]) -> Double {
if let strokeWidth = styleParts["stroke-width"] {
let characterSet = NSCharacterSet.decimalDigits.union(NSCharacterSet.punctuationCharacters).inverted
let digitsArray = strokeWidth.components(separatedBy: characterSet)
let digits = digitsArray.joined()
if let value = Double(digits) {
return value
}
if let strokeWidth = styleParts["stroke-width"], let value = doubleFromString(strokeWidth) {
return value
}
return 1
}
@ -836,7 +841,7 @@ open class SVGParser {
if let anchor = textAnchor {
if anchor == "middle" {
return .mid
} else if anchor == "right" {
} else if anchor == "end" {
return .max
}
}
@ -1261,17 +1266,14 @@ open class SVGParser {
}
fileprivate func getFontName(_ attributes: [String: String]) -> String? {
return attributes["font-family"]
return attributes["font-family"]?.trimmingCharacters(in: .whitespacesAndNewlines)
}
fileprivate func getFontSize(_ attributes: [String: String]) -> Int? {
guard let fontSize = attributes["font-size"] else {
guard let fontSize = attributes["font-size"], let size = doubleFromString(fontSize) else {
return .none
}
if let size = Double(fontSize) {
return (Int(round(size)))
}
return .none
return Int(round(size))
}
fileprivate func getFontStyle(_ attributes: [String: String], style: String) -> Bool? {
@ -1331,6 +1333,20 @@ open class SVGParser {
}
return false
}
fileprivate func getFillRule(_ attributes: [String: String]) -> FillRule? {
if let rule = attributes["fill-rule"] {
switch rule {
case "nonzero":
return .nonzero
case "evenodd":
return .evenodd
default:
return .none
}
}
return .none
}
fileprivate func copyNode(_ referenceNode: Node) -> Node? {
let pos = referenceNode.place