Skip to content

Commit d7ecf8c

Browse files
committed
PresentationAttributes
1 parent c917da3 commit d7ecf8c

22 files changed

+218
-150
lines changed

Examples/Sources/ViewController.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class ViewController: UIViewController {
6565

6666
override func loadView() {
6767
let imageView = UIImageView(frame: UIScreen.main.bounds)
68-
imageView.image = Image(named: "angry.svg", in: .samples)?.rasterize()
68+
imageView.image = Image(named: "stylesheet-ring.svg", in: .samples)?.rasterize()
6969
imageView.contentMode = .scaleAspectFit
7070
imageView.backgroundColor = .white
7171
self.view = imageView

Samples/stylesheet-ring.svg

+43
Loading

Samples/stylesheet.svg

+28-15
Loading

SwiftDraw/DOM.Element.swift

+35-48
Original file line numberDiff line numberDiff line change
@@ -35,62 +35,49 @@ protocol ContainerElement {
3535
var childElements: [DOM.GraphicsElement] { get set }
3636
}
3737

38-
protocol PresentationAttributes {
39-
var opacity: DOM.Float? { get set }
40-
var display: DOM.DisplayMode? { get set }
41-
var color: DOM.Color? { get set }
42-
43-
var stroke: DOM.Fill? { get set }
44-
var strokeWidth: DOM.Float? { get set }
45-
var strokeOpacity: DOM.Float? { get set }
46-
var strokeLineCap: DOM.LineCap? { get set }
47-
var strokeLineJoin: DOM.LineJoin? { get set }
48-
var strokeDashArray: [DOM.Float]? { get set }
49-
50-
var fill: DOM.Fill? { get set }
51-
var fillOpacity: DOM.Float? { get set }
52-
var fillRule: DOM.FillRule? { get set }
53-
54-
var fontFamily: String? { get set }
55-
var fontSize: Float? { get set }
56-
57-
var transform: [DOM.Transform]? { get set }
58-
var clipPath: DOM.URL? { get set }
59-
var clipRule: DOM.FillRule? { get set }
60-
var mask: DOM.URL? { get set }
61-
var filter: DOM.URL? { get set }
38+
// PresentationAttributes cascade;
39+
// attribute --> .element --> .class ---> .id ---> style=
40+
41+
struct PresentationAttributes {
42+
var opacity: DOM.Float?
43+
var display: DOM.DisplayMode?
44+
var color: DOM.Color?
45+
46+
var stroke: DOM.Fill?
47+
var strokeWidth: DOM.Float?
48+
var strokeOpacity: DOM.Float?
49+
var strokeLineCap: DOM.LineCap?
50+
var strokeLineJoin: DOM.LineJoin?
51+
var strokeDashArray: [DOM.Float]?
52+
53+
var fill: DOM.Fill?
54+
var fillOpacity: DOM.Float?
55+
var fillRule: DOM.FillRule?
56+
57+
var fontFamily: String?
58+
var fontSize: Float?
59+
60+
var transform: [DOM.Transform]?
61+
var clipPath: DOM.URL?
62+
var clipRule: DOM.FillRule?
63+
var mask: DOM.URL?
64+
var filter: DOM.URL?
65+
}
66+
67+
protocol ElementAttributes {
68+
var id: String? { get set }
69+
var `class`: String? { get set }
6270
}
6371

6472
extension DOM {
6573

6674
class Element {}
6775

68-
class GraphicsElement: Element, PresentationAttributes {
76+
class GraphicsElement: Element, ElementAttributes {
6977
var id: String?
78+
var `class`: String?
7079

71-
var opacity: DOM.Float?
72-
var display: DOM.DisplayMode?
73-
var color: DOM.Color?
74-
75-
var stroke: DOM.Fill?
76-
var strokeWidth: DOM.Float?
77-
var strokeOpacity: DOM.Float?
78-
var strokeLineCap: DOM.LineCap?
79-
var strokeLineJoin: DOM.LineJoin?
80-
var strokeDashArray: [DOM.Float]?
81-
82-
var fill: DOM.Fill?
83-
var fillOpacity: DOM.Float?
84-
var fillRule: DOM.FillRule?
85-
86-
var fontFamily: String?
87-
var fontSize: Float?
88-
89-
var transform: [DOM.Transform]?
90-
var clipPath: URL?
91-
var clipRule: DOM.FillRule?
92-
var mask: URL?
93-
var filter: URL?
80+
var attributes = PresentationAttributes()
9481
}
9582

9683
final class Line: GraphicsElement {

SwiftDraw/DOM.SVG.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,13 @@ extension DOM {
7575
}
7676

7777
struct StyleSheet {
78+
7879
enum Selector: Hashable {
7980
case element(String)
8081
case id(String)
8182
case `class`(String)
8283
}
8384

84-
var entries: [Selector: PresentationAttributes] = [:]
85+
var attributes: [Selector: PresentationAttributes] = [:]
8586
}
8687
}

SwiftDraw/LayerTree.Builder.Layer.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ extension LayerTree.Builder {
6161
static func makeTextContents(from text: DOM.Text, with state: State) -> LayerTree.Layer.Contents {
6262
let point = Point(text.x ?? 0, text.y ?? 0)
6363
var att = makeTextAttributes(with: state)
64-
att.fontName = text.fontFamily ?? att.fontName
65-
att.size = text.fontSize ?? att.size
64+
att.fontName = text.attributes.fontFamily ?? att.fontName
65+
att.size = text.attributes.fontSize ?? att.size
6666
return .text(text.value, point, att)
6767
}
6868

SwiftDraw/LayerTree.Builder.swift

+7-6
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ extension LayerTree {
4444
}
4545

4646
func makeLayer() -> Layer {
47-
let state = Builder.createState(for: svg, inheriting: State())
47+
let state = Builder.createState(for: svg.attributes, inheriting: State())
4848
let l = makeLayer(from: svg, inheriting: state)
4949
l.transform = Builder.makeTransform(for: svg.viewBox,
5050
width: svg.width,
@@ -76,14 +76,15 @@ extension LayerTree {
7676
}
7777

7878
func makeLayer(from element: DOM.GraphicsElement, inheriting previousState: State) -> Layer {
79-
let state = Builder.createState(for: element, inheriting: previousState)
79+
let attributes = element.attributes
80+
let state = Builder.createState(for: attributes, inheriting: previousState)
8081
let l = Layer()
8182

8283
guard state.display == .inline else { return l }
8384

84-
l.transform = Builder.createTransforms(from: element.transform ?? [])
85+
l.transform = Builder.createTransforms(from: attributes.transform ?? [])
8586
l.clip = createClipShapes(for: element)
86-
l.clipRule = element.clipRule
87+
l.clipRule = attributes.clipRule
8788
l.mask = createMaskLayer(for: element)
8889
l.opacity = state.opacity
8990
l.contents = makeAllContents(from: element, with: state)
@@ -133,14 +134,14 @@ extension LayerTree {
133134
}
134135

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

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

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

146147
let l = Layer()

SwiftDraw/Parser.XML.Element.swift

+24-5
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ extension XMLParser {
9898
default: return nil
9999
}
100100

101-
ge.id = e.attributes["id"]
101+
ge.attributes = try parsePresentationAttributes(att)
102102

103-
let presentation = try parsePresentationAttributes(att)
104-
ge.updateAttributes(from: presentation)
103+
let elementAtt = try parseElementAttributes(att)
104+
ge.updateAttributes(from: elementAtt)
105105

106106
return ge
107107
}
@@ -213,7 +213,7 @@ extension XMLParser {
213213
}
214214

215215
func parsePresentationAttributes(_ att: AttributeParser) throws -> PresentationAttributes {
216-
let el = DOM.GraphicsElement()
216+
var el = PresentationAttributes()
217217

218218
el.opacity = try att.parsePercentage("opacity")
219219
el.display = try att.parseRaw("display")
@@ -253,6 +253,18 @@ extension XMLParser {
253253
return el
254254
}
255255

256+
func parseElementAttributes(_ att: AttributeParser) throws -> ElementAttributes {
257+
var el = ElementAtt()
258+
el.id = try? att.parseString("id")
259+
el.class = try? att.parseString("class")
260+
return el
261+
}
262+
263+
private struct ElementAtt: ElementAttributes {
264+
var id: String?
265+
var `class`: String?
266+
}
267+
256268
static func logParsingError(for error: Swift.Error, filename: String?, parsing element: XML.Element? = nil) {
257269
let elementName = element.map { "<\($0.name)>" } ?? ""
258270
let filename = filename ?? ""
@@ -303,5 +315,12 @@ extension PresentationAttributes {
303315
mask = attributes.mask
304316
filter = attributes.filter
305317
}
306-
318+
}
319+
320+
extension ElementAttributes {
321+
322+
mutating func updateAttributes(from attributes: ElementAttributes) {
323+
self.id = attributes.id
324+
self.class = attributes.class
325+
}
307326
}

SwiftDraw/Parser.XML.SVG.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,14 @@ extension XMLParser {
5555
guard let w = width else { throw XMLParser.Error.missingAttribute(name: "width") }
5656
guard let h = height else { throw XMLParser.Error.missingAttribute(name: "height") }
5757

58-
var svg = DOM.SVG(width: DOM.Length(w), height: DOM.Length(h))
58+
let svg = DOM.SVG(width: DOM.Length(w), height: DOM.Length(h))
5959
svg.childElements = try parseContainerChildren(e)
6060
svg.viewBox = try parseViewBox(try att.parseString("viewBox"))
6161

6262
svg.defs = try parseSVGDefs(e)
6363
svg.styles = parseStyleSheetElements(within: e)
6464

65-
let presentation = try parsePresentationAttributes(att)
66-
svg.updateAttributes(from: presentation)
65+
svg.attributes = try parsePresentationAttributes(att)
6766

6867
return svg
6968
}

SwiftDraw/Parser.XML.StyleSheet.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ extension XMLParser {
6262
let entries = try Self.parseEntries(text)
6363

6464
var sheet = DOM.StyleSheet()
65-
sheet.entries = try entries.mapValues(parsePresentationAttributes)
65+
sheet.attributes = try entries.mapValues(parsePresentationAttributes)
6666
return sheet
6767
}
6868

SwiftDraw/Parser.XML.Text.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ extension XMLParser {
4747
let element = DOM.Text(value: value)
4848
element.x = try att.parseCoordinate("x")
4949
element.y = try att.parseCoordinate("y")
50-
element.fontFamily = (try att.parseString("font-family"))?.trimmingCharacters(in: .whitespacesAndNewlines)
51-
element.fontSize = try att.parseFloat("font-size")
52-
50+
element.attributes.fontFamily = (try att.parseString("font-family"))?.trimmingCharacters(in: .whitespacesAndNewlines)
51+
element.attributes.fontSize = try att.parseFloat("font-size")
5352
return element
5453
}
5554
}

SwiftDraw/XML.Formatter.SVG.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,14 @@ extension XML.Formatter {
9191
}
9292

9393
func makeGraphicsAttributes(from graphic: DOM.GraphicsElement) -> [String: String] {
94+
makeGraphicsAttributes(from: graphic.attributes, element: graphic)
95+
}
96+
97+
func makeGraphicsAttributes(from graphic: PresentationAttributes,
98+
element: ElementAttributes) -> [String: String] {
9499
var attributes: [String: String] = [:]
95100

96-
attributes["id"] = graphic.id
101+
attributes["id"] = element.id
97102
attributes["opacity"] = formatter.format(graphic.opacity)
98103
attributes["display"] = graphic.display?.rawValue
99104
attributes["stroke"] = graphic.stroke.map(encodeFill)

0 commit comments

Comments
 (0)