Files
2024-12-30 04:21:24 +08:00

201 lines
8.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//MIT, 2019-present, WinterDev
using System;
using System.IO;
namespace Typography.OpenFont.Tables
{
//https://docs.microsoft.com/en-us/typography/opentype/spec/fvar
//'fvar' Header
//The format of the font variations table header is as follows.
//Note: The 'fvar' table describes a fonts variation space,
//and other variation tables provide variation data to describe
//how different data items are varied across the fonts variation space
/// <summary>
/// fvar font variations
/// </summary>
class FVar : TableEntry
{
public const string _N = "fvar";
public override string Name => _N;
public VariableAxisRecord[] variableAxisRecords;
public InstanceRecord[] instanceRecords;
//
protected override void ReadContentFrom(BinaryReader reader)
{
//Font variations header:
//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 beginAt = reader.BaseStream.Position;
//header:
ushort majorVersion = reader.ReadUInt16();
ushort minorVersion = reader.ReadUInt16();
ushort axesArrayOffset = reader.ReadUInt16();
ushort reserved = reader.ReadUInt16();//set to 2
ushort axisCount = reader.ReadUInt16();
ushort axisSize = reader.ReadUInt16();
ushort instanceCount = reader.ReadUInt16();
ushort instanceSize = reader.ReadUInt16();
//The header is followed by axes and instances arrays.
//The location of the axes array is specified in the axesArrayOffset field;
//the instances array directly follows the axes array.
//Type Name Description
//VariationAxisRecord axes[axisCount] The variation axis array.
//InstanceRecord instances[instanceCount] The named instance array.
//Note: The axisSize and instanceSize fields indicate
//the size of the VariationAxisRecord and InstanceRecord structures.
//In this version of the 'fvar' table, the InstanceRecord structure has an optional field,
//and so two different size formulations are possible.
//Future minor-version updates of the 'fvar' table may define compatible extensions to either formats.
//***Implementations must use the axisSize and instanceSize fields to determine the start of each record.***
//The set of axes that make up the fonts variation space are defined by an array of variation axis records.
//The number of records, and the number of axes, is determined by the axisCount field.
//A functional variable font must have an axisCount value that is greater than zero.
//If axisCount is zero, then the font is not functional as a variable font, ***
//and must be treated as a non-variable font; ***
//any variation-specific tables or data is ignored.
variableAxisRecords = new VariableAxisRecord[axisCount];
for (int i = 0; i < axisCount; ++i)
{
long pos = reader.BaseStream.Position;
VariableAxisRecord varAxisRecord = new VariableAxisRecord();
varAxisRecord.ReadContent(reader);
variableAxisRecords[i] = varAxisRecord;
if (reader.BaseStream.Position != pos + axisSize)
{
//***Implementations must use the axisSize and instanceSize fields to determine the start of each record.***
reader.BaseStream.Position = pos + axisSize;
}
}
instanceRecords = new InstanceRecord[instanceCount];
for (int i = 0; i < instanceCount; ++i)
{
long pos = reader.BaseStream.Position;
InstanceRecord instanecRec = new InstanceRecord();
instanecRec.ReadContent(reader, axisCount, instanceSize);
if (reader.BaseStream.Position != pos + instanceSize)
{
//***Implementations must use the axisSize and instanceSize fields to determine the start of each record.***
reader.BaseStream.Position = pos + instanceSize;
}
}
}
public class VariableAxisRecord
{
//VariationAxisRecord
//The format of the variation axis record is as follows:
//VariationAxisRecord
//Type Name Description
//Tag axisTag Tag identifying the design variation for the axis.
//Fixed minValue The minimum coordinate value for the axis.
//Fixed defaultValue The default coordinate value for the axis.
//Fixed maxValue The maximum coordinate value for the axis.
//uint16 flags Axis qualifiers — see details below.
//uint16 axisNameID The name ID for entries in the 'name' table that provide a display name for this axis.
public string axisTag;
public float minValue;
public float defaultValue;
public float maxValue;
public ushort flags;
public ushort axisNameID;
public void ReadContent(BinaryReader reader)
{
axisTag = Utils.TagToString(reader.ReadUInt32());//4
minValue = reader.ReadFixed();//4
defaultValue = reader.ReadFixed();//4
maxValue = reader.ReadFixed();//4
flags = reader.ReadUInt16();//2
axisNameID = reader.ReadUInt16();//2
//
}
}
public class InstanceRecord
{
//InstanceRecord
//The instance record format includes an array of n-tuple coordinate arrays
//that define position within the fonts variation space.
//The n-tuple array has the following format:
//Tuple Record(Fixed):
//Type Name Description
//Fixed coordinates[axisCount] Coordinate array specifying a position within the fonts variation space.
//The format of the instance record is as follows.
//InstanceRecord:
//Type Name Description
//uint16 subfamilyNameID The name ID for entries in the 'name' table that provide subfamily names for this instance.
//uint16 flags Reserved for future use — set to 0.
//Tuple coordinates The coordinates array for this instance.
//uint16 postScriptNameID Optional.The name ID for entries in the 'name' table that provide PostScript names for this instance.
public ushort subfamilyNameID;//point to name table, will be resolved later
public ushort flags;
public TupleRecord coordinates;
public ushort postScriptNameID;//point to name table, will be resolved later
public void ReadContent(BinaryReader reader, int axisCount, int instanceRecordSize)
{
long expectedEndPos = reader.BaseStream.Position + instanceRecordSize;
subfamilyNameID = reader.ReadUInt16();
flags = reader.ReadUInt16();
float[] coords = new float[axisCount];
for (int i = 0; i < axisCount; ++i)
{
coords[i] = reader.ReadFixed();
}
coordinates = new TupleRecord(coords);
if (reader.BaseStream.Position < expectedEndPos)
{
//optional field
postScriptNameID = reader.ReadUInt16();
}
}
}
}
}