Skip to content

Commit

Permalink
remove percent encoding from URL fragments
Browse files Browse the repository at this point in the history
  • Loading branch information
swhitty committed Oct 11, 2024
1 parent 67ed5e4 commit 1f30e9b
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 20 deletions.
2 changes: 1 addition & 1 deletion Examples/Sources/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class ViewController: UIViewController {

override func loadView() {
let imageView = UIImageView(frame: UIScreen.main.bounds)
imageView.image = SVG(named: "rgba.svg", in: .samples)?.rasterize()
imageView.image = SVG(named: "stars.svg", in: .samples)?.rasterize()
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .white
self.view = imageView
Expand Down
20 changes: 20 additions & 0 deletions Samples.bundle/stars.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion SwiftDraw/LayerTree.Builder.Layer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extension LayerTree.Builder {

func makeUseLayerContents(from use: DOM.Use, with state: State) throws -> LayerTree.Layer.Contents {
guard
let id = use.href.fragment,
let id = use.href.fragmentID,
let element = svg.firstGraphicsElement(with: id) else {
throw LayerTree.Error.invalid("missing referenced element: \(use.href)")
}
Expand Down
20 changes: 10 additions & 10 deletions SwiftDraw/LayerTree.Builder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ extension LayerTree {
}

func createClipShapes(for element: DOM.GraphicsElement) -> [Shape] {
guard let clipId = element.attributes.clipPath?.fragment,
guard let clipId = element.attributes.clipPath?.fragmentID,
let clip = svg.defs.clipPaths.first(where: { $0.id == clipId }) else { return [] }

return clip.childElements.compactMap{ Builder.makeShape(from: $0) }
}

func createMaskLayer(for element: DOM.GraphicsElement) -> Layer? {
guard let maskId = element.attributes.mask?.fragment,
guard let maskId = element.attributes.mask?.fragmentID,
let mask = svg.defs.masks.first(where: { $0.id == maskId }) else { return nil }

let l = Layer()
Expand All @@ -145,7 +145,7 @@ extension LayerTree {
}

func makeFilters(for state: State) -> [Filter] {
guard let filterId = state.filter?.fragment,
guard let filterId = state.filter?.fragmentID,
let filter = svg.defs.filters.first(where: { $0.id == filterId }) else { return [] }
return filter.effects
}
Expand Down Expand Up @@ -191,15 +191,15 @@ extension LayerTree.Builder {
.withAlpha(state.fillOpacity).maybeNone()

if case .url(let patternId) = state.fill,
let element = svg.defs.patterns.first(where: { $0.id == patternId.fragment }) {
let element = svg.defs.patterns.first(where: { $0.id == patternId.fragmentID }) {
let pattern = makePattern(for: element)
return LayerTree.FillAttributes(pattern: pattern, rule: state.fillRule, opacity: state.fillOpacity)
} else if case .url(let gradientId) = state.fill,
let element = svg.defs.linearGradients.first(where: { $0.id == gradientId.fragment }),
let element = svg.defs.linearGradients.first(where: { $0.id == gradientId.fragmentID }),
let gradient = makeGradient(for: element) {
return LayerTree.FillAttributes(linear: gradient, rule: state.fillRule, opacity: state.fillOpacity)
} else if case .url(let gradientId) = state.fill,
let element = svg.defs.radialGradients.first(where: { $0.id == gradientId.fragment }),
let element = svg.defs.radialGradients.first(where: { $0.id == gradientId.fragmentID }),
let gradient = makeGradient(for: element) {
return LayerTree.FillAttributes(radial: gradient, rule: state.fillRule, opacity: state.fillOpacity)
} else {
Expand All @@ -208,15 +208,15 @@ extension LayerTree.Builder {
}

func makeLinearGradient(for gradientId: URL) -> LayerTree.LinearGradient? {
guard let element = svg.defs.linearGradients.first(where: { $0.id == gradientId.fragment }),
guard let element = svg.defs.linearGradients.first(where: { $0.id == gradientId.fragmentID }),
let gradient = makeGradient(for: element) else {
return nil
}
return gradient
}

func makeRadialGradient(for gradientId: URL) -> LayerTree.RadialGradient? {
guard let element = svg.defs.radialGradients.first(where: { $0.id == gradientId.fragment }),
guard let element = svg.defs.radialGradients.first(where: { $0.id == gradientId.fragmentID }),
let gradient = makeGradient(for: element) else {
return nil
}
Expand Down Expand Up @@ -249,7 +249,7 @@ extension LayerTree.Builder {
let y2 = element.y2 ?? 0

var stops = [LayerTree.Gradient.Stop]()
if let id = element.href?.fragment,
if let id = element.href?.fragmentID,
let reference = svg.defs.linearGradients.first(where: { $0.id == id }) {
stops = makeGradientStops(for: reference)
} else {
Expand All @@ -272,7 +272,7 @@ extension LayerTree.Builder {

func makeGradient(for element: DOM.RadialGradient) -> LayerTree.RadialGradient? {
var stops = [LayerTree.Gradient.Stop]()
if let id = element.href?.fragment,
if let id = element.href?.fragmentID,
let reference = svg.defs.radialGradients.first(where: { $0.id == id }) {
stops = makeGradientStops(for: reference)
} else {
Expand Down
44 changes: 44 additions & 0 deletions SwiftDraw/URL+Fragment.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// URL+Fragment.swift
// SwiftDraw
//
// Created by Simon Whitty on 12/10/24.
// Copyright 2024 Simon Whitty
//
// Distributed under the permissive zlib license
// Get the latest version from here:
//
// https://github.com/swhitty/SwiftDraw
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

import Foundation

extension URL {

var fragmentID: String? {
if #available(iOS 16.0, *) {
return fragment(percentEncoded: false)
} else {
return fragment
}
}

}
8 changes: 4 additions & 4 deletions SwiftDrawTests/Parser.GraphicAttributeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ final class ParserGraphicAttributeTests: XCTestCase {
XCTAssertEqual(parsed.fillOpacity, 0.25)
XCTAssertEqual(parsed.fillRule, .evenodd)
XCTAssertEqual(parsed.transform!, [.scale(sx: 15, sy: 15)])
XCTAssertEqual(parsed.clipPath?.fragment, "circlePath")
XCTAssertEqual(parsed.mask?.fragment, "fancyMask")
XCTAssertEqual(parsed.filter?.fragment, "blur")
XCTAssertEqual(parsed.clipPath?.fragmentID, "circlePath")
XCTAssertEqual(parsed.mask?.fragmentID, "fancyMask")
XCTAssertEqual(parsed.filter?.fragmentID, "blur")
}

func testCircle() throws {
Expand All @@ -93,7 +93,7 @@ final class ParserGraphicAttributeTests: XCTestCase {
let parsed = try XMLParser().parseGraphicsElement(el)
let circle = parsed as? DOM.Circle
XCTAssertNotNil(circle)
XCTAssertEqual(circle?.style.clipPath?.fragment, "cp1")
XCTAssertEqual(circle?.style.clipPath?.fragmentID, "cp1")
XCTAssertEqual(circle?.style.fill, .color(.keyword(.black)))
XCTAssertEqual(circle?.style.strokeWidth, 2)
}
Expand Down
4 changes: 2 additions & 2 deletions SwiftDrawTests/UseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ final class UseTests: XCTestCase {
var node = ["xlink:href": "#line2", "href": "#line1"]

var parsed = try XMLParser().parseUse(node)
XCTAssertEqual(parsed.href.fragment, "line2")
XCTAssertEqual(parsed.href.fragmentID, "line2")
XCTAssertNil(parsed.x)
XCTAssertNil(parsed.y)

node["x"] = "20"
node["y"] = "30"

parsed = try XMLParser().parseUse(node)
XCTAssertEqual(parsed.href.fragment, "line2")
XCTAssertEqual(parsed.href.fragmentID, "line2")
XCTAssertEqual(parsed.x, 20)
XCTAssertEqual(parsed.y, 30)
}
Expand Down
4 changes: 2 additions & 2 deletions SwiftDrawTests/ValueParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,15 @@ final class ValueParserTests: XCTestCase {
}

func testUrl() {
XCTAssertEqual(try parser.parseUrl("#testingId").fragment, "testingId")
XCTAssertEqual(try parser.parseUrl("#testing🐟").fragmentID, "testing🐟")
XCTAssertEqual(try parser.parseUrl("http://www.google.com").host, "www.google.com")

//XCTAssertThrowsError(try parser.parseUrl("www.google.com"))
//XCTAssertThrowsError(try parser.parseUrl("sd"))
}

func testUrlSelector() {
XCTAssertEqual(try parser.parseUrlSelector("url(#testingId)").fragment, "testingId")
XCTAssertEqual(try parser.parseUrlSelector("url(#testingId)").fragmentID, "testingId")
XCTAssertEqual(try parser.parseUrlSelector("url(http://www.google.com)").host, "www.google.com")

XCTAssertThrowsError(try parser.parseUrlSelector("url(#testingId) other"))
Expand Down

0 comments on commit 1f30e9b

Please sign in to comment.