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 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.lowerLimit = lowerLimit
self.nucleus = nucleus
@@ -29,7 +32,8 @@ extension Math {
get {
guard let nucleus else { return 0 }
if let upperLimit {
return nucleus.ascent + extraPadding + upperLimit.ascent + upperLimitGap + upperLimit.descent
return nucleus.ascent + extraPadding + upperLimit.ascent + upperLimitGap
+ upperLimit.descent
}
return nucleus.ascent
}
@@ -40,7 +44,8 @@ extension Math {
get {
guard let nucleus else { return 0 }
if let lowerLimit {
return nucleus.descent + extraPadding + lowerLimitGap + lowerLimit.descent + lowerLimit.ascent
return nucleus.descent + extraPadding + lowerLimitGap + lowerLimit.descent
+ lowerLimit.ascent
}
return nucleus.descent
}

View File

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

View File

@@ -19,6 +19,25 @@ extension Math {
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 {
didSet { updateRadicandPosition() }
}

View File

@@ -7,7 +7,9 @@ extension Math {
var font: Math.Font
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.font = font
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 PlatformBezierPath = NSBezierPath
#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
var error: Math.ParserError? = nil
let list = Math.Parser.build(fromString: str, error: &error)
#expect(list == nil)
#expect(list == nil)
#expect(error != nil)
let num = testCase.1
#expect(error?.code == num)
@@ -2301,7 +2301,7 @@ struct ParserTests {
let str = "\\dfrac{1}{2}"
var error: Math.ParserError? = nil
let list = Math.Parser.build(fromString: str, error: &error)
#expect(error == nil)
let unwrappedList = try #require(list)
#expect(unwrappedList.atoms.count == 1)
@@ -2336,7 +2336,7 @@ struct ParserTests {
let str = "\\tfrac{a}{b}"
var error: Math.ParserError? = nil
let list = Math.Parser.build(fromString: str, error: &error)
#expect(error == nil)
let unwrappedList = try #require(list)
#expect(unwrappedList.atoms.count == 1)
@@ -2370,7 +2370,7 @@ struct ParserTests {
let str = "y'=-\\dfrac{2}{x^{3}}"
var error: Math.ParserError? = nil
let list = Math.Parser.build(fromString: str, error: &error)
#expect(error == nil)
let unwrappedList = try #require(list)
#expect(unwrappedList.atoms.count >= 4)