1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:07:34 +00:00

LibTTF: Parse TTF "name" table

This commit is contained in:
Stephan Unverwerth 2021-01-01 00:16:18 +01:00 committed by Andreas Kling
parent f12754ee10
commit 2c4e13f14a
3 changed files with 91 additions and 2 deletions

View file

@ -174,6 +174,29 @@ Optional<Hmtx> Hmtx::from_slice(const ReadonlyBytes& slice, u32 num_glyphs, u32
return Hmtx(slice, num_glyphs, number_of_h_metrics); return Hmtx(slice, num_glyphs, number_of_h_metrics);
} }
Optional<Name> Name::from_slice(const ReadonlyBytes& slice)
{
return Name(slice);
}
String Name::string_for_id(NameId id) const
{
auto num_entries = be_u16(m_slice.offset_pointer(2));
auto string_offset = be_u16(m_slice.offset_pointer(4));
for (int i = 0; i < num_entries; ++i) {
auto this_id = be_u16(m_slice.offset_pointer(6 + i * 12 + 6));
if (this_id != (u16)id)
continue;
auto length = be_u16(m_slice.offset_pointer(6 + i * 12 + 8));
auto offset = be_u16(m_slice.offset_pointer(6 + i * 12 + 10));
return String((const char*)m_slice.offset_pointer(string_offset + offset), length);
}
return String::empty();
}
GlyphHorizontalMetrics Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const GlyphHorizontalMetrics Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const
{ {
ASSERT(glyph_id < m_num_glyphs); ASSERT(glyph_id < m_num_glyphs);
@ -252,6 +275,7 @@ RefPtr<Font> Font::load_from_offset(ByteBuffer&& buffer, u32 offset)
} }
Optional<ReadonlyBytes> opt_head_slice = {}; Optional<ReadonlyBytes> opt_head_slice = {};
Optional<ReadonlyBytes> opt_name_slice = {};
Optional<ReadonlyBytes> opt_hhea_slice = {}; Optional<ReadonlyBytes> opt_hhea_slice = {};
Optional<ReadonlyBytes> opt_maxp_slice = {}; Optional<ReadonlyBytes> opt_maxp_slice = {};
Optional<ReadonlyBytes> opt_hmtx_slice = {}; Optional<ReadonlyBytes> opt_hmtx_slice = {};
@ -260,6 +284,7 @@ RefPtr<Font> Font::load_from_offset(ByteBuffer&& buffer, u32 offset)
Optional<ReadonlyBytes> opt_glyf_slice = {}; Optional<ReadonlyBytes> opt_glyf_slice = {};
Optional<Head> opt_head = {}; Optional<Head> opt_head = {};
Optional<Name> opt_name = {};
Optional<Hhea> opt_hhea = {}; Optional<Hhea> opt_hhea = {};
Optional<Maxp> opt_maxp = {}; Optional<Maxp> opt_maxp = {};
Optional<Hmtx> opt_hmtx = {}; Optional<Hmtx> opt_hmtx = {};
@ -292,6 +317,8 @@ RefPtr<Font> Font::load_from_offset(ByteBuffer&& buffer, u32 offset)
// Get the table offsets we need. // Get the table offsets we need.
if (tag == tag_from_str("head")) { if (tag == tag_from_str("head")) {
opt_head_slice = buffer_here; opt_head_slice = buffer_here;
} else if (tag == tag_from_str("name")) {
opt_name_slice = buffer_here;
} else if (tag == tag_from_str("hhea")) { } else if (tag == tag_from_str("hhea")) {
opt_hhea_slice = buffer_here; opt_hhea_slice = buffer_here;
} else if (tag == tag_from_str("maxp")) { } else if (tag == tag_from_str("maxp")) {
@ -313,6 +340,12 @@ RefPtr<Font> Font::load_from_offset(ByteBuffer&& buffer, u32 offset)
} }
auto head = opt_head.value(); auto head = opt_head.value();
if (!opt_name_slice.has_value() || !(opt_name = Name::from_slice(opt_name_slice.value())).has_value()) {
dbg() << "Could not load Name";
return nullptr;
}
auto name = opt_name.value();
if (!opt_hhea_slice.has_value() || !(opt_hhea = Hhea::from_slice(opt_hhea_slice.value())).has_value()) { if (!opt_hhea_slice.has_value() || !(opt_hhea = Hhea::from_slice(opt_hhea_slice.value())).has_value()) {
dbgln("Could not load Hhea"); dbgln("Could not load Hhea");
return nullptr; return nullptr;
@ -369,7 +402,7 @@ RefPtr<Font> Font::load_from_offset(ByteBuffer&& buffer, u32 offset)
} }
} }
return adopt(*new Font(move(buffer), move(head), move(hhea), move(maxp), move(hmtx), move(cmap), move(loca), move(glyf))); return adopt(*new Font(move(buffer), move(head), move(name), move(hhea), move(maxp), move(hmtx), move(cmap), move(loca), move(glyf)));
} }
ScaledFontMetrics Font::metrics(float x_scale, float y_scale) const ScaledFontMetrics Font::metrics(float x_scale, float y_scale) const
@ -432,6 +465,22 @@ u16 Font::units_per_em() const
return m_head.units_per_em(); return m_head.units_per_em();
} }
String Font::family() const
{
auto string = m_name.typographic_family_name();
if (!string.is_empty())
return string;
return m_name.family_name();
}
String Font::subfamily() const
{
auto string = m_name.typographic_subfamily_name();
if (!string.is_empty())
return string;
return m_name.subfamily_name();
}
int ScaledFont::width(const StringView& string) const int ScaledFont::width(const StringView& string) const
{ {
Utf8View utf8 { string }; Utf8View utf8 { string };

View file

@ -74,6 +74,8 @@ public:
u32 glyph_count() const; u32 glyph_count() const;
u16 units_per_em() const; u16 units_per_em() const;
u32 glyph_id_for_codepoint(u32 codepoint) const { return m_cmap.glyph_id_for_codepoint(codepoint); } u32 glyph_id_for_codepoint(u32 codepoint) const { return m_cmap.glyph_id_for_codepoint(codepoint); }
String family() const;
String subfamily() const;
private: private:
enum class Offsets { enum class Offsets {
@ -88,9 +90,10 @@ private:
}; };
static RefPtr<Font> load_from_offset(ByteBuffer&&, unsigned index = 0); static RefPtr<Font> load_from_offset(ByteBuffer&&, unsigned index = 0);
Font(ByteBuffer&& buffer, Head&& head, Hhea&& hhea, Maxp&& maxp, Hmtx&& hmtx, Cmap&& cmap, Loca&& loca, Glyf&& glyf) Font(ByteBuffer&& buffer, Head&& head, Name&& name, Hhea&& hhea, Maxp&& maxp, Hmtx&& hmtx, Cmap&& cmap, Loca&& loca, Glyf&& glyf)
: m_buffer(move(buffer)) : m_buffer(move(buffer))
, m_head(move(head)) , m_head(move(head))
, m_name(move(name))
, m_hhea(move(hhea)) , m_hhea(move(hhea))
, m_maxp(move(maxp)) , m_maxp(move(maxp))
, m_hmtx(move(hmtx)) , m_hmtx(move(hmtx))
@ -104,6 +107,7 @@ private:
ByteBuffer m_buffer; ByteBuffer m_buffer;
// These are stateful wrappers around non-owning slices // These are stateful wrappers around non-owning slices
Head m_head; Head m_head;
Name m_name;
Hhea m_hhea; Hhea m_hhea;
Maxp m_maxp; Maxp m_maxp;
Hmtx m_hmtx; Hmtx m_hmtx;

View file

@ -146,4 +146,40 @@ private:
u32 m_number_of_h_metrics { 0 }; u32 m_number_of_h_metrics { 0 };
}; };
class Name {
public:
static Optional<Name> from_slice(const ReadonlyBytes&);
String family_name() const { return string_for_id(NameId::FamilyName); }
String subfamily_name() const { return string_for_id(NameId::SubfamilyName); }
String typographic_family_name() const { return string_for_id(NameId::TypographicFamilyName); }
String typographic_subfamily_name() const { return string_for_id(NameId::TypographicSubfamilyName); }
private:
enum class NameId {
Copyright = 0,
FamilyName = 1,
SubfamilyName = 2,
UniqueIdentifier = 3,
FullName = 4,
VersionString = 5,
PostscriptName = 6,
Trademark = 7,
Manufacturer = 8,
Designer = 9,
Description = 10,
TypographicFamilyName = 16,
TypographicSubfamilyName = 17,
};
Name(const ReadonlyBytes& slice)
: m_slice(slice)
{
}
String string_for_id(NameId id) const;
ReadonlyBytes m_slice;
};
} }