summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibTTF
diff options
context:
space:
mode:
authorStephan Unverwerth <s.unverwerth@gmx.de>2021-01-01 00:16:18 +0100
committerAndreas Kling <kling@serenityos.org>2021-02-15 08:50:48 +0100
commit2c4e13f14af5762b568f72ba4688979c096f03d2 (patch)
tree6b1fc0078b9e6af0ccba58d306cb3229a9194a8d /Userland/Libraries/LibTTF
parentf12754ee10ae1a1fcf4b5cf8b18fd06b5f4c13d2 (diff)
downloadserenity-2c4e13f14af5762b568f72ba4688979c096f03d2.zip
LibTTF: Parse TTF "name" table
Diffstat (limited to 'Userland/Libraries/LibTTF')
-rw-r--r--Userland/Libraries/LibTTF/Font.cpp51
-rw-r--r--Userland/Libraries/LibTTF/Font.h6
-rw-r--r--Userland/Libraries/LibTTF/Tables.h36
3 files changed, 91 insertions, 2 deletions
diff --git a/Userland/Libraries/LibTTF/Font.cpp b/Userland/Libraries/LibTTF/Font.cpp
index 39ef6754a2..083d9db405 100644
--- a/Userland/Libraries/LibTTF/Font.cpp
+++ b/Userland/Libraries/LibTTF/Font.cpp
@@ -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);
}
+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
{
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_name_slice = {};
Optional<ReadonlyBytes> opt_hhea_slice = {};
Optional<ReadonlyBytes> opt_maxp_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<Head> opt_head = {};
+ Optional<Name> opt_name = {};
Optional<Hhea> opt_hhea = {};
Optional<Maxp> opt_maxp = {};
Optional<Hmtx> opt_hmtx = {};
@@ -292,6 +317,8 @@ RefPtr<Font> Font::load_from_offset(ByteBuffer&& buffer, u32 offset)
// Get the table offsets we need.
if (tag == tag_from_str("head")) {
opt_head_slice = buffer_here;
+ } else if (tag == tag_from_str("name")) {
+ opt_name_slice = buffer_here;
} else if (tag == tag_from_str("hhea")) {
opt_hhea_slice = buffer_here;
} 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();
+ 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()) {
dbgln("Could not load Hhea");
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
@@ -432,6 +465,22 @@ u16 Font::units_per_em() const
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
{
Utf8View utf8 { string };
diff --git a/Userland/Libraries/LibTTF/Font.h b/Userland/Libraries/LibTTF/Font.h
index 79185411c0..939f1944e4 100644
--- a/Userland/Libraries/LibTTF/Font.h
+++ b/Userland/Libraries/LibTTF/Font.h
@@ -74,6 +74,8 @@ public:
u32 glyph_count() const;
u16 units_per_em() const;
u32 glyph_id_for_codepoint(u32 codepoint) const { return m_cmap.glyph_id_for_codepoint(codepoint); }
+ String family() const;
+ String subfamily() const;
private:
enum class Offsets {
@@ -88,9 +90,10 @@ private:
};
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_head(move(head))
+ , m_name(move(name))
, m_hhea(move(hhea))
, m_maxp(move(maxp))
, m_hmtx(move(hmtx))
@@ -104,6 +107,7 @@ private:
ByteBuffer m_buffer;
// These are stateful wrappers around non-owning slices
Head m_head;
+ Name m_name;
Hhea m_hhea;
Maxp m_maxp;
Hmtx m_hmtx;
diff --git a/Userland/Libraries/LibTTF/Tables.h b/Userland/Libraries/LibTTF/Tables.h
index 5264911ad9..d5f5014bd4 100644
--- a/Userland/Libraries/LibTTF/Tables.h
+++ b/Userland/Libraries/LibTTF/Tables.h
@@ -146,4 +146,40 @@ private:
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;
+};
+
}