-
-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathKerningTable.cs
More file actions
98 lines (81 loc) · 3.05 KB
/
KerningTable.cs
File metadata and controls
98 lines (81 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.Fonts.Tables.General.Kern;
internal sealed class KerningTable : Table
{
internal const string TableName = "kern";
private readonly KerningSubTable[] kerningSubTable;
public KerningTable(KerningSubTable[] kerningSubTable)
=> this.kerningSubTable = kerningSubTable;
public int Count => this.kerningSubTable.Length;
public static KerningTable Load(FontReader fontReader)
{
if (!fontReader.TryGetReaderAtTablePosition(TableName, out BigEndianBinaryReader? binaryReader))
{
// this table is optional.
return new KerningTable([]);
}
using (binaryReader)
{
// Move to start of table.
return Load(binaryReader);
}
}
public static KerningTable Load(BigEndianBinaryReader reader)
{
// +--------+---------+-------------------------------------------+
// | Type | Field | Description |
// +========+=========+===========================================+
// | uint16 | version | Table version number(0) |
// +--------+---------+-------------------------------------------+
// | uint16 | nTables | Number of subtables in the kerning table. |
// +--------+---------+-------------------------------------------+
ushort version = reader.ReadUInt16();
ushort subTableCount = reader.ReadUInt16();
List<KerningSubTable> tables = new(subTableCount);
for (int i = 0; i < subTableCount; i++)
{
KerningSubTable? t = KerningSubTable.Load(reader); // returns null for unknown/supported table format
if (t != null)
{
tables.Add(t);
}
}
return new KerningTable([.. tables]);
}
public void UpdatePositions(FontMetrics fontMetrics, GlyphPositioningCollection collection, int left, int right)
{
if (this.Count == 0 || collection.Count == 0)
{
return;
}
GlyphShapingData current = collection[left];
if (current.IsKerned)
{
// Already kerned via previous processing.
return;
}
ushort currentId = current.GlyphId;
ushort nextId = collection[right].GlyphId;
if (this.TryGetKerningOffset(currentId, nextId, out Vector2 result))
{
collection.Advance(fontMetrics, left, currentId, (short)result.X, (short)result.Y);
current.IsKerned = true;
}
}
public bool TryGetKerningOffset(ushort current, ushort next, out Vector2 result)
{
result = Vector2.Zero;
if (this.Count == 0 || current == 0 || next == 0)
{
return false;
}
bool kerned = false;
foreach (KerningSubTable sub in this.kerningSubTable)
{
kerned |= sub.TryApplyOffset(current, next, ref result);
}
return kerned;
}
}