refactor: rename RDReaderView -> RDEpubReaderView, update pod config and docs
- Rename source module from RDReaderView to RDEpubReaderView - Move all source files from Sources/RDReaderView/ to Sources/RDEpubReaderView/ - Update podspec: RDReaderView.podspec -> RDEpubReaderView.podspec - Update Podfile, demo project, and CocoaPods config for new pod name - Delete old RDReaderView pod support files from ReadViewDemo/Pods - Add new RDEpubReaderView pod support files - Update documentation (API ref, architecture, UML, conventions, etc.) - Add FixedLayoutRotationTests - Update .gitignore: exclude .DS_Store, manual unpack backups, _ssoft-output
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import UIKit
|
||||
|
||||
#if canImport(DTCoreText)
|
||||
import DTCoreText
|
||||
|
||||
/// Redistributes the leftover space at the bottom of a page into the gaps
|
||||
/// between lines so the last line sits flush with the content bottom edge
|
||||
/// (vertical justification), keeping page character ranges untouched.
|
||||
///
|
||||
/// Mutating each line's `baselineOrigin` is sufficient: DTCoreText derives
|
||||
/// line frames, glyph-run frames and attachment positions from it lazily,
|
||||
/// so drawing, selection, highlights and hit-testing all stay consistent.
|
||||
enum RDEPUBTextPageVerticalJustifier {
|
||||
|
||||
/// Leftover larger than this many typical line advances is kept as
|
||||
/// whitespace instead of being stretched: it usually comes from a whole
|
||||
/// block (image, table) pushed to the next page, and stretching would
|
||||
/// make the line spacing visibly sparse.
|
||||
static let maxStretchLineAdvanceRatio: CGFloat = 1.5
|
||||
|
||||
static func justify(
|
||||
_ layoutFrame: DTCoreTextLayoutFrame,
|
||||
contentHeight: CGFloat,
|
||||
isChapterLastPage: Bool,
|
||||
pixelScale: CGFloat
|
||||
) {
|
||||
guard !isChapterLastPage,
|
||||
contentHeight > 0,
|
||||
let lines = layoutFrame.lines as? [DTCoreTextLayoutLine],
|
||||
lines.count >= 2,
|
||||
let firstLine = lines.first,
|
||||
let lastLine = lines.last else {
|
||||
return
|
||||
}
|
||||
|
||||
let leftover = contentHeight - lastLine.frame.maxY
|
||||
guard leftover > 0.5 else { return }
|
||||
|
||||
let gapCount = CGFloat(lines.count - 1)
|
||||
let typicalAdvance = (lastLine.baselineOrigin.y - firstLine.baselineOrigin.y) / gapCount
|
||||
guard typicalAdvance > 0,
|
||||
leftover <= typicalAdvance * maxStretchLineAdvanceRatio else {
|
||||
return
|
||||
}
|
||||
|
||||
let scale = max(pixelScale, 1)
|
||||
for (index, line) in lines.enumerated() where index > 0 {
|
||||
// Round each cumulative shift down to the pixel grid so glyphs
|
||||
// stay sharp and the last line never overshoots the bottom edge.
|
||||
let shift = floor(leftover * CGFloat(index) / gapCount * scale) / scale
|
||||
var origin = line.baselineOrigin
|
||||
origin.y += shift
|
||||
line.baselineOrigin = origin
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user