mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:47:45 +00:00
LibGfx: Use FourCC as OpenType::Tag type
The one deviation from the spec here is to use this in the WOFF TableDirectoryEntry's tag field. However, *not* making that a Tag made a lot of things more complicated than they need to be.
This commit is contained in:
parent
0423225290
commit
54d0aafff0
5 changed files with 97 additions and 127 deletions
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <AK/Endian.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibGfx/FourCC.h>
|
||||
|
||||
// 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<LongDateTime, 8>());
|
||||
|
||||
using Tag = BigEndian<u32>;
|
||||
using Tag = Gfx::FourCC;
|
||||
|
||||
using Offset16 = BigEndian<u16>;
|
||||
// FIXME: Offset24
|
||||
|
|
|
@ -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<NonnullRefPtr<Font>> 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<NonnullRefPtr<Font>> Font::try_load_from_externally_owned_memory(Readonl
|
|||
FixedMemoryStream stream { buffer };
|
||||
|
||||
auto tag = TRY(stream.read_value<Tag>());
|
||||
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<TTCHeaderV1>());
|
||||
|
@ -100,10 +94,10 @@ ErrorOr<NonnullRefPtr<Font>> Font::try_load_from_externally_owned_memory(Readonl
|
|||
auto offset = TRY(stream.read_value<BigEndian<u32>>());
|
||||
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<NonnullRefPtr<Font>> 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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> Head::from_slice(ReadonlyBytes slice)
|
||||
{
|
||||
if (slice.size() < sizeof(FontHeaderTable))
|
||||
|
@ -576,7 +566,7 @@ Optional<i16> GPOS::glyph_kerning(u16 left_glyph_id, u16 right_glyph_id) const
|
|||
|
||||
Optional<Offset16> 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;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ static_assert(AssertSize<Header, 44>());
|
|||
|
||||
// https://www.w3.org/TR/WOFF/#TableDirectory
|
||||
struct [[gnu::packed]] TableDirectoryEntry {
|
||||
BigEndian<u32> tag; // 4-byte sfnt table identifier.
|
||||
OpenType::Tag tag; // 4-byte sfnt table identifier.
|
||||
BigEndian<u32> offset; // Offset to the data, from beginning of WOFF file.
|
||||
BigEndian<u32> comp_length; // Length of the compressed data, excluding padding.
|
||||
BigEndian<u32> orig_length; // Length of the uncompressed table, excluding padding.
|
||||
|
|
|
@ -125,19 +125,10 @@ enum class TransformationVersion {
|
|||
|
||||
struct TableDirectoryEntry {
|
||||
TransformationVersion transformation_version { TransformationVersion::Version0 };
|
||||
DeprecatedString tag;
|
||||
OpenType::Tag tag;
|
||||
u32 original_length { 0 };
|
||||
Optional<u32> transform_length;
|
||||
|
||||
u32 tag_to_u32() const
|
||||
{
|
||||
VERIFY(tag.length() == 4);
|
||||
return (static_cast<u8>(tag[0]) << 24)
|
||||
| (static_cast<u8>(tag[1]) << 16)
|
||||
| (static_cast<u8>(tag[2]) << 8)
|
||||
| static_cast<u8>(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<StringView, 63> 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<OpenType::Tag, 63> 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<NonnullRefPtr<Font>> 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<OpenType::Tag>());
|
||||
}
|
||||
|
||||
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<NonnullRefPtr<Font>> 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<NonnullRefPtr<Font>> 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<NonnullRefPtr<Font>> 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<NonnullRefPtr<Font>> 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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue