diff --git a/Samples.bundle/checkmark.svg b/Samples.bundle/checkmark.svg new file mode 100644 index 0000000..22a4a4f --- /dev/null +++ b/Samples.bundle/checkmark.svg @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/SwiftDraw/Parser.XML.Color.swift b/SwiftDraw/Parser.XML.Color.swift index eeb283f..cbc1e39 100644 --- a/SwiftDraw/Parser.XML.Color.swift +++ b/SwiftDraw/Parser.XML.Color.swift @@ -55,7 +55,8 @@ extension XMLParser { } private func parseColorNone(data: String) -> DOM.Color? { - if data.trimmingCharacters(in: .whitespaces) == "none" { + let trimmed = data.trimmingCharacters(in: .whitespaces) + if trimmed == "none" || trimmed == "transparent" { return DOM.Color.none // .none resolves to Optional.none } return nil diff --git a/SwiftDraw/Renderer.SFSymbol.swift b/SwiftDraw/Renderer.SFSymbol.swift index f669c20..b05d9c6 100644 --- a/SwiftDraw/Renderer.SFSymbol.swift +++ b/SwiftDraw/Renderer.SFSymbol.swift @@ -126,7 +126,6 @@ extension SFSymbolRenderer { case black } - func getInsets(for variant: Variant) -> CommandLine.Insets { switch variant { case .regular: @@ -177,7 +176,8 @@ extension SFSymbolRenderer { static func getSymbolPaths(for layer: LayerTree.Layer, ctm: LayerTree.Transform.Matrix = .identity) -> [SymbolPath] { - guard layer.opacity > 0 else { return [] } + let isSFSymbolLayer = containsAcceptedName(layer.class) + guard isSFSymbolLayer || layer.opacity > 0 else { return [] } guard layer.clip.isEmpty else { print("Warning:", "clip-path unsupported in SF Symbols.", to: &.standardError) return [] @@ -190,12 +190,15 @@ extension SFSymbolRenderer { let ctm = ctm.concatenated(layer.transform.toMatrix()) var paths = [SymbolPath]() - let symbolClass = containsAcceptedName(layer.class) ? layer.class : nil + let symbolClass = isSFSymbolLayer ? layer.class : nil for c in layer.contents { switch c { case let .shape(shape, stroke, fill): - if let path = makePath(for: shape, stoke: stroke, fill: fill)?.applying(matrix: ctm) { + if let path = makePath(for: shape, + stoke: stroke, + fill: fill, + preserve: isSFSymbolLayer)?.applying(matrix: ctm) { if fill.rule == .evenodd { paths.append(SymbolPath(class: symbolClass, path: path.makeNonZero())) } else { @@ -218,13 +221,14 @@ extension SFSymbolRenderer { static func makePath(for shape: LayerTree.Shape, stoke: LayerTree.StrokeAttributes, - fill: LayerTree.FillAttributes) -> LayerTree.Path? { + fill: LayerTree.FillAttributes, + preserve: Bool) -> LayerTree.Path? { - if fill.fill != .none && fill.opacity > 0 { + if preserve || (fill.fill != .none && fill.opacity > 0) { return shape.path } - if stoke.color != .none && stoke.width > 0 { + if preserve || (stoke.color != .none && stoke.width > 0) { #if canImport(CoreGraphics) return expandOutlines(for: shape.path, stroke: stoke) #else diff --git a/SwiftDrawTests/Parser.XML.ColorTests.swift b/SwiftDrawTests/Parser.XML.ColorTests.swift index da2006c..f258e7f 100644 --- a/SwiftDrawTests/Parser.XML.ColorTests.swift +++ b/SwiftDrawTests/Parser.XML.ColorTests.swift @@ -40,6 +40,12 @@ final class ParserColorTests: XCTestCase { XCTAssertEqual(try XMLParser().parseColor("\t none \t"), .none) } + func testColorTransparent() { + XCTAssertEqual(try XMLParser().parseColor("transparent"), .none) + XCTAssertEqual(try XMLParser().parseColor(" transparent"), .none) + XCTAssertEqual(try XMLParser().parseColor("\t transparent \t"), .none) + } + func testColorCurrent() { XCTAssertEqual(try XMLParser().parseColor("currentColor"), .currentColor) XCTAssertEqual(try XMLParser().parseColor(" currentColor"), .currentColor) diff --git a/SwiftDrawTests/Renderer.SFSymbolTests.swift b/SwiftDrawTests/Renderer.SFSymbolTests.swift index df50d09..7ee254f 100644 --- a/SwiftDrawTests/Renderer.SFSymbolTests.swift +++ b/SwiftDrawTests/Renderer.SFSymbolTests.swift @@ -72,6 +72,62 @@ final class RendererSFSymbolTests: XCTestCase { } + func testTransparentLayers_Are_Removed() throws { + let source = try DOM.SVG.parse(#""" + + + + + + + """#) + + let template = try SFSymbolTemplate.parse( + SFSymbolRenderer.render(svg: source) + ) + + XCTAssertEqual( + template.ultralight.contents.paths.count, + 1 + ) + XCTAssertEqual( + template.regular.contents.paths.count, + 1 + ) + XCTAssertEqual( + template.black.contents.paths.count, + 1 + ) + } + + func testTransparentSFSymboleLayers_AreNot_Removed() throws { + let source = try DOM.SVG.parse(#""" + + + + + + + """#) + + let template = try SFSymbolTemplate.parse( + SFSymbolRenderer.render(svg: source) + ) + + XCTAssertEqual( + template.ultralight.contents.paths.count, + 3 + ) + XCTAssertEqual( + template.regular.contents.paths.count, + 3 + ) + XCTAssertEqual( + template.black.contents.paths.count, + 3 + ) + } + #if canImport(CoreGraphics) func testStrokeSymbol() throws { let url = try Bundle.test.url(forResource: "key.svg")