-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from petersktang/main
Sunset MathTable, added MTFontV2, MTFontMathTableV2 and MathImage Thanks for your work on this.
- Loading branch information
Showing
10 changed files
with
464 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// | ||
// MTFontMathTableV2.swift | ||
// | ||
// | ||
// Created by Peter Tang on 15/9/2023. | ||
// | ||
|
||
import Foundation | ||
import CoreGraphics | ||
import CoreText | ||
|
||
internal class MTFontMathTableV2: MTFontMathTable { | ||
private let mathFont: MathFont | ||
private let fontSize: CGFloat | ||
private let unitsPerEm: UInt | ||
private let mTable: NSDictionary | ||
init(mathFont: MathFont, size: CGFloat) { | ||
self.mathFont = mathFont | ||
self.fontSize = size | ||
mTable = mathFont.mathTable() | ||
unitsPerEm = mathFont.ctFont(withSize: fontSize).unitsPerEm | ||
super.init(withFont: mathFont.mtfont(size: fontSize), mathTable: mTable) | ||
super._mathTable = nil | ||
// disable all possible access to _mathTable in superclass! | ||
} | ||
override var _mathTable: NSDictionary? { | ||
set { fatalError("\(#function) change to _mathTable \(mathFont.rawValue) not allowed.") } | ||
get { mTable } | ||
} | ||
override var muUnit: CGFloat { fontSize/18 } | ||
|
||
override func fontUnitsToPt(_ fontUnits:Int) -> CGFloat { | ||
CGFloat(fontUnits) * fontSize / CGFloat(unitsPerEm) | ||
} | ||
override func constantFromTable(_ constName: String) -> CGFloat { | ||
guard let consts = mTable[kConstants] as? NSDictionary, let val = consts[constName] as? NSNumber else { | ||
return .zero | ||
} | ||
return fontUnitsToPt(val.intValue) | ||
} | ||
override func percentFromTable(_ percentName: String) -> CGFloat { | ||
guard let consts = mTable[kConstants] as? NSDictionary, let val = consts[percentName] as? NSNumber else { | ||
return .zero | ||
} | ||
return CGFloat(val.floatValue) / 100 | ||
} | ||
/** Returns an Array of all the vertical variants of the glyph if any. If | ||
there are no variants for the glyph, the array contains the given glyph. */ | ||
override func getVerticalVariantsForGlyph(_ glyph: CGGlyph) -> [NSNumber?] { | ||
guard let variants = mTable[kVertVariants] as? NSDictionary else { return [] } | ||
return self.getVariantsForGlyph(glyph, inDictionary: variants) | ||
} | ||
/** Returns an Array of all the horizontal variants of the glyph if any. If | ||
there are no variants for the glyph, the array contains the given glyph. */ | ||
override func getHorizontalVariantsForGlyph(_ glyph: CGGlyph) -> [NSNumber?] { | ||
guard let variants = mTable[kHorizVariants] as? NSDictionary else { return [] } | ||
return self.getVariantsForGlyph(glyph, inDictionary:variants) | ||
} | ||
override func getVariantsForGlyph(_ glyph: CGGlyph, inDictionary variants: NSDictionary) -> [NSNumber?] { | ||
let font = mathFont.mtfont(size: fontSize) | ||
let glyphName = font.get(nameForGlyph: glyph) | ||
|
||
var glyphArray = [NSNumber]() | ||
let variantGlyphs = variants[glyphName] as? NSArray | ||
|
||
guard let variantGlyphs = variantGlyphs, variantGlyphs.count != .zero else { | ||
// There are no extra variants, so just add the current glyph to it. | ||
let glyph = font.get(glyphWithName: glyphName) | ||
glyphArray.append(NSNumber(value:glyph)) | ||
return glyphArray | ||
} | ||
for gvn in variantGlyphs { | ||
if let glyphVariantName = gvn as? String { | ||
let variantGlyph = font.get(glyphWithName: glyphVariantName) | ||
glyphArray.append(NSNumber(value:variantGlyph)) | ||
} | ||
} | ||
return glyphArray | ||
} | ||
/** Returns a larger vertical variant of the given glyph if any. | ||
If there is no larger version, this returns the current glyph. | ||
*/ | ||
override func getLargerGlyph(_ glyph: CGGlyph) -> CGGlyph { | ||
let font = mathFont.mtfont(size: fontSize) | ||
let glyphName = font.get(nameForGlyph: glyph) | ||
|
||
guard let variants = mTable[kVertVariants] as? NSDictionary, | ||
let variantGlyphs = variants[glyphName] as? NSArray, variantGlyphs.count != .zero else { | ||
// There are no extra variants, so just returnt the current glyph. | ||
return glyph | ||
} | ||
// Find the first variant with a different name. | ||
for gvn in variantGlyphs { | ||
if let glyphVariantName = gvn as? String, glyphVariantName != glyphName { | ||
let variantGlyph = font.get(glyphWithName: glyphVariantName) | ||
return variantGlyph | ||
} | ||
} | ||
// We did not find any variants of this glyph so return it. | ||
return glyph | ||
} | ||
/** Returns the italic correction for the given glyph if any. If there | ||
isn't any this returns 0. */ | ||
override func getItalicCorrection(_ glyph: CGGlyph) -> CGFloat { | ||
let font = mathFont.mtfont(size: fontSize) | ||
let glyphName = font.get(nameForGlyph: glyph) | ||
|
||
guard let italics = mTable[kItalic] as? NSDictionary, let val = italics[glyphName] as? NSNumber else { | ||
return .zero | ||
} | ||
// if val is nil, this returns 0. | ||
return fontUnitsToPt(val.intValue) | ||
} | ||
override func getTopAccentAdjustment(_ glyph: CGGlyph) -> CGFloat { | ||
let font = mathFont.mtfont(size: fontSize) | ||
let glyphName = font.get(nameForGlyph: glyph) | ||
|
||
guard let accents = mTable[kAccents] as? NSDictionary, let val = accents[glyphName] as? NSNumber else { | ||
// If no top accent is defined then it is the center of the advance width. | ||
var glyph = glyph | ||
var advances = CGSize.zero | ||
CTFontGetAdvancesForGlyphs(font.ctFont, .horizontal, &glyph, &advances, 1) | ||
return advances.width/2 | ||
} | ||
return fontUnitsToPt(val.intValue) | ||
} | ||
override func getVerticalGlyphAssembly(forGlyph glyph: CGGlyph) -> [GlyphPart] { | ||
let font = mathFont.mtfont(size: fontSize) | ||
let glyphName = font.get(nameForGlyph: glyph) | ||
|
||
guard let assemblyTable = mTable[kVertAssembly] as? NSDictionary, | ||
let assemblyInfo = assemblyTable[glyphName] as? NSDictionary, | ||
let parts = assemblyInfo[kAssemblyParts] as? NSArray else { | ||
// No vertical assembly defined for glyph | ||
// parts should always have been defined, but if it isn't return nil | ||
return [] | ||
} | ||
|
||
var rv = [GlyphPart]() | ||
for part in parts { | ||
guard let partInfo = part as? NSDictionary, | ||
let adv = partInfo["advance"] as? NSNumber, | ||
let end = partInfo["endConnector"] as? NSNumber, | ||
let start = partInfo["startConnector"] as? NSNumber, | ||
let ext = partInfo["extender"] as? NSNumber, | ||
let glyphName = partInfo["glyph"] as? String else { continue } | ||
let fullAdvance = fontUnitsToPt(adv.intValue) | ||
let endConnectorLength = fontUnitsToPt(end.intValue) | ||
let startConnectorLength = fontUnitsToPt(start.intValue) | ||
let isExtender = ext.boolValue | ||
let glyph = font.get(glyphWithName: glyphName) | ||
let part = GlyphPart(glyph: glyph, fullAdvance: fullAdvance, | ||
startConnectorLength: startConnectorLength, | ||
endConnectorLength: endConnectorLength, | ||
isExtender: isExtender) | ||
rv.append(part) | ||
} | ||
return rv | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// | ||
// MTFontV2.swift | ||
// | ||
// | ||
// Created by Peter Tang on 15/9/2023. | ||
// | ||
|
||
import Foundation | ||
import CoreGraphics | ||
import CoreText | ||
|
||
extension MathFont { | ||
public func mtfont(size: CGFloat) -> MTFontV2 { | ||
MTFontV2(font: self, size: size) | ||
} | ||
} | ||
public final class MTFontV2: MTFont { | ||
let font: MathFont | ||
let size: CGFloat | ||
private lazy var _cgFont: CGFont = { | ||
font.cgFont() | ||
}() | ||
private lazy var _ctFont: CTFont = { | ||
font.ctFont(withSize: size) | ||
}() | ||
private lazy var _mathTab = MTFontMathTableV2(mathFont: font, size: size) | ||
init(font: MathFont = .latinModernFont, size: CGFloat) { | ||
self.font = font | ||
self.size = size | ||
|
||
super.init() | ||
|
||
super.defaultCGFont = nil | ||
super.ctFont = nil | ||
super.mathTable = nil | ||
super.rawMathTable = nil | ||
} | ||
override var defaultCGFont: CGFont! { | ||
set { fatalError("\(#function): change to \(font.fontName) not allowed.") } | ||
get { _cgFont } | ||
} | ||
override var ctFont: CTFont! { | ||
set { fatalError("\(#function): change to \(font.fontName) not allowed.") } | ||
get { _ctFont } | ||
} | ||
override var mathTable: MTFontMathTable? { | ||
set { fatalError("\(#function): change to \(font.rawValue) not allowed.") } | ||
get { _mathTab } | ||
} | ||
override var rawMathTable: NSDictionary? { | ||
set { fatalError("\(#function): change to \(font.rawValue) not allowed.") } | ||
get { fatalError("\(#function): access to \(font.rawValue) not allowed.") } | ||
} | ||
public override func copy(withSize size: CGFloat) -> MTFont { | ||
MTFontV2(font: font, size: size) | ||
} | ||
} |
Oops, something went wrong.