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

LibGfx: Remove bit casting in OpenType OS2 table after construction

This commit is contained in:
Sam Atkins 2023-10-30 16:15:00 +00:00 committed by Andreas Kling
parent d4e1305413
commit fe2e1a0282
3 changed files with 46 additions and 21 deletions

View file

@ -213,7 +213,7 @@ ErrorOr<NonnullRefPtr<Font>> Font::try_load_from_offset(ReadonlyBytes buffer, u3
Optional<OS2> os2; Optional<OS2> os2;
if (opt_os2_slice.has_value()) if (opt_os2_slice.has_value())
os2 = OS2(opt_os2_slice.value()); os2 = TRY(OS2::from_slice(opt_os2_slice.value()));
Optional<Kern> kern {}; Optional<Kern> kern {};
if (opt_kern_slice.has_value()) if (opt_kern_slice.has_value())

View file

@ -345,46 +345,76 @@ Optional<i16> Kern::read_glyph_kerning_format0(ReadonlyBytes slice, u16 left_gly
return pair->value; return pair->value;
} }
ErrorOr<OS2> OS2::from_slice(ReadonlyBytes slice)
{
// All OS2 tables begin with a version.
if (slice.size() < sizeof(BigEndian<u16>))
return Error::from_string_literal("Could not load OS2: Not enough data");
u16 version = *bit_cast<BigEndian<u16> const*>(slice.data());
// NOTE: We assume that this table only ever has new fields added to the end in future versions.
switch (version) {
case 0: {
if (slice.size() < sizeof(Version0))
return Error::from_string_literal("Could not load OS2 v0: Not enough data");
return OS2(bit_cast<Version0 const*>(slice.data()));
}
case 1: {
if (slice.size() < sizeof(Version1))
return Error::from_string_literal("Could not load OS2 v1: Not enough data");
return OS2(bit_cast<Version1 const*>(slice.data()));
}
case 2:
default: {
if (slice.size() < sizeof(Version2))
return Error::from_string_literal("Could not load OS2 v2: Not enough data");
return OS2(bit_cast<Version2 const*>(slice.data()));
}
}
}
u16 OS2::weight_class() const u16 OS2::weight_class() const
{ {
return header().us_weight_class; return m_data.visit([](auto* any) { return any->us_weight_class; });
} }
u16 OS2::width_class() const u16 OS2::width_class() const
{ {
return header().us_width_class; return m_data.visit([](auto* any) { return any->us_width_class; });
} }
u16 OS2::selection() const u16 OS2::selection() const
{ {
return header().fs_selection; return m_data.visit([](auto* any) { return any->fs_selection; });
} }
i16 OS2::typographic_ascender() const i16 OS2::typographic_ascender() const
{ {
return header().s_typo_ascender; return m_data.visit([](auto* any) { return any->s_typo_ascender; });
} }
i16 OS2::typographic_descender() const i16 OS2::typographic_descender() const
{ {
return header().s_typo_descender; return m_data.visit([](auto* any) { return any->s_typo_descender; });
} }
i16 OS2::typographic_line_gap() const i16 OS2::typographic_line_gap() const
{ {
return header().s_typo_line_gap; return m_data.visit([](auto* any) { return any->s_typo_line_gap; });
} }
bool OS2::use_typographic_metrics() const bool OS2::use_typographic_metrics() const
{ {
return header().fs_selection & 0x80; return m_data.visit([](auto* any) { return any->fs_selection & 0x80; });
} }
Optional<i16> OS2::x_height() const Optional<i16> OS2::x_height() const
{ {
if (header().version < 2) return m_data.visit(
return {}; []<typename T> requires(requires { T::sx_height; })(T * data)->Optional<i16> {
return header_v2().sx_height; return data->sx_height;
},
[](auto*) { return Optional<i16>(); });
} }
ErrorOr<CBLC> CBLC::from_slice(ReadonlyBytes slice) ErrorOr<CBLC> CBLC::from_slice(ReadonlyBytes slice)

View file

@ -272,6 +272,8 @@ private:
// OS/2: OS/2 and Windows Metrics Table // OS/2: OS/2 and Windows Metrics Table
class OS2 { class OS2 {
public: public:
static ErrorOr<OS2> from_slice(ReadonlyBytes);
u16 weight_class() const; u16 weight_class() const;
u16 width_class() const; u16 width_class() const;
u16 selection() const; u16 selection() const;
@ -283,11 +285,6 @@ public:
[[nodiscard]] Optional<i16> x_height() const; [[nodiscard]] Optional<i16> x_height() const;
explicit OS2(ReadonlyBytes slice)
: m_slice(slice)
{
}
private: private:
struct [[gnu::packed]] Version0 { struct [[gnu::packed]] Version0 {
BigEndian<u16> version; BigEndian<u16> version;
@ -338,14 +335,12 @@ private:
}; };
static_assert(AssertSize<Version2, 96>()); static_assert(AssertSize<Version2, 96>());
Version0 const& header() const { return *bit_cast<Version0 const*>(m_slice.data()); } explicit OS2(Variant<Version0 const*, Version1 const*, Version2 const*> data)
Version2 const& header_v2() const : m_data(move(data))
{ {
VERIFY(header().version >= 2);
return *bit_cast<Version2 const*>(m_slice.data());
} }
ReadonlyBytes m_slice; Variant<Version0 const*, Version1 const*, Version2 const*> m_data;
}; };
// https://learn.microsoft.com/en-us/typography/opentype/spec/name // https://learn.microsoft.com/en-us/typography/opentype/spec/name