Files
QuickLook/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Typography.OpenFont/Tables.AdvancedLayout/ScriptTable.cs
2024-12-30 04:21:24 +08:00

173 lines
8.9 KiB
C#

//Apache2, 2016-present, WinterDev
//https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record
using System.IO;
namespace Typography.OpenFont.Tables
{
//Script Table and Language System Record
//A Script table identifies each language system that defines how to use the glyphs in a script for a particular language.
//It also references a default language system that defines how to use the script's glyphs in the absence of language-specific knowledge.
//A Script table begins with an offset to the Default Language System table (DefaultLangSys),
//which defines the set of features that regulate the default behavior of the script.
//Next, Language System Count (LangSysCount) defines the number of language systems (excluding the DefaultLangSys) that use the script.
//In addition, an array of Language System Records (LangSysRecord) defines each language system (excluding the default)
//with an identification tag (LangSysTag) and an offset to a Language System table (LangSys).
//The LangSysRecord array stores the records alphabetically by LangSysTag.
//If no language-specific script behavior is defined, the LangSysCount is set to zero (0), and no LangSysRecords are allocated.
//-----------------------
//Script table
//Type Name Description
//Offset16 defaultLangSys Offset to DefaultLangSys table-from beginning of Script table-may be NULL
//uint16 langSysCount Number of LangSysRecords for this script-excluding the DefaultLangSys
//LangSysRecord langSysRecords[langSysCount] Array of LangSysRecords-listed alphabetically by LangSysTag
//-----------------------
//LangSysRecord
//Type Name Description
//Tag langSysTag 4-byte LangSysTag identifier
//Offset16 langSysOffset Offset to LangSys table-from beginning of Script table
//-----------------------
//
//Language System Table
//-----------------------
//The Language System table (LangSys) identifies language-system features
//used to render the glyphs in a script. (The LookupOrder offset is reserved for future use.)
//Optionally, a LangSys table may define a Required Feature Index (ReqFeatureIndex) to specify one feature as required
//within the context of a particular language system. For example, in the Cyrillic script,
//the Serbian language system always renders certain glyphs differently than the Russian language system.
//Only one feature index value can be tagged as the ReqFeatureIndex.
//This is not a functional limitation, however, because the feature and lookup definitions in OpenType
//Layout are structured so that one feature table can reference many glyph substitution and positioning lookups.
//When no required features are defined, then the ReqFeatureIndex is set to 0xFFFF.
//All other features are optional. For each optional feature,
//a zero-based index value references a record (FeatureRecord) in the FeatureRecord array,
//which is stored in a Feature List table (FeatureList).
//The feature indices themselves (excluding the ReqFeatureIndex) are stored in arbitrary order in the FeatureIndex array.
//The FeatureCount specifies the total number of features listed in the FeatureIndex array.
//Features are specified in full in the FeatureList table, FeatureRecord, and Feature table,
//which are described later in this chapter.
//Example 2 at the end of this chapter shows a Script table, LangSysRecord, and LangSys table used for contextual positioning in the Arabic script.
//---------------------
//LangSys table
//Type Name Description
//Offset16 lookupOrder = NULL (reserved for an offset to a reordering table)
//uint16 requiredFeatureIndex Index of a feature required for this language system- if no required features = 0xFFFF
//uint16 featureIndexCount Number of FeatureIndex values for this language system-excludes the required feature
//uint16 featureIndices[featureIndexCount] Array of indices into the FeatureList-in arbitrary order
//---------------------
public class ScriptTable
{
public uint scriptTag { get; internal set; }
public LangSysTable defaultLang { get; private set; }// be NULL
public LangSysTable[] langSysTables { get; private set; }
public string ScriptTagName => Utils.TagToString(this.scriptTag);
public static ScriptTable CreateFrom(BinaryReader reader, long beginAt)
{
reader.BaseStream.Seek(beginAt, SeekOrigin.Begin);
//---------------
//Script table
//Type Name Description
//Offset16 defaultLangSys Offset to DefaultLangSys table-from beginning of Script table-may be NULL
//uint16 langSysCount Number of LangSysRecords for this script-excluding the DefaultLangSys
//LangSysRecord langSysRecords[langSysCount] Array of LangSysRecords-listed alphabetically by LangSysTag
//---------------
ScriptTable scriptTable = new ScriptTable();
ushort defaultLangSysOffset = reader.ReadUInt16();
ushort langSysCount = reader.ReadUInt16();
LangSysTable[] langSysTables = scriptTable.langSysTables = new LangSysTable[langSysCount];
for (int i = 0; i < langSysCount; ++i)
{
//-----------------------
//LangSysRecord
//Type Name Description
//Tag langSysTag 4-byte LangSysTag identifier
//Offset16 langSysOffset Offset to LangSys table-from beginning of Script table
//-----------------------
langSysTables[i] = new LangSysTable(
reader.ReadUInt32(), // 4-byte LangSysTag identifier
reader.ReadUInt16()); //offset
}
//-----------
if (defaultLangSysOffset > 0)
{
scriptTable.defaultLang = new LangSysTable(0, defaultLangSysOffset);
reader.BaseStream.Seek(beginAt + defaultLangSysOffset, SeekOrigin.Begin);
scriptTable.defaultLang.ReadFrom(reader);
}
//-----------
//read actual content of each table
for (int i = 0; i < langSysCount; ++i)
{
LangSysTable langSysTable = langSysTables[i];
reader.BaseStream.Seek(beginAt + langSysTable.offset, SeekOrigin.Begin);
langSysTable.ReadFrom(reader);
}
return scriptTable;
}
#if DEBUG
public override string ToString()
{
return Utils.TagToString(this.scriptTag);
}
#endif
public class LangSysTable
{
//The Language System table (LangSys) identifies language-system features
//used to render the glyphs in a script. (The LookupOrder offset is reserved for future use.)
//
public uint langSysTagIden { get; private set; }
internal readonly ushort offset;
//
public ushort[] featureIndexList { get; private set; }
public ushort RequiredFeatureIndex { get; private set; }
public LangSysTable(uint langSysTagIden, ushort offset)
{
this.offset = offset;
this.langSysTagIden = langSysTagIden;
}
public void ReadFrom(BinaryReader reader)
{
//---------------------
//LangSys table
//Type Name Description
//Offset16 lookupOrder = NULL (reserved for an offset to a reordering table)
//uint16 requiredFeatureIndex Index of a feature required for this language system- if no required features = 0xFFFF
//uint16 featureIndexCount Number of FeatureIndex values for this language system-excludes the required feature
//uint16 featureIndices[featureIndexCount] Array of indices into the FeatureList-in arbitrary order
//---------------------
ushort lookupOrder = reader.ReadUInt16();//reserve
RequiredFeatureIndex = reader.ReadUInt16();
ushort featureIndexCount = reader.ReadUInt16();
featureIndexList = Utils.ReadUInt16Array(reader, featureIndexCount);
}
public bool HasRequireFeature => RequiredFeatureIndex != 0xFFFF;
public string LangSysTagIdenString => (langSysTagIden == 0) ? "" : Utils.TagToString(langSysTagIden);
#if DEBUG
public override string ToString() => LangSysTagIdenString;
#endif
}
}
}