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;
if (opt_os2_slice.has_value())
os2 = OS2(opt_os2_slice.value());
os2 = TRY(OS2::from_slice(opt_os2_slice.value()));
Optional<Kern> kern {};
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;
}
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
{
return header().us_weight_class;
return m_data.visit([](auto* any) { return any->us_weight_class; });
}
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
{
return header().fs_selection;
return m_data.visit([](auto* any) { return any->fs_selection; });
}
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
{
return header().s_typo_descender;
return m_data.visit([](auto* any) { return any->s_typo_descender; });
}
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
{
return header().fs_selection & 0x80;
return m_data.visit([](auto* any) { return any->fs_selection & 0x80; });
}
Optional<i16> OS2::x_height() const
{
if (header().version < 2)
return {};
return header_v2().sx_height;
return m_data.visit(
[]<typename T> requires(requires { T::sx_height; })(T * data)->Optional<i16> {
return data->sx_height;
},
[](auto*) { return Optional<i16>(); });
}
ErrorOr<CBLC> CBLC::from_slice(ReadonlyBytes slice)

View file

@ -272,6 +272,8 @@ private:
// OS/2: OS/2 and Windows Metrics Table
class OS2 {
public:
static ErrorOr<OS2> from_slice(ReadonlyBytes);
u16 weight_class() const;
u16 width_class() const;
u16 selection() const;
@ -283,11 +285,6 @@ public:
[[nodiscard]] Optional<i16> x_height() const;
explicit OS2(ReadonlyBytes slice)
: m_slice(slice)
{
}
private:
struct [[gnu::packed]] Version0 {
BigEndian<u16> version;
@ -338,14 +335,12 @@ private:
};
static_assert(AssertSize<Version2, 96>());
Version0 const& header() const { return *bit_cast<Version0 const*>(m_slice.data()); }
Version2 const& header_v2() const
explicit OS2(Variant<Version0 const*, Version1 const*, Version2 const*> data)
: 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