Skip to content

Commit a8baa6d

Browse files
authored
Merge pull request #83 from Alex293/feature/accessibility-and-weight-support
[WIP] add dynamic type and weight support
2 parents 8c84e10 + 820ec74 commit a8baa6d

File tree

2 files changed

+91
-70
lines changed

2 files changed

+91
-70
lines changed

Sources/ZMarkupParser/Core/MarkupStyle/MarkupStyleFont.swift

Lines changed: 89 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public struct MarkupStyleFont: MarkupStyleItem {
2424
}
2525
public enum FontFamily {
2626
case familyNames([String])
27-
27+
2828
#if canImport(UIKit)
2929
func getFont(size: CGFloat) -> UIFont? {
3030
switch self {
@@ -53,106 +53,105 @@ public struct MarkupStyleFont: MarkupStyleItem {
5353
}
5454
public enum FontWeightStyle: String, CaseIterable {
5555
case ultraLight, light, thin, regular, medium, semibold, bold, heavy, black
56-
56+
5757
public init?(rawValue: String) {
5858
guard let matchedStyle = FontWeightStyle.allCases.first(where: { style in
5959
return rawValue.lowercased().contains(style.rawValue)
6060
}) else {
6161
return nil
6262
}
63-
63+
6464
self = matchedStyle
6565
}
66-
66+
6767
#if canImport(UIKit)
6868
init?(font: UIFont) {
6969
if let traits = font.fontDescriptor.fontAttributes[.traits] as? [UIFontDescriptor.TraitKey: Any], let weight = traits[.weight] as? UIFont.Weight {
7070
self = weight.convertFontWeightStyle()
7171
return
72-
} else if font.fontDescriptor.symbolicTraits.contains(.traitBold) {
73-
self = .bold
74-
return
7572
} else if let weightName = font.fontDescriptor.object(forKey: .face) as? String, let weight = Self.init(rawValue: weightName) {
7673
self = weight
7774
return
7875
}
79-
76+
8077
return nil
8178
}
8279
#elseif canImport(AppKit)
8380
init?(font: NSFont) {
8481
if let traits = font.fontDescriptor.fontAttributes[.traits] as? [NSFontDescriptor.TraitKey: Any], let weight = traits[.weight] as? NSFont.Weight {
8582
self = weight.convertFontWeightStyle()
8683
return
87-
} else if font.fontDescriptor.symbolicTraits.contains(.bold) {
88-
self = .bold
89-
return
9084
} else if let weightName = font.fontDescriptor.object(forKey: .face) as? String, let weight = Self.init(rawValue: weightName) {
9185
self = weight
9286
return
9387
}
94-
88+
9589
return nil
9690
}
9791
#endif
9892
}
99-
93+
10094
public var size: CGFloat?
10195
public var weight: FontWeight?
10296
public var italic: Bool?
97+
public var bold: Bool?
10398
public var familyName: FontFamily?
104-
105-
public init(size: CGFloat? = nil, weight: FontWeight? = nil, italic: Bool? = nil, familyName: FontFamily? = nil) {
99+
100+
public init(size: CGFloat? = nil, weight: FontWeight? = nil, bold: Bool? = nil, italic: Bool? = nil, familyName: FontFamily? = nil) {
106101
self.size = size
107102
self.weight = weight
103+
self.bold = bold
108104
self.italic = italic
109105
self.familyName = familyName
110106
}
111-
107+
112108
mutating func fillIfNil(from: MarkupStyleFont?) {
113109
self.size = self.size ?? from?.size
114110
self.weight = self.weight ?? from?.weight
115111
self.italic = self.italic ?? from?.italic
112+
self.bold = self.bold ?? from?.bold
116113
self.familyName = self.familyName ?? from?.familyName
117114
}
118-
115+
119116
func isNil() -> Bool {
120117
return !([size,
121-
weight,
122-
italic,
123-
familyName] as [Any?]).contains(where: { $0 != nil})
118+
weight,
119+
italic,
120+
bold,
121+
familyName] as [Any?]).contains(where: { $0 != nil})
124122
}
125-
123+
126124
func sizeOf(string: String) -> CGSize? {
127125
guard let font = getFont() else {
128126
return nil
129127
}
130-
128+
131129
return (string as NSString).size(withAttributes: [.font: font])
132130
}
133131
}
134132

135133
#if canImport(UIKit)
136134

137135
extension MarkupStyleFont {
138-
136+
139137
public init(_ font: UIFont) {
140138
self.size = font.pointSize
141139
self.italic = font.fontDescriptor.symbolicTraits.contains(.traitItalic)
140+
self.bold = font.fontDescriptor.symbolicTraits.contains(.traitBold)
142141
if let fontWeight = FontWeightStyle.init(font: font) {
143142
self.weight = FontWeight.style(fontWeight)
144143
}
145144
self.familyName = .familyNames([font.familyName])
146145
}
147-
146+
148147
func getFont() -> UIFont? {
149148
guard !isNil() else { return nil }
150-
151-
var traits: [UIFontDescriptor.SymbolicTraits] = []
152-
149+
150+
var traits: UIFontDescriptor.SymbolicTraits = []
151+
153152
let size = (self.size ?? MarkupStyle.default.font.size) ?? UIFont.systemFontSize
154153
let weight = self.weight?.convertToUIFontWeight() ?? .regular
155-
154+
156155
// There is no direct method in UIFont to specify the font family, italic and weight together.
157156

158157
let font: UIFont
@@ -163,28 +162,16 @@ extension MarkupStyleFont {
163162
// System Font
164163
font = UIFont.systemFont(ofSize: size, weight: weight)
165164
}
166-
167-
if weight.rawValue >= UIFont.Weight.medium.rawValue {
168-
traits.append(.traitBold)
165+
166+
if bold == true {
167+
traits.insert(.traitBold)
169168
}
170-
169+
171170
if let italic = self.italic, italic {
172-
traits.append(.traitItalic)
173-
}
174-
175-
if traits.isEmpty {
176-
return font
177-
} else {
178-
return withTraits(font: font, traits: traits)
171+
traits.insert(.traitItalic)
179172
}
180-
}
181-
182-
private func withTraits(font: UIFont, traits: [UIFontDescriptor.SymbolicTraits]) -> UIFont {
183-
guard let descriptor = font.fontDescriptor
184-
.withSymbolicTraits(UIFontDescriptor.SymbolicTraits(traits)) else {
185-
return font
186-
}
187-
return UIFont(descriptor: descriptor, size: font.pointSize)
173+
174+
return font.with(weight: weight, symbolicTraits: traits)
188175
}
189176
}
190177

@@ -245,6 +232,27 @@ private extension UIFont.Weight {
245232
}
246233
}
247234

235+
private extension UIFont {
236+
237+
/// Returns a font object that is the same as the receiver but which has the specified weight and symbolic traits
238+
func with(weight: Weight, symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont {
239+
240+
var mergedsymbolicTraits = fontDescriptor.symbolicTraits
241+
mergedsymbolicTraits.formUnion(symbolicTraits)
242+
243+
var traits = fontDescriptor.fontAttributes[.traits] as? [UIFontDescriptor.TraitKey: Any] ?? [:]
244+
traits[.weight] = weight
245+
traits[.symbolic] = mergedsymbolicTraits.rawValue
246+
247+
var fontAttributes: [UIFontDescriptor.AttributeName: Any] = [:]
248+
fontAttributes[.family] = familyName
249+
fontAttributes[.traits] = traits
250+
251+
let font = UIFont(descriptor: UIFontDescriptor(fontAttributes: fontAttributes), size: pointSize)
252+
return UIFontMetrics.default.scaledFont(for: font)
253+
}
254+
}
255+
248256
#elseif canImport(AppKit)
249257

250258
extension MarkupStyleFont {
@@ -258,15 +266,15 @@ extension MarkupStyleFont {
258266
self.familyName = .familyNames([familyName])
259267
}
260268
}
261-
269+
262270
func getFont() -> NSFont? {
263271
guard !isNil() else { return nil }
264-
265-
var traits: [NSFontDescriptor.SymbolicTraits] = []
266-
272+
273+
var traits: NSFontDescriptor.SymbolicTraits = []
274+
267275
let size = (self.size ?? MarkupStyle.default.font.size) ?? NSFont.systemFontSize
268276
let weight = self.weight?.convertToUIFontWeight() ?? .regular
269-
277+
270278
// There is no direct method in UIFont to specify the font family, italic and weight together.
271279

272280
let font: NSFont
@@ -277,25 +285,16 @@ extension MarkupStyleFont {
277285
// System Font
278286
font = NSFont.systemFont(ofSize: size, weight: weight)
279287
}
280-
281-
if weight.rawValue >= NSFont.Weight.medium.rawValue {
282-
traits.append(.bold)
288+
289+
if bold == true {
290+
traits.insert(.bold)
283291
}
284-
292+
285293
if let italic = self.italic, italic {
286-
traits.append(.italic)
287-
}
288-
289-
if traits.isEmpty {
290-
return font
291-
} else {
292-
return withTraits(font: font, traits: traits)
294+
traits.insert(.italic)
293295
}
294-
}
295-
296-
private func withTraits(font: NSFont, traits: [NSFontDescriptor.SymbolicTraits]) -> NSFont {
297-
let descriptor = font.fontDescriptor.withSymbolicTraits(NSFontDescriptor.SymbolicTraits(traits))
298-
return NSFont(descriptor: descriptor, size: font.pointSize) ?? font
296+
297+
return font.with(weight: weight, symbolicTraits: traits)
299298
}
300299
}
301300

@@ -356,4 +355,26 @@ private extension NSFont.Weight {
356355
}
357356
}
358357

358+
private extension NSFont {
359+
360+
/// Returns a font object that is the same as the receiver but which has the specified weight and symbolic traits
361+
func with(weight: Weight, symbolicTraits: NSFontDescriptor.SymbolicTraits) -> NSFont {
362+
363+
var mergedsymbolicTraits = fontDescriptor.symbolicTraits
364+
mergedsymbolicTraits.formUnion(symbolicTraits)
365+
366+
var traits = fontDescriptor.fontAttributes[.traits] as? [NSFontDescriptor.TraitKey: Any] ?? [:]
367+
traits[.weight] = weight
368+
traits[.symbolic] = mergedsymbolicTraits.rawValue
369+
370+
var fontAttributes: [NSFontDescriptor.AttributeName: Any] = [:]
371+
fontAttributes[.family] = familyName
372+
fontAttributes[.traits] = traits
373+
374+
let font = NSFont(descriptor: NSFontDescriptor(fontAttributes: fontAttributes), size: pointSize)
375+
// return UIFontMetrics.default.scaledFont(for: font)
376+
return font ?? self
377+
}
378+
}
379+
359380
#endif

Tests/ZMarkupParserTests/Core/MarkupStyleFontTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import AppKit
1717
final class MarkupStyleFontTests: XCTestCase {
1818
func testInit() {
1919
#if canImport(UIKit)
20-
let markupStyleFont = MarkupStyleFont(UIFont.boldSystemFont(ofSize: 16))
20+
let markupStyleFont = MarkupStyleFont(UIFont.systemFont(ofSize: 16, weight: .bold))
2121
if case let .style(weight) = markupStyleFont.weight, weight == .bold {
2222
// Success
2323
XCTAssertEqual(markupStyleFont.size, 16)
@@ -161,7 +161,7 @@ final class MarkupStyleFontTests: XCTestCase {
161161

162162
XCTAssertEqual(resultMarkupStyleFont.size, markupStyleFont.size!)
163163
if case let .style(weight) = resultMarkupStyleFont.weight {
164-
XCTAssertEqual(weight, .bold)
164+
XCTAssertEqual(weight, .heavy)
165165
} else {
166166
XCTFail()
167167
}

0 commit comments

Comments
 (0)