Place characters vertically in the middle of line (close #373)

This commit is contained in:
1024jp 2020-03-15 11:36:49 +09:00
parent 57bf293878
commit 3c7123cf66
5 changed files with 33 additions and 10 deletions

View File

@ -7,10 +7,16 @@ Change Log
### Improvements
- Adjust the text baseline to draw characters vertically center in lines.
- Adjust invisible characters position in the vertical text orientation.
- Improve drawing performance.
### Fixes
- Fix an issue where the line numbers could be shifted when printing vertical text orientation document.
3.8.12 (400)
--------------------------

View File

@ -79,7 +79,6 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
private(set) var spaceWidth: CGFloat = 0
private(set) var replacementGlyphWidth: CGFloat = 0
private(set) var defaultBaselineOffset: CGFloat = 0 // defaultBaselineOffset for textFont
private(set) var showsOtherInvisibles = false
@ -88,6 +87,7 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
private var defaultsObservers: [UserDefaultsObservation] = []
private var defaultLineHeight: CGFloat = 1.0
private var defaultBaselineOffset: CGFloat = 0
private var showsSpace = false
private var showsTab = false
@ -202,6 +202,8 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0)
}
let baselineOffset = self.baselineOffset(for: layoutOrientation ?? .horizontal)
// draw invisibles glyph by glyph
let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil)
for charIndex in characterRange.lowerBound..<characterRange.upperBound {
@ -238,8 +240,7 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
let glyphIndex = self.glyphIndexForCharacter(at: charIndex)
let lineOrigin = self.lineFragmentRect(forGlyphAt: glyphIndex, effectiveRange: nil, withoutAdditionalLayout: true).origin
let glyphLocation = self.location(forGlyphAt: glyphIndex)
var point = lineOrigin.offset(by: origin).offsetBy(dx: glyphLocation.x,
dy: self.defaultBaselineOffset)
var point = lineOrigin.offset(by: origin).offsetBy(dx: glyphLocation.x, dy: baselineOffset)
if layoutOrientation == .vertical {
let bounds = line.bounds()
point.y += bounds.minY + bounds.height / 2
@ -310,6 +311,21 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
}
/// Fixed baseline offset to place glyphs vertically in the middle of a line.
///
/// - Parameter layoutOrientation: The text layout orientation.
/// - Returns: The baseline offset.
func baselineOffset(for layoutOrientation: TextLayoutOrientation) -> CGFloat {
switch layoutOrientation {
case .vertical:
return self.lineHeight / 2
default:
return (self.lineHeight + self.defaultBaselineOffset) / 2
}
}
// MARK: Private Methods

View File

@ -33,7 +33,6 @@ final class LineNumberView: NSView {
let fontSize: CGFloat
let charWidth: CGFloat
let ascent: CGFloat
let wrappedMarkGlyph: CGGlyph
let digitGlyphs: [CGGlyph]
let padding: CGFloat
@ -50,7 +49,6 @@ final class LineNumberView: NSView {
// calculate font size for number
self.fontSize = (scale * LineNumberView.fontSizeFactor * textFont.pointSize).rounded(interval: 0.5)
self.ascent = scale * textFont.ascender
// prepare glyphs
let font = CTFontCreateWithGraphicsFont(LineNumberView.lineNumberFont, self.fontSize, nil, nil)
@ -291,6 +289,7 @@ final class LineNumberView: NSView {
guard
let drawingInfo = self.drawingInfo,
let textView = self.textView,
let layoutManager = textView.layoutManager as? LayoutManager,
let context = NSGraphicsContext.current?.cgContext
else { return assertionFailure() }
@ -306,7 +305,8 @@ final class LineNumberView: NSView {
// adjust drawing coordinate
let relativePoint = self.convert(NSPoint.zero, from: textView)
let lineBase = (scale * textView.textContainerOrigin.y) + drawingInfo.ascent
let baselineOffset = layoutManager.baselineOffset(for: textView.layoutOrientation)
let lineBase = scale * (textView.textContainerOrigin.y + baselineOffset)
switch textView.layoutOrientation {
case .horizontal:
context.translateBy(x: self.thickness, y: relativePoint.y - lineBase)

View File

@ -244,12 +244,13 @@ final class PrintTextView: NSTextView, NSLayoutManagerDelegate, Themable, URLDet
// adjust position to draw
let width = CGFloat(numberString.count) * charSize.width
var point = NSPoint(x: horizontalOrigin, y: lineRect.maxY - charSize.height)
var point = NSPoint(x: horizontalOrigin, y: lineRect.midY)
if isVerticalText {
point = NSPoint(x: -point.y - (width + charSize.height) / 2,
point = NSPoint(x: -point.y - width / 2,
y: point.x - charSize.height)
} else {
point.x -= width // align right
point.y -= charSize.height / 2
}
// draw number

View File

@ -43,8 +43,8 @@ final class Typesetter: NSATSTypesetter {
lineRect.pointee.size.height = manager.lineHeight
usedRect.pointee.size.height = manager.lineHeight
// avoid baseline shifting when the glyph height is higher than the fixed line height, such as 𓆏.
baselineOffset.pointee = manager.defaultBaselineOffset
// vertically center the glyphs in the line fragment
baselineOffset.pointee = manager.baselineOffset(for: self.currentTextContainer?.layoutOrientation ?? .horizontal)
}