Add font infrastructure
This commit is contained in:
114
Sources/SwiftUIMath/Internal/Font/FontRegistry.swift
Normal file
114
Sources/SwiftUIMath/Internal/Font/FontRegistry.swift
Normal file
@@ -0,0 +1,114 @@
|
||||
@preconcurrency import CoreGraphics
|
||||
@preconcurrency import CoreText
|
||||
import Foundation
|
||||
|
||||
extension Math {
|
||||
final class FontRegistry: Sendable {
|
||||
static let shared = FontRegistry()
|
||||
|
||||
private struct Cache {
|
||||
var graphicsFonts: [Font.Name: CGFont] = [:]
|
||||
var tables: [Font.Name: Table] = [:]
|
||||
let fonts = NSCache<KeyBox<Font>, CTFont>()
|
||||
}
|
||||
|
||||
private let cache = ReadWriteLockIsolated<Cache>(Cache())
|
||||
|
||||
func graphicsFont(named name: Font.Name) -> CGFont? {
|
||||
cache.withValue { cache in
|
||||
if let graphicsFont = cache.graphicsFonts[name] {
|
||||
return graphicsFont
|
||||
}
|
||||
|
||||
guard let (graphicsFont, _) = registerGraphicsFont(named: name, cache: &cache) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return graphicsFont
|
||||
}
|
||||
}
|
||||
|
||||
func table(named name: Font.Name) -> Table? {
|
||||
cache.withValue { cache in
|
||||
if let table = cache.tables[name] {
|
||||
return table
|
||||
}
|
||||
|
||||
guard let (_, table) = registerGraphicsFont(named: name, cache: &cache) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
}
|
||||
|
||||
func font(named name: Font.Name, size: CGFloat) -> CTFont? {
|
||||
cache.withValue { cache in
|
||||
let key = KeyBox(Font(name: name, size: size))
|
||||
|
||||
if let font = cache.fonts.object(forKey: key) {
|
||||
return font
|
||||
}
|
||||
|
||||
guard
|
||||
let graphicsFont = cache.graphicsFonts[name]
|
||||
?? registerGraphicsFont(named: name, cache: &cache)?.0
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let font = CTFontCreateWithGraphicsFont(graphicsFont, size, nil, nil)
|
||||
cache.fonts.setObject(font, forKey: key)
|
||||
|
||||
return font
|
||||
}
|
||||
}
|
||||
|
||||
private func registerGraphicsFont(
|
||||
named name: Font.Name,
|
||||
cache: inout Cache
|
||||
) -> (CGFont, Table)? {
|
||||
guard let graphicsFont = CGFont.named(name), let table = Table.named(name) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard CTFontManagerRegisterGraphicsFont(graphicsFont, nil) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
cache.graphicsFonts[name] = graphicsFont
|
||||
cache.tables[name] = table
|
||||
|
||||
return (graphicsFont, table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CGFont {
|
||||
fileprivate static func named(_ name: Math.Font.Name) -> CGFont? {
|
||||
guard
|
||||
let bundleURL = Bundle.module.url(forResource: "mathFonts", withExtension: "bundle"),
|
||||
let url = Bundle(url: bundleURL)?.url(forResource: name.rawValue, withExtension: "otf"),
|
||||
let data = try? Data(contentsOf: url),
|
||||
let dataProvider = CGDataProvider(data: data as CFData)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return CGFont(dataProvider)
|
||||
}
|
||||
}
|
||||
|
||||
extension Math.Table {
|
||||
fileprivate static func named(_ name: Math.Font.Name) -> Math.Table? {
|
||||
guard
|
||||
let bundleURL = Bundle.module.url(forResource: "mathFonts", withExtension: "bundle"),
|
||||
let url = Bundle(url: bundleURL)?.url(forResource: name.rawValue, withExtension: "plist"),
|
||||
let data = try? Data(contentsOf: url)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return try? PropertyListDecoder().decode(Math.Table.self, from: data)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user