// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.Fonts.Tables.General {
///
/// Represents the vertical metrics table, which contains the vertical layout metrics
/// (advance heights and top side bearings) for each glyph.
///
///
internal sealed class VerticalMetricsTable : Table
{
///
/// The table name identifier.
///
internal const string TableName = "vmtx";
///
/// The top side bearings array for all glyphs.
///
private readonly short[] topSideBearings;
///
/// The advance heights array for glyphs with full metric records.
///
private readonly ushort[] advancedHeights;
///
/// Initializes a new instance of the class.
///
/// The advance heights for each glyph.
/// The top side bearings for each glyph.
public VerticalMetricsTable(ushort[] advancedHeights, short[] topSideBearings)
{
this.advancedHeights = advancedHeights;
this.topSideBearings = topSideBearings;
}
///
/// Gets the advance height for the specified glyph. If the glyph index exceeds the
/// number of metric records, the first record's advance height is returned.
///
/// The glyph index.
/// The advance height in font design units.
public ushort GetAdvancedHeight(int glyphIndex)
{
if (glyphIndex >= this.advancedHeights.Length)
{
return this.advancedHeights[0];
}
return this.advancedHeights[glyphIndex];
}
///
/// Gets the top side bearing for the specified glyph.
///
/// The glyph index.
/// The top side bearing in font design units.
internal short GetTopSideBearing(int glyphIndex)
{
if (glyphIndex >= this.topSideBearings.Length)
{
return this.topSideBearings[0];
}
return this.topSideBearings[glyphIndex];
}
///
/// Loads the from the specified font reader.
///
/// The font reader.
/// The , or if the table is not present.
public static VerticalMetricsTable? Load(FontReader reader)
{
// You should load all dependent tables prior to manipulating the reader
VerticalHeadTable headTable = reader.GetTable();
MaximumProfileTable profileTable = reader.GetTable();
// Move to start of table
if (!reader.TryGetReaderAtTablePosition(TableName, out BigEndianBinaryReader? binaryReader))
{
return null;
}
using (binaryReader)
{
return Load(binaryReader, headTable.NumberOfVMetrics, profileTable.GlyphCount);
}
}
///
/// Loads the from the specified binary reader.
///
/// The big-endian binary reader.
/// The number of vertical metric records (from 'vhea').
/// The total number of glyphs in the font (from 'maxp').
/// The .
public static VerticalMetricsTable Load(BigEndianBinaryReader reader, int metricCount, int glyphCount)
{
// Type | Name | Description
// longVerMetric | vMetrics[numberOfVMetrics] | Paired advance height and top side bearing values for each glyph. Records are indexed by glyph ID.
// int16 | leftSideBearing[numGlyphs - numberOfVMetrics] | Top side bearings for glyph IDs greater than or equal to numberOfVMetrics.
int bearingCount = glyphCount - metricCount;
ushort[] advancedHeights = new ushort[metricCount];
short[] topSideBearings = new short[glyphCount];
for (int i = 0; i < metricCount; i++)
{
// longVerMetric Record:
// Type | Name | Description
// -------| ------------- | -----------------------------------------------------------
// uint16 | advanceHeight | The advance height of the glyph.Signed integer in FUnits.
// int16 | topSideBearing| The top side bearing of the glyph. Signed integer in FUnits
advancedHeights[i] = reader.ReadUInt16();
topSideBearings[i] = reader.ReadInt16();
}
for (int i = 0; i < bearingCount; i++)
{
topSideBearings[metricCount + i] = reader.ReadInt16();
}
return new VerticalMetricsTable(advancedHeights, topSideBearings);
}
}
}