Skip to content

Commit 9c9ed8c

Browse files
author
Daniil Manin
committed
#203 add transform and viewBox for patterns
1 parent 385fc94 commit 9c9ed8c

File tree

3 files changed

+38
-13
lines changed

3 files changed

+38
-13
lines changed

Source/model/draw/Pattern.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
open class Pattern: Fill {
22

3+
public let viewBox: Rect
34
public let content: Node
45
public let bounds: Rect
56
public let userSpace: Bool
7+
public let position: Transform
68

7-
public init(content: Node, bounds: Rect, userSpace: Bool = false) {
9+
public init(content: Node, bounds: Rect, viewBox: Rect, userSpace: Bool = false, position: Transform) {
10+
self.viewBox = viewBox
811
self.content = content
912
self.bounds = bounds
1013
self.userSpace = userSpace
14+
self.position = position
1115
}
1216
}

Source/render/ShapeRenderer.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ class ShapeRenderer: NodeRenderer {
186186
let boundsTranform = BoundsUtils.transformForLocusInRespectiveCoords(respectiveLocus: pattern.bounds, absoluteLocus: shape.form)
187187
patternBounds = pattern.bounds.applying(boundsTranform)
188188
}
189-
let tileImage = renderer.renderToImage(bounds: patternBounds, inset: 0)
189+
let tileImage = renderer.renderToImage(bounds: pattern.viewBox, inset: 0)
190+
ctx?.concatenate(pattern.position.toCG())
190191
ctx?.clip()
191192
ctx?.draw(tileImage.cgImage!, in: patternBounds.toCG(), byTiling: true)
192193
}

Source/svg/SVGParser.swift

+31-11
Original file line numberDiff line numberDiff line change
@@ -365,12 +365,20 @@ open class SVGParser {
365365
parentPattern = defPatterns[id]
366366
}
367367

368+
var viewBox: Rect = .zero()
369+
if let viewBoxString = element.allAttributes["viewBox"]?.text {
370+
let nums = viewBoxString.components(separatedBy: .whitespaces).map { Double($0) }
371+
if nums.count == 4, let x = nums[0], let y = nums[1], let w = nums[2], let h = nums[3] {
372+
viewBox = Rect(x: x, y: y, w: w, h: h)
373+
}
374+
}
375+
368376
let x = getDoubleValue(element, attribute: "x") ?? parentPattern?.bounds.x ?? 0
369377
let y = getDoubleValue(element, attribute: "y") ?? parentPattern?.bounds.y ?? 0
370378
let w = getDoubleValue(element, attribute: "width") ?? parentPattern?.bounds.w ?? 0
371379
let h = getDoubleValue(element, attribute: "height") ?? parentPattern?.bounds.h ?? 0
372380
let bounds = Rect(x: x, y: y, w: w, h: h)
373-
381+
374382
guard bounds.w > 0 && bounds.h > 0 else {
375383
return .none
376384
}
@@ -384,6 +392,8 @@ open class SVGParser {
384392
contentUserSpace = false
385393
}
386394

395+
let position = getPatternPosition(element)
396+
387397
var contentNode: Node?
388398
if pattern.children.isEmpty {
389399
if let parentPattern = parentPattern {
@@ -402,11 +412,10 @@ open class SVGParser {
402412
}
403413
contentNode = Group(contents: shapes)
404414
}
405-
415+
406416
if let contentNode = contentNode {
407-
return UserSpacePattern(content: contentNode, bounds: bounds, userSpace: userSpace, contentUserSpace: contentUserSpace)
417+
return UserSpacePattern(content: contentNode, bounds: bounds, viewBox: viewBox, userSpace: userSpace, contentUserSpace: contentUserSpace, position: position)
408418
}
409-
410419
return .none
411420
}
412421

