Add Typesetter

This commit is contained in:
Guille Gonzalez
2026-01-03 08:11:38 +01:00
parent 8e4db3cf0e
commit e26d7d01b5
7 changed files with 2911 additions and 8 deletions

View File

@@ -12,7 +12,10 @@ extension Math {
var lowerLimitGap: CGFloat = 0 { didSet { updateLowerLimitPosition() } } var lowerLimitGap: CGFloat = 0 { didSet { updateLowerLimitPosition() } }
var extraPadding: CGFloat = 0 var extraPadding: CGFloat = 0
init(nucleus: DisplayNode?, upperLimit: DisplayList?, lowerLimit: DisplayList?, limitShift: CGFloat, extraPadding: CGFloat) { init(
nucleus: DisplayNode?, upperLimit: DisplayList?, lowerLimit: DisplayList?,
limitShift: CGFloat, extraPadding: CGFloat
) {
self.upperLimit = upperLimit self.upperLimit = upperLimit
self.lowerLimit = lowerLimit self.lowerLimit = lowerLimit
self.nucleus = nucleus self.nucleus = nucleus
@@ -29,7 +32,8 @@ extension Math {
get { get {
guard let nucleus else { return 0 } guard let nucleus else { return 0 }
if let upperLimit { if let upperLimit {
return nucleus.ascent + extraPadding + upperLimit.ascent + upperLimitGap + upperLimit.descent return nucleus.ascent + extraPadding + upperLimit.ascent + upperLimitGap
+ upperLimit.descent
} }
return nucleus.ascent return nucleus.ascent
} }
@@ -40,7 +44,8 @@ extension Math {
get { get {
guard let nucleus else { return 0 } guard let nucleus else { return 0 }
if let lowerLimit { if let lowerLimit {
return nucleus.descent + extraPadding + lowerLimitGap + lowerLimit.descent + lowerLimit.ascent return nucleus.descent + extraPadding + lowerLimitGap + lowerLimit.descent
+ lowerLimit.ascent
} }
return nucleus.descent return nucleus.descent
} }

View File

@@ -9,6 +9,9 @@ extension Math {
var position: CGPoint = .zero var position: CGPoint = .zero
var range: NSRange = NSRange(location: 0, length: 0) var range: NSRange = NSRange(location: 0, length: 0)
var hasScript: Bool = false var hasScript: Bool = false
var textColor: PlatformColor?
var localTextColor: PlatformColor?
var localBackgroundColor: PlatformColor?
func bounds() -> CGRect { func bounds() -> CGRect {
CGRect(x: position.x, y: position.y - descent, width: width, height: ascent + descent) CGRect(x: position.x, y: position.y - descent, width: width, height: ascent + descent)

View File

@@ -19,6 +19,25 @@ extension Math {
self.range = range self.range = range
} }
func setDegree(_ degree: DisplayList?, fontMetrics: Math.FontMetrics) {
guard let degree else { return }
let kernBefore = fontMetrics.radicalKernBeforeDegree
let kernAfter = fontMetrics.radicalKernAfterDegree
let raise = fontMetrics.radicalDegreeBottomRaisePercent * (ascent - descent)
self.degree = degree
var shift = kernBefore + degree.width + kernAfter
if shift < 0 {
shift = 0
}
radicalShift = shift
degree.position = CGPoint(x: position.x + kernBefore, y: position.y + raise)
width = shift + (radicalGlyph?.width ?? 0) + (radicand?.width ?? 0)
updateRadicandPosition()
}
override var position: CGPoint { override var position: CGPoint {
didSet { updateRadicandPosition() } didSet { updateRadicandPosition() }
} }

View File

@@ -7,7 +7,9 @@ extension Math {
var font: Math.Font var font: Math.Font
var atoms: [Math.Atom] var atoms: [Math.Atom]
init(text: String, font: Math.Font, position: CGPoint = .zero, range: NSRange, atoms: [Math.Atom]) { init(
text: String, font: Math.Font, position: CGPoint = .zero, range: NSRange, atoms: [Math.Atom]
) {
self.text = text self.text = text
self.font = font self.font = font
self.atoms = atoms self.atoms = atoms

File diff suppressed because it is too large Load Diff

View File

@@ -7,3 +7,25 @@ import SwiftUI
typealias PlatformColor = NSColor typealias PlatformColor = NSColor
typealias PlatformBezierPath = NSBezierPath typealias PlatformBezierPath = NSBezierPath
#endif #endif
extension PlatformColor {
convenience init?(fromHexString hexString: String) {
self.init(hexString: hexString)
}
convenience init?(hexString: String) {
guard !hexString.isEmpty, hexString.hasPrefix("#") else { return nil }
var rgbValue = UInt64(0)
let scanner = Scanner(string: hexString)
scanner.charactersToBeSkipped = CharacterSet(charactersIn: "#")
guard scanner.scanHexInt64(&rgbValue) else { return nil }
self.init(
red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
alpha: 1.0
)
}
}

View File

@@ -1189,7 +1189,7 @@ struct ParserTests {
let str = testCase.0 let str = testCase.0
var error: Math.ParserError? = nil var error: Math.ParserError? = nil
let list = Math.Parser.build(fromString: str, error: &error) let list = Math.Parser.build(fromString: str, error: &error)
#expect(list == nil) #expect(list == nil)
#expect(error != nil) #expect(error != nil)
let num = testCase.1 let num = testCase.1
#expect(error?.code == num) #expect(error?.code == num)