Skip to content

Commit

Permalink
LibGfx: Define and use OpenType data types for struct definitions
Browse files Browse the repository at this point in the history
A few closely-related changes:
- Move our definitions of the OpenType spec's "data types" into their
  own header file.
- Add definitions for the integer types there too, for completeness.
  (Plus Uint16 matches the spec term, and is less verbose than
  BigEndian<u16>.)
- Include Traits for the non-BigEndian types so that we can read them
  from Streams. (BigEndian<integer-type> already has this.)
- Use the integer types in our struct definitions.

As a bonus, this fixes a bug in Hmtx, which read the left-side bearings
as i16 instead of BigEndian<i16>.
  • Loading branch information
AtkinsSJ authored and awesomekling committed Nov 8, 2023
1 parent a28f035 commit 2a4d7a1
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 203 deletions.
73 changes: 73 additions & 0 deletions Userland/Libraries/LibGfx/Font/OpenType/DataTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2020, Srimanta Barua <[email protected]>
* Copyright (c) 2022, Jelle Raaijmakers <[email protected]>
* Copyright (c) 2023, Lukas Affolter <[email protected]>
* Copyright (c) 2023, Sam Atkins <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/Endian.h>
#include <AK/Types.h>

// https://learn.microsoft.com/en-us/typography/opentype/spec/otff#data-types
namespace OpenType {

using Uint8 = u8;
using Int8 = i8;
using Uint16 = BigEndian<u16>;
using Int16 = BigEndian<i16>;
// FIXME: Uint24
using Uint32 = BigEndian<u32>;
using Int32 = BigEndian<i32>;

struct [[gnu::packed]] Fixed {
BigEndian<u16> integer;
BigEndian<u16> fraction;
};
static_assert(AssertSize<Fixed, 4>());

using FWord = BigEndian<i16>;
using UFWord = BigEndian<u16>;

// FIXME: F2Dot14

struct [[gnu::packed]] LongDateTime {
BigEndian<u64> value;
};
static_assert(AssertSize<LongDateTime, 8>());

using Tag = BigEndian<u32>;

using Offset16 = BigEndian<u16>;
// FIXME: Offset24
using Offset32 = BigEndian<u32>;

struct [[gnu::packed]] Version16Dot16 {
BigEndian<u16> major;
BigEndian<u16> minor;
};
static_assert(AssertSize<Version16Dot16, 4>());

}

namespace AK {
template<>
struct Traits<OpenType::Fixed const> : public GenericTraits<OpenType::Fixed const> {
static constexpr bool is_trivially_serializable() { return true; }
};
template<>
struct Traits<OpenType::LongDateTime const> : public GenericTraits<OpenType::LongDateTime const> {
static constexpr bool is_trivially_serializable() { return true; }
};
template<>
struct Traits<OpenType::Tag const> : public GenericTraits<OpenType::Tag const> {
static constexpr bool is_trivially_serializable() { return true; }
};
template<>
struct Traits<OpenType::Version16Dot16 const> : public GenericTraits<OpenType::Version16Dot16 const> {
static constexpr bool is_trivially_serializable() { return true; }
};
}
8 changes: 4 additions & 4 deletions Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,16 @@ u16 Maxp::num_glyphs() const

ErrorOr<Hmtx> Hmtx::from_slice(ReadonlyBytes slice, u32 num_glyphs, u32 number_of_h_metrics)
{
if (slice.size() < number_of_h_metrics * sizeof(LongHorMetric) + (num_glyphs - number_of_h_metrics) * sizeof(i16))
if (slice.size() < number_of_h_metrics * sizeof(LongHorMetric) + (num_glyphs - number_of_h_metrics) * sizeof(Int16))
return Error::from_string_literal("Could not load Hmtx: Not enough data");

// The Horizontal Metrics table is LongHorMetric[number_of_h_metrics] followed by i16[num_glyphs - number_of_h_metrics];
// The Horizontal Metrics table is LongHorMetric[number_of_h_metrics] followed by Int16[num_glyphs - number_of_h_metrics];
ReadonlySpan<LongHorMetric> long_hor_metrics { bit_cast<LongHorMetric*>(slice.data()), number_of_h_metrics };
ReadonlySpan<i16> left_side_bearings {};
ReadonlySpan<Int16> left_side_bearings {};
auto number_of_left_side_bearings = num_glyphs - number_of_h_metrics;
if (number_of_left_side_bearings > 0) {
left_side_bearings = {
bit_cast<i16*>(slice.offset(number_of_h_metrics * sizeof(LongHorMetric))),
bit_cast<Int16*>(slice.offset(number_of_h_metrics * sizeof(LongHorMetric))),
number_of_left_side_bearings
};
}
Expand Down
Loading

0 comments on commit 2a4d7a1

Please sign in to comment.