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