// 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); } } }