mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
88 lines
2.6 KiB
Swift
88 lines
2.6 KiB
Swift
#if os(iOS)
|
|
import CoreText
|
|
import UIKit
|
|
|
|
extension UIFont {
|
|
func withFontFeatureSettings(_ value: String) -> UIFont {
|
|
var featureSettings: [[UIFontDescriptor.FeatureKey: Int]] = featureSettings ?? [[:]]
|
|
value.split(separator: ",")
|
|
.compactMap { Feature($0.trimmingCharacters(in: [" "])) }
|
|
.forEach { featureSettings.setFeature($0) }
|
|
|
|
var attributes = fontDescriptor.fontAttributes
|
|
attributes.removeValue(forKey: .featureSettings)
|
|
let descriptor = UIFontDescriptor(fontAttributes: attributes)
|
|
.addingAttributes([.featureSettings: featureSettings])
|
|
return UIFont(descriptor: descriptor, size: 0.0)
|
|
}
|
|
|
|
var featureSettings: [[UIFontDescriptor.FeatureKey: Int]]? {
|
|
fontDescriptor.fontAttributes
|
|
.first { $0.key == .featureSettings }?
|
|
.value as? [[UIFontDescriptor.FeatureKey: Int]]
|
|
}
|
|
}
|
|
|
|
extension [[UIFontDescriptor.FeatureKey: Int]] {
|
|
fileprivate mutating func setFeature(_ feature: Feature) {
|
|
let featureDict = [
|
|
UIFontDescriptor.FeatureKey.featureIdentifier: feature.type,
|
|
UIFontDescriptor.FeatureKey.typeIdentifier: feature.selector,
|
|
]
|
|
if feature.isEnabled {
|
|
append(featureDict)
|
|
} else {
|
|
removeAll { $0 == featureDict }
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct Feature {
|
|
let type: Int
|
|
let selector: Int
|
|
let isEnabled: Bool
|
|
|
|
init?(_ value: String) {
|
|
let items = value.split(separator: " ")
|
|
let count = items.count
|
|
if count == 0 || count > 2 {
|
|
DivKitLogger.error("Invalid font feature: \(value)")
|
|
return nil
|
|
}
|
|
|
|
let rawName = items[0]
|
|
guard rawName.starts(with: "'") || rawName.starts(with: "\"") else {
|
|
DivKitLogger.error("Invalid font feature: \(value)")
|
|
return nil
|
|
}
|
|
let name = rawName.trimmingCharacters(in: ["'", "\""])
|
|
guard let params = featureParams[name] else {
|
|
DivKitLogger.error("Unknown font feature: \(name)")
|
|
return nil
|
|
}
|
|
|
|
type = params.0
|
|
selector = params.1
|
|
|
|
if count == 1 {
|
|
isEnabled = true
|
|
} else {
|
|
let state = items[1].lowercased()
|
|
isEnabled = state == "on" || state == "1"
|
|
}
|
|
}
|
|
}
|
|
|
|
private let featureParams: [String: (Int, Int)] = [
|
|
"c2sc": (kUpperCaseType, kUpperCaseSmallCapsSelector),
|
|
"frac": (kFractionsType, kDiagonalFractionsSelector),
|
|
"lnum": (kNumberCaseType, kUpperCaseNumbersSelector),
|
|
"ordn": (kVerticalPositionType, kOrdinalsSelector),
|
|
"pnum": (kNumberSpacingType, kProportionalNumbersSelector),
|
|
"smcp": (kLowerCaseType, kLowerCaseSmallCapsSelector),
|
|
"subs": (kVerticalPositionType, kInferiorsSelector),
|
|
"sups": (kVerticalPositionType, kSuperiorsSelector),
|
|
"tnum": (kNumberSpacingType, kMonospacedNumbersSelector),
|
|
]
|
|
#endif
|