// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.Fonts.Tables.General { /// /// Represents the horizontal header table, which contains information needed to lay out fonts /// whose characters are written horizontally. /// /// internal class HorizontalHeadTable : Table { /// /// The table name identifier. /// internal const string TableName = "hhea"; /// /// Initializes a new instance of the class. /// /// The typographic ascender. /// The typographic descender. /// The typographic line gap. /// The maximum advance width in font design units. /// The minimum left side bearing. /// The minimum right side bearing. /// The maximum x extent: max(lsb + (xMax - xMin)). /// The caret slope rise used to calculate the slope of the caret. /// The caret slope run used to calculate the slope of the caret. /// The caret offset for slanted fonts. /// The number of horizontal metrics in the 'hmtx' table. public HorizontalHeadTable( short ascender, short descender, short lineGap, ushort advanceWidthMax, short minLeftSideBearing, short minRightSideBearing, short xMaxExtent, short caretSlopeRise, short caretSlopeRun, short caretOffset, ushort numberOfHMetrics) { this.Ascender = ascender; this.Descender = descender; this.LineGap = lineGap; this.AdvanceWidthMax = advanceWidthMax; this.MinLeftSideBearing = minLeftSideBearing; this.MinRightSideBearing = minRightSideBearing; this.XMaxExtent = xMaxExtent; this.CaretSlopeRise = caretSlopeRise; this.CaretSlopeRun = caretSlopeRun; this.CaretOffset = caretOffset; this.NumberOfHMetrics = numberOfHMetrics; } /// /// Gets the maximum advance width, in font design units. /// public ushort AdvanceWidthMax { get; } /// /// Gets the typographic ascender distance from the baseline. /// public short Ascender { get; } /// /// Gets the caret offset for slanted fonts. Set to 0 for non-slanted fonts. /// public short CaretOffset { get; } /// /// Gets the caret slope rise. Set to 1 for a vertical caret. /// public short CaretSlopeRise { get; } /// /// Gets the caret slope run. Set to 0 for a vertical caret. /// public short CaretSlopeRun { get; } /// /// Gets the typographic descender distance from the baseline (typically negative). /// public short Descender { get; } /// /// Gets the typographic line gap. /// public short LineGap { get; } /// /// Gets the minimum left side bearing value. /// public short MinLeftSideBearing { get; } /// /// Gets the minimum right side bearing value. /// public short MinRightSideBearing { get; } /// /// Gets the number of horizontal metrics in the 'hmtx' table. /// public ushort NumberOfHMetrics { get; } /// /// Gets the maximum x extent: max(lsb + (xMax - xMin)). /// public short XMaxExtent { get; } /// /// Loads the from the specified font reader. /// /// The font reader. /// The , or if the table is not present. public static HorizontalHeadTable? Load(FontReader fontReader) { if (!fontReader.TryGetReaderAtTablePosition(TableName, out BigEndianBinaryReader? binaryReader)) { return null; } using (binaryReader) { return Load(binaryReader); } } /// /// Loads the from the specified binary reader. /// /// The big-endian binary reader. /// The . public static HorizontalHeadTable Load(BigEndianBinaryReader reader) { // +--------+---------------------+---------------------------------------------------------------------------------+ // | Type | Name | Description | // +========+=====================+=================================================================================+ // | Fixed | version | 0x00010000 (1.0) | // +--------+---------------------+---------------------------------------------------------------------------------+ // | FWord | ascent | Distance from baseline of highest ascender | // +--------+---------------------+---------------------------------------------------------------------------------+ // | FWord | descent | Distance from baseline of lowest descender | // +--------+---------------------+---------------------------------------------------------------------------------+ // | FWord | lineGap | typographic line gap | // +--------+---------------------+---------------------------------------------------------------------------------+ // | uFWord | advanceWidthMax | must be consistent with horizontal metrics | // +--------+---------------------+---------------------------------------------------------------------------------+ // | FWord | minLeftSideBearing | must be consistent with horizontal metrics | // +--------+---------------------+---------------------------------------------------------------------------------+ // | FWord | minRightSideBearing | must be consistent with horizontal metrics | // +--------+---------------------+---------------------------------------------------------------------------------+ // | FWord | xMaxExtent | max(lsb + (xMax-xMin)) | // +--------+---------------------+---------------------------------------------------------------------------------+ // | int16 | caretSlopeRise | used to calculate the slope of the caret (rise/run) set to 1 for vertical caret | // +--------+---------------------+---------------------------------------------------------------------------------+ // | int16 | caretSlopeRun | 0 for vertical | // +--------+---------------------+---------------------------------------------------------------------------------+ // | FWord | caretOffset | set value to 0 for non-slanted fonts | // +--------+---------------------+---------------------------------------------------------------------------------+ // | int16 | reserved | set value to 0 | // +--------+---------------------+---------------------------------------------------------------------------------+ // | int16 | reserved | set value to 0 | // +--------+---------------------+---------------------------------------------------------------------------------+ // | int16 | reserved | set value to 0 | // +--------+---------------------+---------------------------------------------------------------------------------+ // | int16 | reserved | set value to 0 | // +--------+---------------------+---------------------------------------------------------------------------------+ // | int16 | metricDataFormat | 0 for current format | // +--------+---------------------+---------------------------------------------------------------------------------+ // | uint16 | numOfLongHorMetrics | number of advance widths in metrics table | // +--------+---------------------+---------------------------------------------------------------------------------+ ushort majorVersion = reader.ReadUInt16(); ushort minorVersion = reader.ReadUInt16(); short ascender = reader.ReadFWORD(); short descender = reader.ReadFWORD(); short lineGap = reader.ReadFWORD(); ushort advanceWidthMax = reader.ReadUFWORD(); short minLeftSideBearing = reader.ReadFWORD(); short minRightSideBearing = reader.ReadFWORD(); short xMaxExtent = reader.ReadFWORD(); short caretSlopeRise = reader.ReadInt16(); short caretSlopeRun = reader.ReadInt16(); short caretOffset = reader.ReadInt16(); reader.ReadInt16(); // reserved reader.ReadInt16(); // reserved reader.ReadInt16(); // reserved reader.ReadInt16(); // reserved short metricDataFormat = reader.ReadInt16(); // 0 if (metricDataFormat != 0) { throw new InvalidFontTableException($"Expected metricDataFormat = 0 found {metricDataFormat}", TableName); } ushort numberOfHMetrics = reader.ReadUInt16(); return new HorizontalHeadTable( ascender, descender, lineGap, advanceWidthMax, minLeftSideBearing, minRightSideBearing, xMaxExtent, caretSlopeRise, caretSlopeRun, caretOffset, numberOfHMetrics); } } }