@@ -425,7 +434,14 @@ open class SVGParser {
425434

426435
fileprivate func getPosition(_ element: SWXMLHash.XMLElement) -> Transform {
427436
guard let transformAttribute = element.allAttributes["transform"]?.text else {
428-
return Transform.identity
437+
return .identity
438+
}
439+
return parseTransformationAttribute(transformAttribute)
440+
}
441+
442+
fileprivate func getPatternPosition(_ element: SWXMLHash.XMLElement) -> Transform {
443+
guard let transformAttribute = element.allAttributes["patternTransform"]?.text else {
444+
return .identity
429445
}
430446
return parseTransformationAttribute(transformAttribute)
431447
}
@@ -665,7 +681,7 @@ open class SVGParser {
665681
fillColor = String(fallbackColor)
666682
}
667683
}
668-
684+
669685
if fillColor == SVGKeys.currentColor, let currentColor = groupStyle[SVGKeys.color] {
670686
fillColor = currentColor
671687
}
@@ -676,14 +692,14 @@ open class SVGParser {
676692
fileprivate func getPatternFill(pattern: UserSpacePattern, locus: Locus?) -> Pattern {
677693
if pattern.userSpace == false && pattern.contentUserSpace == true {
678694
let tranform = BoundsUtils.transformForLocusInRespectiveCoords(respectiveLocus: pattern.bounds, absoluteLocus: locus!)
679-
return Pattern(content: pattern.content, bounds: pattern.bounds.applying(tranform), userSpace: true)
695+
return Pattern(content: pattern.content, bounds: pattern.bounds.applying(tranform), viewBox: pattern.viewBox, userSpace: true, position: pattern.position)
680696
}
681697
if pattern.userSpace == true && pattern.contentUserSpace == false {
682698
if let patternNode = BoundsUtils.createNodeFromRespectiveCoords(respectiveNode: pattern.content, absoluteLocus: locus!) {
683-
return Pattern(content: patternNode, bounds: pattern.bounds, userSpace: pattern.userSpace)
699+
return Pattern(content: patternNode, bounds: pattern.bounds, viewBox: pattern.viewBox, userSpace: pattern.userSpace, position: pattern.position)
684700
}
685701
}
686-
return Pattern(content: pattern.content, bounds: pattern.bounds, userSpace: true)
702+
return Pattern(content: pattern.content, bounds: pattern.bounds, viewBox: pattern.viewBox, userSpace: true, position: pattern.position)
687703
}
688704

689705
fileprivate func getStroke(_ styleParts: [String: String], groupStyle: [String: String] = [:]) -> Stroke? {
@@ -1893,7 +1909,7 @@ fileprivate extension String {
18931909
let end = index(endIndex, offsetBy: -fromEnd)
18941910
return String(self[start..<end])
18951911
}
1896-
1912+
18971913
func slice(from: String, to: String) -> String? {
18981914
return (range(of: from)?.upperBound).flatMap { substringFrom in
18991915
(range(of: to, range: substringFrom..<endIndex)?.lowerBound).map { substringTo in
@@ -1924,16 +1940,20 @@ fileprivate class UserSpaceNode {
19241940
}
19251941

19261942
fileprivate class UserSpacePattern {
1943+
let viewBox: Rect
19271944
let content: Node
19281945
let bounds: Rect
19291946
let userSpace: Bool
19301947
let contentUserSpace: Bool
1948+
let position: Transform
19311949

1932-
init(content: Node, bounds: Rect, userSpace: Bool = false, contentUserSpace: Bool = true) {
1950+
init(content: Node, bounds: Rect, viewBox: Rect = Rect(x: 0, y: 0, w: 0, h: 0), userSpace: Bool = false, contentUserSpace: Bool = true, position: Transform = .identity) {
1951+
self.viewBox = viewBox
19331952
self.content = content
19341953
self.bounds = bounds
19351954
self.userSpace = userSpace
19361955
self.contentUserSpace = contentUserSpace
1956+
self.position = position
19371957
}
19381958
}
19391959

0 commit comments

Comments
 (0)