diff --git a/Userland/Libraries/LibGfx/Font/OpenType/DataTypes.h b/Userland/Libraries/LibGfx/Font/OpenType/DataTypes.h index f8803434d6..15042597fb 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/DataTypes.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/DataTypes.h @@ -11,6 +11,7 @@ #include #include +#include // https://learn.microsoft.com/en-us/typography/opentype/spec/otff#data-types namespace OpenType { @@ -39,7 +40,7 @@ struct [[gnu::packed]] LongDateTime { }; static_assert(AssertSize()); -using Tag = BigEndian; +using Tag = Gfx::FourCC; using Offset16 = BigEndian; // FIXME: Offset24 diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp index 53ce004bc5..8f37b79fc2 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp @@ -48,7 +48,6 @@ u16 be_u16(u8 const*); u32 be_u32(u8 const*); i16 be_i16(u8 const*); float be_fword(u8 const*); -u32 tag_from_str(char const*); u16 be_u16(u8 const* ptr) { @@ -70,11 +69,6 @@ float be_fword(u8 const* ptr) return (float)be_i16(ptr) / (float)(1 << 14); } -u32 tag_from_str(char const* str) -{ - return be_u32((u8 const*)str); -} - ErrorOr> Font::try_load_from_resource(Core::Resource const& resource, unsigned index) { auto font = TRY(try_load_from_externally_owned_memory(resource.data(), index)); @@ -87,7 +81,7 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Readonl FixedMemoryStream stream { buffer }; auto tag = TRY(stream.read_value()); - if (tag == tag_from_str("ttcf")) { + if (tag == Tag("ttcf")) { // It's a font collection TRY(stream.seek(0, SeekMode::SetPosition)); auto ttc_header_v1 = TRY(stream.read_in_place()); @@ -100,10 +94,10 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Readonl auto offset = TRY(stream.read_value>()); return try_load_from_offset(buffer, offset); } - if (tag == tag_from_str("OTTO")) + if (tag == Tag("OTTO")) return Error::from_string_literal("CFF fonts not supported yet"); - if (tag != 0x00010000 && tag != tag_from_str("true")) + if (tag.to_u32() != 0x00010000 && tag != Tag("true")) return Error::from_string_literal("Not a valid font"); return try_load_from_offset(buffer, 0); @@ -145,35 +139,35 @@ ErrorOr> Font::try_load_from_offset(ReadonlyBytes buffer, u3 auto buffer_here = buffer.slice(table_record.offset, table_record.length); // Get the table offsets we need. - if (table_record.table_tag == tag_from_str("head")) { + if (table_record.table_tag == Tag("head")) { opt_head_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("name")) { + } else if (table_record.table_tag == Tag("name")) { opt_name_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("hhea")) { + } else if (table_record.table_tag == Tag("hhea")) { opt_hhea_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("maxp")) { + } else if (table_record.table_tag == Tag("maxp")) { opt_maxp_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("hmtx")) { + } else if (table_record.table_tag == Tag("hmtx")) { opt_hmtx_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("cmap")) { + } else if (table_record.table_tag == Tag("cmap")) { opt_cmap_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("loca")) { + } else if (table_record.table_tag == Tag("loca")) { opt_loca_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("glyf")) { + } else if (table_record.table_tag == Tag("glyf")) { opt_glyf_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("OS/2")) { + } else if (table_record.table_tag == Tag("OS/2")) { opt_os2_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("kern")) { + } else if (table_record.table_tag == Tag("kern")) { opt_kern_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("fpgm")) { + } else if (table_record.table_tag == Tag("fpgm")) { opt_fpgm_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("prep")) { + } else if (table_record.table_tag == Tag("prep")) { opt_prep_slice = buffer_here; - } else if (table_record.table_tag == tag_from_str("CBLC")) { + } else if (table_record.table_tag == Tag("CBLC")) { cblc = TRY(CBLC::from_slice(buffer_here)); - } else if (table_record.table_tag == tag_from_str("CBDT")) { + } else if (table_record.table_tag == Tag("CBDT")) { cbdt = TRY(CBDT::from_slice(buffer_here)); - } else if (table_record.table_tag == tag_from_str("GPOS")) { + } else if (table_record.table_tag == Tag("GPOS")) { gpos = TRY(GPOS::from_slice(buffer_here)); } } diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp index 520c02bcb7..09d2b1dd11 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp @@ -16,16 +16,6 @@ namespace OpenType { -static u32 be_u32(u8 const* ptr) -{ - return (((u32)ptr[0]) << 24) | (((u32)ptr[1]) << 16) | (((u32)ptr[2]) << 8) | ((u32)ptr[3]); -} - -static u32 tag_from_str(char const* str) -{ - return be_u32((u8 const*)str); -} - ErrorOr Head::from_slice(ReadonlyBytes slice) { if (slice.size() < sizeof(FontHeaderTable)) @@ -576,7 +566,7 @@ Optional GPOS::glyph_kerning(u16 left_glyph_id, u16 right_glyph_id) const Optional kern_feature_offset; for (auto const& feature_record : m_feature_records) { - if (feature_record.feature_tag == tag_from_str("kern")) { + if (feature_record.feature_tag == Tag("kern")) { kern_feature_offset = feature_record.feature_offset; break; } diff --git a/Userland/Libraries/LibGfx/Font/WOFF/Font.cpp b/Userland/Libraries/LibGfx/Font/WOFF/Font.cpp index defe013699..cc01e9ab85 100644 --- a/Userland/Libraries/LibGfx/Font/WOFF/Font.cpp +++ b/Userland/Libraries/LibGfx/Font/WOFF/Font.cpp @@ -36,7 +36,7 @@ static_assert(AssertSize()); // https://www.w3.org/TR/WOFF/#TableDirectory struct [[gnu::packed]] TableDirectoryEntry { - BigEndian tag; // 4-byte sfnt table identifier. + OpenType::Tag tag; // 4-byte sfnt table identifier. BigEndian offset; // Offset to the data, from beginning of WOFF file. BigEndian comp_length; // Length of the compressed data, excluding padding. BigEndian orig_length; // Length of the uncompressed table, excluding padding. diff --git a/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp b/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp index b3533e52a1..f125ac78fd 100644 --- a/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp +++ b/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp @@ -125,19 +125,10 @@ enum class TransformationVersion { struct TableDirectoryEntry { TransformationVersion transformation_version { TransformationVersion::Version0 }; - DeprecatedString tag; + OpenType::Tag tag; u32 original_length { 0 }; Optional transform_length; - u32 tag_to_u32() const - { - VERIFY(tag.length() == 4); - return (static_cast(tag[0]) << 24) - | (static_cast(tag[1]) << 16) - | (static_cast(tag[2]) << 8) - | static_cast(tag[3]); - } - bool has_transformation() const { return transform_length.has_value(); @@ -145,70 +136,70 @@ struct TableDirectoryEntry { }; // NOTE: Any tags less than 4 characters long are padded with spaces at the end. -static constexpr Array known_tag_names = { - "cmap"sv, - "head"sv, - "hhea"sv, - "hmtx"sv, - "maxp"sv, - "name"sv, - "OS/2"sv, - "post"sv, - "cvt "sv, - "fpgm"sv, - "glyf"sv, - "loca"sv, - "prep"sv, - "CFF "sv, - "VORG"sv, - "EBDT"sv, - "EBLC"sv, - "gasp"sv, - "hdmx"sv, - "kern"sv, - "LTSH"sv, - "PCLT"sv, - "VDMX"sv, - "vhea"sv, - "vmtx"sv, - "BASE"sv, - "GDEF"sv, - "GPOS"sv, - "GSUB"sv, - "EBSC"sv, - "JSTF"sv, - "MATH"sv, - "CBDT"sv, - "CBLC"sv, - "COLR"sv, - "CPAL"sv, - "SVG "sv, - "sbix"sv, - "acnt"sv, - "avar"sv, - "bdat"sv, - "bloc"sv, - "bsln"sv, - "cvar"sv, - "fdsc"sv, - "feat"sv, - "fmtx"sv, - "fvar"sv, - "gvar"sv, - "hsty"sv, - "just"sv, - "lcar"sv, - "mort"sv, - "morx"sv, - "opbd"sv, - "prop"sv, - "trak"sv, - "Zapf"sv, - "Silf"sv, - "Glat"sv, - "Gloc"sv, - "Feat"sv, - "Sill"sv, +static constexpr Array known_tag_names = { + OpenType::Tag("cmap"), + OpenType::Tag("head"), + OpenType::Tag("hhea"), + OpenType::Tag("hmtx"), + OpenType::Tag("maxp"), + OpenType::Tag("name"), + OpenType::Tag("OS/2"), + OpenType::Tag("post"), + OpenType::Tag("cvt "), + OpenType::Tag("fpgm"), + OpenType::Tag("glyf"), + OpenType::Tag("loca"), + OpenType::Tag("prep"), + OpenType::Tag("CFF "), + OpenType::Tag("VORG"), + OpenType::Tag("EBDT"), + OpenType::Tag("EBLC"), + OpenType::Tag("gasp"), + OpenType::Tag("hdmx"), + OpenType::Tag("kern"), + OpenType::Tag("LTSH"), + OpenType::Tag("PCLT"), + OpenType::Tag("VDMX"), + OpenType::Tag("vhea"), + OpenType::Tag("vmtx"), + OpenType::Tag("BASE"), + OpenType::Tag("GDEF"), + OpenType::Tag("GPOS"), + OpenType::Tag("GSUB"), + OpenType::Tag("EBSC"), + OpenType::Tag("JSTF"), + OpenType::Tag("MATH"), + OpenType::Tag("CBDT"), + OpenType::Tag("CBLC"), + OpenType::Tag("COLR"), + OpenType::Tag("CPAL"), + OpenType::Tag("SVG "), + OpenType::Tag("sbix"), + OpenType::Tag("acnt"), + OpenType::Tag("avar"), + OpenType::Tag("bdat"), + OpenType::Tag("bloc"), + OpenType::Tag("bsln"), + OpenType::Tag("cvar"), + OpenType::Tag("fdsc"), + OpenType::Tag("feat"), + OpenType::Tag("fmtx"), + OpenType::Tag("fvar"), + OpenType::Tag("gvar"), + OpenType::Tag("hsty"), + OpenType::Tag("just"), + OpenType::Tag("lcar"), + OpenType::Tag("mort"), + OpenType::Tag("morx"), + OpenType::Tag("opbd"), + OpenType::Tag("prop"), + OpenType::Tag("trak"), + OpenType::Tag("Zapf"), + OpenType::Tag("Silf"), + OpenType::Tag("Glat"), + OpenType::Tag("Gloc"), + OpenType::Tag("Feat"), + OpenType::Tag("Sill"), }; struct CoordinateTripletEncoding { @@ -916,16 +907,13 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Seekabl if (tag_number != 0x3F) { table_directory_entry.tag = known_tag_names[tag_number]; } else { - u8 tag_buffer[5] {}; - TRY(stream.read_until_filled(Bytes { tag_buffer, 4 })); - table_directory_entry.tag = StringView { tag_buffer, 4 }; + table_directory_entry.tag = TRY(stream.read_value()); } - VERIFY(table_directory_entry.tag.length() == 4); table_directory_entry.original_length = TRY(read_uint_base_128(stream)); bool needs_to_read_transform_length = false; - if (table_directory_entry.tag.is_one_of("glyf"sv, "loca"sv)) + if (table_directory_entry.tag == OpenType::Tag("glyf") || table_directory_entry.tag == OpenType::Tag("loca")) needs_to_read_transform_length = table_directory_entry.transformation_version == TransformationVersion::Version0; else needs_to_read_transform_length = table_directory_entry.transformation_version != TransformationVersion::Version0; @@ -944,11 +932,11 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Seekabl // FIXME: Read in collection header and entries. auto glyf_table = table_entries.find_if([](TableDirectoryEntry const& entry) { - return entry.tag == "glyf"sv; + return entry.tag == OpenType::Tag("glyf"); }); auto loca_table = table_entries.find_if([](TableDirectoryEntry const& entry) { - return entry.tag == "loca"sv; + return entry.tag == OpenType::Tag("loca"); }); // "In other words, both glyf and loca tables must either be present in their transformed format or with null transform applied to both tables." @@ -991,17 +979,15 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Seekabl size_t table_directory_offset = SFNT_HEADER_SIZE + table_entry_index * SFNT_TABLE_SIZE; if (table_entry.has_transformation()) { - if (table_entry.tag == "glyf"sv) { + if (table_entry.tag == OpenType::Tag("glyf")) { auto table_stream = FixedMemoryStream(table_bytes); glyf_and_loca_buffer = TRY(create_glyf_and_loca_tables_from_transformed_glyf_table(table_stream)); - constexpr u32 GLYF_TAG = 0x676C7966; - if (font_buffer.size() < (font_buffer_offset + glyf_and_loca_buffer->glyf_table.size())) TRY(font_buffer.try_resize(font_buffer_offset + glyf_and_loca_buffer->glyf_table.size())); OpenType::TableRecord table_record { - .table_tag = GLYF_TAG, + .table_tag = table_entry.tag, .checksum = 0, // FIXME: WOFF2 does not give us the original checksum. .offset = font_buffer_offset, .length = glyf_and_loca_buffer->glyf_table.size(), @@ -1010,15 +996,14 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Seekabl font_buffer.overwrite(font_buffer_offset, glyf_and_loca_buffer->glyf_table.data(), glyf_and_loca_buffer->glyf_table.size()); font_buffer_offset += glyf_and_loca_buffer->glyf_table.size(); - } else if (table_entry.tag == "loca"sv) { + } else if (table_entry.tag == OpenType::Tag("loca")) { // FIXME: Handle loca table coming before glyf table in input? VERIFY(glyf_and_loca_buffer.has_value()); if (font_buffer.size() < (font_buffer_offset + glyf_and_loca_buffer->loca_table.size())) TRY(font_buffer.try_resize(font_buffer_offset + glyf_and_loca_buffer->loca_table.size())); - constexpr u32 LOCA_TAG = 0x6C6F6361; OpenType::TableRecord table_record { - .table_tag = LOCA_TAG, + .table_tag = table_entry.tag, .checksum = 0, // FIXME: WOFF2 does not give us the original checksum. .offset = font_buffer_offset, .length = glyf_and_loca_buffer->loca_table.size(), @@ -1027,14 +1012,14 @@ ErrorOr> Font::try_load_from_externally_owned_memory(Seekabl font_buffer.overwrite(font_buffer_offset, glyf_and_loca_buffer->loca_table.data(), glyf_and_loca_buffer->loca_table.size()); font_buffer_offset += glyf_and_loca_buffer->loca_table.size(); - } else if (table_entry.tag == "hmtx"sv) { + } else if (table_entry.tag == OpenType::Tag("hmtx")) { return Error::from_string_literal("Decoding transformed hmtx table not yet supported"); } else { return Error::from_string_literal("Unknown transformation"); } } else { OpenType::TableRecord table_record { - .table_tag = table_entry.tag_to_u32(), + .table_tag = table_entry.tag, .checksum = 0, // FIXME: WOFF2 does not give us the original checksum. .offset = font_buffer_offset, .length = length_to_read,