Skip to content

Commit

Permalink
LibGfx: Remove bit casting in OpenType OS2 table after construction
Browse files Browse the repository at this point in the history
  • Loading branch information
AtkinsSJ authored and awesomekling committed Nov 8, 2023
1 parent d4e1305 commit fe2e1a0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Userland/Libraries/LibGfx/Font/OpenType/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
50 changes: 40 additions & 10 deletions Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 5 additions & 10 deletions Userland/Libraries/LibGfx/Font/OpenType/Tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ class Hmtx {
// 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;
Expand All @@ -283,11 +285,6 @@ class OS2 {

[[nodiscard]] Optional<i16> x_height() const;

explicit OS2(ReadonlyBytes slice)
: m_slice(slice)
{
}

private:
struct [[gnu::packed]] Version0 {
BigEndian<u16> version;
Expand Down Expand Up @@ -338,14 +335,12 @@ class OS2 {
};
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
Expand Down

0 comments on commit fe2e1a0

Please sign in to comment.