diff --git a/Libraries/LibGfx/TTFont.cpp b/Libraries/LibGfx/TTFont.cpp index 8aab1fbd1d..6f5ec9304a 100644 --- a/Libraries/LibGfx/TTFont.cpp +++ b/Libraries/LibGfx/TTFont.cpp @@ -52,37 +52,37 @@ static u32 tag_from_str(const char *str) return be_u32((const u8*) str); } -u16 Head::units_per_em() const +u16 Font::Head::units_per_em() const { return be_u16(m_slice.offset_pointer(18)); } -i16 Head::xmin() const +i16 Font::Head::xmin() const { return be_i16(m_slice.offset_pointer(36)); } -i16 Head::ymin() const +i16 Font::Head::ymin() const { return be_i16(m_slice.offset_pointer(38)); } -i16 Head::xmax() const +i16 Font::Head::xmax() const { return be_i16(m_slice.offset_pointer(40)); } -i16 Head::ymax() const +i16 Font::Head::ymax() const { return be_i16(m_slice.offset_pointer(42)); } -u16 Head::lowest_recommended_ppem() const +u16 Font::Head::lowest_recommended_ppem() const { return be_u16(m_slice.offset_pointer(46)); } -Result Head::index_to_loc_format() const +Font::IndexToLocFormat Font::Head::index_to_loc_format() const { i16 raw = be_i16(m_slice.offset_pointer(50)); switch (raw) { @@ -91,21 +91,21 @@ Result Head::index_to_loc_format() const case 1: return IndexToLocFormat::Offset32; default: - return raw; + ASSERT_NOT_REACHED(); } } -u16 Hhea::number_of_h_metrics() const +u16 Font::Hhea::number_of_h_metrics() const { return be_u16(m_slice.offset_pointer(34)); } -u16 Maxp::num_glyphs() const +u16 Font::Maxp::num_glyphs() const { return be_u16(m_slice.offset_pointer(4)); } -GlyphHorizontalMetrics Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const +Font::GlyphHorizontalMetrics Font::Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const { ASSERT(glyph_id < m_num_glyphs); auto offset = glyph_id * 2; @@ -125,39 +125,39 @@ GlyphHorizontalMetrics Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const } } -CmapSubtablePlatform CmapSubtable::platform_id() const +Font::Cmap::Subtable::Platform Font::Cmap::Subtable::platform_id() const { switch (m_raw_platform_id) { - case 0: return CmapSubtablePlatform::Unicode; - case 1: return CmapSubtablePlatform::Macintosh; - case 3: return CmapSubtablePlatform::Windows; - case 4: return CmapSubtablePlatform::Custom; + case 0: return Platform::Unicode; + case 1: return Platform::Macintosh; + case 3: return Platform::Windows; + case 4: return Platform::Custom; default: ASSERT_NOT_REACHED(); } } -CmapSubtableFormat CmapSubtable::format() const +Font::Cmap::Subtable::Format Font::Cmap::Subtable::format() const { switch (be_u16(m_slice.offset_pointer(0))) { - case 0: return CmapSubtableFormat::ByteEncoding; - case 2: return CmapSubtableFormat::HighByte; - case 4: return CmapSubtableFormat::SegmentToDelta; - case 6: return CmapSubtableFormat::TrimmedTable; - case 8: return CmapSubtableFormat::Mixed16And32; - case 10: return CmapSubtableFormat::TrimmedArray; - case 12: return CmapSubtableFormat::SegmentedCoverage; - case 13: return CmapSubtableFormat::ManyToOneRange; - case 14: return CmapSubtableFormat::UnicodeVariationSequences; + case 0: return Format::ByteEncoding; + case 2: return Format::HighByte; + case 4: return Format::SegmentToDelta; + case 6: return Format::TrimmedTable; + case 8: return Format::Mixed16And32; + case 10: return Format::TrimmedArray; + case 12: return Format::SegmentedCoverage; + case 13: return Format::ManyToOneRange; + case 14: return Format::UnicodeVariationSequences; default: ASSERT_NOT_REACHED(); } } -u32 Cmap::num_subtables() const +u32 Font::Cmap::num_subtables() const { return be_u16(m_slice.offset_pointer(2)); } -Optional Cmap::subtable(u32 index) const +Optional Font::Cmap::subtable(u32 index) const { if (index >= num_subtables()) { return {}; @@ -168,23 +168,23 @@ Optional Cmap::subtable(u32 index) const u32 subtable_offset = be_u32(m_slice.offset_pointer(record_offset + 4)); ASSERT(subtable_offset < m_slice.size()); auto subtable_slice = ByteBuffer::wrap(m_slice.offset_pointer(subtable_offset), m_slice.size() - subtable_offset); - return CmapSubtable(move(subtable_slice), platform_id, encoding_id); + return Subtable(move(subtable_slice), platform_id, encoding_id); } // FIXME: This only handles formats 4 (SegmentToDelta) and 12 (SegmentedCoverage) for now. -u32 CmapSubtable::glyph_id_for_codepoint(u32 codepoint) const +u32 Font::Cmap::Subtable::glyph_id_for_codepoint(u32 codepoint) const { switch (format()) { - case CmapSubtableFormat::SegmentToDelta: + case Format::SegmentToDelta: return glyph_id_for_codepoint_table_4(codepoint); - case CmapSubtableFormat::SegmentedCoverage: + case Format::SegmentedCoverage: return glyph_id_for_codepoint_table_12(codepoint); default: return 0; } } -u32 CmapSubtable::glyph_id_for_codepoint_table_4(u32 codepoint) const +u32 Font::Cmap::Subtable::glyph_id_for_codepoint_table_4(u32 codepoint) const { u32 segcount_x2 = be_u16(m_slice.offset_pointer(6)); if (m_slice.size() < segcount_x2 * 4 + 16) { @@ -212,7 +212,7 @@ u32 CmapSubtable::glyph_id_for_codepoint_table_4(u32 codepoint) const return 0; } -u32 CmapSubtable::glyph_id_for_codepoint_table_12(u32 codepoint) const +u32 Font::Cmap::Subtable::glyph_id_for_codepoint_table_12(u32 codepoint) const { u32 num_groups = be_u32(m_slice.offset_pointer(12)); ASSERT(m_slice.size() >= 16 + 12 * num_groups); @@ -231,7 +231,7 @@ u32 CmapSubtable::glyph_id_for_codepoint_table_12(u32 codepoint) const return 0; } -u32 Cmap::glyph_id_for_codepoint(u32 codepoint) const +u32 Font::Cmap::glyph_id_for_codepoint(u32 codepoint) const { auto opt_subtable = subtable(m_active_index); if (!opt_subtable.has_value()) { @@ -241,6 +241,19 @@ u32 Cmap::glyph_id_for_codepoint(u32 codepoint) const return subtable.glyph_id_for_codepoint(codepoint); } +u32 Font::Loca::get_glyph_offset(u32 glyph_id) const +{ + ASSERT(glyph_id < m_num_glyphs); + switch (m_index_to_loc_format) { + case IndexToLocFormat::Offset16: + return ((u32) be_u16(m_slice.offset_pointer(glyph_id * 2))) * 2; + case IndexToLocFormat::Offset32: + return be_u32(m_slice.offset_pointer(glyph_id * 4)); + default: + ASSERT_NOT_REACHED(); + } +} + OwnPtr Font::load_from_file(const StringView& path, unsigned index) { dbg() << "path: " << path << " | index: " << index; @@ -279,78 +292,137 @@ OwnPtr Font::load_from_file(const StringView& path, unsigned index) } } -Font::Font(AK::ByteBuffer&& buffer, u32 offset) - : m_buffer(move(buffer)) - { - ASSERT(m_buffer.size() >= offset + 12); - Optional head_slice = {}; - Optional hhea_slice = {}; - Optional maxp_slice = {}; - Optional hmtx_slice = {}; - Optional cmap_slice = {}; +Font::Glyf::Glyph Font::Glyf::Glyph::simple(ByteBuffer&& slice, u16 num_contours, i16 xmin, i16 ymin, i16 xmax, i16 ymax) +{ + auto ret = Glyph(move(slice), Type::Composite); + ret.m_meta.simple = Simple { + .num_contours = num_contours, + .xmin = xmin, + .ymin = ymin, + .xmax = xmax, + .ymax = ymax, + }; + dbg() << "Loaded simple glyph:" + << "\n num_contours: " << num_contours + << "\n xmin: " << xmin + << "\n ymin: " << ymin + << "\n xmax: " << xmax + << "\n ymax: " << ymax; + return ret; +} - //auto sfnt_version = be_u32(data + offset); - auto num_tables = be_u16(m_buffer.offset_pointer(offset + 4)); - ASSERT(m_buffer.size() >= offset + 12 + num_tables * 16); +// FIXME: This is currently just a dummy. Need to add support for composite glyphs. +Font::Glyf::Glyph Font::Glyf::Glyph::composite(ByteBuffer&& slice) +{ + auto ret = Glyph(move(slice), Type::Composite); + ret.m_meta.composite = Composite(); + return ret; +} - for (auto i = 0; i < num_tables; i++) { - u32 record_offset = offset + 12 + i * 16; - u32 tag = be_u32(m_buffer.offset_pointer(record_offset)); - u32 table_offset = be_u32(m_buffer.offset_pointer(record_offset + 8)); - u32 table_length = be_u32(m_buffer.offset_pointer(record_offset + 12)); - ASSERT(m_buffer.size() >= table_offset + table_length); - auto buffer = ByteBuffer::wrap(m_buffer.offset_pointer(table_offset), table_length); - - // Get the table offsets we need. - if (tag == tag_from_str("head")) { - head_slice = move(buffer); - } else if (tag == tag_from_str("hhea")) { - hhea_slice = move(buffer); - } else if (tag == tag_from_str("maxp")) { - maxp_slice = move(buffer); - } else if (tag == tag_from_str("hmtx")) { - hmtx_slice = move(buffer); - } else if (tag == tag_from_str("cmap")) { - cmap_slice = move(buffer); - } - } - - // Check that we've got everything we need. - ASSERT(head_slice.has_value()); - ASSERT(hhea_slice.has_value()); - ASSERT(maxp_slice.has_value()); - ASSERT(hmtx_slice.has_value()); - ASSERT(cmap_slice.has_value()); - - // Load the tables. - m_head = Head(move(head_slice.value())); - m_hhea = Hhea(move(hhea_slice.value())); - m_maxp = Maxp(move(maxp_slice.value())); - m_hmtx = Hmtx(move(hmtx_slice.value()), m_maxp.num_glyphs(), m_hhea.number_of_h_metrics()); - m_cmap = Cmap(move(cmap_slice.value())); - - // Select cmap table. FIXME: Do this better. Right now, just looks for platform "Windows" - // and corresponding encoding "Unicode full repertoire", or failing that, "Unicode BMP" - for (u32 i = 0; i < m_cmap.num_subtables(); i++) { - auto opt_subtable = m_cmap.subtable(i); - if (!opt_subtable.has_value()) { - continue; - } - auto subtable = opt_subtable.value(); - if (subtable.platform_id() == CmapSubtablePlatform::Windows) { - if (subtable.encoding_id() == 10) { - m_cmap.set_active_index(i); - break; - } - if (subtable.encoding_id() == 1) { - m_cmap.set_active_index(i); - break; - } - } - } - - dbg() << "Glyph ID for 'A': " << m_cmap.glyph_id_for_codepoint('A'); - dbg() << "Glyph ID for 'B': " << m_cmap.glyph_id_for_codepoint('B'); +Font::Glyf::Glyph Font::Glyf::glyph(u32 offset) const +{ + ASSERT(m_slice.size() >= offset + 10); + i16 num_contours = be_i16(m_slice.offset_pointer(offset)); + i16 xmin = be_i16(m_slice.offset_pointer(offset + 2)); + i16 ymin = be_i16(m_slice.offset_pointer(offset + 4)); + i16 xmax = be_i16(m_slice.offset_pointer(offset + 6)); + i16 ymax = be_i16(m_slice.offset_pointer(offset + 8)); + auto slice = ByteBuffer::wrap(m_slice.offset_pointer(offset), m_slice.size() - offset); + if (num_contours < 0) { + return Glyph::composite(move(slice)); + } else { + return Glyph::simple(move(slice), num_contours, xmin, ymin, xmax, ymax); } } + +// FIXME: "loca" and "glyf" are not available for CFF fonts. +Font::Font(ByteBuffer&& buffer, u32 offset) + : m_buffer(move(buffer)) +{ + ASSERT(m_buffer.size() >= offset + 12); + Optional head_slice = {}; + Optional hhea_slice = {}; + Optional maxp_slice = {}; + Optional hmtx_slice = {}; + Optional cmap_slice = {}; + Optional loca_slice = {}; + Optional glyf_slice = {}; + + //auto sfnt_version = be_u32(data + offset); + auto num_tables = be_u16(m_buffer.offset_pointer(offset + 4)); + ASSERT(m_buffer.size() >= offset + 12 + num_tables * 16); + + for (auto i = 0; i < num_tables; i++) { + u32 record_offset = offset + 12 + i * 16; + u32 tag = be_u32(m_buffer.offset_pointer(record_offset)); + u32 table_offset = be_u32(m_buffer.offset_pointer(record_offset + 8)); + u32 table_length = be_u32(m_buffer.offset_pointer(record_offset + 12)); + ASSERT(m_buffer.size() >= table_offset + table_length); + auto buffer = ByteBuffer::wrap(m_buffer.offset_pointer(table_offset), table_length); + + // Get the table offsets we need. + if (tag == tag_from_str("head")) { + head_slice = move(buffer); + } else if (tag == tag_from_str("hhea")) { + hhea_slice = move(buffer); + } else if (tag == tag_from_str("maxp")) { + maxp_slice = move(buffer); + } else if (tag == tag_from_str("hmtx")) { + hmtx_slice = move(buffer); + } else if (tag == tag_from_str("cmap")) { + cmap_slice = move(buffer); + } else if (tag == tag_from_str("loca")) { + loca_slice = move(buffer); + } else if (tag == tag_from_str("glyf")) { + glyf_slice = move(buffer); + } + } + + // Check that we've got everything we need. + ASSERT(head_slice.has_value()); + ASSERT(hhea_slice.has_value()); + ASSERT(maxp_slice.has_value()); + ASSERT(hmtx_slice.has_value()); + ASSERT(cmap_slice.has_value()); + ASSERT(loca_slice.has_value()); + ASSERT(glyf_slice.has_value()); + + // Load the tables. + m_head = Head(move(head_slice.value())); + m_hhea = Hhea(move(hhea_slice.value())); + m_maxp = Maxp(move(maxp_slice.value())); + m_hmtx = Hmtx(move(hmtx_slice.value()), m_maxp.num_glyphs(), m_hhea.number_of_h_metrics()); + m_cmap = Cmap(move(cmap_slice.value())); + m_loca = Loca(move(loca_slice.value()), m_maxp.num_glyphs(), m_head.index_to_loc_format()); + m_glyf = Glyf(move(glyf_slice.value())); + + // Select cmap table. FIXME: Do this better. Right now, just looks for platform "Windows" + // and corresponding encoding "Unicode full repertoire", or failing that, "Unicode BMP" + for (u32 i = 0; i < m_cmap.num_subtables(); i++) { + auto opt_subtable = m_cmap.subtable(i); + if (!opt_subtable.has_value()) { + continue; + } + auto subtable = opt_subtable.value(); + if (subtable.platform_id() == Cmap::Subtable::Platform::Windows) { + if (subtable.encoding_id() == 10) { + m_cmap.set_active_index(i); + break; + } + if (subtable.encoding_id() == 1) { + m_cmap.set_active_index(i); + break; + } + } + } + + dbg() << "Glyph ID for 'A': " << m_cmap.glyph_id_for_codepoint('A'); + dbg() << "Glyph ID for 'B': " << m_cmap.glyph_id_for_codepoint('B'); + + auto gid = m_cmap.glyph_id_for_codepoint('A'); + auto glyph_offset = m_loca.get_glyph_offset(gid); + auto glyph = m_glyf.glyph(glyph_offset); +} + +} } diff --git a/Libraries/LibGfx/TTFont.h b/Libraries/LibGfx/TTFont.h index e75954c2cb..3bafedb2ca 100644 --- a/Libraries/LibGfx/TTFont.h +++ b/Libraries/LibGfx/TTFont.h @@ -28,7 +28,6 @@ #include #include -#include #include namespace Gfx { @@ -36,165 +35,231 @@ namespace TTF { class Font; -enum class IndexToLocFormat { - Offset16, - Offset32, -}; - -class Head { -private: - Head() {} - Head(ByteBuffer&& slice) - : m_slice(move(slice)) - { - ASSERT(m_slice.size() >= 54); - } - u16 units_per_em() const; - i16 xmin() const; - i16 ymin() const; - i16 xmax() const; - i16 ymax() const; - u16 lowest_recommended_ppem() const; - Result index_to_loc_format() const; - - ByteBuffer m_slice; - - friend Font; -}; - -class Hhea { -private: - Hhea() {} - Hhea(ByteBuffer&& slice) - : m_slice(move(slice)) - { - ASSERT(m_slice.size() >= 36); - } - u16 number_of_h_metrics() const; - - ByteBuffer m_slice; - - friend Font; -}; - -class Maxp { -private: - Maxp() {} - Maxp(ByteBuffer&& slice) - : m_slice(move(slice)) - { - ASSERT(m_slice.size() >= 6); - } - u16 num_glyphs() const; - - ByteBuffer m_slice; - - friend Font; -}; - -struct GlyphHorizontalMetrics { - u16 advance_width; - i16 left_side_bearing; -}; - -class Hmtx { -private: - Hmtx() {} - Hmtx(ByteBuffer&& slice, u32 num_glyphs, u32 number_of_h_metrics) - : m_slice(move(slice)) - , m_num_glyphs(num_glyphs) - , m_number_of_h_metrics(number_of_h_metrics) - { - ASSERT(m_slice.size() >= number_of_h_metrics * 2 + num_glyphs * 2); - } - GlyphHorizontalMetrics get_glyph_horizontal_metrics(u32 glyph_id) const; - - ByteBuffer m_slice; - u32 m_num_glyphs; - u32 m_number_of_h_metrics; - - friend Font; -}; - -enum class CmapSubtablePlatform { - Unicode, - Macintosh, - Windows, - Custom, -}; - -enum class CmapSubtableFormat { - ByteEncoding, - HighByte, - SegmentToDelta, - TrimmedTable, - Mixed16And32, - TrimmedArray, - SegmentedCoverage, - ManyToOneRange, - UnicodeVariationSequences, -}; - -class Cmap; - -class CmapSubtable { -public: - CmapSubtablePlatform platform_id() const; - u16 encoding_id() const { return m_encoding_id; } - CmapSubtableFormat format() const; - -private: - CmapSubtable(ByteBuffer&& slice, u16 platform_id, u16 encoding_id) - : m_slice(move(slice)) - , m_raw_platform_id(platform_id) - , m_encoding_id(encoding_id) - { - } - // Returns 0 if glyph not found. This corresponds to the "missing glyph" - u32 glyph_id_for_codepoint(u32 codepoint) const; - u32 glyph_id_for_codepoint_table_4(u32 codepoint) const; - u32 glyph_id_for_codepoint_table_12(u32 codepoint) const; - - ByteBuffer m_slice; - u16 m_raw_platform_id; - u16 m_encoding_id; - - friend Cmap; -}; - -class Cmap { -private: - Cmap() {} - Cmap(ByteBuffer&& slice) - : m_slice(move(slice)) - { - ASSERT(m_slice.size() > 4); - } - u32 num_subtables() const; - Optional subtable(u32 index) const; - void set_active_index(u32 index) { m_active_index = index; } - // Returns 0 if glyph not found. This corresponds to the "missing glyph" - u32 glyph_id_for_codepoint(u32 codepoint) const; - - ByteBuffer m_slice; - u32 m_active_index { UINT32_MAX }; - - friend Font; -}; - class Font { public: static OwnPtr load_from_file(const StringView& path, unsigned index); private: - Font(AK::ByteBuffer&& buffer, u32 offset); + enum class IndexToLocFormat { + Offset16, + Offset32, + }; - AK::ByteBuffer m_buffer; + class Head { + public: + Head() {} + Head(ByteBuffer&& slice) + : m_slice(move(slice)) + { + ASSERT(m_slice.size() >= 54); + } + u16 units_per_em() const; + i16 xmin() const; + i16 ymin() const; + i16 xmax() const; + i16 ymax() const; + u16 lowest_recommended_ppem() const; + IndexToLocFormat index_to_loc_format() const; + + private: + ByteBuffer m_slice; + }; + + class Hhea { + public: + Hhea() {} + Hhea(ByteBuffer&& slice) + : m_slice(move(slice)) + { + ASSERT(m_slice.size() >= 36); + } + u16 number_of_h_metrics() const; + + private: + ByteBuffer m_slice; + }; + + class Maxp { + public: + Maxp() {} + Maxp(ByteBuffer&& slice) + : m_slice(move(slice)) + { + ASSERT(m_slice.size() >= 6); + } + u16 num_glyphs() const; + + private: + ByteBuffer m_slice; + }; + + struct GlyphHorizontalMetrics { + u16 advance_width; + i16 left_side_bearing; + }; + + class Hmtx { + public: + Hmtx() {} + Hmtx(ByteBuffer&& slice, u32 num_glyphs, u32 number_of_h_metrics) + : m_slice(move(slice)) + , m_num_glyphs(num_glyphs) + , m_number_of_h_metrics(number_of_h_metrics) + { + ASSERT(m_slice.size() >= number_of_h_metrics * 2 + num_glyphs * 2); + } + GlyphHorizontalMetrics get_glyph_horizontal_metrics(u32 glyph_id) const; + + private: + ByteBuffer m_slice; + u32 m_num_glyphs; + u32 m_number_of_h_metrics; + }; + + class Cmap { + public: + class Subtable { + public: + enum class Platform { + Unicode, + Macintosh, + Windows, + Custom, + }; + + enum class Format { + ByteEncoding, + HighByte, + SegmentToDelta, + TrimmedTable, + Mixed16And32, + TrimmedArray, + SegmentedCoverage, + ManyToOneRange, + UnicodeVariationSequences, + }; + + Subtable(ByteBuffer&& slice, u16 platform_id, u16 encoding_id) + : m_slice(move(slice)) + , m_raw_platform_id(platform_id) + , m_encoding_id(encoding_id) + { + } + // Returns 0 if glyph not found. This corresponds to the "missing glyph" + u32 glyph_id_for_codepoint(u32 codepoint) const; + Platform platform_id() const; + u16 encoding_id() const { return m_encoding_id; } + Format format() const; + + private: + u32 glyph_id_for_codepoint_table_4(u32 codepoint) const; + u32 glyph_id_for_codepoint_table_12(u32 codepoint) const; + + ByteBuffer m_slice; + u16 m_raw_platform_id; + u16 m_encoding_id; + }; + + Cmap() {} + Cmap(ByteBuffer&& slice) + : m_slice(move(slice)) + { + ASSERT(m_slice.size() > 4); + } + + u32 num_subtables() const; + Optional subtable(u32 index) const; + void set_active_index(u32 index) { m_active_index = index; } + // Returns 0 if glyph not found. This corresponds to the "missing glyph" + u32 glyph_id_for_codepoint(u32 codepoint) const; + + private: + ByteBuffer m_slice; + u32 m_active_index { UINT32_MAX }; + }; + + class Loca { + public: + Loca() {} + Loca(ByteBuffer&& slice, u32 num_glyphs, IndexToLocFormat index_to_loc_format) + : m_slice(move(slice)) + , m_num_glyphs(num_glyphs) + , m_index_to_loc_format(index_to_loc_format) + { + switch (m_index_to_loc_format) { + case IndexToLocFormat::Offset16: + ASSERT(m_slice.size() >= m_num_glyphs * 2); + break; + case IndexToLocFormat::Offset32: + ASSERT(m_slice.size() >= m_num_glyphs * 4); + break; + } + } + u32 get_glyph_offset(u32 glyph_id) const; + + private: + ByteBuffer m_slice; + u32 m_num_glyphs; + IndexToLocFormat m_index_to_loc_format; + }; + + class Glyf { + public: + class Glyph { + public: + static Glyph simple(ByteBuffer&& slice, u16 num_contours, i16 xmin, i16 ymin, i16 xmax, i16 ymax); + static Glyph composite(ByteBuffer&& slice); // FIXME: This is currently just a dummy. Need to add support for composite glyphs. + + private: + enum class Type { + Simple, + Composite, + }; + struct Simple { + u16 num_contours; + i16 xmin; + i16 ymin; + i16 xmax; + i16 ymax; + }; + struct Composite { + }; + + Glyph(ByteBuffer&& slice, Type type) + : m_type(type) + , m_slice(move(slice)) + { + } + + Type m_type; + ByteBuffer m_slice; + union { + Simple simple; + Composite composite; + } m_meta; + }; + + Glyf() {} + Glyf(ByteBuffer&& slice) + : m_slice(move(slice)) + { + } + Glyph glyph(u32 offset) const; + + private: + ByteBuffer m_slice; + }; + + Font(ByteBuffer&& buffer, u32 offset); + + ByteBuffer m_buffer; Head m_head; Hhea m_hhea; Maxp m_maxp; Hmtx m_hmtx; Cmap m_cmap; + Loca m_loca; + Glyf m_glyf; }; }