ImageSharp/SixLabors.Fonts/Tables/AdvancedTypographic/Variations/FVarTable.cs
2026-08-03 22:31:27 +02:00

129 lines
7.3 KiB
C#

// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
namespace SixLabors.Fonts.Tables.AdvancedTypographic.Variations {
/// <summary>
/// Implements reading the Font Variations Table `fvar`.
/// <see href="https://docs.microsoft.com/de-de/typography/opentype/spec/fvar"/>
/// </summary>
internal class FVarTable : Table
{
/// <summary>
/// The table name identifier for the fvar table.
/// </summary>
internal const string TableName = "fvar";
/// <summary>
/// Initializes a new instance of the <see cref="FVarTable"/> class.
/// </summary>
/// <param name="axisCount">The number of variation axes.</param>
/// <param name="axes">The array of variation axis records.</param>
/// <param name="instances">The array of named instance records.</param>
public FVarTable(ushort axisCount, VariationAxisRecord[] axes, InstanceRecord[] instances)
{
this.AxisCount = axisCount;
this.Axes = axes;
this.Instances = instances;
}
/// <summary>
/// Gets the number of variation axes defined in this font.
/// </summary>
public ushort AxisCount { get; }
/// <summary>
/// Gets the array of variation axis records defining each axis (e.g. weight, width).
/// </summary>
public VariationAxisRecord[] Axes { get; }
/// <summary>
/// Gets the array of named instance records defined in this font.
/// </summary>
public InstanceRecord[] Instances { get; }
/// <summary>
/// Loads the fvar table from the specified font reader.
/// </summary>
/// <param name="reader">The font reader.</param>
/// <returns>The <see cref="FVarTable"/>, or <see langword="null"/> if the table is not present.</returns>
public static FVarTable? Load(FontReader reader)
{
if (!reader.TryGetReaderAtTablePosition(TableName, out BigEndianBinaryReader? binaryReader))
{
return null;
}
using (binaryReader)
{
return Load(binaryReader);
}
}
/// <summary>
/// Loads the fvar table from the specified binary reader.
/// </summary>
/// <param name="reader">The big-endian binary reader positioned at the start of the fvar table.</param>
/// <returns>The <see cref="FVarTable"/>.</returns>
public static FVarTable Load(BigEndianBinaryReader reader)
{
// VariationsTable `fvar`
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | Type | Name | Description |
// +=================+========================================+================================================================+
// | uint16 | majorVersion | Major version number of the font variations table — set to 1. |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | uint16 | minorVersion | Minor version number of the font variations table — set to 0. |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | Offset16 | axesArrayOffset | Offset in bytes from the beginning of the table to the start |
// | | | of the VariationAxisRecord array. |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | uint16 | (reserved) | This field is permanently reserved. Set to 2. |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | uint16 | axisCount | The number of variation axes in the font |
// | | | (the number of records in the axes array). |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | uint16 | axisSize | The size in bytes of each VariationAxisRecord |
// | | | — set to 20 (0x0014) for this version. |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | uint16 | instanceCount | The number of named instances defined in the font |
// | | | (the number of records in the instances array). |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
// | uint16 | instanceSize | The size in bytes of each InstanceRecord |
// | | | — set to either axisCount * sizeof(Fixed) + 4, |
// | | | or to axisCount * sizeof(Fixed) + 6. |
// +-----------------+----------------------------------------+----------------------------------------------------------------+
long startOffset = reader.BaseStream.Position;
ushort major = reader.ReadUInt16();
ushort minor = reader.ReadUInt16();
ushort axesArrayOffset = reader.ReadOffset16();
ushort reserved = reader.ReadUInt16();
ushort axisCount = reader.ReadUInt16();
ushort axisSize = reader.ReadUInt16();
ushort instanceCount = reader.ReadUInt16();
ushort instanceSize = reader.ReadUInt16();
if (major != 1)
{
throw new NotSupportedException("Only version 1 of fvar table is supported");
}
VariationAxisRecord[] axesArray = new VariationAxisRecord[axisCount];
for (int i = 0; i < axisCount; i++)
{
axesArray[i] = VariationAxisRecord.Load(reader, axesArrayOffset + (axisSize * i));
}
InstanceRecord[] instances = new InstanceRecord[instanceCount];
long instancesOffset = reader.BaseStream.Position - startOffset;
for (int i = 0; i < instanceCount; i++)
{
instances[i] = InstanceRecord.Load(reader, instancesOffset + (i * instanceSize), axisCount);
}
return new FVarTable(axisCount, axesArray, instances);
}
}
}