1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-24 22:33:52 +03:00

GH-666 Remove old (slow) run with ligatures method

This commit is contained in:
Tae Won Ha 2018-08-31 16:37:29 +02:00
parent a739e6bb39
commit f0dfd94d9a
2 changed files with 1 additions and 572 deletions

View File

@ -5,34 +5,6 @@
import Cocoa
struct PositionedUtf16Cell {
var utf16: [Unicode.UTF16.CodeUnit]
var column: Int
}
struct CellIndexedUtf16Char {
var codeUnit: Unicode.UTF16.CodeUnit
var index: Int
}
struct Utf16IndexedGlyph {
var glyph: CGGlyph
var index: CFIndex
var position: CGPoint
var advance: CGSize
}
struct CellGlyphUnion {
var positionedUtf16Cells: [PositionedUtf16Cell]
var utf16IndexedGlyphs: [Utf16IndexedGlyph]
}
class Typesetter {
final func fontGlyphRunsWithLigatures(
@ -110,7 +82,7 @@ class Typesetter {
var cellIndex = 0
var i = 0
repeat {
defer { cellIndex += 1}
defer { cellIndex += 1 }
if nvimUtf16Cells[cellIndex].isEmpty {
continue
@ -136,83 +108,6 @@ class Typesetter {
return utf16Chars
}
final func fontGlyphRunsWithLigatures_old(
nvimUtf16Cells: [[Unicode.UTF16.CodeUnit]],
startColumn: Int,
offset: CGPoint,
foreground: Int,
font: NSFont,
cellWidth: CGFloat
) -> [FontGlyphRun] {
let utf16Chars = nvimUtf16Cells.flatMap { $0 }
let ctRuns = self.ctRuns(
from: utf16Chars, font: font, foreground: foreground
)
let utf16IndexedGlyphs = self.utf16IndexedGlyphs(from: ctRuns)
let cellIndexedUtf16Chars = nvimUtf16Cells
.filter { !$0.isEmpty }
.enumerated()
.map { element in
element.1.map { utf16 in
CellIndexedUtf16Char(codeUnit: utf16, index: element.0)
}
}
.flatMap { $0 }
let positionedCells = nvimUtf16Cells
.enumerated()
.compactMap { element -> PositionedUtf16Cell? in
if element.1.isEmpty { return nil }
return PositionedUtf16Cell(
utf16: element.1, column: startColumn + element.0
)
}
let groupedCellsAndGlyphs = self.groupUtf16CellsAndGlyphs(
positionedCells: positionedCells,
cellIndexedUtf16Chars: cellIndexedUtf16Chars,
utf16IndexedGlyphs: utf16IndexedGlyphs
)
let stringRanges = ctRuns.map { run -> CountableRange<Int> in
let range = CTRunGetStringRange(run)
return range.location..<(range.location + range.length)
}
let fonts = ctRuns.map { run -> NSFont in
guard
let attrs = CTRunGetAttributes(run) as? [NSAttributedStringKey: Any],
let font = attrs[NSAttributedStringKey.font] as? NSFont
else {
// FIXME: GH-666: Return the default font
preconditionFailure("Could not get font from CTRun!")
}
return font
}
let fontRanges = self.groupByStringRanges(
stringRanges: stringRanges, groupedCellsAndGlyphs: groupedCellsAndGlyphs
)
let cellsAndGlyphsGroupedByFont = fontRanges.map { range in
Array(groupedCellsAndGlyphs[range])
}
let fontGlyphRuns = self.fontGlyphRuns(
fonts: fonts,
cellsAndGlyphsGroupedByFont: cellsAndGlyphsGroupedByFont,
estimatedGlyphsCount: utf16Chars.count,
cellWidth: cellWidth,
offset: offset
)
return fontGlyphRuns
}
final func fontGlyphRunsWithoutLigatures(
nvimCells: [String],
startColumn: Int,
@ -294,146 +189,6 @@ class Typesetter {
return runs.flatMap { $0 }
}
// For testing internal
func groupUtf16CellsAndGlyphs(
positionedCells: [PositionedUtf16Cell],
cellIndexedUtf16Chars: [CellIndexedUtf16Char],
utf16IndexedGlyphs: [Utf16IndexedGlyph]
) -> [CellGlyphUnion] {
let utf16IndicesOfGlyphs = utf16IndexedGlyphs.map { $0.index }.uniqued()
let extendedUtf16Indices
= utf16IndicesOfGlyphs + [cellIndexedUtf16Chars.count]
let utf16RangesOfGlyphs = (0..<utf16IndicesOfGlyphs.count).map { i in
extendedUtf16Indices[i]..<extendedUtf16Indices[i + 1]
}
let nonUniqueGroupedUtf16CellIndices = utf16RangesOfGlyphs.map { range in
cellIndexedUtf16Chars[range]
.map { $0.index }
.uniqued()
}
var groupedUtf16CellIndices = [[Int]]()
groupedUtf16CellIndices.reserveCapacity(
nonUniqueGroupedUtf16CellIndices.count
)
var lastIndex = -1
nonUniqueGroupedUtf16CellIndices.forEach { element in
guard let first = element.first, let last = element.last else {
preconditionFailure("There are no first and last element in " +
"a grouped UTF16 cell indices " +
"non-unique collection!")
}
guard first > lastIndex else { return }
groupedUtf16CellIndices.append(element)
lastIndex = last
}
let groupedUtf16CellRanges = groupedUtf16CellIndices
.map { ind -> CountableClosedRange<Int> in
guard let first = ind.first, let last = ind.last else {
preconditionFailure("There are no first and last element in " +
"a grouped UTF16 cell indices!")
}
return first...last
}
let partitionedUtf16Cells = groupedUtf16CellRanges.map { range in
Array(positionedCells[range])
}
let partitionedGlyphs = utf16IndexedGlyphs
.map { cellIndexedUtf16Chars[$0.index].index }
.groupedRanges { _, cellIndexOfUtf16Index, _ in cellIndexOfUtf16Index }
.map { Array(utf16IndexedGlyphs[$0]) }
return zip(partitionedUtf16Cells, partitionedGlyphs)
.map { zip in
CellGlyphUnion(
positionedUtf16Cells: zip.0,
utf16IndexedGlyphs: zip.1
)
}
}
// For testing internal
func groupByStringRanges(
stringRanges: [CountableRange<Int>],
groupedCellsAndGlyphs: [CellGlyphUnion]
) -> [CountableClosedRange<Int>] {
var lastLength = 0
var lastIndex = 0
var result = Array<CountableClosedRange<Int>>()
result.reserveCapacity(stringRanges.count)
for range in stringRanges {
for i in (lastIndex..<groupedCellsAndGlyphs.count) {
lastLength += groupedCellsAndGlyphs[i]
.positionedUtf16Cells
.reduce(0) { result, element in
result + element.utf16.count
}
if lastLength == range.upperBound {
result.append(lastIndex...i)
lastIndex = i + 1
break
}
}
}
return result
}
private func fontGlyphRuns(
fonts: [NSFont],
cellsAndGlyphsGroupedByFont: [[CellGlyphUnion]],
estimatedGlyphsCount: Int,
cellWidth: CGFloat,
offset: CGPoint
) -> [FontGlyphRun] {
let zipped = zip(fonts, cellsAndGlyphsGroupedByFont)
let fontGlyphRuns = zipped.map { zip -> FontGlyphRun in
let font = zip.0
let cellsAndGlyphs = zip.1
var glyphs = Array<CGGlyph>()
glyphs.reserveCapacity(estimatedGlyphsCount)
var positions = Array<CGPoint>()
positions.reserveCapacity(estimatedGlyphsCount)
for element in cellsAndGlyphs {
let cells = element.positionedUtf16Cells
let indexedGlyphs = element.utf16IndexedGlyphs
let startColumnPosition
= offset.x + CGFloat(cells[0].column) * cellWidth
let deltaX = startColumnPosition - indexedGlyphs[0].position.x
glyphs.append(contentsOf: indexedGlyphs.map { $0.glyph })
positions.append(contentsOf: indexedGlyphs.map { indexedGlyph in
CGPoint(x: indexedGlyph.position.x + deltaX, y: offset.y)
})
}
// FIXME: GH-666: Proper error handling
if glyphs.count != positions.count {
print("Counts of glyphs and positions are not the same")
}
return FontGlyphRun(
font: font, glyphs: glyphs, positions: positions
)
}
return fontGlyphRuns
}
private func ctRuns(
from utf16Chars: [Unicode.UTF16.CodeUnit],
font: NSFont,
@ -453,39 +208,6 @@ class Typesetter {
return ctRuns
}
private func utf16IndexedGlyphs(
from ctRuns: [CTRun]
) -> [Utf16IndexedGlyph] {
let utf16IndexedGlyphs = ctRuns
.map { run -> [Utf16IndexedGlyph] in
let glyphCount = CTRunGetGlyphCount(run)
var indices = Array(repeating: CFIndex(), count: glyphCount)
CTRunGetStringIndices(run, .zero, &indices)
var glyphs = Array(repeating: CGGlyph(), count: glyphCount)
CTRunGetGlyphs(run, .zero, &glyphs)
var positions = Array(repeating: CGPoint.zero, count: glyphCount)
CTRunGetPositions(run, .zero, &positions)
var advances = Array(repeating: CGSize.zero, count: glyphCount)
CTRunGetAdvances(run, .zero, &advances)
return (0..<glyphCount).map { i in
Utf16IndexedGlyph(
glyph: glyphs[i],
index: indices[i],
position: positions[i],
advance: advances[i]
)
}
}
.flatMap { $0 }
return utf16IndexedGlyphs
}
private struct NvimUtf16CellsRun {
var startColumn: Int

View File

@ -333,299 +333,6 @@ class TypesetterWithoutLigaturesTest: XCTestCase {
class TypesetterWithLigaturesTest: XCTestCase {
func testGroupGlyphsAndUtf16Cells() {
let cells = typesetter.groupUtf16CellsAndGlyphs(
positionedCells: [
PositionedUtf16Cell(utf16: [0, 1, 2], column: 1),
PositionedUtf16Cell(utf16: [3, 4], column: 3),
PositionedUtf16Cell(utf16: [5, 6], column: 5),
PositionedUtf16Cell(utf16: [7], column: 6),
],
cellIndexedUtf16Chars: [
CellIndexedUtf16Char(codeUnit: 0, index: 0),
CellIndexedUtf16Char(codeUnit: 1, index: 0),
CellIndexedUtf16Char(codeUnit: 2, index: 0),
CellIndexedUtf16Char(codeUnit: 3, index: 1),
CellIndexedUtf16Char(codeUnit: 4, index: 1),
CellIndexedUtf16Char(codeUnit: 5, index: 2),
CellIndexedUtf16Char(codeUnit: 6, index: 2),
CellIndexedUtf16Char(codeUnit: 7, index: 3),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 0, index: 0, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 1, index: 1, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 2, index: 2, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 3, index: 3, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 4, index: 7, position: .zero, advance: .zero
),
])
expect(cells).to(haveCount(3))
var cell = cells[0]
var utf16Cells = cell.positionedUtf16Cells
var glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(1))
expect(utf16Cells[0].utf16).to(equal([0, 1, 2]))
expect(utf16Cells[0].column).to(equal(1))
expect(glyphs).to(haveCount(3))
expect(glyphs[0].glyph).to(equal(0))
expect(glyphs[1].glyph).to(equal(1))
expect(glyphs[2].glyph).to(equal(2))
cell = cells[1]
utf16Cells = cell.positionedUtf16Cells
glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(2))
expect(utf16Cells[0].utf16).to(equal([3, 4]))
expect(utf16Cells[0].column).to(equal(3))
expect(utf16Cells[1].utf16).to(equal([5, 6]))
expect(utf16Cells[1].column).to(equal(5))
expect(glyphs).to(haveCount(1))
expect(glyphs[0].glyph).to(equal(3))
cell = cells[2]
utf16Cells = cell.positionedUtf16Cells
glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(1))
expect(utf16Cells[0].utf16).to(equal([7]))
expect(utf16Cells[0].column).to(equal(6))
expect(glyphs).to(haveCount(1))
expect(glyphs[0].glyph).to(equal(4))
}
func testGroupGlyphsAndUtf16Cells2() {
let cells = typesetter.groupUtf16CellsAndGlyphs(
positionedCells: [
PositionedUtf16Cell(utf16: [0, 1, 2], column: 1),
PositionedUtf16Cell(utf16: [3, 4], column: 3),
PositionedUtf16Cell(utf16: [5, 6], column: 5),
PositionedUtf16Cell(utf16: [7], column: 6),
PositionedUtf16Cell(utf16: [8], column: 7),
PositionedUtf16Cell(utf16: [9], column: 8),
],
cellIndexedUtf16Chars: [
CellIndexedUtf16Char(codeUnit: 0, index: 0),
CellIndexedUtf16Char(codeUnit: 1, index: 0),
CellIndexedUtf16Char(codeUnit: 2, index: 0),
CellIndexedUtf16Char(codeUnit: 3, index: 1),
CellIndexedUtf16Char(codeUnit: 4, index: 1),
CellIndexedUtf16Char(codeUnit: 5, index: 2),
CellIndexedUtf16Char(codeUnit: 6, index: 2),
CellIndexedUtf16Char(codeUnit: 7, index: 3),
CellIndexedUtf16Char(codeUnit: 8, index: 4),
CellIndexedUtf16Char(codeUnit: 9, index: 5),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 0, index: 0, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 1, index: 2, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 2, index: 3, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 3, index: 7, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 4, index: 8, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 5, index: 8, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 6, index: 8, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 7, index: 9, position: .zero, advance: .zero
),
])
expect(cells).to(haveCount(5))
var cell = cells[0]
var utf16Cells = cell.positionedUtf16Cells
var glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(1))
expect(utf16Cells[0].utf16).to(equal([0, 1, 2]))
expect(utf16Cells[0].column).to(equal(1))
expect(glyphs).to(haveCount(2))
expect(glyphs[0].glyph).to(equal(0))
expect(glyphs[1].glyph).to(equal(1))
cell = cells[1]
utf16Cells = cell.positionedUtf16Cells
glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(2))
expect(utf16Cells[0].utf16).to(equal([3, 4]))
expect(utf16Cells[0].column).to(equal(3))
expect(utf16Cells[1].utf16).to(equal([5, 6]))
expect(utf16Cells[1].column).to(equal(5))
expect(glyphs).to(haveCount(1))
expect(glyphs[0].glyph).to(equal(2))
cell = cells[2]
utf16Cells = cell.positionedUtf16Cells
glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(1))
expect(utf16Cells[0].utf16).to(equal([7]))
expect(utf16Cells[0].column).to(equal(6))
expect(glyphs).to(haveCount(1))
expect(glyphs[0].glyph).to(equal(3))
cell = cells[3]
utf16Cells = cell.positionedUtf16Cells
glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(1))
expect(utf16Cells[0].utf16).to(equal([8]))
expect(utf16Cells[0].column).to(equal(7))
expect(glyphs).to(haveCount(3))
expect(glyphs[0].glyph).to(equal(4))
expect(glyphs[1].glyph).to(equal(5))
expect(glyphs[2].glyph).to(equal(6))
cell = cells[4]
utf16Cells = cell.positionedUtf16Cells
glyphs = cell.utf16IndexedGlyphs
expect(utf16Cells).to(haveCount(1))
expect(utf16Cells[0].utf16).to(equal([9]))
expect(utf16Cells[0].column).to(equal(8))
expect(glyphs).to(haveCount(1))
expect(glyphs[0].glyph).to(equal(7))
}
func testGroupByStringRanges() {
let groups = typesetter.groupByStringRanges(
stringRanges: [
0..<5,
5..<9,
],
groupedCellsAndGlyphs: [
CellGlyphUnion(
positionedUtf16Cells: [
PositionedUtf16Cell(utf16: [0, 1, 2], column: 1),
PositionedUtf16Cell(utf16: [3, 4], column: 2)
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 0, index: 0, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 1, index: 3, position: .zero, advance: .zero
),
]
),
CellGlyphUnion(
positionedUtf16Cells: [
PositionedUtf16Cell(utf16: [5], column: 3),
PositionedUtf16Cell(utf16: [6], column: 4),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 2, index: 5, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 3, index: 6, position: .zero, advance: .zero
),
]
),
CellGlyphUnion(
positionedUtf16Cells: [
PositionedUtf16Cell(utf16: [7], column: 5),
PositionedUtf16Cell(utf16: [8], column: 6),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 4, index: 7, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 5, index: 8, position: .zero, advance: .zero
),
]
),
])
expect(groups).to(haveCount(2))
expect(groups[0]).to(equal(0...0))
expect(groups[1]).to(equal(1...2))
}
func testGroupByStringRanges2() {
let groups = typesetter.groupByStringRanges(
stringRanges: [
0..<5,
5..<7,
7..<8,
],
groupedCellsAndGlyphs: [
CellGlyphUnion(
positionedUtf16Cells: [
PositionedUtf16Cell(utf16: [0], column: 1),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 0, index: 0, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 1, index: 0, position: .zero, advance: .zero
),
]
),
CellGlyphUnion(
positionedUtf16Cells: [
PositionedUtf16Cell(utf16: [1], column: 2),
PositionedUtf16Cell(utf16: [2], column: 3),
PositionedUtf16Cell(utf16: [3], column: 4),
PositionedUtf16Cell(utf16: [4], column: 5),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 2, index: 1, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 3, index: 3, position: .zero, advance: .zero
),
]
),
CellGlyphUnion(
positionedUtf16Cells: [
PositionedUtf16Cell(utf16: [5], column: 6),
PositionedUtf16Cell(utf16: [6], column: 7),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 4, index: 5, position: .zero, advance: .zero
),
Utf16IndexedGlyph(
glyph: 5, index: 6, position: .zero, advance: .zero
),
]
),
CellGlyphUnion(
positionedUtf16Cells: [
PositionedUtf16Cell(utf16: [7], column: 6),
],
utf16IndexedGlyphs: [
Utf16IndexedGlyph(
glyph: 6, index: 7, position: .zero, advance: .zero
),
]
),
])
expect(groups).to(haveCount(3))
expect(groups[0]).to(equal(0...1))
expect(groups[1]).to(equal(2...2))
expect(groups[2]).to(equal(3...3))
}
func testSimpleAsciiChars() {
let runs = typesetter.fontGlyphRunsWithLigatures(
nvimUtf16Cells: utf16Chars(emojiMarked(