mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-12 10:19:07 +00:00
290 lines
13 KiB
C#
290 lines
13 KiB
C#
//MIT, 2019-present, WinterDev
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace Typography.OpenFont.Tables
|
|
{
|
|
/// <summary>
|
|
/// The Justification table
|
|
/// </summary>
|
|
public partial class JSTF : TableEntry
|
|
{
|
|
//https://docs.microsoft.com/en-us/typography/opentype/spec/jstf
|
|
|
|
public const string _N = "JSTF";
|
|
public override string Name => _N;
|
|
JstfScriptTable[] _jsftScriptTables;
|
|
|
|
//The Justification table(JSTF) provides font developers with additional control over glyph substitution and
|
|
//positioning in justified text.
|
|
|
|
//Text-processing clients now have more options to expand or
|
|
//shrink word and glyph spacing so text fills the specified line length.
|
|
|
|
protected override void ReadContentFrom(BinaryReader reader)
|
|
{
|
|
//test this with Arial font
|
|
|
|
//JSTF header
|
|
//Type Name Description
|
|
//uint16 majorVersion Major version of the JSTF table, = 1
|
|
//uint16 minorVersion Minor version of the JSTF table, = 0
|
|
//uint16 jstfScriptCount Number of JstfScriptRecords in this table
|
|
//JstfScriptRecord jstfScriptRecords[jstfScriptCount] Array of JstfScriptRecords, in alphabetical order by jstfScriptTag
|
|
|
|
//----------
|
|
//JstfScriptRecord
|
|
//Type Name Description
|
|
//Tag jstfScriptTag 4-byte JstfScript identification
|
|
//Offset16 jstfScriptOffset Offset to JstfScript table, from beginning of JSTF Header
|
|
|
|
long tableStartAt = reader.BaseStream.Position;
|
|
//
|
|
ushort majorVersion = reader.ReadUInt16();
|
|
ushort minorVersion = reader.ReadUInt16();
|
|
ushort jstfScriptCount = reader.ReadUInt16();
|
|
|
|
JstfScriptRecord[] recs = new JstfScriptRecord[jstfScriptCount];
|
|
for (int i = 0; i < recs.Length; ++i)
|
|
{
|
|
recs[i] = new JstfScriptRecord(
|
|
Utils.TagToString(reader.ReadUInt32()),
|
|
reader.ReadUInt16()
|
|
);
|
|
}
|
|
|
|
_jsftScriptTables = new JstfScriptTable[recs.Length];
|
|
for (int i = 0; i < recs.Length; ++i)
|
|
{
|
|
JstfScriptRecord rec = recs[i];
|
|
reader.BaseStream.Position = tableStartAt + rec.jstfScriptOffset;
|
|
|
|
JstfScriptTable jstfScriptTable = ReadJstfScriptTable(reader);
|
|
jstfScriptTable.ScriptTag = rec.jstfScriptTag;
|
|
_jsftScriptTables[i] = jstfScriptTable;
|
|
}
|
|
}
|
|
readonly struct JstfScriptRecord
|
|
{
|
|
public readonly string jstfScriptTag;
|
|
public readonly ushort jstfScriptOffset;
|
|
public JstfScriptRecord(string jstfScriptTag, ushort jstfScriptOffset)
|
|
{
|
|
this.jstfScriptTag = jstfScriptTag;
|
|
this.jstfScriptOffset = jstfScriptOffset;
|
|
}
|
|
}
|
|
|
|
public class JstfScriptTable
|
|
{
|
|
public ushort[] extenderGlyphs;
|
|
|
|
public JstfLangSysRecord defaultLangSys;
|
|
public JstfLangSysRecord[] other;
|
|
|
|
public JstfScriptTable()
|
|
{
|
|
}
|
|
public string ScriptTag { get; set; }
|
|
#if DEBUG
|
|
public override string ToString()
|
|
{
|
|
return ScriptTag;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static JstfScriptTable ReadJstfScriptTable(BinaryReader reader)
|
|
{
|
|
//A Justification Script(JstfScript) table describes the justification information for a single script.
|
|
//It consists of an offset to a table that defines extender glyphs(extenderGlyphOffset),
|
|
//an offset to a default justification table for the script (defJstfLangSysOffset),
|
|
//and a count of the language systems that define justification data(jstfLangSysCount).
|
|
|
|
//If a script uses the same justification information for all language systems,
|
|
//the font developer defines only the default JstfLangSys table and
|
|
//sets the jstfLangSysCount value to zero(0).
|
|
|
|
//However, if any language system has unique justification suggestions,
|
|
//jstfLangSysCount will be a positive value,
|
|
//and the JstfScript table must include an array of records(jstfLangSysRecords),
|
|
//one for each language system.Each JstfLangSysRecord contains a language system tag(jstfLangSysTag) and
|
|
//an offset to a justification language system table(jstfLangSysOffset).
|
|
|
|
//In the jstfLangSysRecords array, records are ordered alphabetically by jstfLangSysTag.
|
|
|
|
//JstfScript table
|
|
//Type Name Description
|
|
//Offset16 extenderGlyphOffset Offset to ExtenderGlyph table, from beginning of JstfScript table(may be NULL)
|
|
//Offset16 defJstfLangSysOffset Offset to default JstfLangSys table, from beginning of JstfScript table(may be NULL)
|
|
//uint16 jstfLangSysCount Number of JstfLangSysRecords in this table - may be zero(0)
|
|
//JstfLangSysRecord jstfLangSysRecords[jstfLangSysCount] Array of JstfLangSysRecords, in alphabetical order by JstfLangSysTag
|
|
|
|
JstfScriptTable jstfScriptTable = new JstfScriptTable();
|
|
|
|
long tableStartAt = reader.BaseStream.Position;
|
|
|
|
ushort extenderGlyphOffset = reader.ReadUInt16();
|
|
ushort defJstfLangSysOffset = reader.ReadUInt16();
|
|
ushort jstfLangSysCount = reader.ReadUInt16();
|
|
|
|
if (jstfLangSysCount > 0)
|
|
{
|
|
JstfLangSysRecord[] recs = new JstfLangSysRecord[jstfLangSysCount];
|
|
for (int i = 0; i < jstfLangSysCount; ++i)
|
|
{
|
|
recs[i] = ReadJstfLangSysRecord(reader);
|
|
}
|
|
jstfScriptTable.other = recs;
|
|
}
|
|
|
|
|
|
if (extenderGlyphOffset > 0)
|
|
{
|
|
reader.BaseStream.Position = tableStartAt + extenderGlyphOffset;
|
|
jstfScriptTable.extenderGlyphs = ReadExtenderGlyphTable(reader);
|
|
}
|
|
|
|
if (defJstfLangSysOffset > 0)
|
|
{
|
|
reader.BaseStream.Position = tableStartAt + defJstfLangSysOffset;
|
|
jstfScriptTable.defaultLangSys = ReadJstfLangSysRecord(reader);
|
|
}
|
|
return jstfScriptTable;
|
|
}
|
|
static ushort[] ReadExtenderGlyphTable(BinaryReader reader)
|
|
{
|
|
//Extender Glyph Table
|
|
|
|
//The Extender Glyph table(ExtenderGlyph) lists indices of glyphs, 3
|
|
//such as Arabic kashidas,
|
|
//that a client may insert to extend the length of the line for justification.
|
|
//The table consists of a count of the extender glyphs for the script (glyphCount) and
|
|
//an array of extender glyph indices(extenderGlyphs), arranged in increasing numerical order.
|
|
|
|
//ExtenderGlyph table
|
|
//Type Name Description
|
|
//uint16 glyphCount Number of extender glyphs in this script
|
|
//uint16 extenderGlyphs[glyphCount] Extender glyph IDs — in increasing numerical order
|
|
|
|
ushort glyphCount = reader.ReadUInt16();
|
|
return Utils.ReadUInt16Array(reader, glyphCount);
|
|
}
|
|
|
|
|
|
public struct JstfLangSysRecord
|
|
{
|
|
public JstfPriority[] jstfPriority;
|
|
|
|
}
|
|
static JstfLangSysRecord ReadJstfLangSysRecord(BinaryReader reader)
|
|
{
|
|
//Justification Language System Table
|
|
|
|
//The Justification Language System(JstfLangSys) table contains an array of justification suggestions,
|
|
//ordered by priority.
|
|
//A text-processing client doing justification should begin with the suggestion that has a zero(0) priority,
|
|
//and then-as necessary - apply suggestions of increasing priority until the text is justified.
|
|
|
|
//The font developer defines the number and the meaning of the priority levels.
|
|
//Each priority level stands alone; its suggestions are not added to the previous levels.
|
|
//The JstfLangSys table consists of a count of the number of priority levels(jstfPriorityCount) and
|
|
//an array of offsets to Justification Priority tables(jstfPriorityOffsets),
|
|
//stored in priority order.
|
|
|
|
//JstfLangSys table
|
|
|
|
//stfLangSys table
|
|
//Type Name Description
|
|
//uint16 jstfPriorityCount Number of JstfPriority tables
|
|
//Offset16 jstfPriorityOffsets[jstfPriorityCount] Array of offsets to JstfPriority tables, from beginning of JstfLangSys table, in priority order
|
|
|
|
long tableStartAt = reader.BaseStream.Position;
|
|
ushort jstfPriorityCount = reader.ReadUInt16();
|
|
ushort[] jstfPriorityOffsets = Utils.ReadUInt16Array(reader, jstfPriorityCount);
|
|
|
|
JstfPriority[] jstPriorities = new JstfPriority[jstfPriorityCount];
|
|
|
|
for (int i = 0; i < jstfPriorityOffsets.Length; ++i)
|
|
{
|
|
reader.BaseStream.Position = tableStartAt + jstfPriorityOffsets[i];
|
|
jstPriorities[i] = ReadJstfPriority(reader);
|
|
}
|
|
|
|
return new JstfLangSysRecord() { jstfPriority = jstPriorities };
|
|
|
|
}
|
|
|
|
public class JstfPriority
|
|
{
|
|
//JstfPriority table
|
|
|
|
//Type Name Description
|
|
//Offset16 shrinkageEnableGSUB Offset to shrinkage-enable JstfGSUBModList table, from beginning of JstfPriority table(may be NULL)
|
|
//Offset16 shrinkageDisableGSUB Offset to shrinkage-disable JstfGSUBModList table, from beginning of JstfPriority table(may be NULL)
|
|
public ushort shrinkageEnableGSUB;
|
|
public ushort shrinkageDisableGSUB;
|
|
|
|
//Offset16 shrinkageEnableGPOS Offset to shrinkage-enable JstfGPOSModList table, from beginning of JstfPriority table(may be NULL)
|
|
//Offset16 shrinkageDisableGPOS Offset to shrinkage-disable JstfGPOSModList table, from beginning of JstfPriority table(may be NULL)
|
|
|
|
public ushort shrinkageEnableGPOS;
|
|
public ushort shrinkageDisableGPOS;
|
|
|
|
//Offset16 shrinkageJstfMax Offset to shrinkage JstfMax table, from beginning of JstfPriority table(may be NULL)
|
|
public ushort shrinkageJstfMax;
|
|
|
|
//Offset16 extensionEnableGSUB Offset to extension-enable JstfGSUBModList table, from beginnning of JstfPriority table(may be NULL)
|
|
//Offset16 extensionDisableGSUB Offset to extension-disable JstfGSUBModList table, from beginning of JstfPriority table(may be NULL)
|
|
|
|
public ushort extensionEnableGSUB;
|
|
public ushort extensionDisableGSUB;
|
|
|
|
//Offset16 extensionEnableGPOS Offset to extension-enable JstfGPOSModList table, from beginning of JstfPriority table(may be NULL)
|
|
//Offset16 extensionDisableGPOS Offset to extension-disable JstfGPOSModList table, from beginning of JstfPriority table(may be NULL)
|
|
|
|
public ushort extensionEnableGPOS;
|
|
public ushort extensionDisableGPOS;
|
|
|
|
//Offset16 extensionJstfMax Offset to extension JstfMax table, from beginning of JstfPriority table(may be NULL)
|
|
public ushort extensionJstfMax;
|
|
}
|
|
|
|
static JstfPriority ReadJstfPriority(BinaryReader reader)
|
|
{
|
|
//Justification Priority Table
|
|
//A Justification Priority(JstfPriority)
|
|
//table defines justification suggestions for a single priority level.
|
|
|
|
//Each priority level specifies whether to enable or disable GSUB and GPOS lookups or
|
|
//apply text justification lookups to shrink and extend lines of text.
|
|
|
|
//JstfPriority has offsets to four tables with line shrinkage data:
|
|
//two are JstfGSUBModList tables for enabling and disabling glyph substitution lookups, and
|
|
//two are JstfGPOSModList tables for enabling and disabling glyph positioning lookups.
|
|
//Offsets to JstfGSUBModList and JstfGPOSModList tables also are defined for line extension.
|
|
|
|
return new JstfPriority()
|
|
{
|
|
shrinkageEnableGSUB = reader.ReadUInt16(),
|
|
shrinkageDisableGSUB = reader.ReadUInt16(),
|
|
|
|
shrinkageEnableGPOS = reader.ReadUInt16(),
|
|
shrinkageDisableGPOS = reader.ReadUInt16(),
|
|
|
|
shrinkageJstfMax = reader.ReadUInt16(),
|
|
|
|
extensionEnableGSUB = reader.ReadUInt16(),
|
|
extensionDisableGSUB = reader.ReadUInt16(),
|
|
|
|
extensionEnableGPOS = reader.ReadUInt16(),
|
|
extensionDisableGPOS = reader.ReadUInt16(),
|
|
|
|
extensionJstfMax = reader.ReadUInt16(),
|
|
};
|
|
}
|
|
|
|
}
|
|
} |