88
99import Cairo
1010import CCairo
11- import CFontConfig
11+ import FontConfig
1212import Foundation
1313#if os(macOS)
1414import struct CoreGraphics. CGAffineTransform
@@ -34,7 +34,7 @@ public struct CGFont {
3434
3535 // MARK: - Initialization
3636
37- public init ? ( name: String ) {
37+ public init ? ( name: String , configuration : FontConfiguration = . current ) {
3838
3939 if let cachedFont = CGFont . cache [ name] {
4040
@@ -43,10 +43,11 @@ public struct CGFont {
4343 } else {
4444
4545 // create new font
46- guard let ( fontConfigPattern, family) = FcPattern ( name: name)
46+ guard let pattern = FontConfig . Pattern ( cgFont: name, configuration: configuration) ,
47+ let family = pattern. family
4748 else { return nil }
4849
49- let face = FontFace ( fontConfigPattern : fontConfigPattern )
50+ let face = FontFace ( pattern : pattern )
5051
5152 let options = FontOptions ( )
5253 options. hintMetrics = . off
@@ -147,93 +148,59 @@ public extension CGFont {
147148 }
148149}
149150
150- // MARK: - Private
151+ // MARK: - Font Config Pattern
151152
152- /// Initialize a pointer to a `FcPattern` object created from the specified PostScript font name.
153- internal func FcPattern( name: String ) -> ( pointer: OpaquePointer , family: String ) ? {
153+ internal extension FontConfig . Pattern {
154154
155- guard let pattern = FcPatternCreate ( )
156- else { return nil }
157-
158- /// hacky way to cleanup, `defer` will copy initial value of `Bool` so this is needed.
159- /// ARC will cleanup for us
160- final class ErrorCleanup {
155+ convenience init ? ( cgFont name: String , configuration: FontConfiguration = . current) {
156+ self . init ( )
161157
162- var shouldCleanup = true
158+ let separator : Character = " - "
163159
164- let cleanup : ( ) -> ( )
160+ let traits : String ?
165161
166- deinit { if shouldCleanup { cleanup ( ) } }
162+ let family : String
167163
168- init ( cleanup: @escaping ( ) -> ( ) ) {
169-
170- self . cleanup = cleanup
171- }
172- }
173-
174- let cleanup = ErrorCleanup ( cleanup: { FcPatternDestroy ( pattern) } )
175-
176- let separator : Character = " - "
177-
178- let traits : String ?
179-
180- let family : String
181-
182- let components = name. split ( separator: separator, maxSplits: 2 , omittingEmptySubsequences: true )
183-
184- if components. count == 2 {
185- family = String ( components [ 0 ] )
186- traits = String ( components [ 1 ] )
187- } else {
188- family = name
189- traits = nil
190- }
191-
192- guard FcPatternAddString ( pattern, FC_FAMILY, family) != 0
193- else { return nil }
194-
195- // FontConfig assumes Medium Roman Regular, add / replace additional traits
196- if let traits = traits {
164+ let components = name. split ( separator: separator, maxSplits: 2 , omittingEmptySubsequences: true )
197165
198- if traits. contains ( " Bold " ) {
199-
200- guard FcPatternAddInteger ( pattern, FC_WEIGHT, FC_WEIGHT_BOLD) != 0
201- else { return nil }
166+ if components. count == 2 {
167+ family = String ( components [ 0 ] )
168+ traits = String ( components [ 1 ] )
169+ } else {
170+ family = name
171+ traits = nil
202172 }
203173
204- if traits. contains ( " Italic " ) {
205-
206- guard FcPatternAddInteger ( pattern, FC_SLANT, FC_SLANT_ITALIC) != 0
207- else { return nil }
208- }
174+ self . family = family
175+ assert ( self . family == family)
209176
210- if traits. contains ( " Oblique " ) {
177+ // FontConfig assumes Medium Roman Regular, add / replace additional traits
178+ if let traits = traits {
211179
212- guard FcPatternAddInteger ( pattern, FC_SLANT, FC_SLANT_OBLIQUE) != 0
213- else { return nil }
214- }
215-
216- if traits. contains ( " Condensed " ) {
180+ if traits. contains ( " Bold " ) {
181+ self . weight = . bold
182+ }
217183
218- guard FcPatternAddInteger ( pattern, FC_WIDTH, FC_WIDTH_CONDENSED) != 0
219- else { return nil }
184+ if traits. contains ( " Italic " ) {
185+ self . slant = . italic
186+ }
187+
188+ if traits. contains ( " Oblique " ) {
189+ self . slant = . oblique
190+ }
191+
192+ if traits. contains ( " Condensed " ) {
193+ self . width = . condensed
194+ }
220195 }
196+
197+ guard configuration. substitute ( pattern: self , kind: FcMatchPattern)
198+ else { return nil }
199+
200+ self . defaultSubstitutions ( )
201+
202+ guard configuration. match ( self ) != nil
203+ else { return nil }
204+
221205 }
222-
223- let matchPattern = FcMatchKind ( rawValue: 0 ) // FcMatchPattern
224-
225- guard FcConfigSubstitute ( nil , pattern, matchPattern) != 0
226- else { return nil }
227-
228- FcDefaultSubstitute ( pattern)
229-
230- var result = FcResult ( 0 )
231-
232- guard FcFontMatch ( nil , pattern, & result) != nil
233- else { return nil }
234-
235- // success
236- cleanup. shouldCleanup = false
237-
238- return ( pattern, family)
239206}
0 commit comments