// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System; using System.Diagnostics; using System.IO; namespace SixLabors.Fonts.Tables.AdvancedTypographic.Variations { /// /// Item variation data, docs: /// [DebuggerDisplay("ItemCount: {ItemCount}, WordDeltaCount: {WordDeltaCount}, RegionIndexCount: {RegionIndexes.Length}")] internal sealed class ItemVariationData { /// /// Count of "word" deltas. /// private const int WordDeltaCountMask = 0x7FFF; /// /// Flag indicating that "word" deltas are long (int32). /// private const int LongWordsMask = 0x8000; /// /// Initializes a new instance of the class. /// /// The number of delta sets for distinct items. /// The packed word delta count field. /// The array of region indices referenced by this subtable. /// The array of delta set rows. private ItemVariationData(ushort itemCount, ushort wordDeltaCount, ushort[] regionIndices, DeltaSet[] deltaSets) { this.ItemCount = itemCount; this.WordDeltaCount = wordDeltaCount; this.RegionIndexes = regionIndices; this.DeltaSets = deltaSets; } /// /// Gets the number of delta sets for distinct items. /// public ushort ItemCount { get; } /// /// Gets the packed word delta count field. The high bit is a flag indicating long words; /// the low 15 bits give the count of word-sized deltas. /// public ushort WordDeltaCount { get; } /// /// Gets the array of indices into the variation region list for the regions referenced by this subtable. /// public ushort[] RegionIndexes { get; } /// /// Gets the array of delta set rows, one per item. /// public DeltaSet[] DeltaSets { get; } /// /// Loads an from the specified binary reader. /// /// The big-endian binary reader. /// The byte offset from the start of the stream to this subtable. /// The . public static ItemVariationData Load(BigEndianBinaryReader reader, long offset) { // ItemVariationData // +-----------------+----------------------------------------+----------------------------------------------------------------+ // | Type | Name | Description | // +=================+========================================+================================================================+ // | uint16 | itemCount | The number of delta sets for distinct items. | // +-----------------+----------------------------------------+----------------------------------------------------------------+ // | uint16 | wordDeltaCount | A packed field: the high bit is a flag. | // +-----------------+----------------------------------------+----------------------------------------------------------------+ // + uint16 | regionIndexCount | The number of variation regions referenced. | // +-----------------+----------------------------------------+----------------------------------------------------------------+ // + uint16 | regionIndexes[regionIndexCount] | Array of indices into the variation region list for | // + | | the regions referenced by this item variation data table. | // +-----------------+----------------------------------------+----------------------------------------------------------------+ // + DeltaSet | deltaSets[itemCount] | Delta-set rows. | // +-----------------+----------------------------------------+----------------------------------------------------------------+ reader.Seek(offset, SeekOrigin.Begin); ushort itemCount = reader.ReadUInt16(); ushort wordDeltaCount = reader.ReadUInt16(); ushort regionIndexCount = reader.ReadUInt16(); ushort[] regionIndexes = new ushort[regionIndexCount]; for (int i = 0; i < regionIndexCount; i++) { regionIndexes[i] = reader.ReadUInt16(); } // The deltaSets array represents a logical two-dimensional table of delta values with itemCount rows and regionIndexCount columns. // Logically, each DeltaSet record has regionIndexCount number of elements. The elements are represented using long and short types. // These are either int16 and int8, or int32 and int16, according to whether the LONG_WORDS flag is set. // The delta array has a sequence of deltas using the long type followed by a sequence of deltas using the short type. bool longWords = (wordDeltaCount & LongWordsMask) != 0; int wordDeltas = wordDeltaCount & WordDeltaCountMask; var deltaSets = new DeltaSet[itemCount]; for (int i = 0; i < itemCount; i++) { var deltaSet = new DeltaSet(reader, wordDeltas, longWords, regionIndexCount); deltaSets[i] = deltaSet; } return new ItemVariationData(itemCount, wordDeltaCount, regionIndexes, deltaSets); } /// public override int GetHashCode() => HashCode.Combine(this.ItemCount, this.WordDeltaCount, this.RegionIndexes); } }