// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Diagnostics.CodeAnalysis; using SixLabors.Fonts.Tables.AdvancedTypographic.Variations; namespace SixLabors.Fonts.Tables.AdvancedTypographic { /// /// The GDEF table contains three kinds of information in subtables: /// 1. glyph class definitions that classify different types of glyphs in a font; /// 2. attachment point lists that identify glyph positioning attachments for each glyph; /// and 3. ligature caret lists that provide information for caret positioning and text selection involving ligatures. /// /// internal sealed class GlyphDefinitionTable : Table { /// /// The OpenType table tag for the GDEF table. /// internal const string TableName = "GDEF"; /// /// Gets the class definition table for glyph types (base, ligature, mark, component). /// public ClassDefinitionTable? GlyphClassDefinition { get; private set; } /// /// Gets the attachment point list table for identifying glyph attachment points. /// public AttachmentListTable? AttachmentListTable { get; private set; } /// /// Gets the ligature caret list table for positioning carets within ligatures. /// public LigatureCaretList? LigatureCaretList { get; private set; } /// /// Gets the class definition table for mark attachment types. /// public ClassDefinitionTable? MarkAttachmentClassDef { get; private set; } /// /// Gets the mark glyph sets table for filtering marks during lookup processing. /// public MarkGlyphSetsTable? MarkGlyphSetsTable { get; private set; } /// /// Gets the item variation store table for variable font GDEF variations. /// public ItemVariationStore? ItemVariationStore { get; private set; } /// /// Loads the from the font reader. /// /// The font reader. /// The , or if not present. public static GlyphDefinitionTable? Load(FontReader reader) { if (!reader.TryGetReaderAtTablePosition(TableName, out BigEndianBinaryReader? binaryReader)) { return null; } using (binaryReader) { return Load(binaryReader); } } /// /// Tries to get the glyph class for the specified glyph. /// /// The glyph identifier. /// When this method returns, contains the glyph class if found. /// if the glyph class was found; otherwise, . public bool TryGetGlyphClass(ushort glyphId, [NotNullWhen(true)] out GlyphClassDef? glyphClass) { glyphClass = null; if (this.GlyphClassDefinition is null) { return false; } glyphClass = (GlyphClassDef)this.GlyphClassDefinition.ClassIndexOf(glyphId); return true; } /// /// Tries to get the mark attachment class for the specified glyph. /// /// The glyph identifier. /// When this method returns, contains the mark attachment class if found. /// if the mark attachment class was found; otherwise, . public bool TryGetMarkAttachmentClass(ushort glyphId, [NotNullWhen(true)] out GlyphClassDef? markAttachmentClass) { markAttachmentClass = null; if (this.MarkAttachmentClassDef is null) { return false; } markAttachmentClass = (GlyphClassDef)this.MarkAttachmentClassDef.ClassIndexOf(glyphId); return true; } /// /// Determines whether the specified glyph belongs to the given mark glyph set. /// /// The index of the mark glyph set. /// The glyph identifier. /// if the glyph is in the set; otherwise, . public bool IsInMarkGlyphSet(ushort markGlyphSetIndex, ushort glyphId) => this.MarkGlyphSetsTable?.Contains(markGlyphSetIndex, glyphId) == true; /// /// Loads the from a big endian binary reader. /// /// The big endian binary reader. /// The . public static GlyphDefinitionTable Load(BigEndianBinaryReader reader) { // Header version 1.0 // Type | Name | Description // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // uint16 | majorVersion | Major version of the GDEF table, = 1 // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // uint16 | minorVersion | Minor version of the GDEF table, = 0 // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | glyphClassDefOffset | Offset to class definition table for glyph type, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | attachListOffset | Offset to attachment point list table, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | ligCaretListOffset | Offset to ligature caret list table, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | markAttachClassDefOffset | Offset to class definition table for mark attachment type, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Header version 1.2 // Type | Name | Description // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // uint16 | majorVersion | Major version of the GDEF table, = 1 // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // uint16 | minorVersion | Minor version of the GDEF table, = 0 // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | glyphClassDefOffset | Offset to class definition table for glyph type, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | attachListOffset | Offset to attachment point list table, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | ligCaretListOffset | Offset to ligature caret list table, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | markAttachClassDefOffset | Offset to class definition table for mark attachment type, from beginning of GDEF header (may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | markGlyphSetsDefOffset | Offset to the table of mark glyph set definitions, from beginning of GDEF header (may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Header version 1.3 // Type | Name | Description // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // uint16 | majorVersion | Major version of the GDEF table, = 1 // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // uint16 | minorVersion | Minor version of the GDEF table, = 0 // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | glyphClassDefOffset | Offset to class definition table for glyph type, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | attachListOffset | Offset to attachment point list table, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | ligCaretListOffset | Offset to ligature caret list table, from beginning of GDEF header(may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | markAttachClassDefOffset | Offset to class definition table for mark attachment type, from beginning of GDEF header (may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset16 | markGlyphSetsDefOffset | Offset to the table of mark glyph set definitions, from beginning of GDEF header (may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- // Offset32 | itemVarStoreOffset | Offset to the Item Variation Store table, from beginning of GDEF header (may be NULL). // ----------|--------------------------|-------------------------------------------------------------------------------------------------------- ushort majorVersion = reader.ReadUInt16(); ushort minorVersion = reader.ReadUInt16(); ushort glyphClassDefOffset = reader.ReadUInt16(); ushort attachListOffset = reader.ReadUInt16(); ushort ligatureCaretListOffset = reader.ReadOffset16(); ushort markAttachClassDefOffset = reader.ReadOffset16(); ushort markGlyphSetsDefOffset = 0; uint itemVarStoreOffset = 0; switch (minorVersion) { case 0: break; case 2: markGlyphSetsDefOffset = reader.ReadUInt16(); break; case 3: markGlyphSetsDefOffset = reader.ReadUInt16(); itemVarStoreOffset = reader.ReadUInt32(); break; default: throw new InvalidFontFileException($"Invalid value for 'minor version' {minorVersion} of GDEF table. Should be '0', '2' or '3'."); } ClassDefinitionTable.TryLoad(reader, glyphClassDefOffset, out ClassDefinitionTable? classDefinitionTable); AttachmentListTable? attachmentListTable = attachListOffset is 0 ? null : AttachmentListTable.Load(reader, attachListOffset); LigatureCaretList? ligatureCaretList = ligatureCaretListOffset is 0 ? null : LigatureCaretList.Load(reader, ligatureCaretListOffset); ClassDefinitionTable.TryLoad(reader, markAttachClassDefOffset, out ClassDefinitionTable? markAttachmentClassDef); MarkGlyphSetsTable? markGlyphSetsTable = markGlyphSetsDefOffset is 0 ? null : MarkGlyphSetsTable.Load(reader, markGlyphSetsDefOffset); ItemVariationStore? itemVariationStore = null; if (itemVarStoreOffset != 0) { itemVariationStore = ItemVariationStore.Load(reader, itemVarStoreOffset); } return new GlyphDefinitionTable() { GlyphClassDefinition = classDefinitionTable, AttachmentListTable = attachmentListTable, LigatureCaretList = ligatureCaretList, MarkAttachmentClassDef = markAttachmentClassDef, MarkGlyphSetsTable = markGlyphSetsTable, ItemVariationStore = itemVariationStore }; } } }