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

307 lines
16 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.Collections.Generic;
using System.IO;
namespace Typography.OpenFont.Tables
{
//https://docs.microsoft.com/en-us/typography/opentype/spec/mvar
/// <summary>
/// MVAR — Metrics Variations Table
/// </summary>
class MVar : TableEntry
{
public const string _N = "MVAR";
public override string Name => _N;
//The metrics variations table is used in variable fonts
//to provide variations for font-wide metric values
//found in the OS/2 table and other font tables
//The metrics variations table contains an item variation store structure to represent variation data.
//The item variation store and constituent formats are described in the chapter,
//OpenType Font Variations Common Table Formats.
//The item variation store is also used in the HVAR and GDEF tables,
//**BUT** is different from the formats for variation data used in the 'cvar' or 'gvar' tables.
//The item variation store format uses delta-set indices to reference variation delta data
//for particular target font-data items to which they are applied.
//Data external to the item variation store identifies the delta-set index to be used for each given target item.
//Within the MVAR table, an array of value tag records identifies a set of target items,
//and provides the delta-set index used for each.
//The target items are identified by four-byte tags,
//with a given tag representing some font-wide value found in another table
//The item variation store format uses a two-level organization for variation data:
//a store can have multiple item variation data subtables, and each subtable has multiple delta-set rows.
//A delta-set index is a two-part index:
//an outer index that selects a particular item variation data subtable,
//and an inner index that selects a particular delta-set row within that subtable.
//A value record specifies both the outer and inner portions of the delta-set index.
public ValueRecord[] valueRecords;
public ItemVariationStoreTable itemVariationStore;
public MVar()
{
}
protected override void ReadContentFrom(BinaryReader reader)
{
long startAt = reader.BaseStream.Position;
//Metrics variations table:
//Type Name Description
//uint16 majorVersion Major version number of the metrics variations table — set to 1.
//uint16 minorVersion Minor version number of the metrics variations table — set to 0.
//uint16 (reserved) Not used; set to 0.
//uint16 valueRecordSize The size in bytes of each value record — must be greater than zero.
//uint16 valueRecordCount The number of value records — may be zero.
//Offset16 itemVariationStoreOffset Offset in bytes from the start of this table to the item variation store table.
// If valueRecordCount is zero, set to zero;
// if valueRecordCount is greater than zero, must be greater than zero.
//ValueRecord valueRecords[valueRecordCount] Array of value records that identify target items and the associated delta-set index for each.
// The valueTag records must be in binary order of their valueTag field.
//-----------
//
//The valueRecordSize field indicates the size of each value record.
//Future, minor version updates of the MVAR table may define compatible extensions to the value record format with additional fields.
//**Implementations must use the valueRecordSize field to determine the start of each record.**
//The valueRecords array is an array of value records that identify the target,
//font -wide measures for which variation adjustment data is provided (target items),
//and outer and inner delta-set indices for each item into the item variation store data.
ushort majorVersion = reader.ReadUInt16();
ushort minorVersion = reader.ReadUInt16();
ushort reserved = reader.ReadUInt16();
ushort valueRecordSize = reader.ReadUInt16();
ushort valueRecordCount = reader.ReadUInt16();
ushort itemVariationStoreOffset = reader.ReadUInt16();
valueRecords = new ValueRecord[valueRecordCount];
for (int i = 0; i < valueRecordCount; ++i)
{
long recStartAt = reader.BaseStream.Position;
valueRecords[i] = new ValueRecord(
reader.ReadUInt32(),
reader.ReadUInt16(),
reader.ReadUInt16()
);
reader.BaseStream.Position = recStartAt + valueRecordSize;//**Implementations must use the valueRecordSize field to determine the start of each record.**
}
//
//item variation store table
if (valueRecordCount > 0)
{
reader.BaseStream.Position = startAt + itemVariationStoreOffset;
itemVariationStore = new ItemVariationStoreTable();
itemVariationStore.ReadContentFrom(reader);
}
}
public readonly struct ValueRecord
{
//ValueRecord:
//Type Name Description
//Tag valueTag Four-byte tag identifying a font-wide measure.
//uint16 deltaSetOuterIndex A delta-set outer index — used to select an item variation data subtable within the item variation store.
//uint16 deltaSetInnerIndex A delta-set inner index — used to select a delta-set row within an item variation data subtable.
//The value records must be given in binary order of the valueTag values.
//Each tag identifies a font-wide measure found in some other font table.
//For example, if a value record has a value tag of 'hasc',
//this corresponds to the OS/2.sTypoAscender field. Details on the tags used within the MVAR table are provided below.
public readonly uint tag;
public readonly ushort deltaSetOuterIndex;
public readonly ushort deltaSetInnerIndex;
public ValueRecord(uint tag, ushort deltaSetOuterIndex, ushort deltaSetInnerIndex)
{
this.tag = tag;
this.deltaSetOuterIndex = deltaSetOuterIndex;
this.deltaSetInnerIndex = deltaSetInnerIndex;
//Tags in the metrics variations table are case sensitive.
//Tags defined in this table use only lowercase letters or digits.
//Tags that are used in a fonts metrics variations table should be those that are documented in this table specification.
//A font may also use privately-defined tags, which have semantics known only by private agreement.
//Private-use tags must use begin with an uppercase letter and use only uppercase letters or digits.
//If a private-use tag is used in a given font, any application that does not recognize that tag should ignore it.
}
public string TranslatedTag => Utils.TagToString(tag);
#if DEBUG
public override string ToString()
{
return Utils.TagToString(tag) + ",outer:" + deltaSetOuterIndex + ",inner:" + deltaSetInnerIndex;
}
#endif
}
class ValueTagInfo
{
public readonly string Tag;
public readonly string Mnemonic;
public readonly string ValueRepresented;
public ValueTagInfo(string tag, string mnemonic, string valueRepresented)
{
this.Tag = tag;
this.Mnemonic = mnemonic;
this.ValueRepresented = valueRepresented;
}
#if DEBUG
public override string ToString()
{
return Tag + ", " + Mnemonic + ", " + ValueRepresented;
}
#endif
}
static class ValueTags
{
static Dictionary<string, ValueTagInfo> s_registerTags = new Dictionary<string, ValueTagInfo>();
public static bool TryGetValueTagInfo(string tag, out ValueTagInfo valueTagInfo)
{
return s_registerTags.TryGetValue(tag, out valueTagInfo);
}
static void RegisterValueTagInfo(string tag, string mnemonic, string valueRepresented)
{
s_registerTags.Add(tag, new ValueTagInfo(tag, mnemonic, valueRepresented));
}
static ValueTags()
{
//Value tags, ordered by logical grouping:
//Tag Mnemonic Value represented
//'hasc' horizontal ascender OS/2.sTypoAscender
//'hdsc' horizontal descender OS/2.sTypoDescender
//'hlgp' horizontal line gap OS/2.sTypoLineGap
//'hcla' horizontal clipping ascent OS/2.usWinAscent
//'hcld' horizontal clipping descent OS/2.usWinDescent
RegisterValueTagInfo("hasc", "horizontal ascender", "OS/2.sTypoAscender");
RegisterValueTagInfo("hdsc", "horizontal descender", "OS/2.sTypoDescender");
RegisterValueTagInfo("hlgp", "horizontal line gap", "OS/2.sTypoLineGap");
RegisterValueTagInfo("hcla", "horizontal clipping ascent", "OS/2.usWinAscent");
RegisterValueTagInfo("hcld", "horizontal clipping descent", "OS/2.usWinDescent");
//Tag Mnemonic Value represented
//'vasc' vertical ascender vhea.ascent
//'vdsc' vertical descender vhea.descent
//'vlgp' vertical line gap vhea.lineGap
RegisterValueTagInfo("vasc", "vertical ascender", "vhea.ascent");
RegisterValueTagInfo("vdsc", "vertical descender", "vhea.descent");
RegisterValueTagInfo("vlgp", "vertical line gap", "vhea.lineGap");
//Tag Mnemonic Value represented
//'hcrs' horizontal caret rise hhea.caretSlopeRise
//'hcrn' horizontal caret run hhea.caretSlopeRun
//'hcof' horizontal caret offset hhea.caretOffset
RegisterValueTagInfo("hcrs", "horizontal caret rise", "hhea.caretSlopeRise");
RegisterValueTagInfo("hcrn", "horizontal caret run", "hhea.caretSlopeRun");
RegisterValueTagInfo("hcof", "horizontal caret offset", "hhea.caretOffset");
//Tag Mnemonic Value represented
//'vcrs' vertical caret rise vhea.caretSlopeRise
//'vcrn' vertical caret run vhea.caretSlopeRun
//'vcof' vertical caret offset vhea.caretOffset
RegisterValueTagInfo("vcrs", "vertical caret rise", "vhea.caretSlopeRise");
RegisterValueTagInfo("vcrn", "vertical caret run", "vhea.caretSlopeRun");
RegisterValueTagInfo("vcof", "vertical caret offset", "vhea.caretOffset");
//Tag Mnemonic Value represented
//'xhgt' x height OS/2.sxHeight
//'cpht' cap height OS/2.sCapHeight
//'sbxs' subscript em x size OS/2.ySubscriptXSize
//'sbys' subscript em y size OS/2.ySubscriptYSize
//'sbxo' subscript em x offset OS/2.ySubscriptXOffset
//'sbyo' subscript em y offset OS/2.ySubscriptYOffset
//'spxs' superscript em x size OS/2.ySuperscriptXSize
//'spys' superscript em y size OS/2.ySuperscriptYSize
//'spxo' superscript em x offset OS/2.ySuperscriptXOffset
//'spyo' superscript em y offset OS/2.ySuperscriptYOffset
//'strs' strikeout size OS/2.yStrikeoutSize
//'stro' strikeout offset OS/2.yStrikeoutPosition
RegisterValueTagInfo("xhgt", "x height", "OS/2.sTypoAscender");
RegisterValueTagInfo("cpht", "cap height", "OS/2.sTypoDescender");
RegisterValueTagInfo("sbxs", "subscript em x size", "OS/2.ySubscriptXSize");
RegisterValueTagInfo("sbys", "subscript em y size", "OS/2.ySubscriptYSize");
RegisterValueTagInfo("sbxo", "subscript em x offset", "OS/2.ySubscriptXOffset");
RegisterValueTagInfo("sbyo", "subscript em y offset", "OS/2.ySubscriptYOffset");
RegisterValueTagInfo("spxs", "superscript em x size", "OS/2.ySuperscriptXSize");
RegisterValueTagInfo("spys", "superscript em y size", "OS/2.ySuperscriptYSize");
RegisterValueTagInfo("spxo", "superscript em x offset", "OS/2.ySuperscriptXOffset");
RegisterValueTagInfo("spyo", "superscript em y offset", "OS/2.ySuperscriptYOffset");
RegisterValueTagInfo("strs", "strikeout size", "OS/2.yStrikeoutSize");
RegisterValueTagInfo("stro", "strikeout offset", "OS/2.yStrikeoutPosition");
//Tag Mnemonic Value represented
//'unds' underline size post.underlineThickness
//'undo' underline offset post.underlinePosition
RegisterValueTagInfo("unds", "underline size", "post.underlineThickness");
RegisterValueTagInfo("undo", "underline offset", "post.underlinePosition");
//Tag Mnemonic Value represented
//'gsp0' gaspRange[0] gasp.gaspRange[0].rangeMaxPPEM
//'gsp1' gaspRange[1] gasp.gaspRange[1].rangeMaxPPEM
//'gsp2' gaspRange[2] gasp.gaspRange[2].rangeMaxPPEM
//'gsp3' gaspRange[3] gasp.gaspRange[3].rangeMaxPPEM
//'gsp4' gaspRange[4] gasp.gaspRange[4].rangeMaxPPEM
//'gsp5' gaspRange[5] gasp.gaspRange[5].rangeMaxPPEM
//'gsp6' gaspRange[6] gasp.gaspRange[6].rangeMaxPPEM
//'gsp7' gaspRange[7] gasp.gaspRange[7].rangeMaxPPEM
//'gsp8' gaspRange[8] gasp.gaspRange[8].rangeMaxPPEM
//'gsp9' gaspRange[9] gasp.gaspRange[9].rangeMaxPPEM
RegisterValueTagInfo("gsp0", "gaspRange[0]", "gasp.gaspRange[0].rangeMaxPPEM");
RegisterValueTagInfo("gsp1", "gaspRange[1]", "gasp.gaspRange[1].rangeMaxPPEM");
RegisterValueTagInfo("gsp2", "gaspRange[2]", "gasp.gaspRange[2].rangeMaxPPEM");
RegisterValueTagInfo("gsp3", "gaspRange[3]", "gasp.gaspRange[3].rangeMaxPPEM");
RegisterValueTagInfo("gsp4", "gaspRange[4]", "gasp.gaspRange[4].rangeMaxPPEM");
RegisterValueTagInfo("gsp5", "gaspRange[5]", "gasp.gaspRange[5].rangeMaxPPEM");
RegisterValueTagInfo("gsp6", "gaspRange[6]", "gasp.gaspRange[6].rangeMaxPPEM");
RegisterValueTagInfo("gsp7", "gaspRange[7]", "gasp.gaspRange[7].rangeMaxPPEM");
RegisterValueTagInfo("gsp8", "gaspRange[8]", "gasp.gaspRange[8].rangeMaxPPEM");
RegisterValueTagInfo("gsp9", "gaspRange[9]", "gasp.gaspRange[9].rangeMaxPPEM");
}
}
}
}