swhitty / SwiftDraw

@@ -216,7 +216,8 @@
Loading
216 216
    
217 217
    el.opacity = try att.parsePercentage("opacity")
218 218
    el.display = try att.parseRaw("display")
219 -
    
219 +
    el.color = try att.parseColor("color")
220 +
220 221
    el.stroke = try att.parseColor("stroke")
221 222
    el.strokeWidth = try att.parseFloat("stroke-width")
222 223
    el.strokeOpacity = try att.parsePercentage("stroke-opacity")
@@ -262,6 +263,7 @@
Loading
262 263
  mutating func updateAttributes(from attributes: PresentationAttributes) {
263 264
    opacity = attributes.opacity
264 265
    display = attributes.display
266 +
    color = attributes.color
265 267
    stroke = attributes.stroke
266 268
    strokeWidth = attributes.strokeWidth
267 269
    strokeOpacity = attributes.strokeOpacity

@@ -33,6 +33,7 @@
Loading
33 33
  
34 34
  enum Color: Equatable {
35 35
    case none
36 +
    case currentColor
36 37
    case keyword(Keyword)
37 38
    case rgbi(UInt8, UInt8, UInt8)
38 39
    case rgbf(DOM.Float, DOM.Float, DOM.Float)

@@ -38,7 +38,8 @@
Loading
38 38
protocol PresentationAttributes {
39 39
  var opacity: DOM.Float?  { get set }
40 40
  var display: DOM.DisplayMode?  { get set }
41 -
  
41 +
  var color: DOM.Color?  { get set }
42 +
42 43
  var stroke: DOM.Color?  { get set }
43 44
  var strokeWidth: DOM.Float?  { get set }
44 45
  var strokeOpacity: DOM.Float?  { get set }
@@ -67,7 +68,8 @@
Loading
67 68
    
68 69
    var opacity: DOM.Float?
69 70
    var display: DOM.DisplayMode?
70 -
    
71 +
    var color: DOM.Color?
72 +
71 73
    var stroke: DOM.Color?
72 74
    var strokeWidth: DOM.Float?
73 75
    var strokeOpacity: DOM.Float?

@@ -157,7 +157,9 @@
Loading
157 157
    let stroke: LayerTree.Color
158 158
159 159
    if state.strokeWidth > 0.0 {
160 -
      stroke = LayerTree.Color.create(from: state.stroke).withAlpha(state.strokeOpacity).maybeNone()
160 +
      stroke = LayerTree.Color
161 +
            .create(from: state.stroke, current: state.color)
162 +
            .withAlpha(state.strokeOpacity).maybeNone()
161 163
    } else {
162 164
      stroke = .none
163 165
    }
@@ -170,7 +172,9 @@
Loading
170 172
  }
171 173
172 174
  func makeFillAttributes(with state: State) -> LayerTree.FillAttributes {
173 -
    let fill = LayerTree.Color.create(from: state.fill.makeColor()).withAlpha(state.fillOpacity).maybeNone()
175 +
    let fill = LayerTree.Color
176 +
          .create(from: state.fill.makeColor(), current: state.color)
177 +
          .withAlpha(state.fillOpacity).maybeNone()
174 178
175 179
    if case .url(let patternId) = state.fill,
176 180
      let element = svg.defs.patterns.first(where: { $0.id == patternId.fragment }) {
@@ -186,7 +190,9 @@
Loading
186 190
  }
187 191
188 192
  static func makeTextAttributes(with state: State) -> LayerTree.TextAttributes {
189 -
      let fill = LayerTree.Color.create(from: state.fill.makeColor()).withAlpha(state.fillOpacity).maybeNone()
193 +
      let fill = LayerTree.Color
194 +
          .create(from: state.fill.makeColor(), current: state.color)
195 +
          .withAlpha(state.fillOpacity).maybeNone()
190 196
      return LayerTree.TextAttributes(
191 197
        color: fill,
192 198
        fontName: state.fontFamily,
@@ -232,7 +238,7 @@
Loading
232 238
  func makeGradientStops(for element: DOM.LinearGradient) -> [LayerTree.Gradient.Stop] {
233 239
    return element.stops.map {
234 240
      LayerTree.Gradient.Stop(offset: $0.offset,
235 -
                              color: LayerTree.Color($0.color),
241 +
                              color: LayerTree.Color.create(from: $0.color, current: .none),
236 242
                              opacity: $0.opacity)
237 243
    }
238 244
  }
@@ -241,6 +247,7 @@
Loading
241 247
  struct State {
242 248
    var opacity: DOM.Float
243 249
    var display: DOM.DisplayMode
250 +
    var color: DOM.Color
244 251
245 252
    var stroke: DOM.Color
246 253
    var strokeWidth: DOM.Float
@@ -261,6 +268,7 @@
Loading
261 268
      //default root SVG element state
262 269
      opacity = 1.0
263 270
      display = .inline
271 +
      color = .keyword(.black)
264 272
265 273
      stroke = .none
266 274
      strokeWidth = 1.0
@@ -284,6 +292,7 @@
Loading
284 292
285 293
    state.opacity = attributes.opacity ?? 1.0
286 294
    state.display = attributes.display ?? existing.display
295 +
    state.color = attributes.color ?? existing.color
287 296
288 297
    state.stroke = attributes.stroke ?? existing.stroke
289 298
    state.strokeWidth = attributes.strokeWidth ?? existing.strokeWidth
@@ -297,7 +306,7 @@
Loading
297 306
    state.fillRule = attributes.fillRule ?? existing.fillRule
298 307
299 308
    state.fontFamily = attributes.fontFamily ?? existing.fontFamily
300 -
      state.fontSize = attributes.fontSize ?? existing.fontSize
309 +
    state.fontSize = attributes.fontSize ?? existing.fontSize
301 310
302 311
    return state
303 312
  }

@@ -48,15 +48,13 @@
Loading
48 48
}
49 49
50 50
extension LayerTree.Color {
51 -
  
52 -
  init(_ color: DOM.Color) {
53 -
    self = LayerTree.Color.create(from: color)
54 -
  }
55 -
  
56 -
  static func create(from color: DOM.Color) -> LayerTree.Color {
51 +
52 +
  static func create(from color: DOM.Color, current: DOM.Color) -> LayerTree.Color {
57 53
    switch(color){
58 54
    case .none:
59 55
      return .none
56 +
    case .currentColor:
57 +
      return create(from: current, current: .none)
60 58
    case let .keyword(c):
61 59
      let rgbi = c.rgbi
62 60
      return LayerTree.Color(rgbi.0, rgbi.1, rgbi.2)

@@ -39,12 +39,12 @@
Loading
39 39
  final class SAXParser: NSObject, XMLParserDelegate {
40 40
    
41 41
    #if canImport(FoundationXML)
42 -
    typealias XMLParser = FoundationXML.XMLParser
42 +
    typealias FoundationXMLParser = FoundationXML.XMLParser
43 43
    #else
44 -
    typealias XMLParser = Foundation.XMLParser
44 +
    typealias FoundationXMLParser = Foundation.XMLParser
45 45
    #endif
46 46
    
47 -
    private let parser: XMLParser
47 +
    private let parser: FoundationXMLParser
48 48
    private let namespaceURI = "http://www.w3.org/2000/svg"
49 49
    
50 50
    private var rootNode: Element?
@@ -55,7 +55,7 @@
Loading
55 55
    }
56 56
    
57 57
    private init(data: Data) {
58 -
      self.parser = XMLParser(data: data)
58 +
      self.parser = FoundationXMLParser(data: data)
59 59
      elements = [Element]()
60 60
      super.init()
61 61
      
@@ -69,7 +69,7 @@
Loading
69 69
      guard
70 70
        parser.parser.parse(),
71 71
        let rootNode = parser.rootNode else {
72 -
          let error = parser.parser.parserError ?? SwiftDraw.XMLParser.Error.invalid
72 +
          let error = parser.parser.parserError ?? XMLParser.Error.invalid
73 73
          throw error
74 74
      }
75 75
      
@@ -81,7 +81,7 @@
Loading
81 81
      return try parse(data: data)
82 82
    }
83 83
    
84 -
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName _: String?, attributes attributeDict: [String: String] = [:]) {
84 +
    func parser(_ parser: FoundationXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName _: String?, attributes attributeDict: [String: String] = [:]) {
85 85
      guard
86 86
        self.parser === parser,
87 87
        namespaceURI == self.namespaceURI else {
@@ -99,7 +99,7 @@
Loading
99 99
      }
100 100
    }
101 101
    
102 -
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName _: String?) {
102 +
    func parser(_ parser: FoundationXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName _: String?) {
103 103
      guard
104 104
        namespaceURI == self.namespaceURI,
105 105
        currentElement.name == elementName else {
@@ -109,7 +109,7 @@
Loading
109 109
      elements.removeLast()
110 110
    }
111 111
    
112 -
    func parser(_ parser: XMLParser, foundCharacters string: String) {
112 +
    func parser(_ parser: FoundationXMLParser, foundCharacters string: String) {
113 113
      guard let element = elements.last else { return }
114 114
      let text = element.innerText.map { $0.appending(string) }
115 115
      element.innerText = text ?? string

@@ -39,6 +39,8 @@
Loading
39 39
      return .color(c)
40 40
    } else if let c = try parseColorP3(data: data) {
41 41
      return .color(c)
42 +
    } else if let c = parseCurrentColor(data: data) {
43 +
      return .color(c)
42 44
    } else if let c = parseColorKeyword(data: data) {
43 45
      return .color(c)
44 46
    } else if let c = parseColorNone(data: data) {
@@ -58,7 +60,15 @@
Loading
58 60
    }
59 61
    return nil
60 62
  }
61 -
  
63 +
64 +
  private func parseCurrentColor(data: String) -> DOM.Color? {
65 +
    let raw = data.trimmingCharacters(in: .whitespaces)
66 +
    guard raw == "currentColor" else {
67 +
      return nil
68 +
    }
69 +
    return .currentColor
70 +
  }
71 +
62 72
  private func parseColorKeyword(data: String) -> DOM.Color? {
63 73
    let raw = data.trimmingCharacters(in: .whitespaces)
64 74
    guard let keyword = DOM.Color.Keyword(rawValue: raw) else {

@@ -108,11 +108,13 @@
Loading
108 108
public extension Image {
109 109
110 110
  convenience init?(fileURL url: URL) {
111 -
    guard let svg = try? DOM.SVG.parse(fileURL: url) else {
111 +
    do {
112 +
      let svg = try DOM.SVG.parse(fileURL: url)
113 +
      self.init(svg: svg)
114 +
    } catch {
115 +
      print("[swiftdraw]", "parsing error", error)
112 116
      return nil
113 117
    }
114 -
115 -
    self.init(svg: svg)
116 118
  }
117 119
118 120
  convenience init?(named name: String, in bundle: Bundle = Bundle.main) {
Files Coverage
SwiftDraw 76.06%
Project Totals (59 files) 76.06%
1
ignore:
2
  - "SwiftDrawTests"
3
  - "CommandLine"
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading