// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.Fonts.Tables.AdvancedTypographic;
using SixLabors.Fonts.Tables.AdvancedTypographic.Variations;
using SixLabors.Fonts.Tables.Cff;
using SixLabors.Fonts.Tables.General;
using SixLabors.Fonts.Tables.General.Colr;
using SixLabors.Fonts.Tables.General.Kern;
using SixLabors.Fonts.Tables.General.Name;
using SixLabors.Fonts.Tables.General.Post;
using SixLabors.Fonts.Tables.General.Svg;
using SixLabors.Fonts.Tables.TrueType;
using SixLabors.Fonts.Tables.TrueType.Glyphs;
using SixLabors.Fonts.Tables.TrueType.Hinting;
using System;
using System.Collections.Generic;
namespace SixLabors.Fonts.Tables {
///
/// Provides registration and loading of font tables by tag or CLR type.
/// Maps four-byte table tags (e.g. "cmap", "head") to their static Load factory methods.
///
internal class TableLoader
{
private readonly Dictionary> loaders = [];
private readonly Dictionary types = [];
private readonly Dictionary> typesLoaders = [];
///
/// Initializes a new instance of the class
/// with all known table parsers registered.
///
public TableLoader()
{
// We will hard code mapping registration in here for all the tables
this.Register(NameTable.TableName, NameTable.Load);
this.Register(CMapTable.TableName, CMapTable.Load);
this.Register(HeadTable.TableName, HeadTable.Load);
this.Register(HorizontalHeadTable.TableName, HorizontalHeadTable.Load);
this.Register(HorizontalMetricsTable.TableName, HorizontalMetricsTable.Load);
this.Register(VerticalHeadTable.TableName, VerticalHeadTable.Load);
this.Register(VerticalMetricsTable.TableName, VerticalMetricsTable.Load);
this.Register(MaximumProfileTable.TableName, MaximumProfileTable.Load);
this.Register(OS2Table.TableName, OS2Table.Load);
this.Register(IndexLocationTable.TableName, IndexLocationTable.Load);
this.Register(GlyphTable.TableName, GlyphTable.Load);
this.Register(KerningTable.TableName, KerningTable.Load);
this.Register(ColrTable.TableName, ColrTable.Load);
this.Register(CpalTable.TableName, CpalTable.Load);
this.Register(GPosTable.TableName, GPosTable.Load);
this.Register(GSubTable.TableName, GSubTable.Load);
this.Register(CvtTable.TableName, CvtTable.Load);
this.Register(FpgmTable.TableName, FpgmTable.Load);
this.Register(PrepTable.TableName, PrepTable.Load);
this.Register(GlyphDefinitionTable.TableName, GlyphDefinitionTable.Load);
this.Register(PostTable.TableName, PostTable.Load);
this.Register(Cff1Table.TableName, Cff1Table.Load);
this.Register(Cff2Table.TableName, Cff2Table.Load);
this.Register(AVarTable.TableName, AVarTable.Load);
this.Register(GVarTable.TableName, GVarTable.Load);
this.Register(FVarTable.TableName, FVarTable.Load);
this.Register(HVarTable.TableName, HVarTable.Load);
this.Register(VVarTable.TableName, VVarTable.Load);
this.Register(MVarTable.TableName, MVarTable.Load);
this.Register(CVarTable.TableName, _ => null);
this.Register(SvgTable.TableName, SvgTable.Load);
}
///
/// Gets the default shared instance with all standard tables registered.
///
public static TableLoader Default { get; } = new();
///
/// Gets the four-byte tag string associated with the given table type.
///
/// The CLR type of the table.
/// The tag string, or if the type is not registered.
public string? GetTag(Type type)
{
this.types.TryGetValue(type, out string? value);
return value;
}
///
/// Gets the four-byte tag string associated with the given table type.
///
/// The CLR type of the table.
/// The tag string.
public string GetTag()
{
this.types.TryGetValue(typeof(TType), out string? value);
return value!;
}
///
/// Gets all registered table CLR types.
///
internal IEnumerable RegisteredTypes() => this.types.Keys;
///
/// Gets all registered four-byte table tags.
///
internal IEnumerable RegisteredTags() => this.types.Values;
private void Register(string tag, Func createFunc)
where T : Table
{
lock (this.loaders)
{
if (!this.loaders.ContainsKey(tag))
{
this.loaders.Add(tag, createFunc);
this.types.Add(typeof(T), tag);
this.typesLoaders.Add(typeof(T), createFunc);
}
}
}
///
/// Loads a table by its four-byte tag string.
/// Returns an if no parser is registered for the tag.
///
/// The four-byte table tag.
/// The font reader.
/// The loaded table, or an for unrecognized tags.
internal Table? Load(string tag, FontReader reader)
// loader missing? register an unknown type loader and carry on
=> this.loaders.TryGetValue(tag, out Func? func)
? func.Invoke(reader)
: new UnknownTable(tag);
///
/// Loads a table by its CLR type.
///
/// The table type to load.
/// The font reader.
/// The loaded table instance, or .
/// Thrown when the table type has not been registered.
internal TTable? Load(FontReader reader)
where TTable : Table
{
// loader missing register an unknown type loader and carry on
if (this.typesLoaders.TryGetValue(typeof(TTable), out Func? func))
{
return (TTable?)func.Invoke(reader);
}
throw new MissingFontTableException("Font table not registered.", nameof(TTable));
}
}
}