mirror of https://github.com/ZDoom/gzdoom.git
Add support for getting TTC font names and sharing the font file data between multiple TrueTypeFont instances
This commit is contained in:
parent
96b812e880
commit
10ce3abb77
|
@ -11,13 +11,14 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TrueTypeFont::TrueTypeFont(std::vector<uint8_t> initdata, int ttcFontIndex) : data(std::move(initdata))
|
TrueTypeFont::TrueTypeFont(std::shared_ptr<TrueTypeFontFileData> initdata, int ttcFontIndex) : data(std::move(initdata))
|
||||||
{
|
{
|
||||||
if (data.size() > 0x7fffffff)
|
if (data->size() > 0x7fffffff)
|
||||||
throw std::runtime_error("TTF file is larger than 2 gigabytes!");
|
throw std::runtime_error("TTF file is larger than 2 gigabytes!");
|
||||||
|
|
||||||
TrueTypeFileReader reader(data.data(), data.size());
|
TrueTypeFileReader reader(data->data(), data->size());
|
||||||
ttf_Tag versionTag = reader.ReadTag();
|
ttf_Tag versionTag = reader.ReadTag();
|
||||||
|
reader.Seek(0);
|
||||||
|
|
||||||
if (memcmp(versionTag.data(), "ttcf", 4) == 0) // TTC header
|
if (memcmp(versionTag.data(), "ttcf", 4) == 0) // TTC header
|
||||||
{
|
{
|
||||||
|
@ -26,10 +27,6 @@ TrueTypeFont::TrueTypeFont(std::vector<uint8_t> initdata, int ttcFontIndex) : da
|
||||||
throw std::runtime_error("TTC font index out of bounds");
|
throw std::runtime_error("TTC font index out of bounds");
|
||||||
reader.Seek(ttcHeader.tableDirectoryOffsets[ttcFontIndex]);
|
reader.Seek(ttcHeader.tableDirectoryOffsets[ttcFontIndex]);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
reader.Seek(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
directory.Load(reader);
|
directory.Load(reader);
|
||||||
|
|
||||||
|
@ -38,32 +35,32 @@ TrueTypeFont::TrueTypeFont(std::vector<uint8_t> initdata, int ttcFontIndex) : da
|
||||||
|
|
||||||
// Load required tables:
|
// Load required tables:
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "head");
|
reader = directory.GetReader(data->data(), data->size(), "head");
|
||||||
head.Load(reader);
|
head.Load(reader);
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "hhea");
|
reader = directory.GetReader(data->data(), data->size(), "hhea");
|
||||||
hhea.Load(reader);
|
hhea.Load(reader);
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "maxp");
|
reader = directory.GetReader(data->data(), data->size(), "maxp");
|
||||||
maxp.Load(reader);
|
maxp.Load(reader);
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "hmtx");
|
reader = directory.GetReader(data->data(), data->size(), "hmtx");
|
||||||
hmtx.Load(hhea, maxp, reader);
|
hmtx.Load(hhea, maxp, reader);
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "name");
|
reader = directory.GetReader(data->data(), data->size(), "name");
|
||||||
name.Load(reader);
|
name.Load(reader);
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "OS/2");
|
reader = directory.GetReader(data->data(), data->size(), "OS/2");
|
||||||
os2.Load(reader);
|
os2.Load(reader);
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "cmap");
|
reader = directory.GetReader(data->data(), data->size(), "cmap");
|
||||||
cmap.Load(reader);
|
cmap.Load(reader);
|
||||||
|
|
||||||
LoadCharacterMapEncoding(reader);
|
LoadCharacterMapEncoding(reader);
|
||||||
|
|
||||||
// Load TTF Outlines:
|
// Load TTF Outlines:
|
||||||
|
|
||||||
reader = directory.GetReader(data.data(), data.size(), "loca");
|
reader = directory.GetReader(data->data(), data->size(), "loca");
|
||||||
loca.Load(head, maxp, reader);
|
loca.Load(head, maxp, reader);
|
||||||
|
|
||||||
glyf = directory.GetRecord("glyf");
|
glyf = directory.GetRecord("glyf");
|
||||||
|
@ -302,7 +299,7 @@ void TrueTypeFont::LoadGlyph(TTF_SimpleGlyph& g, uint32_t glyphIndex, int compos
|
||||||
if (glyphIndex >= loca.offsets.size())
|
if (glyphIndex >= loca.offsets.size())
|
||||||
throw std::runtime_error("Glyph index out of bounds");
|
throw std::runtime_error("Glyph index out of bounds");
|
||||||
|
|
||||||
TrueTypeFileReader reader = glyf.GetReader(data.data(), data.size());
|
TrueTypeFileReader reader = glyf.GetReader(data->data(), data->size());
|
||||||
reader.Seek(loca.offsets[glyphIndex]);
|
reader.Seek(loca.offsets[glyphIndex]);
|
||||||
|
|
||||||
ttf_int16 numberOfContours = reader.ReadInt16();
|
ttf_int16 numberOfContours = reader.ReadInt16();
|
||||||
|
@ -631,6 +628,49 @@ void TrueTypeFont::LoadCharacterMapEncoding(TrueTypeFileReader& reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<TTCFontName> TrueTypeFont::GetFontNames(const std::shared_ptr<TrueTypeFontFileData>& data)
|
||||||
|
{
|
||||||
|
if (data->size() > 0x7fffffff)
|
||||||
|
throw std::runtime_error("TTF file is larger than 2 gigabytes!");
|
||||||
|
|
||||||
|
TrueTypeFileReader reader(data->data(), data->size());
|
||||||
|
ttf_Tag versionTag = reader.ReadTag();
|
||||||
|
reader.Seek(0);
|
||||||
|
|
||||||
|
std::vector<TTCFontName> names;
|
||||||
|
if (memcmp(versionTag.data(), "ttcf", 4) == 0) // TTC header
|
||||||
|
{
|
||||||
|
TTC_Header ttcHeader;
|
||||||
|
ttcHeader.Load(reader);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ttcHeader.tableDirectoryOffsets.size(); i++)
|
||||||
|
{
|
||||||
|
reader.Seek(ttcHeader.tableDirectoryOffsets[i]);
|
||||||
|
|
||||||
|
TTF_TableDirectory directory;
|
||||||
|
directory.Load(reader);
|
||||||
|
|
||||||
|
TTF_NamingTable name;
|
||||||
|
auto name_reader = directory.GetReader(data->data(), data->size(), "name");
|
||||||
|
name.Load(name_reader);
|
||||||
|
|
||||||
|
names.push_back(name.GetFontName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TTF_TableDirectory directory;
|
||||||
|
directory.Load(reader);
|
||||||
|
|
||||||
|
TTF_NamingTable name;
|
||||||
|
auto name_reader = directory.GetReader(data->data(), data->size(), "name");
|
||||||
|
name.Load(name_reader);
|
||||||
|
|
||||||
|
names.push_back(name.GetFontName());
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TTF_CMapSubtable0::Load(TrueTypeFileReader& reader)
|
void TTF_CMapSubtable0::Load(TrueTypeFileReader& reader)
|
||||||
|
@ -857,6 +897,62 @@ void TTF_MaximumProfile::Load(TrueTypeFileReader& reader)
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static std::string unicode_to_utf8(unsigned int value)
|
||||||
|
{
|
||||||
|
char text[8];
|
||||||
|
|
||||||
|
if ((value < 0x80) && (value > 0))
|
||||||
|
{
|
||||||
|
text[0] = (char)value;
|
||||||
|
text[1] = 0;
|
||||||
|
}
|
||||||
|
else if (value < 0x800)
|
||||||
|
{
|
||||||
|
text[0] = (char)(0xc0 | (value >> 6));
|
||||||
|
text[1] = (char)(0x80 | (value & 0x3f));
|
||||||
|
text[2] = 0;
|
||||||
|
}
|
||||||
|
else if (value < 0x10000)
|
||||||
|
{
|
||||||
|
text[0] = (char)(0xe0 | (value >> 12));
|
||||||
|
text[1] = (char)(0x80 | ((value >> 6) & 0x3f));
|
||||||
|
text[2] = (char)(0x80 | (value & 0x3f));
|
||||||
|
text[3] = 0;
|
||||||
|
}
|
||||||
|
else if (value < 0x200000)
|
||||||
|
{
|
||||||
|
text[0] = (char)(0xf0 | (value >> 18));
|
||||||
|
text[1] = (char)(0x80 | ((value >> 12) & 0x3f));
|
||||||
|
text[2] = (char)(0x80 | ((value >> 6) & 0x3f));
|
||||||
|
text[3] = (char)(0x80 | (value & 0x3f));
|
||||||
|
text[4] = 0;
|
||||||
|
}
|
||||||
|
else if (value < 0x4000000)
|
||||||
|
{
|
||||||
|
text[0] = (char)(0xf8 | (value >> 24));
|
||||||
|
text[1] = (char)(0x80 | ((value >> 18) & 0x3f));
|
||||||
|
text[2] = (char)(0x80 | ((value >> 12) & 0x3f));
|
||||||
|
text[3] = (char)(0x80 | ((value >> 6) & 0x3f));
|
||||||
|
text[4] = (char)(0x80 | (value & 0x3f));
|
||||||
|
text[5] = 0;
|
||||||
|
}
|
||||||
|
else if (value < 0x80000000)
|
||||||
|
{
|
||||||
|
text[0] = (char)(0xfc | (value >> 30));
|
||||||
|
text[1] = (char)(0x80 | ((value >> 24) & 0x3f));
|
||||||
|
text[2] = (char)(0x80 | ((value >> 18) & 0x3f));
|
||||||
|
text[3] = (char)(0x80 | ((value >> 12) & 0x3f));
|
||||||
|
text[4] = (char)(0x80 | ((value >> 6) & 0x3f));
|
||||||
|
text[5] = (char)(0x80 | (value & 0x3f));
|
||||||
|
text[6] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text[0] = 0; // Invalid wchar value
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
void TTF_NamingTable::Load(TrueTypeFileReader& reader)
|
void TTF_NamingTable::Load(TrueTypeFileReader& reader)
|
||||||
{
|
{
|
||||||
version = reader.ReadUInt16();
|
version = reader.ReadUInt16();
|
||||||
|
@ -885,6 +981,34 @@ void TTF_NamingTable::Load(TrueTypeFileReader& reader)
|
||||||
langTagRecord.push_back(record);
|
langTagRecord.push_back(record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (NameRecord& record : nameRecord)
|
||||||
|
{
|
||||||
|
if (record.length > 0 && record.platformID == 3 && record.encodingID == 1)
|
||||||
|
{
|
||||||
|
reader.Seek(storageOffset + record.stringOffset);
|
||||||
|
ttf_uint16 ucs2len = record.length / 2;
|
||||||
|
for (ttf_uint16 i = 0; i < ucs2len; i++)
|
||||||
|
{
|
||||||
|
record.text += unicode_to_utf8(reader.ReadUInt16());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TTCFontName TTF_NamingTable::GetFontName() const
|
||||||
|
{
|
||||||
|
TTCFontName fname;
|
||||||
|
for (const auto& record : nameRecord)
|
||||||
|
{
|
||||||
|
if (record.nameID == 1) fname.FamilyName = record.text;
|
||||||
|
if (record.nameID == 2) fname.SubfamilyName = record.text;
|
||||||
|
if (record.nameID == 3) fname.UniqueID = record.text;
|
||||||
|
if (record.nameID == 4) fname.FullName = record.text;
|
||||||
|
if (record.nameID == 5) fname.VersionString = record.text;
|
||||||
|
if (record.nameID == 6) fname.PostscriptName = record.text;
|
||||||
|
}
|
||||||
|
return fname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -289,6 +289,17 @@ struct TTF_MaximumProfile // 'maxp' Maximum profile
|
||||||
void Load(TrueTypeFileReader& reader);
|
void Load(TrueTypeFileReader& reader);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TTCFontName
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string FamilyName; // Arial
|
||||||
|
std::string SubfamilyName; // Regular
|
||||||
|
std::string FullName; // Arial Regular
|
||||||
|
std::string UniqueID;
|
||||||
|
std::string VersionString;
|
||||||
|
std::string PostscriptName;
|
||||||
|
};
|
||||||
|
|
||||||
struct TTF_NamingTable // 'name' Naming table
|
struct TTF_NamingTable // 'name' Naming table
|
||||||
{
|
{
|
||||||
struct NameRecord
|
struct NameRecord
|
||||||
|
@ -299,6 +310,7 @@ struct TTF_NamingTable // 'name' Naming table
|
||||||
ttf_uint16 nameID = {};
|
ttf_uint16 nameID = {};
|
||||||
ttf_uint16 length = {};
|
ttf_uint16 length = {};
|
||||||
ttf_Offset16 stringOffset = {};
|
ttf_Offset16 stringOffset = {};
|
||||||
|
std::string text;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangTagRecord
|
struct LangTagRecord
|
||||||
|
@ -318,6 +330,8 @@ struct TTF_NamingTable // 'name' Naming table
|
||||||
std::vector<LangTagRecord> langTagRecord; // [langTagCount]
|
std::vector<LangTagRecord> langTagRecord; // [langTagCount]
|
||||||
|
|
||||||
void Load(TrueTypeFileReader& reader);
|
void Load(TrueTypeFileReader& reader);
|
||||||
|
|
||||||
|
TTCFontName GetFontName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TTF_OS2Windows // 'OS/2' Windows specific metrics
|
struct TTF_OS2Windows // 'OS/2' Windows specific metrics
|
||||||
|
@ -428,10 +442,58 @@ public:
|
||||||
double lineGap = 0.0;
|
double lineGap = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TrueTypeFontFileData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TrueTypeFontFileData(std::vector<uint8_t> data) : dataVector(std::move(data))
|
||||||
|
{
|
||||||
|
dataPtr = dataVector.data();
|
||||||
|
dataSize = dataVector.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
TrueTypeFontFileData(const void* data, size_t size, bool copyData = true)
|
||||||
|
{
|
||||||
|
dataSize = size;
|
||||||
|
if (copyData)
|
||||||
|
{
|
||||||
|
dataPtr = new uint8_t[size];
|
||||||
|
deleteDataPtr = true;
|
||||||
|
memcpy(const_cast<void*>(dataPtr), data, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataPtr = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~TrueTypeFontFileData()
|
||||||
|
{
|
||||||
|
if (deleteDataPtr)
|
||||||
|
{
|
||||||
|
delete[](uint8_t*)dataPtr;
|
||||||
|
}
|
||||||
|
dataPtr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* data() const { return dataPtr; }
|
||||||
|
size_t size() const { return dataSize; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> dataVector;
|
||||||
|
const void* dataPtr = nullptr;
|
||||||
|
size_t dataSize = 0;
|
||||||
|
bool deleteDataPtr = false;
|
||||||
|
|
||||||
|
TrueTypeFontFileData(const TrueTypeFontFileData&) = delete;
|
||||||
|
TrueTypeFontFileData& operator=(const TrueTypeFontFileData&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
class TrueTypeFont
|
class TrueTypeFont
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TrueTypeFont(std::vector<uint8_t> data, int ttcFontIndex = 0);
|
TrueTypeFont(std::shared_ptr<TrueTypeFontFileData> data, int ttcFontIndex = 0);
|
||||||
|
|
||||||
|
static std::vector<TTCFontName> GetFontNames(const std::shared_ptr<TrueTypeFontFileData>& data);
|
||||||
|
|
||||||
TrueTypeTextMetrics GetTextMetrics(double height) const;
|
TrueTypeTextMetrics GetTextMetrics(double height) const;
|
||||||
uint32_t GetGlyphIndex(uint32_t codepoint) const;
|
uint32_t GetGlyphIndex(uint32_t codepoint) const;
|
||||||
|
@ -442,7 +504,7 @@ private:
|
||||||
void LoadGlyph(TTF_SimpleGlyph& glyph, uint32_t glyphIndex, int compositeDepth = 0) const;
|
void LoadGlyph(TTF_SimpleGlyph& glyph, uint32_t glyphIndex, int compositeDepth = 0) const;
|
||||||
static float F2DOT14_ToFloat(ttf_F2DOT14 v);
|
static float F2DOT14_ToFloat(ttf_F2DOT14 v);
|
||||||
|
|
||||||
std::vector<uint8_t> data;
|
std::shared_ptr<TrueTypeFontFileData> data;
|
||||||
|
|
||||||
TTC_Header ttcHeader;
|
TTC_Header ttcHeader;
|
||||||
TTF_TableDirectory directory;
|
TTF_TableDirectory directory;
|
||||||
|
|
Loading…
Reference in New Issue