From fad14cfa3b8c6e61ca9ba0742e71367f250e68cc Mon Sep 17 00:00:00 2001 From: Michael Griebling Date: Sat, 14 Jan 2023 15:30:44 -0500 Subject: [PATCH] Working on typesetting test failures. --- .../SwiftMathRender/MathRender/MTFont.swift | 6 +- .../MathRender/MTFontMathTable.swift | 10 +- .../MathRender/MTMathList.swift | 28 ++- .../MathRender/MTMathListDisplay.swift | 24 ++- .../MathRender/MTTypesetter.swift | 198 +++++++----------- .../MTTypesetterTests.swift | 144 ++++++------- 6 files changed, 187 insertions(+), 223 deletions(-) diff --git a/Sources/SwiftMathRender/MathRender/MTFont.swift b/Sources/SwiftMathRender/MathRender/MTFont.swift index e82316a..63f20d0 100644 --- a/Sources/SwiftMathRender/MathRender/MTFont.swift +++ b/Sources/SwiftMathRender/MathRender/MTFont.swift @@ -64,12 +64,12 @@ public class MTFont { } func get(nameForGlyph glyph:CGGlyph) -> String { - let name = self.defaultCGFont.name(for: glyph) - return name! as String + let name = defaultCGFont.name(for: glyph) as? String + return name! } func get(glyphWithName name:String) -> CGGlyph { - return self.defaultCGFont.getGlyphWithGlyphName(name: name as CFString) + return defaultCGFont.getGlyphWithGlyphName(name: name as CFString) } var fontSize:CGFloat { diff --git a/Sources/SwiftMathRender/MathRender/MTFontMathTable.swift b/Sources/SwiftMathRender/MathRender/MTFontMathTable.swift index 0ffedf9..0cc0c6b 100644 --- a/Sources/SwiftMathRender/MathRender/MTFontMathTable.swift +++ b/Sources/SwiftMathRender/MathRender/MTFontMathTable.swift @@ -44,7 +44,7 @@ class GlyphPart { class MTFontMathTable { // The font for this math table. - weak var font:MTFont? // @property (nonatomic, readonly, weak) MTFont* font; + var font:MTFont? // @property (nonatomic, readonly, weak) MTFont* font; var _unitsPerEm: UInt var _fontSize: CGFloat @@ -62,7 +62,7 @@ class MTFontMathTable { init(withFont font: MTFont?, mathTable:NSDictionary) { assert(font != nil, "font has nil value") assert(font!.ctFont != nil, "font.ctFont has nil value") - self.font = font; + self.font = font // do domething with font _unitsPerEm = UInt(CTFontGetUnitsPerEm(font!.ctFont)) _fontSize = font!.fontSize; @@ -202,12 +202,12 @@ class MTFontMathTable { } func getVariantsForGlyph(_ glyph: CGGlyph, inDictionary variants:NSDictionary?) -> [NSNumber?] { - let glyphName = self.font?.get(nameForGlyph: glyph) - let variantGlyphs = variants![glyphName!] as! NSArray? + let glyphName = self.font!.get(nameForGlyph: glyph) + let variantGlyphs = variants![glyphName] as! NSArray? let glyphArray = NSMutableArray(capacity: variantGlyphs!.count) if variantGlyphs == nil { // There are no extra variants, so just add the current glyph to it. - let glyph = self.font?.get(glyphWithName: glyphName!) + let glyph = self.font!.get(glyphWithName: glyphName) glyphArray.add(glyph as Any) return glyphArray as! [NSNumber?] } diff --git a/Sources/SwiftMathRender/MathRender/MTMathList.swift b/Sources/SwiftMathRender/MathRender/MTMathList.swift index 3de9f36..3d473a4 100644 --- a/Sources/SwiftMathRender/MathRender/MTMathList.swift +++ b/Sources/SwiftMathRender/MathRender/MTMathList.swift @@ -129,11 +129,11 @@ public class MTMathAtom: NSObject { } } public var nucleus: String = "" - public var childAtoms = [MTMathAtom]() // atoms that fused to create this one + // public var childAtoms = [MTMathAtom]() // atoms that fused to create this one public var indexRange = NSRange(location: 0, length: 0) // indexRange in list that this atom tracks: var fontStyle: MTFontStyle = .defaultStyle - var fusedAtoms: MTMathList? + var fusedAtoms = [MTMathAtom]() // atoms that fused to create this one init(_ atom:MTMathAtom?) { guard let atom = atom else { return } @@ -143,8 +143,8 @@ public class MTMathAtom: NSObject { self.superScript = MTMathList(atom.superScript) self.indexRange = atom.indexRange self.fontStyle = atom.fontStyle - self.childAtoms = [MTMathAtom](atom.childAtoms) - self.fusedAtoms = MTMathList(atom.fusedAtoms) + // self.childAtoms = [MTMathAtom](atom.childAtoms) + self.fusedAtoms = atom.fusedAtoms } override init() { } @@ -239,19 +239,17 @@ public class MTMathAtom: NSObject { assert(self.subScript == nil, "Cannot fuse into an atom which has a subscript: \(self)"); assert(self.superScript == nil, "Cannot fuse into an atom which has a superscript: \(self)"); assert(atom.type == self.type, "Only atoms of the same type can be fused. \(self), \(atom)"); - guard self.subScript == nil, - self.superScript == nil, - self.type == atom.type - else { - print("Can't fuse these 2 atoms") - return - } + guard self.subScript == nil, self.superScript == nil, self.type == atom.type + else { print("Can't fuse these 2 atoms"); return } - self.childAtoms.append(self) - if atom.childAtoms.count > 0 { - self.childAtoms += atom.childAtoms + // Update the fused atoms list + if self.fusedAtoms.isEmpty { + self.fusedAtoms.append(MTMathAtom(self)) + } + if atom.fusedAtoms.count > 0 { + self.fusedAtoms.append(contentsOf: atom.fusedAtoms) } else { - self.childAtoms.append(atom) + self.fusedAtoms.append(atom) } // Update nucleus: diff --git a/Sources/SwiftMathRender/MathRender/MTMathListDisplay.swift b/Sources/SwiftMathRender/MathRender/MTMathListDisplay.swift index 375c35b..31170c8 100644 --- a/Sources/SwiftMathRender/MathRender/MTMathListDisplay.swift +++ b/Sources/SwiftMathRender/MathRender/MTMathListDisplay.swift @@ -33,7 +33,7 @@ protocol DownShift { // MARK: - MTDisplay /// The base class for rendering a math equation. -class MTDisplay { +class MTDisplay:NSObject { // needed for isIos6Supported() func above static var initialized = false @@ -50,7 +50,6 @@ class MTDisplay { } } - /// Gets the bounding rectangle for the MTDisplay func displayBounds() -> CGRect { return CGRectMake(self.position.x, self.position.y - self.descent, self.width, self.ascent + self.descent) @@ -117,7 +116,11 @@ class MTCTLineDisplay : MTDisplay { var line:CTLine! /// The attributed string used to generate the CTLineRef. Note setting this does not reset the dimensions of /// the display. So set only when - var attributedString:NSAttributedString? + var attributedString:NSAttributedString? { + didSet { + line = CTLineCreateWithAttributedString(attributedString!) + } + } /// An array of MTMathAtoms that this CTLine displays. Used for indexing back into the MTMathList var atoms = [MTMathAtom]() @@ -126,6 +129,7 @@ class MTCTLineDisplay : MTDisplay { super.init() self.position = position self.attributedString = attrString + self.line = CTLineCreateWithAttributedString(attrString!) self.range = range self.atoms = atoms // We can't use typographic bounds here as the ascent and descent returned are for the font and not for the line. @@ -142,10 +146,10 @@ class MTCTLineDisplay : MTDisplay { } } - func set(attrString: NSAttributedString?) { - attributedString = attrString - line = CTLineCreateWithAttributedString(attributedString!) - } +// func set(attrString: NSAttributedString?) { +// attributedString = attrString +// line = CTLineCreateWithAttributedString(attributedString!) +// } func set(textColor:MTColor) { self.textColor = textColor @@ -219,7 +223,7 @@ class MTMathListDisplay : MTDisplay { super.init() self.subDisplays = displays self.position = CGPoint.zero - self.type = .regular //kMTLinePositionRegular; + self.type = .regular self.index = NSNotFound self.range = range self.recomputeDimensions() @@ -623,8 +627,8 @@ class MTLargeOpLimitsDisplay : MTDisplay { self.lowerLimit = lowerLimit; self.nucleus = nucleus; - var maxWidth = max(nucleus!.width, upperLimit!.width); - maxWidth = max(maxWidth, lowerLimit!.width); + var maxWidth = max(nucleus!.width, upperLimit?.width ?? 0) + maxWidth = max(maxWidth, lowerLimit?.width ?? 0) self.limitShift = limitShift; self.upperLimitGap = 0; diff --git a/Sources/SwiftMathRender/MathRender/MTTypesetter.swift b/Sources/SwiftMathRender/MathRender/MTTypesetter.swift index 0769875..ef31c0c 100644 --- a/Sources/SwiftMathRender/MathRender/MTTypesetter.swift +++ b/Sources/SwiftMathRender/MathRender/MTTypesetter.swift @@ -9,7 +9,7 @@ import Foundation import CoreGraphics import CoreText -// Mark: - Inter Element Spacing +// MARK: - - Inter Element Spacing enum InterElementSpaceType : Int { case invalid = -1 @@ -20,10 +20,10 @@ enum InterElementSpaceType : Int { case nsThick } -var interElementSpaceArray:[[InterElementSpaceType]]? = nil +var interElementSpaceArray = [[InterElementSpaceType]]() func getInterElementSpaces() -> [[InterElementSpaceType]] { - if interElementSpaceArray == nil { + if interElementSpaceArray.isEmpty { interElementSpaceArray = // ordinary operator binary relation open close punct fraction [ [.none, .thin, .nsMedium, .nsThick, .none, .none, .none, .nsThin], // ordinary @@ -34,14 +34,14 @@ func getInterElementSpaces() -> [[InterElementSpaceType]] { [.none, .thin, .nsMedium, .nsThick, .none, .none, .none, .nsThin], // close [.nsThin, .nsThin, .invalid, .nsThin, .nsThin, .nsThin, .nsThin, .nsThin], // punct [.nsThin, .thin, .nsMedium, .nsThick, .nsThin, .none, .nsThin, .nsThin], // fraction - [.nsMedium, .nsThin, .nsMedium, .nsThick, .none, .none, .none, .nsThin]] // radical + [.nsMedium, .nsThin, .nsMedium, .nsThick, .none, .none, .none, .nsThin]] // radical } - return interElementSpaceArray! + return interElementSpaceArray } // Get's the index for the given type. If row is true, the index is for the row (i.e. left element) otherwise it is for the column (right element) -func getInterElementSpaceArrayIndexForType(_ type:MTMathAtomType, row:Bool) -> UInt { +func getInterElementSpaceArrayIndexForType(_ type:MTMathAtomType, row:Bool) -> Int { switch type { case .ordinary, .placeholder: // A placeholder is treated as ordinary return 0 @@ -61,22 +61,22 @@ func getInterElementSpaceArrayIndexForType(_ type:MTMathAtomType, row:Bool) -> U .inner: return 7; case .radical: - if (row) { + if row { // Radicals have inter element spaces only when on the left side. // Note: This is a departure from latex but we don't want \sqrt{4}4 to look weird so we put a space in between. // They have the same spacing as ordinary except with ordinary. return 8; } else { assert(false, "Interelement space undefined for radical on the right. Treat radical as ordinary.") - return UInt.max + return Int.max } default: assert(false, "Interelement space undefined for type \(type)") - return UInt.max + return Int.max } } -// Mark: - Italics +// MARK: - - Italics // mathit func getItalicized(_ ch:Character) -> UTF32Char { var unicode = ch.utf32Char @@ -296,38 +296,25 @@ func styleCharacter(_ ch:Character, fontStyle:MTFontStyle) -> UTF32Char { switch fontStyle { case .defaultStyle: return getDefaultStyle(ch); - case .roman: return ch.utf32Char - case .bold: return getBold(ch); - case .italic: return getItalicized(ch); - case .boldItalic: return getBoldItalic(ch); - case .caligraphic: return getCaligraphic(ch); - case .typewriter: return getTypewriter(ch); - case .sansSerif: return getSansSerif(ch); - case .fraktur: return getFraktur(ch); - case .blackboard: return getBlackboard(ch); - -// default: -// NSException(name: NSExceptionName("Invalid style"), reason: "Unknown style \(fontStyle) for font.").raise() } -// return ch.utf32Char } func changeFont(_ str:String, fontStyle:MTFontStyle) -> String { @@ -337,39 +324,20 @@ func changeFont(_ str:String, fontStyle:MTFontStyle) -> String { let ch = codes[i] var unicode = styleCharacter(ch, fontStyle: fontStyle); unicode = NSSwapHostIntToLittle(unicode) - let charStr = String(unicode) + let charStr = String(UnicodeScalar(unicode)!) retval.append(charStr) } return retval } -//func mathItalicize(_ str:String) -> String { -// let retval = NSMutableString(capacity: str.count) -// var charBuffer = [unichar]() -// charBuffer.reserveCapacity(str.count) -// (str as NSString).getCharacters(&charBuffer, range: NSMakeRange(0, str.count)) -// for i in 0 ..< str.count { -// let ch = charBuffer[i] -// var unicode = getItalicized(ch) -// unicode = NSSwapHostIntToLittle(unicode) -// let charStr = NSString(bytes: &unicode, length: MemoryLayout.size(ofValue: unicode), encoding: NSUTF32LittleEndianStringEncoding) -// retval.append(charStr! as String) -// } -// return retval as String -//} - func getBboxDetails(_ bbox:CGRect, ascent:inout CGFloat, descent:inout CGFloat) { - if ascent != 0 { - ascent = max(0, CGRectGetMaxY(bbox) - 0) - } + ascent = max(0, CGRectGetMaxY(bbox) - 0) - if descent != 0 { - // Descent is how much the line goes below the origin. However if the line is all above the origin, then descent can't be negative. - descent = max(0, 0 - CGRectGetMinY(bbox)) - } + // Descent is how much the line goes below the origin. However if the line is all above the origin, then descent can't be negative. + descent = max(0, 0 - CGRectGetMinY(bbox)) } -// Mark: - MTTypesetter +// MARK: - - MTTypesetter class MTTypesetter { var font:MTFont! @@ -378,12 +346,10 @@ class MTTypesetter { var currentLine:NSMutableAttributedString! var currentAtoms = [MTMathAtom]() // List of atoms that make the line var currentLineIndexRange = NSMakeRange(0, 0) - var style:MTLineStyle { - didSet { - self.styleFont = self.font.copy(withSize: Self.getStyleSize(self.style, font: self.font)) - } + var style:MTLineStyle + var styleFont:MTFont { + self.font.copy(withSize: Self.getStyleSize(self.style, font: self.font)) } - var styleFont:MTFont! var cramped = false var spaced = false @@ -405,7 +371,8 @@ class MTTypesetter { let typesetter = MTTypesetter(withFont:font, style:style, cramped:cramped, spaced:spaced) typesetter.createDisplayAtoms(preprocessedAtoms) let lastAtom = mathList!.atoms.last - let line = MTMathListDisplay(withDisplays: typesetter.displayAtoms, range: NSMakeRange(0, NSMaxRange(lastAtom!.indexRange))) + let last = lastAtom?.indexRange ?? NSMakeRange(0, 0) + let line = MTMathListDisplay(withDisplays: typesetter.displayAtoms, range: NSMakeRange(0, NSMaxRange(last))) return line } @@ -466,13 +433,11 @@ class MTTypesetter { let original = font!.fontSize switch style { case .display, .text: - return original; - + return original case .script: - return original * font!.mathTable!.scriptScaleDown; - + return original * font!.mathTable!.scriptScaleDown case .scriptOfScript: - return original * font!.mathTable!.scriptScriptScaleDown; + return original * font!.mathTable!.scriptScriptScaleDown } } @@ -490,8 +455,8 @@ class MTTypesetter { func createDisplayAtoms(_ preprocessed:[MTMathAtom]) { // items should contain all the nodes that need to be layed out. // convert to a list of DisplayAtoms - var prevNode:MTMathAtom? = nil; - var lastType:MTMathAtomType = .style + var prevNode:MTMathAtom? = nil + var lastType:MTMathAtomType! for atom in preprocessed { switch atom.type { case .number, .variable,. unaryOperator: @@ -520,7 +485,7 @@ class MTTypesetter { self.addDisplayLine() } let style = atom as! MTMathStyle - self.style = style.style; + self.style = style.style // We need to preserve the prevNode for any interelement space changes. // so we skip to the next node. continue @@ -695,8 +660,8 @@ class MTTypesetter { // All we need is render the character and set the interelement space. if prevNode != nil { let interElementSpace = self.getInterElementSpace(prevNode!.type, right:atom.type) - if (currentLine.length > 0) { - if (interElementSpace > 0) { + if currentLine.length > 0 { + if interElementSpace > 0 { // add a kerning of that space to the previous character currentLine.addAttribute(kCTKernAttributeName as NSAttributedString.Key, value:NSNumber(floatLiteral: interElementSpace), @@ -704,26 +669,27 @@ class MTTypesetter { } } else { // increase the space - currentPosition.x += interElementSpace; + currentPosition.x += interElementSpace } } var current:NSAttributedString? = nil - if (atom.type == .placeholder) { + if atom.type == .placeholder { let color = MTTypesetter.placeholderColor - current = NSAttributedString(string: atom.nucleus, attributes:[kCTForegroundColorAttributeName as NSAttributedString.Key : color.cgColor]) + current = NSAttributedString(string:atom.nucleus, + attributes:[kCTForegroundColorAttributeName as NSAttributedString.Key : color.cgColor]) } else { current = NSAttributedString(string:atom.nucleus) } currentLine.append(current!) // add the atom to the current range - if (currentLineIndexRange.location == NSNotFound) { - currentLineIndexRange = atom.indexRange; + if currentLineIndexRange.location == NSNotFound { + currentLineIndexRange = atom.indexRange } else { currentLineIndexRange.length += atom.indexRange.length } // add the fused atoms - if !atom.childAtoms.isEmpty { - currentAtoms.append(contentsOf: atom.childAtoms) //.addObjectsFromArray:atom.fusedAtoms) + if !atom.fusedAtoms.isEmpty { + currentAtoms.append(contentsOf: atom.fusedAtoms) //.addObjectsFromArray:atom.fusedAtoms) } else { currentAtoms.append(atom) } @@ -746,14 +712,14 @@ class MTTypesetter { } self.makeScripts(atom, display:line, index:UInt(NSMaxRange(atom.indexRange) - 1), delta:delta) } - } - lastType = atom.type; - prevNode = atom; - } - if (currentLine.length > 0) { + } // switch + lastType = atom.type + prevNode = atom + } // node loop + if currentLine.length > 0 { self.addDisplayLine() } - if spaced { + if spaced && lastType != nil { // If spaced then add an interelement space between the last type and close let display = displayAtoms.last let interElementSpace = self.getInterElementSpace(lastType, right:.close) @@ -764,7 +730,7 @@ class MTTypesetter { @discardableResult func addDisplayLine() -> MTCTLineDisplay? { // add the font - currentLine.addAttribute(kCTFontAttributeName as NSAttributedString.Key, value:styleFont.ctFont!, range:NSMakeRange(0, currentLine.length)) + currentLine.addAttribute(kCTFontAttributeName as NSAttributedString.Key, value:styleFont.ctFont as Any, range:NSMakeRange(0, currentLine.length)) /*assert(currentLineIndexRange.length == numCodePoints(currentLine.string), "The length of the current line: %@ does not match the length of the range (%d, %d)", currentLine, currentLineIndexRange.location, currentLineIndexRange.length);*/ @@ -780,7 +746,7 @@ class MTTypesetter { return displayAtom } - // Mark: Spacing + // MARK: - Spacing // Returned in units of mu = 1/18 em. func getSpacingInMu(_ type: InterElementSpaceType) -> Int { @@ -802,8 +768,8 @@ class MTTypesetter { } func getInterElementSpace(_ left: MTMathAtomType, right:MTMathAtomType) -> CGFloat { - let leftIndex = getInterElementSpaceArrayIndexForType(left, row: true); - let rightIndex = getInterElementSpaceArrayIndexForType(right, row: false); + let leftIndex = getInterElementSpaceArrayIndexForType(left, row: true) + let rightIndex = getInterElementSpaceArrayIndexForType(right, row: false) let spaceArray = getInterElementSpaces()[Int(leftIndex)] let spaceTypeObj = spaceArray[Int(rightIndex)] let spaceType = spaceTypeObj @@ -818,7 +784,7 @@ class MTTypesetter { } - // Mark: Subscript/Superscript + // MARK: - Subscript/Superscript func scriptStyle() -> MTLineStyle { switch style { @@ -922,7 +888,7 @@ class MTTypesetter { currentPosition.x += max(superScript!.width + delta, ssubscript!.width) + styleFont.mathTable!.spaceAfterScript; } - // Mark: - Fractions + // MARK: - - Fractions func numeratorShiftUp(_ hasRule:Bool) -> CGFloat { if hasRule { @@ -1080,7 +1046,7 @@ class MTTypesetter { return innerDisplay } - // Mark: Radicals + // MARK: - Radicals func radicalVerticalGap() -> CGFloat { if style == .display { @@ -1102,7 +1068,7 @@ class MTTypesetter { glyphDisplay = self.constructGlyph(radicalGlyph, withHeight:radicalHeight) } - if glyphDisplay != nil { + if glyphDisplay == nil { // No constructed display so use the glyph we got. glyphDisplay = MTGlyphDisplay(withGlpyh: glyph, range: NSMakeRange(NSNotFound, 0), font:styleFont) glyphDisplay!.ascent = glyphAscent; @@ -1149,7 +1115,7 @@ class MTTypesetter { return radical; } - // Mark: Glyphs + // MARK: - Glyphs func findGlyph(_ glyph:CGGlyph, withHeight height:CGFloat, glyphAscent:inout CGFloat, glyphDescent:inout CGFloat, glyphWidth:inout CGFloat) -> CGGlyph { let variants = styleFont.mathTable!.getVerticalVariantsForGlyph(glyph) @@ -1158,13 +1124,11 @@ class MTTypesetter { glyphs.reserveCapacity(numVariants) for i in 0 ..< numVariants { let glyph = variants[i]!.uint16Value - glyphs[i] = glyph + glyphs.append(glyph) } - var bboxes = [CGRect]() // = [numVariants) - var advances = [CGSize]() // [numVariants) - bboxes.reserveCapacity(numVariants) - advances.reserveCapacity(numVariants) + var bboxes = [CGRect](repeating: CGRect.zero, count: numVariants) + var advances = [CGSize](repeating: CGSize.zero, count: numVariants) // Get the bounds for these glyphs CTFontGetBoundingRectsForGlyphs(styleFont.ctFont, .horizontal, glyphs, &bboxes, numVariants) @@ -1206,10 +1170,10 @@ class MTTypesetter { } func constructGlyphWithParts(_ parts:[GlyphPart], glyphHeight:CGFloat, glyphs:inout [NSNumber], offsets:inout [NSNumber], height:inout CGFloat) { - assert(!glyphs.isEmpty) - assert(!offsets.isEmpty) + // assert(!glyphs.isEmpty) + // assert(!offsets.isEmpty) - for numExtenders in 0...1 { + for numExtenders in 0.. CGGlyph { // Get the character at index taking into account UTF-32 characters - let range = str.rangeOfComposedCharacterSequence(at: index) //.rangeOfComposedCharacterSequenceAtIndex(index) - var chars = str[range].unicodeScalars.map { UInt16($0.value) } + var chars = Array(str[index].utf16) // Get the glyph from the font - var glyph = [CGGlyph](repeating: CGGlyph.zero, count: chars.count) // [range.length) + var glyph = [CGGlyph](repeating: CGGlyph.zero, count: chars.count) let found = CTFontGetGlyphsForCharacters(styleFont.ctFont, &chars, &glyph, chars.count) if !found { // the font did not contain a glyph for our character, so we just return 0 (notdef) @@ -1287,7 +1250,7 @@ class MTTypesetter { return glyph[0] } - // Mark: Large Operators + // MARK: - Large Operators func makeLargeOp(_ op:MTLargeOperator!) -> MTDisplay? { let limits = op.limits && style == .display @@ -1307,7 +1270,7 @@ class MTTypesetter { var ascent=CGFloat(0), descent=CGFloat(0) getBboxDetails(bbox, ascent: &ascent, descent: &descent) let shiftDown = 0.5*(ascent - descent) - styleFont.mathTable!.axisHeight; - let glyphDisplay = MTGlyphDisplay(withGlpyh: glyph, range: op.indexRange, font: styleFont) //initWithGlpyh:glyph range:op.indexRange font:styleFont) + let glyphDisplay = MTGlyphDisplay(withGlpyh: glyph, range: op.indexRange, font: styleFont) glyphDisplay.ascent = ascent; glyphDisplay.descent = descent; glyphDisplay.width = width; @@ -1365,7 +1328,7 @@ class MTTypesetter { } } - // Mark: Large delimiters + // MARK: - Large delimiters // Delimiter shortfall from plain.tex static let kDelimiterFactor = CGFloat(901) @@ -1384,7 +1347,7 @@ class MTTypesetter { // be at most 5pt short. let glyphHeight = max(d1, d2); - var innerElements = [MTDisplay]() // NSMutableArray() + var innerElements = [MTDisplay]() var position = CGPoint.zero if inner!.leftBoundary != nil && !inner!.leftBoundary!.nucleus.isEmpty { let leftGlyph = self.findGlyphForBoundary(inner!.leftBoundary!.nucleus, withHeight:glyphHeight) @@ -1418,7 +1381,7 @@ class MTTypesetter { glyphDisplay = self.constructGlyph(leftGlyph, withHeight:glyphHeight) } - if glyphDisplay != nil { + if glyphDisplay == nil { // Create a glyph display glyphDisplay = MTGlyphDisplay(withGlpyh: glyph, range: NSMakeRange(NSNotFound, 0), font:styleFont) glyphDisplay!.ascent = glyphAscent; @@ -1431,7 +1394,7 @@ class MTTypesetter { return glyphDisplay; } - // Mark: Underline/Overline + // MARK: - Underline/Overline func makeUnderline(_ under:MTUnderLine?) -> MTDisplay? { let innerListDisplay = MTTypesetter.createLineForMathList(under!.innerList, font:font, style:style, cramped:cramped) @@ -1456,19 +1419,20 @@ class MTTypesetter { return overDisplay; } - // Mark: Accents + // MARK: - Accents func isSingleCharAccentee(_ accent:MTAccent?) -> Bool { - if (accent!.innerList!.atoms.count != 1) { + guard let accent = accent else { return false } + if accent.innerList!.atoms.count != 1 { // Not a single char list. return false } - let innerAtom = accent!.innerList!.atoms[0] + let innerAtom = accent.innerList!.atoms[0] if innerAtom.nucleus.count != 1 { // A complex atom, not a simple char. return false } - if (innerAtom.subScript != nil || innerAtom.superScript != nil) { + if innerAtom.subScript != nil || innerAtom.superScript != nil { return false } return true @@ -1476,22 +1440,23 @@ class MTTypesetter { // The distance the accent must be moved from the beginning. func getSkew(_ accent: MTAccent?, accenteeWidth width:CGFloat, accentGlyph:CGGlyph) -> CGFloat { - if accent!.nucleus.isEmpty { + guard let accent = accent else { return 0 } + if accent.nucleus.isEmpty { // No accent - return 0; + return 0 } let accentAdjustment = styleFont.mathTable!.getTopAccentAdjustment(accentGlyph) var accenteeAdjustment = CGFloat(0) if !self.isSingleCharAccentee(accent) { // use the center of the accentee - accenteeAdjustment = width/2; + accenteeAdjustment = width/2 } else { - let innerAtom = accent!.innerList!.atoms[0] + let innerAtom = accent.innerList!.atoms[0] let accenteeGlyph = self.findGlyphForCharacterAtIndex(innerAtom.nucleus.index(innerAtom.nucleus.endIndex, offsetBy:-1), inString:innerAtom.nucleus) accenteeAdjustment = styleFont.mathTable!.getTopAccentAdjustment(accenteeGlyph) } // The adjustments need to aligned, so skew is just the difference. - return (accenteeAdjustment - accentAdjustment); + return (accenteeAdjustment - accentAdjustment) } // Find the largest horizontal variant if exists, with width less than max width. @@ -1581,7 +1546,7 @@ class MTTypesetter { return display; } - // Mark: - Table + // MARK: - Table let kBaseLineSkipMultiplier = CGFloat(1.2) // default base line stretch is 12 pt for 10pt font. let kLineSkipMultiplier = CGFloat(0.1) // default is 1pt for 10pt font. @@ -1599,8 +1564,7 @@ class MTTypesetter { let displays = self.typesetCells(table, columnWidths:&columnWidths) // Position all the columns in each row - var rowDisplays = [MTDisplay]() // NSMutableArray(capacity: table!.cells.count) - rowDisplays.reserveCapacity(table!.cells.count) + var rowDisplays = [MTDisplay]() for row in displays { let rowDisplay = self.makeRowWithColumns(row, forTable:table, columnWidths:columnWidths) rowDisplays.append(rowDisplay!) @@ -1616,16 +1580,14 @@ class MTTypesetter { // Typeset every cell in the table. As a side-effect calculate the max column width of each column. func typesetCells(_ table:MTMathTable?, columnWidths: inout [CGFloat]) -> [[MTDisplay]] { var displays = [[MTDisplay]]() - displays.reserveCapacity(table!.numRows) for row in table!.cells { - var colDisplays = [MTDisplay]() //NSMutableArray(capacity: row.count) - colDisplays.reserveCapacity(row.count) - displays.append(colDisplays) + var colDisplays = [MTDisplay]() for i in 0..