mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 12:17:44 +00:00
LibTTF: Parse TTF "name" table
This commit is contained in:
parent
f12754ee10
commit
2c4e13f14a
3 changed files with 91 additions and 2 deletions
|
@ -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 };
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue