diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp index 797bcef54d..5420a6fb51 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp @@ -3,6 +3,7 @@ * Copyright (c) 2021-2023, Andreas Kling * Copyright (c) 2022, Jelle Raaijmakers * Copyright (c) 2023, Lukas Affolter + * Copyright (c) 2023, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -111,11 +112,9 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Readonl // FIXME: "loca" and "glyf" are not available for CFF fonts. ErrorOr> Font::try_load_from_offset(ReadonlyBytes buffer, u32 offset) { - if (Checked::addition_would_overflow(offset, (u32)Sizes::OffsetTable)) - return Error::from_string_literal("Invalid offset in font header"); - - if (buffer.size() <= offset + (u32)Sizes::OffsetTable) - return Error::from_string_literal("Font file too small"); + FixedMemoryStream stream { buffer }; + TRY(stream.seek(offset, AK::SeekMode::SetPosition)); + auto& table_directory = *TRY(stream.read_in_place()); Optional opt_head_slice = {}; Optional opt_name_slice = {}; @@ -144,54 +143,47 @@ ErrorOr> Font::try_load_from_offset(ReadonlyBytes buffer, u3 Optional cbdt; Optional gpos; - auto num_tables = be_u16(buffer.offset(offset + (u32)Offsets::NumTables)); - if (buffer.size() <= offset + (u32)Sizes::OffsetTable + num_tables * (u32)Sizes::TableRecord) - return Error::from_string_literal("Font file too small"); + for (auto i = 0; i < table_directory.num_tables; i++) { + auto& table_record = *TRY(stream.read_in_place()); - for (auto i = 0; i < num_tables; i++) { - u32 record_offset = offset + (u32)Sizes::OffsetTable + i * (u32)Sizes::TableRecord; - u32 tag = be_u32(buffer.offset(record_offset)); - u32 table_offset = be_u32(buffer.offset(record_offset + (u32)Offsets::TableRecord_Offset)); - u32 table_length = be_u32(buffer.offset(record_offset + (u32)Offsets::TableRecord_Length)); - - if (table_length == 0 || Checked::addition_would_overflow(table_offset, table_length)) + if (table_record.length == 0 || Checked::addition_would_overflow(static_cast(table_record.offset), static_cast(table_record.length))) return Error::from_string_literal("Invalid table offset or length in font"); - if (buffer.size() < table_offset + table_length) + if (buffer.size() < table_record.offset + table_record.length) return Error::from_string_literal("Font file too small"); - auto buffer_here = ReadonlyBytes(buffer.offset(table_offset), table_length); + auto buffer_here = buffer.slice(table_record.offset, table_record.length); // Get the table offsets we need. - if (tag == tag_from_str("head")) { + if (table_record.table_tag == tag_from_str("head")) { opt_head_slice = buffer_here; - } else if (tag == tag_from_str("name")) { + } else if (table_record.table_tag == tag_from_str("name")) { opt_name_slice = buffer_here; - } else if (tag == tag_from_str("hhea")) { + } else if (table_record.table_tag == tag_from_str("hhea")) { opt_hhea_slice = buffer_here; - } else if (tag == tag_from_str("maxp")) { + } else if (table_record.table_tag == tag_from_str("maxp")) { opt_maxp_slice = buffer_here; - } else if (tag == tag_from_str("hmtx")) { + } else if (table_record.table_tag == tag_from_str("hmtx")) { opt_hmtx_slice = buffer_here; - } else if (tag == tag_from_str("cmap")) { + } else if (table_record.table_tag == tag_from_str("cmap")) { opt_cmap_slice = buffer_here; - } else if (tag == tag_from_str("loca")) { + } else if (table_record.table_tag == tag_from_str("loca")) { opt_loca_slice = buffer_here; - } else if (tag == tag_from_str("glyf")) { + } else if (table_record.table_tag == tag_from_str("glyf")) { opt_glyf_slice = buffer_here; - } else if (tag == tag_from_str("OS/2")) { + } else if (table_record.table_tag == tag_from_str("OS/2")) { opt_os2_slice = buffer_here; - } else if (tag == tag_from_str("kern")) { + } else if (table_record.table_tag == tag_from_str("kern")) { opt_kern_slice = buffer_here; - } else if (tag == tag_from_str("fpgm")) { + } else if (table_record.table_tag == tag_from_str("fpgm")) { opt_fpgm_slice = buffer_here; - } else if (tag == tag_from_str("prep")) { + } else if (table_record.table_tag == tag_from_str("prep")) { opt_prep_slice = buffer_here; - } else if (tag == tag_from_str("CBLC")) { + } else if (table_record.table_tag == tag_from_str("CBLC")) { cblc = TRY(CBLC::from_slice(buffer_here)); - } else if (tag == tag_from_str("CBDT")) { + } else if (table_record.table_tag == tag_from_str("CBDT")) { cbdt = TRY(CBDT::from_slice(buffer_here)); - } else if (tag == tag_from_str("GPOS")) { + } else if (table_record.table_tag == tag_from_str("GPOS")) { gpos = TRY(GPOS::from_slice(buffer_here)); } } diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.h b/Userland/Libraries/LibGfx/Font/OpenType/Font.h index 043e384d7a..8b6cc057c7 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Font.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.h @@ -68,17 +68,6 @@ private: EmbeddedBitmapData embedded_bitmap_data_for_glyph(u32 glyph_id) const; - enum class Offsets { - NumTables = 4, - TableRecord_Offset = 8, - TableRecord_Length = 12, - }; - enum class Sizes { - TTCHeaderV1 = 12, - OffsetTable = 12, - TableRecord = 16, - }; - static ErrorOr> try_load_from_offset(ReadonlyBytes, unsigned index = 0); Font( diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Tables.h b/Userland/Libraries/LibGfx/Font/OpenType/Tables.h index b921867653..e4a0e3c978 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Tables.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/Tables.h @@ -67,6 +67,22 @@ struct [[gnu::packed]] TableRecord { }; static_assert(AssertSize()); +} + +template<> +class AK::Traits : public GenericTraits { +public: + static constexpr bool is_trivially_serializable() { return true; } +}; + +template<> +class AK::Traits : public GenericTraits { +public: + static constexpr bool is_trivially_serializable() { return true; } +}; + +namespace OpenType { + // https://learn.microsoft.com/en-us/typography/opentype/spec/head // head: Font Header Table class Head {